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