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