1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <pwd.h> 7 8 #include <errno.h> 9 #include <string.h> 10 #include <unistd.h> 11 12 #include <new> 13 14 #include <OS.h> 15 16 #include <libroot_private.h> 17 #include <RegistrarDefs.h> 18 #include <user_group.h> 19 20 #include <util/KMessage.h> 21 22 23 using BPrivate::UserGroupLocker; 24 using BPrivate::relocate_pointer; 25 26 27 static KMessage sPasswdDBReply; 28 static passwd** sPasswdEntries = NULL; 29 static size_t sPasswdEntryCount = 0; 30 static size_t sIterationIndex = 0; 31 32 static struct passwd sPasswdBuffer; 33 static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE]; 34 35 36 static status_t 37 query_passwd_entry(const char* name, uid_t _uid, struct passwd *passwd, 38 char *buffer, size_t bufferSize, struct passwd **_result) 39 { 40 *_result = NULL; 41 42 KMessage message(BPrivate::B_REG_GET_USER); 43 if (name) 44 message.AddString("name", name); 45 else 46 message.AddInt32("uid", _uid); 47 48 KMessage reply; 49 status_t error = BPrivate::send_authentication_request_to_registrar(message, 50 reply); 51 if (error != B_OK) 52 return error; 53 54 int32 uid; 55 int32 gid; 56 const char* password; 57 const char* home; 58 const char* shell; 59 const char* realName; 60 61 if ((error = reply.FindInt32("uid", &uid)) != B_OK 62 || (error = reply.FindInt32("gid", &gid)) != B_OK 63 || (error = reply.FindString("name", &name)) != B_OK 64 || (error = reply.FindString("password", &password)) != B_OK 65 || (error = reply.FindString("home", &home)) != B_OK 66 || (error = reply.FindString("shell", &shell)) != B_OK 67 || (error = reply.FindString("real name", &realName)) != B_OK) { 68 return error; 69 } 70 71 error = BPrivate::copy_passwd_to_buffer(name, password, uid, gid, home, 72 shell, realName, passwd, buffer, bufferSize); 73 if (error == B_OK) 74 *_result = passwd; 75 76 return error; 77 } 78 79 80 static status_t 81 init_passwd_db() 82 { 83 if (sPasswdEntries != NULL) 84 return B_OK; 85 86 // ask the registrar 87 KMessage message(BPrivate::B_REG_GET_PASSWD_DB); 88 status_t error = BPrivate::send_authentication_request_to_registrar(message, 89 sPasswdDBReply); 90 if (error != B_OK) 91 return error; 92 93 // unpack the reply 94 int32 count; 95 passwd** entries; 96 int32 numBytes; 97 if ((error = sPasswdDBReply.FindInt32("count", &count)) != B_OK 98 || (error = sPasswdDBReply.FindData("entries", B_RAW_TYPE, 99 (const void**)&entries, &numBytes)) != B_OK) { 100 return error; 101 } 102 103 // relocate the entries 104 addr_t baseAddress = (addr_t)entries; 105 for (int32 i = 0; i < count; i++) { 106 passwd* entry = relocate_pointer(baseAddress, entries[i]); 107 relocate_pointer(baseAddress, entry->pw_name); 108 relocate_pointer(baseAddress, entry->pw_passwd); 109 relocate_pointer(baseAddress, entry->pw_dir); 110 relocate_pointer(baseAddress, entry->pw_shell); 111 relocate_pointer(baseAddress, entry->pw_gecos); 112 } 113 114 sPasswdEntries = entries; 115 sPasswdEntryCount = count; 116 117 return B_OK; 118 } 119 120 121 // #pragma mark - 122 123 124 struct passwd* 125 getpwent(void) 126 { 127 struct passwd* result = NULL; 128 int status = getpwent_r(&sPasswdBuffer, sPasswdStringBuffer, 129 sizeof(sPasswdStringBuffer), &result); 130 if (status != 0) 131 errno = status; 132 return result; 133 } 134 135 136 int 137 getpwent_r(struct passwd* passwd, char* buffer, size_t bufferSize, 138 struct passwd** _result) 139 { 140 UserGroupLocker _; 141 142 int status = B_NO_MEMORY; 143 144 *_result = NULL; 145 146 if ((status = init_passwd_db()) == B_OK) { 147 if (sIterationIndex >= sPasswdEntryCount) 148 return ENOENT; 149 150 status = BPrivate::copy_passwd_to_buffer( 151 sPasswdEntries[sIterationIndex], passwd, buffer, bufferSize); 152 153 if (status == B_OK) { 154 sIterationIndex++; 155 *_result = passwd; 156 } 157 } 158 159 return status; 160 } 161 162 163 void 164 setpwent(void) 165 { 166 UserGroupLocker _; 167 168 sIterationIndex = 0; 169 } 170 171 172 void 173 endpwent(void) 174 { 175 UserGroupLocker locker; 176 177 sPasswdDBReply.Unset(); 178 sPasswdEntries = NULL; 179 sPasswdEntryCount = 0; 180 sIterationIndex = 0; 181 } 182 183 184 struct passwd * 185 getpwnam(const char *name) 186 { 187 struct passwd* result = NULL; 188 int status = getpwnam_r(name, &sPasswdBuffer, sPasswdStringBuffer, 189 sizeof(sPasswdStringBuffer), &result); 190 if (status != 0) 191 errno = status; 192 return result; 193 } 194 195 196 int 197 getpwnam_r(const char *name, struct passwd *passwd, char *buffer, 198 size_t bufferSize, struct passwd **_result) 199 { 200 return query_passwd_entry(name, 0, passwd, buffer, bufferSize, _result); 201 } 202 203 204 struct passwd * 205 getpwuid(uid_t uid) 206 { 207 struct passwd* result = NULL; 208 int status = getpwuid_r(uid, &sPasswdBuffer, sPasswdStringBuffer, 209 sizeof(sPasswdStringBuffer), &result); 210 if (status != 0) 211 errno = status; 212 return result; 213 } 214 215 216 int 217 getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer, 218 size_t bufferSize, struct passwd **_result) 219 { 220 return query_passwd_entry(NULL, uid, passwd, buffer, bufferSize, _result); 221 } 222