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