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 24using BPrivate::UserGroupLocker; 25using BPrivate::relocate_pointer; 26 27 28static KMessage sPasswdDBReply; 29static passwd** sPasswdEntries = NULL; 30static size_t sPasswdEntryCount = 0; 31static size_t sIterationIndex = 0; 32 33static struct passwd sPasswdBuffer; 34static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE]; 35 36 37static status_t 38query_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 == ENOENT ? B_OK : 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 81static status_t 82init_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 125struct passwd* 126getpwent(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 137int 138getpwent_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 164void 165setpwent(void) 166{ 167 UserGroupLocker _; 168 169 sIterationIndex = 0; 170} 171 172 173void 174endpwent(void) 175{ 176 UserGroupLocker locker; 177 178 sPasswdDBReply.Unset(); 179 sPasswdEntries = NULL; 180 sPasswdEntryCount = 0; 181 sIterationIndex = 0; 182} 183 184 185struct passwd * 186getpwnam(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 197int 198getpwnam_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 205struct passwd * 206getpwuid(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 217int 218getpwuid_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