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