Libinfo-173.1.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 <rpc/types.h>
33 #include <rpc/xdr.h>
34 #include <pwd.h>
35 #include <netinet/in.h>
36 #include <pthread.h>
37 #include <unistd.h>
38
39 #include "_lu_types.h"
40 #include "lookup.h"
41 #include "lu_utils.h"
42 #include "lu_overrides.h"
43
44 #define USER_CACHE_SIZE 10
45 #define DEFAULT_USER_CACHE_TTL 10
46
47 static pthread_mutex_t _user_cache_lock = PTHREAD_MUTEX_INITIALIZER;
48 static void *_user_cache[USER_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
49 static unsigned int _user_cache_best_before[USER_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
50 static unsigned int _user_cache_index = 0;
51 static unsigned int _user_cache_ttl = DEFAULT_USER_CACHE_TTL;
52
53 static pthread_mutex_t _user_lock = PTHREAD_MUTEX_INITIALIZER;
54
55 #define PW_GET_NAME 1
56 #define PW_GET_UID 2
57 #define PW_GET_ENT 3
58
59 static void
60 free_user_data(struct passwd *p)
61 {
62 if (p == NULL) return;
63
64 if (p->pw_name != NULL) free(p->pw_name);
65 if (p->pw_passwd != NULL) free(p->pw_passwd);
66 if (p->pw_class != NULL) free(p->pw_class);
67 if (p->pw_gecos != NULL) free(p->pw_gecos);
68 if (p->pw_dir != NULL) free(p->pw_dir);
69 if (p->pw_shell != NULL) free(p->pw_shell);
70 }
71
72 static void
73 free_user(struct passwd *p)
74 {
75 if (p == NULL) return;
76 free_user_data(p);
77 free(p);
78 }
79
80 static void
81 free_lu_thread_info_user(void *x)
82 {
83 struct lu_thread_info *tdata;
84
85 if (x == NULL) return;
86
87 tdata = (struct lu_thread_info *)x;
88
89 if (tdata->lu_entry != NULL)
90 {
91 free_user((struct passwd *)tdata->lu_entry);
92 tdata->lu_entry = NULL;
93 }
94
95 _lu_data_free_vm_xdr(tdata);
96
97 free(tdata);
98 }
99
100 static struct passwd *
101 extract_user(XDR *xdr)
102 {
103 int i, j, nvals, nkeys, status;
104 char *key, **vals;
105 struct passwd *p;
106
107 if (xdr == NULL) return NULL;
108
109 if (!xdr_int(xdr, &nkeys)) return NULL;
110
111 p = (struct passwd *)calloc(1, sizeof(struct passwd));
112
113 p->pw_uid = -2;
114 p->pw_gid = -2;
115
116 for (i = 0; i < nkeys; i++)
117 {
118 key = NULL;
119 vals = NULL;
120 nvals = 0;
121
122 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
123 if (status < 0)
124 {
125 free_user(p);
126 return NULL;
127 }
128
129 if (nvals == 0)
130 {
131 free(key);
132 continue;
133 }
134
135 j = 0;
136
137 if ((p->pw_name == NULL) && (!strcmp("name", key)))
138 {
139 p->pw_name = vals[0];
140 j = 1;
141 }
142 else if ((p->pw_passwd == NULL) && (!strcmp("passwd", key)))
143 {
144 p->pw_passwd = vals[0];
145 j = 1;
146 }
147 else if ((p->pw_class == NULL) && (!strcmp("class", key)))
148 {
149 p->pw_class = vals[0];
150 j = 1;
151 }
152 else if ((p->pw_gecos == NULL) && (!strcmp("realname", key)))
153 {
154 p->pw_gecos = vals[0];
155 j = 1;
156 }
157 else if ((p->pw_dir == NULL) && (!strcmp("home", key)))
158 {
159 p->pw_dir = vals[0];
160 j = 1;
161 }
162 else if ((p->pw_shell == NULL) && (!strcmp("shell", key)))
163 {
164 p->pw_shell = vals[0];
165 j = 1;
166 }
167 else if ((p->pw_uid == (uid_t)-2) && (!strcmp("uid", key)))
168 {
169 p->pw_uid = atoi(vals[0]);
170 if ((p->pw_uid == 0) && (strcmp(vals[0], "0"))) p->pw_uid = -2;
171 }
172 else if ((p->pw_gid == (gid_t)-2) && (!strcmp("gid", key)))
173 {
174 p->pw_gid = atoi(vals[0]);
175 if ((p->pw_gid == 0) && (strcmp(vals[0], "0"))) p->pw_gid = -2;
176 }
177 else if (!strcmp("change", key))
178 {
179 p->pw_change = atoi(vals[0]);
180 }
181 else if (!strcmp("expire", key))
182 {
183 p->pw_expire = atoi(vals[0]);
184 }
185
186 free(key);
187 if (vals != NULL)
188 {
189 for (; j < nvals; j++) free(vals[j]);
190 free(vals);
191 }
192 }
193
194 if (p->pw_name == NULL) p->pw_name = strdup("");
195 if (p->pw_passwd == NULL) p->pw_passwd = strdup("");
196 if (p->pw_class == NULL) p->pw_class = strdup("");
197 if (p->pw_gecos == NULL) p->pw_gecos = strdup("");
198 if (p->pw_dir == NULL) p->pw_dir = strdup("");
199 if (p->pw_shell == NULL) p->pw_shell = strdup("");
200
201 return p;
202 }
203
204 static struct passwd *
205 copy_user(struct passwd *in)
206 {
207 struct passwd *p;
208
209 if (in == NULL) return NULL;
210
211 p = (struct passwd *)calloc(1, sizeof(struct passwd));
212
213 p->pw_name = LU_COPY_STRING(in->pw_name);
214 p->pw_passwd = LU_COPY_STRING(in->pw_passwd);
215 p->pw_uid = in->pw_uid;
216 p->pw_gid = in->pw_gid;
217 p->pw_change = in->pw_change;
218 p->pw_class = LU_COPY_STRING(in->pw_class);
219 p->pw_gecos = LU_COPY_STRING(in->pw_gecos);
220 p->pw_dir = LU_COPY_STRING(in->pw_dir);
221 p->pw_shell = LU_COPY_STRING(in->pw_shell);
222 p->pw_expire = in->pw_expire;
223
224 return p;
225 }
226
227 static int
228 copy_user_r(struct passwd *in, struct passwd *out, char *buffer, int buflen)
229 {
230 int hsize;
231 char *bp;
232
233 if (in == NULL) return -1;
234 if (out == NULL) return -1;
235
236 if (buffer == NULL) buflen = 0;
237
238 /* Calculate size of input */
239 hsize = 0;
240 if (in->pw_name != NULL) hsize += strlen(in->pw_name);
241 if (in->pw_passwd != NULL) hsize += strlen(in->pw_passwd);
242 if (in->pw_class != NULL) hsize += strlen(in->pw_class);
243 if (in->pw_gecos != NULL) hsize += strlen(in->pw_gecos);
244 if (in->pw_dir != NULL) hsize += strlen(in->pw_dir);
245 if (in->pw_shell != NULL) hsize += strlen(in->pw_shell);
246
247 /* Check buffer space */
248 if (hsize > buflen) return -1;
249
250 /* Copy result into caller's struct passwd, using buffer for memory */
251 bp = buffer;
252
253 out->pw_name = NULL;
254 if (in->pw_name != NULL)
255 {
256 out->pw_name = bp;
257 hsize = strlen(in->pw_name) + 1;
258 memmove(bp, in->pw_name, hsize);
259 bp += hsize;
260 }
261
262 out->pw_passwd = NULL;
263 if (in->pw_passwd != NULL)
264 {
265 out->pw_passwd = bp;
266 hsize = strlen(in->pw_passwd) + 1;
267 memmove(bp, in->pw_passwd, hsize);
268 bp += hsize;
269 }
270
271 out->pw_uid = in->pw_uid;
272
273 out->pw_gid = in->pw_gid;
274
275 out->pw_change = in->pw_change;
276
277 out->pw_class = NULL;
278 if (in->pw_class != NULL)
279 {
280 out->pw_class = bp;
281 hsize = strlen(in->pw_class) + 1;
282 memmove(bp, in->pw_class, hsize);
283 bp += hsize;
284 }
285
286 out->pw_gecos = NULL;
287 if (in->pw_gecos != NULL)
288 {
289 out->pw_gecos = bp;
290 hsize = strlen(in->pw_gecos) + 1;
291 memmove(bp, in->pw_gecos, hsize);
292 bp += hsize;
293 }
294
295 out->pw_dir = NULL;
296 if (in->pw_dir != NULL)
297 {
298 out->pw_dir = bp;
299 hsize = strlen(in->pw_dir) + 1;
300 memmove(bp, in->pw_dir, hsize);
301 bp += hsize;
302 }
303
304 out->pw_shell = NULL;
305 if (in->pw_shell != NULL)
306 {
307 out->pw_shell = bp;
308 hsize = strlen(in->pw_shell) + 1;
309 memmove(bp, in->pw_shell, hsize);
310 bp += hsize;
311 }
312
313 out->pw_expire = in->pw_expire;
314
315 return 0;
316 }
317
318 static void
319 recycle_user(struct lu_thread_info *tdata, struct passwd *in)
320 {
321 struct passwd *p;
322
323 if (tdata == NULL) return;
324 p = (struct passwd *)tdata->lu_entry;
325
326 if (in == NULL)
327 {
328 free_user(p);
329 tdata->lu_entry = NULL;
330 }
331
332 if (tdata->lu_entry == NULL)
333 {
334 tdata->lu_entry = in;
335 return;
336 }
337
338 free_user_data(p);
339
340 p->pw_name = in->pw_name;
341 p->pw_passwd = in->pw_passwd;
342 p->pw_uid = in->pw_uid;
343 p->pw_gid = in->pw_gid;
344 p->pw_change = in->pw_change;
345 p->pw_class = in->pw_class;
346 p->pw_gecos = in->pw_gecos;
347 p->pw_dir = in->pw_dir;
348 p->pw_shell = in->pw_shell;
349 p->pw_expire = in->pw_expire;
350
351 free(in);
352 }
353
354 __private_extern__ unsigned int
355 get_user_cache_ttl()
356 {
357 return _user_cache_ttl;
358 }
359
360 __private_extern__ void
361 set_user_cache_ttl(unsigned int ttl)
362 {
363 int i;
364
365 pthread_mutex_lock(&_user_cache_lock);
366
367 _user_cache_ttl = ttl;
368
369 if (ttl == 0)
370 {
371 for (i = 0; i < USER_CACHE_SIZE; i++)
372 {
373 if (_user_cache[i] == NULL) continue;
374
375 free_user((struct passwd *)_user_cache[i]);
376 _user_cache[i] = NULL;
377 _user_cache_best_before[i] = 0;
378 }
379 }
380
381 pthread_mutex_unlock(&_user_cache_lock);
382 }
383
384 static void
385 cache_user(struct passwd *pw)
386 {
387 struct timeval now;
388 struct passwd *pwcache;
389
390 if (_user_cache_ttl == 0) return;
391 if (pw == NULL) return;
392
393 pthread_mutex_lock(&_user_cache_lock);
394
395 pwcache = copy_user(pw);
396
397 gettimeofday(&now, NULL);
398
399 if (_user_cache[_user_cache_index] != NULL)
400 free_user((struct passwd *)_user_cache[_user_cache_index]);
401
402 _user_cache[_user_cache_index] = pwcache;
403 _user_cache_best_before[_user_cache_index] = now.tv_sec + _user_cache_ttl;
404 _user_cache_index = (_user_cache_index + 1) % USER_CACHE_SIZE;
405
406 pthread_mutex_unlock(&_user_cache_lock);
407 }
408
409 static struct passwd *
410 cache_getpwnam(const char *name)
411 {
412 int i;
413 struct passwd *pw, *res;
414 struct timeval now;
415
416 if (_user_cache_ttl == 0) return NULL;
417 if (name == NULL) return NULL;
418
419 pthread_mutex_lock(&_user_cache_lock);
420
421 gettimeofday(&now, NULL);
422
423 for (i = 0; i < USER_CACHE_SIZE; i++)
424 {
425 if (_user_cache_best_before[i] == 0) continue;
426 if ((unsigned int)now.tv_sec > _user_cache_best_before[i]) continue;
427
428 pw = (struct passwd *)_user_cache[i];
429
430 if (pw->pw_name == NULL) continue;
431
432 if (!strcmp(name, pw->pw_name))
433 {
434 res = copy_user(pw);
435 pthread_mutex_unlock(&_user_cache_lock);
436 return res;
437 }
438 }
439
440 pthread_mutex_unlock(&_user_cache_lock);
441 return NULL;
442 }
443
444 static struct passwd *
445 cache_getpwuid(int uid)
446 {
447 int i;
448 struct passwd *pw, *res;
449 struct timeval now;
450
451 if (_user_cache_ttl == 0) return NULL;
452
453 pthread_mutex_lock(&_user_cache_lock);
454
455 gettimeofday(&now, NULL);
456
457 for (i = 0; i < USER_CACHE_SIZE; i++)
458 {
459 if (_user_cache_best_before[i] == 0) continue;
460 if ((unsigned int)now.tv_sec > _user_cache_best_before[i]) continue;
461
462 pw = (struct passwd *)_user_cache[i];
463
464 if ((uid_t)uid == pw->pw_uid)
465 {
466 res = copy_user(pw);
467 pthread_mutex_unlock(&_user_cache_lock);
468 return res;
469 }
470 }
471
472 pthread_mutex_unlock(&_user_cache_lock);
473 return NULL;
474 }
475
476 static struct passwd *
477 lu_getpwuid(int uid)
478 {
479 struct passwd *p;
480 unsigned int datalen;
481 XDR inxdr;
482 static int proc = -1;
483 int count;
484 char *lookup_buf;
485
486 if (proc < 0)
487 {
488 if (_lookup_link(_lu_port, "getpwuid_A", &proc) != KERN_SUCCESS)
489 {
490 return NULL;
491 }
492 }
493
494 uid = htonl(uid);
495 datalen = 0;
496 lookup_buf = NULL;
497
498 if (_lookup_all(_lu_port, proc, (unit *)&uid, 1, &lookup_buf, &datalen)
499 != KERN_SUCCESS)
500 {
501 return NULL;
502 }
503
504 datalen *= BYTES_PER_XDR_UNIT;
505 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
506
507 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
508
509 count = 0;
510 if (!xdr_int(&inxdr, &count))
511 {
512 xdr_destroy(&inxdr);
513 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
514 return NULL;
515 }
516
517 if (count == 0)
518 {
519 xdr_destroy(&inxdr);
520 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
521 return NULL;
522 }
523
524 p = extract_user(&inxdr);
525 xdr_destroy(&inxdr);
526 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
527
528 return p;
529 }
530
531 static struct passwd *
532 lu_getpwnam(const char *name)
533 {
534 struct passwd *p;
535 unsigned int datalen;
536 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
537 XDR outxdr;
538 XDR inxdr;
539 static int proc = -1;
540 int count;
541 char *lookup_buf;
542
543 if (proc < 0)
544 {
545 if (_lookup_link(_lu_port, "getpwnam_A", &proc) != KERN_SUCCESS)
546 {
547 return NULL;
548 }
549 }
550
551 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
552 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
553 {
554 xdr_destroy(&outxdr);
555 return NULL;
556 }
557
558 datalen = 0;
559 lookup_buf = NULL;
560
561 if (_lookup_all(_lu_port, proc, (unit *)namebuf,
562 xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
563 != KERN_SUCCESS)
564 {
565 xdr_destroy(&outxdr);
566 return NULL;
567 }
568
569 xdr_destroy(&outxdr);
570
571 datalen *= BYTES_PER_XDR_UNIT;
572 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
573
574 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
575
576 count = 0;
577 if (!xdr_int(&inxdr, &count))
578 {
579 xdr_destroy(&inxdr);
580 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
581 return NULL;
582 }
583
584 if (count == 0)
585 {
586 xdr_destroy(&inxdr);
587 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
588 return NULL;
589 }
590
591 p = extract_user(&inxdr);
592 xdr_destroy(&inxdr);
593 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
594
595
596 return p;
597 }
598
599 static void
600 lu_endpwent(void)
601 {
602 struct lu_thread_info *tdata;
603
604 tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
605 _lu_data_free_vm_xdr(tdata);
606 }
607
608 static int
609 lu_setpwent(void)
610 {
611 lu_endpwent();
612 return 1;
613 }
614
615 static struct passwd *
616 lu_getpwent()
617 {
618 struct passwd *p;
619 static int proc = -1;
620 struct lu_thread_info *tdata;
621
622 tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
623 if (tdata == NULL)
624 {
625 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
626 _lu_data_set_key(_lu_data_key_user, tdata);
627 }
628
629 if (tdata->lu_vm == NULL)
630 {
631 if (proc < 0)
632 {
633 if (_lookup_link(_lu_port, "getpwent_A", &proc) != KERN_SUCCESS)
634 {
635 lu_endpwent();
636 return NULL;
637 }
638 }
639
640 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
641 {
642 lu_endpwent();
643 return NULL;
644 }
645
646 /* mig stubs measure size in words (4 bytes) */
647 tdata->lu_vm_length *= 4;
648
649 if (tdata->lu_xdr != NULL)
650 {
651 xdr_destroy(tdata->lu_xdr);
652 free(tdata->lu_xdr);
653 }
654 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
655
656 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
657 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
658 {
659 lu_endpwent();
660 return NULL;
661 }
662 }
663
664 if (tdata->lu_vm_cursor == 0)
665 {
666 lu_endpwent();
667 return NULL;
668 }
669
670 p = extract_user(tdata->lu_xdr);
671 if (p == NULL)
672 {
673 lu_endpwent();
674 return NULL;
675 }
676
677 tdata->lu_vm_cursor--;
678
679 return p;
680 }
681
682 static struct passwd *
683 getpw_internal(const char *name, uid_t uid, int source)
684 {
685 static char *loginName = NULL;
686 static struct passwd *loginEnt = NULL;
687 struct passwd *res;
688 char *l;
689 int from_cache;
690
691 if (loginName == NULL)
692 {
693 l = getlogin();
694 if ((l != NULL) && (strcmp("root", l) != 0))
695 {
696 pthread_mutex_lock(&_user_lock);
697 if ((loginEnt == NULL) && (l != NULL) && (*l != '\0'))
698 {
699 if (_lu_running())
700 {
701 loginEnt = lu_getpwnam(l);
702 }
703 else
704 {
705 loginEnt = copy_user(_old_getpwnam(l));
706 }
707
708 loginName = l;
709 }
710 pthread_mutex_unlock(&_user_lock);
711 }
712 }
713
714 if (loginEnt != NULL)
715 {
716 switch (source)
717 {
718 case PW_GET_NAME:
719 if (strcmp(name, loginEnt->pw_name) == 0)
720 {
721 name = loginName;
722 }
723 if (strcmp(name, loginEnt->pw_gecos) == 0)
724 {
725 name = loginName;
726 }
727 break;
728 case PW_GET_UID:
729 if (uid == loginEnt->pw_uid)
730 {
731 source = PW_GET_NAME;
732 name = loginName;
733 }
734 break;
735 default:
736 break;
737 }
738 }
739
740 from_cache = 0;
741 res = NULL;
742
743 switch (source)
744 {
745 case PW_GET_NAME:
746 res = cache_getpwnam(name);
747 break;
748 case PW_GET_UID:
749 res = cache_getpwuid(uid);
750 break;
751 default: res = NULL;
752 }
753
754 if (res != NULL)
755 {
756 from_cache = 1;
757 }
758 else if (_lu_running())
759 {
760 switch (source)
761 {
762 case PW_GET_NAME:
763 res = lu_getpwnam(name);
764 break;
765 case PW_GET_UID:
766 res = lu_getpwuid(uid);
767 break;
768 case PW_GET_ENT:
769 res = lu_getpwent();
770 break;
771 default: res = NULL;
772 }
773 }
774 else
775 {
776 pthread_mutex_lock(&_user_lock);
777 switch (source)
778 {
779 case PW_GET_NAME:
780 res = copy_user(_old_getpwnam(name));
781 break;
782 case PW_GET_UID:
783 res = copy_user(_old_getpwuid(uid));
784 break;
785 case PW_GET_ENT:
786 res = copy_user(_old_getpwent());
787 break;
788 default: res = NULL;
789 }
790 pthread_mutex_unlock(&_user_lock);
791 }
792
793 if (from_cache == 0) cache_user(res);
794
795 return res;
796 }
797
798 static struct passwd *
799 getpw(const char *name, uid_t uid, int source)
800 {
801 struct passwd *res = NULL;
802 struct lu_thread_info *tdata;
803
804 tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
805 if (tdata == NULL)
806 {
807 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
808 _lu_data_set_key(_lu_data_key_user, tdata);
809 }
810
811 res = getpw_internal(name, uid, source);
812
813 recycle_user(tdata, res);
814
815 return (struct passwd *)tdata->lu_entry;
816 }
817
818 static int
819 getpw_r(const char *name, uid_t uid, int source, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
820 {
821 struct passwd *res = NULL;
822 int status;
823
824 *result = NULL;
825 errno = 0;
826
827 res = getpw_internal(name, uid, source);
828 if (res == NULL) return -1;
829
830 status = copy_user_r(res, pwd, buffer, bufsize);
831 free_user(res);
832
833 if (status != 0)
834 {
835 errno = ERANGE;
836 return -1;
837 }
838
839 *result = pwd;
840 return 0;
841 }
842
843 struct passwd *
844 getpwnam(const char *name)
845 {
846 return getpw(name, -2, PW_GET_NAME);
847 }
848
849 struct passwd *
850 getpwuid(uid_t uid)
851 {
852 return getpw(NULL, uid, PW_GET_UID);
853 }
854
855 struct passwd *
856 getpwent(void)
857 {
858 return getpw(NULL, -2, PW_GET_ENT);
859 }
860
861 int
862 setpwent(void)
863 {
864 if (_lu_running()) lu_setpwent();
865 else _old_setpwent();
866 return 1;
867 }
868
869 void
870 endpwent(void)
871 {
872 if (_lu_running()) lu_endpwent();
873 else _old_endpwent();
874 }
875
876 int
877 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
878 {
879 return getpw_r(name, -2, PW_GET_NAME, pwd, buffer, bufsize, result);
880 }
881
882 int
883 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
884 {
885 return getpw_r(NULL, uid, PW_GET_UID, pwd, buffer, bufsize, result);
886 }