Libinfo-278.0.3.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_user.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * user information (passwd) lookup
26 * Copyright (C) 1989 by NeXT, Inc.
27 */
28 #include <stdlib.h>
29 #include <mach/mach.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <netinet/in.h>
34 #include <pthread.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include "lu_utils.h"
38 #include "lu_overrides.h"
39
40 #define USER_CACHE_SIZE 10
41
42 static pthread_mutex_t _user_cache_lock = PTHREAD_MUTEX_INITIALIZER;
43 static void *_user_cache[USER_CACHE_SIZE] = { NULL };
44 static unsigned int _user_cache_index = 0;
45 static unsigned int _user_cache_init = 0;
46
47 static pthread_mutex_t _user_lock = PTHREAD_MUTEX_INITIALIZER;
48
49 #define PW_GET_NAME 1
50 #define PW_GET_UID 2
51 #define PW_GET_ENT 3
52
53 #define ENTRY_SIZE sizeof(struct passwd)
54 #define ENTRY_KEY _li_data_key_user
55
56 __private_extern__ struct passwd *LI_files_getpwent();
57 __private_extern__ struct passwd *LI_files_getpwnam(const char *name);
58 __private_extern__ struct passwd *LI_files_getpwuid(uid_t uid);
59 __private_extern__ void LI_files_setpwent();
60 __private_extern__ void LI_files_endpwent();
61
62 static struct passwd *
63 copy_user(struct passwd *in)
64 {
65 if (in == NULL) return NULL;
66
67 return (struct passwd *)LI_ils_create("ss44LssssL", in->pw_name, in->pw_passwd, in->pw_uid, in->pw_gid, in->pw_change, in->pw_class, in->pw_gecos, in->pw_dir, in->pw_shell, in->pw_expire);
68 }
69
70 /*
71 * Extract the next user entry from a kvarray.
72 */
73 static void *
74 extract_user(kvarray_t *in)
75 {
76 struct passwd tmp;
77 uint32_t d, k, kcount;
78
79 if (in == NULL) return NULL;
80
81 d = in->curr;
82 in->curr++;
83
84 if (d >= in->count) return NULL;
85
86 memset(&tmp, 0, ENTRY_SIZE);
87
88 tmp.pw_uid = -2;
89 tmp.pw_gid = -2;
90
91 kcount = in->dict[d].kcount;
92
93 for (k = 0; k < kcount; k++)
94 {
95 if (!strcmp(in->dict[d].key[k], "pw_name"))
96 {
97 if (tmp.pw_name != NULL) continue;
98 if (in->dict[d].vcount[k] == 0) continue;
99
100 tmp.pw_name = (char *)in->dict[d].val[k][0];
101 }
102 else if (!strcmp(in->dict[d].key[k], "pw_passwd"))
103 {
104 if (tmp.pw_passwd != NULL) continue;
105 if (in->dict[d].vcount[k] == 0) continue;
106
107 tmp.pw_passwd = (char *)in->dict[d].val[k][0];
108 }
109 else if (!strcmp(in->dict[d].key[k], "pw_uid"))
110 {
111 if (in->dict[d].vcount[k] == 0) continue;
112 tmp.pw_uid = atoi(in->dict[d].val[k][0]);
113 }
114 else if (!strcmp(in->dict[d].key[k], "pw_gid"))
115 {
116 if (in->dict[d].vcount[k] == 0) continue;
117 tmp.pw_gid = atoi(in->dict[d].val[k][0]);
118 }
119 else if (!strcmp(in->dict[d].key[k], "pw_change"))
120 {
121 if (in->dict[d].vcount[k] == 0) continue;
122 tmp.pw_change = atol(in->dict[d].val[k][0]);
123 }
124 else if (!strcmp(in->dict[d].key[k], "pw_expire"))
125 {
126 if (in->dict[d].vcount[k] == 0) continue;
127 tmp.pw_expire = atol(in->dict[d].val[k][0]);
128 }
129 else if (!strcmp(in->dict[d].key[k], "pw_class"))
130 {
131 if (tmp.pw_class != NULL) continue;
132 if (in->dict[d].vcount[k] == 0) continue;
133
134 tmp.pw_class = (char *)in->dict[d].val[k][0];
135 }
136 else if (!strcmp(in->dict[d].key[k], "pw_gecos"))
137 {
138 if (tmp.pw_gecos != NULL) continue;
139 if (in->dict[d].vcount[k] == 0) continue;
140
141 tmp.pw_gecos = (char *)in->dict[d].val[k][0];
142 }
143 else if (!strcmp(in->dict[d].key[k], "pw_dir"))
144 {
145 if (tmp.pw_dir != NULL) continue;
146 if (in->dict[d].vcount[k] == 0) continue;
147
148 tmp.pw_dir = (char *)in->dict[d].val[k][0];
149 }
150 else if (!strcmp(in->dict[d].key[k], "pw_shell"))
151 {
152 if (tmp.pw_shell != NULL) continue;
153 if (in->dict[d].vcount[k] == 0) continue;
154
155 tmp.pw_shell = (char *)in->dict[d].val[k][0];
156 }
157 }
158
159 if (tmp.pw_name == NULL) tmp.pw_name = "";
160 if (tmp.pw_passwd == NULL) tmp.pw_passwd = "";
161 if (tmp.pw_class == NULL) tmp.pw_class = "";
162 if (tmp.pw_gecos == NULL) tmp.pw_gecos = "";
163 if (tmp.pw_dir == NULL) tmp.pw_dir = "";
164 if (tmp.pw_shell == NULL) tmp.pw_shell = "";
165
166 return copy_user(&tmp);
167 }
168
169 static int
170 copy_user_r(struct passwd *in, struct passwd *out, char *buffer, int buflen)
171 {
172 int hsize;
173 char *bp;
174
175 if (in == NULL) return -1;
176 if (out == NULL) return -1;
177
178 if (buffer == NULL) buflen = 0;
179
180 /* Calculate size of input */
181 hsize = 0;
182 if (in->pw_name != NULL) hsize += (strlen(in->pw_name) + 1);
183 if (in->pw_passwd != NULL) hsize += (strlen(in->pw_passwd) + 1);
184 if (in->pw_class != NULL) hsize += (strlen(in->pw_class) + 1);
185 if (in->pw_gecos != NULL) hsize += (strlen(in->pw_gecos) + 1);
186 if (in->pw_dir != NULL) hsize += (strlen(in->pw_dir) + 1);
187 if (in->pw_shell != NULL) hsize += (strlen(in->pw_shell) + 1);
188
189 /* Check buffer space */
190 if (hsize > buflen) return -1;
191
192 /* Copy result into caller's struct passwd, using buffer for memory */
193 bp = buffer;
194
195 out->pw_name = NULL;
196 if (in->pw_name != NULL)
197 {
198 out->pw_name = bp;
199 hsize = strlen(in->pw_name) + 1;
200 memmove(bp, in->pw_name, hsize);
201 bp += hsize;
202 }
203
204 out->pw_passwd = NULL;
205 if (in->pw_passwd != NULL)
206 {
207 out->pw_passwd = bp;
208 hsize = strlen(in->pw_passwd) + 1;
209 memmove(bp, in->pw_passwd, hsize);
210 bp += hsize;
211 }
212
213 out->pw_uid = in->pw_uid;
214
215 out->pw_gid = in->pw_gid;
216
217 out->pw_change = in->pw_change;
218
219 out->pw_class = NULL;
220 if (in->pw_class != NULL)
221 {
222 out->pw_class = bp;
223 hsize = strlen(in->pw_class) + 1;
224 memmove(bp, in->pw_class, hsize);
225 bp += hsize;
226 }
227
228 out->pw_gecos = NULL;
229 if (in->pw_gecos != NULL)
230 {
231 out->pw_gecos = bp;
232 hsize = strlen(in->pw_gecos) + 1;
233 memmove(bp, in->pw_gecos, hsize);
234 bp += hsize;
235 }
236
237 out->pw_dir = NULL;
238 if (in->pw_dir != NULL)
239 {
240 out->pw_dir = bp;
241 hsize = strlen(in->pw_dir) + 1;
242 memmove(bp, in->pw_dir, hsize);
243 bp += hsize;
244 }
245
246 out->pw_shell = NULL;
247 if (in->pw_shell != NULL)
248 {
249 out->pw_shell = bp;
250 hsize = strlen(in->pw_shell) + 1;
251 memmove(bp, in->pw_shell, hsize);
252 bp += hsize;
253 }
254
255 out->pw_expire = in->pw_expire;
256
257 return 0;
258 }
259
260 static void
261 cache_user(struct passwd *pw)
262 {
263 struct passwd *pwcache;
264
265 if (pw == NULL) return;
266
267 pthread_mutex_lock(&_user_cache_lock);
268
269 pwcache = copy_user(pw);
270
271 if (_user_cache[_user_cache_index] != NULL) LI_ils_free(_user_cache[_user_cache_index], ENTRY_SIZE);
272
273 _user_cache[_user_cache_index] = pwcache;
274 _user_cache_index = (_user_cache_index + 1) % USER_CACHE_SIZE;
275
276 _user_cache_init = 1;
277
278 pthread_mutex_unlock(&_user_cache_lock);
279 }
280
281 static int
282 user_cache_check()
283 {
284 uint32_t i, status;
285
286 /* don't consult cache if it has not been initialized */
287 if (_user_cache_init == 0) return 1;
288
289 status = LI_L1_cache_check(ENTRY_KEY);
290
291 /* don't consult cache if it is disabled or if we can't validate */
292 if ((status == LI_L1_CACHE_DISABLED) || (status == LI_L1_CACHE_FAILED)) return 1;
293
294 /* return 0 if cache is OK */
295 if (status == LI_L1_CACHE_OK) return 0;
296
297 /* flush cache */
298 pthread_mutex_lock(&_user_cache_lock);
299
300 for (i = 0; i < USER_CACHE_SIZE; i++)
301 {
302 LI_ils_free(_user_cache[i], ENTRY_SIZE);
303 _user_cache[i] = NULL;
304 }
305
306 _user_cache_index = 0;
307
308 pthread_mutex_unlock(&_user_cache_lock);
309
310 /* don't consult cache - it's now empty */
311 return 1;
312 }
313
314 static struct passwd *
315 cache_getpwnam(const char *name)
316 {
317 uint32_t i;
318 struct passwd *pw, *res;
319
320 if (name == NULL) return NULL;
321 if (user_cache_check() != 0) return NULL;
322
323 pthread_mutex_lock(&_user_cache_lock);
324
325 for (i = 0; i < USER_CACHE_SIZE; i++)
326 {
327 pw = (struct passwd *)_user_cache[i];
328 if (pw == NULL) continue;
329 if (pw->pw_name == NULL) continue;
330
331 if (!strcmp(name, pw->pw_name))
332 {
333 res = copy_user(pw);
334 pthread_mutex_unlock(&_user_cache_lock);
335 return res;
336 }
337 }
338
339 pthread_mutex_unlock(&_user_cache_lock);
340 return NULL;
341 }
342
343 static struct passwd *
344 cache_getpwuid(uid_t uid)
345 {
346 uint32_t i;
347 struct passwd *pw, *res;
348
349 if (user_cache_check() != 0) return NULL;
350
351 pthread_mutex_lock(&_user_cache_lock);
352
353 for (i = 0; i < USER_CACHE_SIZE; i++)
354 {
355 pw = (struct passwd *)_user_cache[i];
356 if (pw == NULL) continue;
357
358 if (uid == pw->pw_uid)
359 {
360 res = copy_user(pw);
361 pthread_mutex_unlock(&_user_cache_lock);
362 return res;
363 }
364 }
365
366 pthread_mutex_unlock(&_user_cache_lock);
367
368 return NULL;
369 }
370
371 static struct passwd *
372 ds_getpwuid(uid_t uid)
373 {
374 static int proc = -1;
375 char val[16];
376
377 snprintf(val, sizeof(val), "%d", (int)uid);
378 return (struct passwd *)LI_getone("getpwuid", &proc, extract_user, "uid", val);
379 }
380
381 static struct passwd *
382 ds_getpwnam(const char *name)
383 {
384 static int proc = -1;
385
386 return (struct passwd *)LI_getone("getpwnam", &proc, extract_user, "login", name);
387 }
388
389 static void
390 ds_endpwent(void)
391 {
392 LI_data_free_kvarray(LI_data_find_key(ENTRY_KEY));
393 }
394
395 static int
396 ds_setpwent(void)
397 {
398 ds_endpwent();
399 return 1;
400 }
401
402 static struct passwd *
403 ds_getpwent()
404 {
405 static int proc = -1;
406
407 return (struct passwd *)LI_getent("getpwent", &proc, extract_user, ENTRY_KEY, ENTRY_SIZE);
408 }
409
410 static struct passwd *
411 getpw_internal(const char *name, uid_t uid, int source)
412 {
413 struct passwd *res;
414 int add_to_cache;
415
416 add_to_cache = 0;
417 res = NULL;
418
419 switch (source)
420 {
421 case PW_GET_NAME:
422 res = cache_getpwnam(name);
423 break;
424 case PW_GET_UID:
425 res = cache_getpwuid(uid);
426 break;
427 default: res = NULL;
428 }
429
430 if (res != NULL)
431 {
432 }
433 else if (_ds_running())
434 {
435 switch (source)
436 {
437 case PW_GET_NAME:
438 res = ds_getpwnam(name);
439 break;
440 case PW_GET_UID:
441 res = ds_getpwuid(uid);
442 break;
443 case PW_GET_ENT:
444 res = ds_getpwent();
445 break;
446 default: res = NULL;
447 }
448
449 if (res != NULL) add_to_cache = 1;
450 }
451 else
452 {
453 pthread_mutex_lock(&_user_lock);
454
455 switch (source)
456 {
457 case PW_GET_NAME:
458 res = copy_user(LI_files_getpwnam(name));
459 break;
460 case PW_GET_UID:
461 res = copy_user(LI_files_getpwuid(uid));
462 break;
463 case PW_GET_ENT:
464 res = copy_user(LI_files_getpwent());
465 break;
466 default: res = NULL;
467 }
468
469 pthread_mutex_unlock(&_user_lock);
470 }
471
472 if (add_to_cache == 1) cache_user(res);
473
474 return res;
475 }
476
477 static struct passwd *
478 getpw(const char *name, uid_t uid, int source)
479 {
480 struct passwd *res = NULL;
481 struct li_thread_info *tdata;
482
483 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
484 if (tdata == NULL) return NULL;
485
486 res = getpw_internal(name, uid, source);
487
488 LI_data_recycle(tdata, res, ENTRY_SIZE);
489 return (struct passwd *)tdata->li_entry;
490 }
491
492 static int
493 getpw_r(const char *name, uid_t uid, int source, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
494 {
495 struct passwd *res = NULL;
496 int status;
497
498 *result = NULL;
499
500 res = getpw_internal(name, uid, source);
501 if (res == NULL) return 0;
502
503 status = copy_user_r(res, pwd, buffer, bufsize);
504
505 LI_ils_free(res, ENTRY_SIZE);
506
507 if (status != 0) return ERANGE;
508
509 *result = pwd;
510 return 0;
511 }
512
513 struct passwd *
514 getpwnam(const char *name)
515 {
516 return getpw(name, -2, PW_GET_NAME);
517 }
518
519 struct passwd *
520 getpwuid(uid_t uid)
521 {
522 return getpw(NULL, uid, PW_GET_UID);
523 }
524
525 struct passwd *
526 getpwent(void)
527 {
528 return getpw(NULL, -2, PW_GET_ENT);
529 }
530
531 void
532 setpwent(void)
533 {
534 if (_ds_running()) ds_setpwent();
535 else LI_files_setpwent();
536 }
537
538 void
539 endpwent(void)
540 {
541 if (_ds_running()) ds_endpwent();
542 else LI_files_endpwent();
543 }
544
545 int
546 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
547 {
548 return getpw_r(name, -2, PW_GET_NAME, pwd, buffer, bufsize, result);
549 }
550
551 int
552 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
553 {
554 return getpw_r(NULL, uid, PW_GET_UID, pwd, buffer, bufsize, result);
555 }