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