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 <shadow.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 <AutoDeleter.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 sShadowPwdDBReply; 29 static spwd** sShadowPwdEntries = NULL; 30 static size_t sShadowPwdEntryCount = 0; 31 static size_t sIterationIndex = 0; 32 33 static struct spwd sShadowPwdBuffer; 34 static char sShadowPwdStringBuffer[MAX_SHADOW_PWD_BUFFER_SIZE]; 35 36 37 static status_t 38 init_shadow_pwd_db() 39 { 40 if (sShadowPwdEntries != NULL) 41 return B_OK; 42 43 // ask the registrar 44 KMessage message(BPrivate::B_REG_GET_SHADOW_PASSWD_DB); 45 status_t error = BPrivate::send_authentication_request_to_registrar(message, 46 sShadowPwdDBReply); 47 if (error != B_OK) 48 return error; 49 50 // unpack the reply 51 int32 count; 52 spwd** entries; 53 int32 numBytes; 54 if ((error = sShadowPwdDBReply.FindInt32("count", &count)) != B_OK 55 || (error = sShadowPwdDBReply.FindData("entries", B_RAW_TYPE, 56 (const void**)&entries, &numBytes)) != B_OK) { 57 return error; 58 } 59 60 // relocate the entries 61 addr_t baseAddress = (addr_t)entries; 62 for (int32 i = 0; i < count; i++) { 63 spwd* entry = relocate_pointer(baseAddress, entries[i]); 64 relocate_pointer(baseAddress, entry->sp_namp); 65 relocate_pointer(baseAddress, entry->sp_pwdp); 66 } 67 68 sShadowPwdEntries = entries; 69 sShadowPwdEntryCount = count; 70 71 return B_OK; 72 } 73 74 75 // #pragma mark - 76 77 78 struct spwd* 79 getspent(void) 80 { 81 struct spwd* result = NULL; 82 int status = getspent_r(&sShadowPwdBuffer, sShadowPwdStringBuffer, 83 sizeof(sShadowPwdStringBuffer), &result); 84 if (status != 0) 85 errno = status; 86 return result; 87 } 88 89 90 int 91 getspent_r(struct spwd* spwd, char* buffer, size_t bufferSize, 92 struct spwd** _result) 93 { 94 UserGroupLocker _; 95 96 int status = B_NO_MEMORY; 97 98 *_result = NULL; 99 100 if ((status = init_shadow_pwd_db()) == B_OK) { 101 if (sIterationIndex >= sShadowPwdEntryCount) 102 return ENOENT; 103 104 status = BPrivate::copy_shadow_pwd_to_buffer( 105 sShadowPwdEntries[sIterationIndex], spwd, buffer, bufferSize); 106 107 if (status == B_OK) { 108 sIterationIndex++; 109 *_result = spwd; 110 } 111 } 112 113 return status; 114 } 115 116 117 void 118 setspent(void) 119 { 120 UserGroupLocker _; 121 122 sIterationIndex = 0; 123 } 124 125 126 void 127 endspent(void) 128 { 129 UserGroupLocker locker; 130 131 sShadowPwdDBReply.Unset(); 132 sShadowPwdEntries = NULL; 133 sShadowPwdEntryCount = 0; 134 sIterationIndex = 0; 135 } 136 137 138 struct spwd * 139 getspnam(const char *name) 140 { 141 struct spwd* result = NULL; 142 int status = getspnam_r(name, &sShadowPwdBuffer, sShadowPwdStringBuffer, 143 sizeof(sShadowPwdStringBuffer), &result); 144 if (status != 0) 145 errno = status; 146 return result; 147 } 148 149 150 int 151 getspnam_r(const char *name, struct spwd *spwd, char *buffer, 152 size_t bufferSize, struct spwd **_result) 153 { 154 *_result = NULL; 155 156 KMessage message(BPrivate::B_REG_GET_USER); 157 message.AddString("name", name); 158 message.AddBool("shadow", true); 159 160 KMessage reply; 161 status_t error = BPrivate::send_authentication_request_to_registrar(message, 162 reply); 163 if (error != B_OK) 164 return error; 165 166 const char* password; 167 int32 lastChanged; 168 int32 min; 169 int32 max; 170 int32 warn; 171 int32 inactive; 172 int32 expiration; 173 int32 flags; 174 175 if ((error = reply.FindString("name", &name)) != B_OK 176 || (error = reply.FindString("shadow password", &password)) != B_OK 177 || (error = reply.FindInt32("last changed", &lastChanged)) != B_OK 178 || (error = reply.FindInt32("min", &min)) != B_OK 179 || (error = reply.FindInt32("max", &max)) != B_OK 180 || (error = reply.FindInt32("warn", &warn)) != B_OK 181 || (error = reply.FindInt32("inactive", &inactive)) != B_OK 182 || (error = reply.FindInt32("expiration", &expiration)) != B_OK 183 || (error = reply.FindInt32("flags", &flags)) != B_OK) { 184 return error; 185 } 186 187 error = BPrivate::copy_shadow_pwd_to_buffer(name, password, lastChanged, 188 min, max, warn, inactive, expiration, flags, spwd, buffer, bufferSize); 189 if (error == B_OK) 190 *_result = spwd; 191 192 return error; 193 } 194 195 196 struct spwd* 197 sgetspent(const char* line) 198 { 199 struct spwd* result = NULL; 200 int status = sgetspent_r(line, &sShadowPwdBuffer, sShadowPwdStringBuffer, 201 sizeof(sShadowPwdStringBuffer), &result); 202 if (status != 0) 203 errno = status; 204 return result; 205 } 206 207 208 int 209 sgetspent_r(const char* _line, struct spwd *spwd, char *buffer, 210 size_t bufferSize, struct spwd** _result) 211 { 212 *_result = NULL; 213 214 if (_line == NULL) 215 return B_BAD_VALUE; 216 217 // we need a mutable copy of the line 218 char* line = strdup(_line); 219 if (line == NULL) 220 return B_NO_MEMORY; 221 MemoryDeleter _(line); 222 223 char* name; 224 char* password; 225 int lastChanged; 226 int min; 227 int max; 228 int warn; 229 int inactive; 230 int expiration; 231 int flags; 232 233 status_t status = BPrivate::parse_shadow_pwd_line(line, name, password, 234 lastChanged, min, max, warn, inactive, expiration, flags); 235 if (status != B_OK) 236 return status; 237 238 status = BPrivate::copy_shadow_pwd_to_buffer(name, password, lastChanged, 239 min, max, warn, inactive, expiration, flags, spwd, buffer, bufferSize); 240 if (status != B_OK) 241 return status; 242 243 *_result = spwd; 244 return 0; 245 } 246 247 248 struct spwd* 249 fgetspent(FILE* file) 250 { 251 struct spwd* result = NULL; 252 int status = fgetspent_r(file, &sShadowPwdBuffer, sShadowPwdStringBuffer, 253 sizeof(sShadowPwdStringBuffer), &result); 254 if (status != 0) 255 errno = status; 256 return result; 257 } 258 259 260 int 261 fgetspent_r(FILE* file, struct spwd* spwd, char* buffer, size_t bufferSize, 262 struct spwd** _result) 263 { 264 *_result = NULL; 265 266 // read a line 267 char lineBuffer[LINE_MAX + 1]; 268 errno = 0; 269 char* line = fgets(lineBuffer, sizeof(lineBuffer), file); 270 if (line == NULL) { 271 if (errno != 0) 272 return errno; 273 return ENOENT; 274 } 275 276 return sgetspent_r(line, spwd, buffer, bufferSize, _result); 277 } 278