]> git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/lu_group.c
Libinfo-173.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 * 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 * Unix group lookup
27 * Copyright (C) 1989 by NeXT, Inc.
28 */
29
30 #include <stdlib.h>
31 #include <mach/mach.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <rpc/types.h>
36 #include <rpc/xdr.h>
37 #include <grp.h>
38 #include <netinet/in.h>
39 #include <sys/param.h>
40 #include <unistd.h>
41 #include <pthread.h>
42
43 #include "_lu_types.h"
44 #include "lookup.h"
45 #include "lu_utils.h"
46 #include "lu_overrides.h"
47
48 #define GROUP_CACHE_SIZE 10
49 #define DEFAULT_GROUP_CACHE_TTL 10
50
51 static pthread_mutex_t _group_cache_lock = PTHREAD_MUTEX_INITIALIZER;
52 static void *_group_cache[GROUP_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
53 static unsigned int _group_cache_best_before[GROUP_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
54 static unsigned int _group_cache_index = 0;
55 static unsigned int _group_cache_ttl = DEFAULT_GROUP_CACHE_TTL;
56
57 static pthread_mutex_t _group_lock = PTHREAD_MUTEX_INITIALIZER;
58
59 #define GR_GET_NAME 1
60 #define GR_GET_GID 2
61 #define GR_GET_ENT 3
62
63 static void
64 free_group_data(struct group *g)
65 {
66 char **mem;
67
68 if (g == NULL) return;
69
70 if (g->gr_name != NULL) free(g->gr_name);
71 if (g->gr_passwd != NULL) free(g->gr_passwd);
72
73 mem = g->gr_mem;
74 if (mem != NULL)
75 {
76 while (*mem != NULL) free(*mem++);
77 free(g->gr_mem);
78 }
79 }
80
81 static void
82 free_group(struct group *g)
83 {
84 if (g == NULL) return;
85 free_group_data(g);
86 free(g);
87 }
88
89 static void
90 free_lu_thread_info_group(void *x)
91 {
92 struct lu_thread_info *tdata;
93
94 if (x == NULL) return;
95
96 tdata = (struct lu_thread_info *)x;
97
98 if (tdata->lu_entry != NULL)
99 {
100 free_group((struct group *)tdata->lu_entry);
101 tdata->lu_entry = NULL;
102 }
103
104 _lu_data_free_vm_xdr(tdata);
105
106 free(tdata);
107 }
108
109 static struct group *
110 extract_group(XDR *xdr)
111 {
112 int i, j, nkeys, nvals, status;
113 char *key, **vals;
114 struct group *g;
115
116 if (xdr == NULL) return NULL;
117
118 if (!xdr_int(xdr, &nkeys)) return NULL;
119
120 g = (struct group *)calloc(1, sizeof(struct group));
121 g->gr_gid = -2;
122
123 for (i = 0; i < nkeys; i++)
124 {
125 key = NULL;
126 vals = NULL;
127 nvals = 0;
128
129 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
130 if (status < 0)
131 {
132 free_group(g);
133 return NULL;
134 }
135
136 if (nvals == 0)
137 {
138 free(key);
139 continue;
140 }
141
142 j = 0;
143
144 if ((g->gr_name == NULL) && (!strcmp("name", key)))
145 {
146 g->gr_name = vals[0];
147 j = 1;
148 }
149 else if ((g->gr_passwd == NULL) && (!strcmp("passwd", key)))
150 {
151 g->gr_passwd = vals[0];
152 j = 1;
153 }
154 else if ((g->gr_gid == (gid_t)-2) && (!strcmp("gid", key)))
155 {
156 g->gr_gid = atoi(vals[0]);
157 if ((g->gr_gid == 0) && (strcmp(vals[0], "0"))) g->gr_gid = -2;
158 }
159 else if ((g->gr_mem == NULL) && (!strcmp("users", key)))
160 {
161 g->gr_mem = vals;
162 j = nvals;
163 vals = NULL;
164 }
165
166 free(key);
167 if (vals != NULL)
168 {
169 for (; j < nvals; j++) free(vals[j]);
170 free(vals);
171 }
172 }
173
174 if (g->gr_name == NULL) g->gr_name = strdup("");
175 if (g->gr_passwd == NULL) g->gr_passwd = strdup("");
176 if (g->gr_mem == NULL) g->gr_mem = (char **)calloc(1, sizeof(char *));
177
178 return g;
179 }
180
181 static struct group *
182 copy_group(struct group *in)
183 {
184 struct group *g;
185 int i, len;
186
187 if (in == NULL) return NULL;
188
189 g = (struct group *)calloc(1, sizeof(struct group));
190
191 g->gr_name = LU_COPY_STRING(in->gr_name);
192 g->gr_passwd = LU_COPY_STRING(in->gr_passwd);
193 g->gr_gid = in->gr_gid;
194
195 len = 0;
196 if (in->gr_mem != NULL)
197 {
198 for (len = 0; in->gr_mem[len] != NULL; len++);
199 }
200
201 g->gr_mem = (char **)calloc(len + 1, sizeof(char *));
202 for (i = 0; i < len; i++)
203 {
204 g->gr_mem[i] = strdup(in->gr_mem[i]);
205 }
206
207 return g;
208 }
209
210 static int
211 copy_group_r(struct group *in, struct group *out, char *buffer, int buflen)
212 {
213 int i, len, hsize;
214 unsigned long addr;
215 char *bp, *ap;
216
217 if (in == NULL) return -1;
218 if (out == NULL) return -1;
219
220 if (buffer == NULL) buflen = 0;
221
222 /* Calculate size of input */
223 hsize = 0;
224 if (in->gr_name != NULL) hsize += strlen(in->gr_name);
225 if (in->gr_passwd != NULL) hsize += strlen(in->gr_passwd);
226
227 /* NULL pointer at end of list */
228 hsize += sizeof(char *);
229
230 len = 0;
231 if (in->gr_mem != NULL)
232 {
233 for (len = 0; in->gr_mem[len] != NULL; len++)
234 {
235 hsize += sizeof(char *);
236 hsize += strlen(in->gr_mem[len]);
237 }
238 }
239
240 /* Check buffer space */
241 if (hsize > buflen) return -1;
242
243 /* Copy result into caller's struct group, using buffer for memory */
244 bp = buffer;
245
246 out->gr_name = NULL;
247 if (in->gr_name != NULL)
248 {
249 out->gr_name = bp;
250 hsize = strlen(in->gr_name) + 1;
251 memmove(bp, in->gr_name, hsize);
252 bp += hsize;
253 }
254
255 out->gr_passwd = NULL;
256 if (in->gr_passwd != NULL)
257 {
258 out->gr_passwd = bp;
259 hsize = strlen(in->gr_passwd) + 1;
260 memmove(bp, in->gr_passwd, hsize);
261 bp += hsize;
262 }
263
264 out->gr_gid = in->gr_gid;
265
266 out->gr_mem = NULL;
267 ap = bp + ((len + 1) * sizeof(char *));
268
269 if (in->gr_mem != NULL)
270 {
271 out->gr_mem = (char **)bp;
272 for (i = 0; i < len; i++)
273 {
274 addr = (unsigned long)ap;
275 memmove(bp, &addr, sizeof(unsigned long));
276 bp += sizeof(unsigned long);
277
278 hsize = strlen(in->gr_mem[i]) + 1;
279 memmove(ap, in->gr_mem[i], hsize);
280 ap += hsize;
281 }
282 }
283
284 memset(bp, 0, sizeof(unsigned long));
285 bp = ap;
286
287 return 0;
288 }
289
290 static void
291 recycle_group(struct lu_thread_info *tdata, struct group *in)
292 {
293 struct group *g;
294
295 if (tdata == NULL) return;
296 g = (struct group *)tdata->lu_entry;
297
298 if (in == NULL)
299 {
300 free_group(g);
301 tdata->lu_entry = NULL;
302 }
303
304 if (tdata->lu_entry == NULL)
305 {
306 tdata->lu_entry = in;
307 return;
308 }
309
310 free_group_data(g);
311
312 g->gr_name = in->gr_name;
313 g->gr_passwd = in->gr_passwd;
314 g->gr_gid = in->gr_gid;
315 g->gr_mem = in->gr_mem;
316
317 free(in);
318 }
319
320 __private_extern__ unsigned int
321 get_group_cache_ttl()
322 {
323 return _group_cache_ttl;
324 }
325
326 __private_extern__ void
327 set_group_cache_ttl(unsigned int ttl)
328 {
329 int i;
330
331 pthread_mutex_lock(&_group_cache_lock);
332
333 _group_cache_ttl = ttl;
334
335 if (ttl == 0)
336 {
337 for (i = 0; i < GROUP_CACHE_SIZE; i++)
338 {
339 if (_group_cache[i] == NULL) continue;
340
341 free_group((struct group *)_group_cache[i]);
342 _group_cache[i] = NULL;
343 _group_cache_best_before[i] = 0;
344 }
345 }
346
347 pthread_mutex_unlock(&_group_cache_lock);
348 }
349
350 static void
351 cache_group(struct group *gr)
352 {
353 struct timeval now;
354 struct group *grcache;
355
356 if (_group_cache_ttl == 0) return;
357 if (gr == NULL) return;
358
359 pthread_mutex_lock(&_group_cache_lock);
360
361 grcache = copy_group(gr);
362
363 gettimeofday(&now, NULL);
364
365 if (_group_cache[_group_cache_index] != NULL)
366 free_group((struct group *)_group_cache[_group_cache_index]);
367
368 _group_cache[_group_cache_index] = grcache;
369 _group_cache_best_before[_group_cache_index] = now.tv_sec + _group_cache_ttl;
370 _group_cache_index = (_group_cache_index + 1) % GROUP_CACHE_SIZE;
371
372 pthread_mutex_unlock(&_group_cache_lock);
373 }
374
375 static struct group *
376 cache_getgrnam(const char *name)
377 {
378 int i;
379 struct group *gr, *res;
380 struct timeval now;
381
382 if (_group_cache_ttl == 0) return NULL;
383 if (name == NULL) return NULL;
384
385 pthread_mutex_lock(&_group_cache_lock);
386
387 gettimeofday(&now, NULL);
388
389 for (i = 0; i < GROUP_CACHE_SIZE; i++)
390 {
391 if (_group_cache_best_before[i] == 0) continue;
392 if ((unsigned int)now.tv_sec > _group_cache_best_before[i]) continue;
393
394 gr = (struct group *)_group_cache[i];
395
396 if (gr->gr_name == NULL) continue;
397
398 if (!strcmp(name, gr->gr_name))
399 {
400 res = copy_group(gr);
401 pthread_mutex_unlock(&_group_cache_lock);
402 return res;
403 }
404 }
405
406 pthread_mutex_unlock(&_group_cache_lock);
407 return NULL;
408 }
409
410 static struct group *
411 cache_getgrgid(int gid)
412 {
413 int i;
414 struct group *gr, *res;
415 struct timeval now;
416
417 if (_group_cache_ttl == 0) return NULL;
418
419 pthread_mutex_lock(&_group_cache_lock);
420
421 gettimeofday(&now, NULL);
422
423 for (i = 0; i < GROUP_CACHE_SIZE; i++)
424 {
425 if (_group_cache_best_before[i] == 0) continue;
426 if ((unsigned int)now.tv_sec > _group_cache_best_before[i]) continue;
427
428 gr = (struct group *)_group_cache[i];
429
430 if ((gid_t)gid == gr->gr_gid)
431 {
432 res = copy_group(gr);
433 pthread_mutex_unlock(&_group_cache_lock);
434 return res;
435 }
436 }
437
438 pthread_mutex_unlock(&_group_cache_lock);
439 return NULL;
440 }
441
442 static struct group *
443 lu_getgrgid(int gid)
444 {
445 struct group *g;
446 unsigned int datalen;
447 XDR inxdr;
448 static int proc = -1;
449 int count;
450 char *lookup_buf;
451
452 if (proc < 0)
453 {
454 if (_lookup_link(_lu_port, "getgrgid", &proc) != KERN_SUCCESS)
455 {
456 return NULL;
457 }
458 }
459
460 gid = htonl(gid);
461 datalen = 0;
462 lookup_buf = NULL;
463
464 if (_lookup_all(_lu_port, proc, (unit *)&gid, 1, &lookup_buf, &datalen) != KERN_SUCCESS)
465 {
466 return NULL;
467 }
468
469 datalen *= BYTES_PER_XDR_UNIT;
470 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
471
472 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
473
474 count = 0;
475 if (!xdr_int(&inxdr, &count))
476 {
477 xdr_destroy(&inxdr);
478 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
479 return NULL;
480 }
481
482 if (count == 0)
483 {
484 xdr_destroy(&inxdr);
485 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
486 return NULL;
487 }
488
489 g = extract_group(&inxdr);
490 xdr_destroy(&inxdr);
491 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
492
493 return g;
494 }
495
496 static struct group *
497 lu_getgrnam(const char *name)
498 {
499 struct group *g;
500 unsigned int datalen;
501 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
502 XDR outxdr;
503 XDR inxdr;
504 static int proc = -1;
505 int count;
506 char *lookup_buf;
507
508 if (proc < 0)
509 {
510 if (_lookup_link(_lu_port, "getgrnam", &proc) != KERN_SUCCESS)
511 {
512 return NULL;
513 }
514 }
515
516 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
517
518 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
519 {
520 xdr_destroy(&outxdr);
521 return NULL;
522 }
523
524 datalen = 0;
525 lookup_buf = NULL;
526
527 if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
528 {
529 return NULL;
530 }
531
532 xdr_destroy(&outxdr);
533
534 datalen *= BYTES_PER_XDR_UNIT;
535 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
536
537 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
538
539 count = 0;
540 if (!xdr_int(&inxdr, &count))
541 {
542 xdr_destroy(&inxdr);
543 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
544 return NULL;
545 }
546
547 if (count == 0)
548 {
549 xdr_destroy(&inxdr);
550 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
551 return NULL;
552 }
553
554 g = extract_group(&inxdr);
555 xdr_destroy(&inxdr);
556 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
557
558 return g;
559 }
560
561 int
562 _old_getgrouplist(const char *uname, int agroup, int *groups, int *grpcnt)
563 {
564 struct group *grp;
565 int i, ngroups;
566 int ret, maxgroups;
567
568 ret = 0;
569 ngroups = 0;
570 maxgroups = *grpcnt;
571
572 /*
573 * When installing primary group, duplicate it;
574 * the first element of groups is the effective gid
575 * and will be overwritten when a setgid file is executed.
576 */
577 groups[ngroups++] = agroup;
578 if (maxgroups > 1) groups[ngroups++] = agroup;
579
580 /*
581 * Scan the group file to find additional groups.
582 */
583 setgrent();
584
585 while ((grp = getgrent()))
586 {
587 if (grp->gr_gid == (gid_t)agroup) continue;
588 for (i = 0; grp->gr_mem[i]; i++)
589 {
590 if (!strcmp(grp->gr_mem[i], uname))
591 {
592 if (ngroups >= maxgroups)
593 {
594 ret = -1;
595 break;
596 }
597
598 groups[ngroups++] = grp->gr_gid;
599 break;
600 }
601 }
602 }
603
604 endgrent();
605 *grpcnt = ngroups;
606 return ret;
607 }
608
609 static int
610 lu_getgrouplist(const char *name, int basegid, int *groups, int *grpcnt, int dupbase)
611 {
612 unsigned int datalen;
613 XDR outxdr;
614 XDR inxdr;
615 static int proc = -1;
616 char *lookup_buf;
617 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
618 int ngroups;
619 int a_group;
620 int i, j, count;
621
622 if (groups == NULL) return -1;
623 if (*grpcnt == 0) return -1;
624
625 ngroups = 0;
626 groups[ngroups++] = basegid;
627 if (*grpcnt == 1) return 0;
628
629 if (dupbase != 0)
630 {
631 /* getgrouplist duplicates the primary group! */
632 groups[ngroups++] = basegid;
633 if (*grpcnt == 2) return 0;
634 }
635
636 if (proc < 0)
637 {
638 if (_lookup_link(_lu_port, "initgroups", &proc) != KERN_SUCCESS)
639 {
640 return -1;
641 }
642 }
643
644 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
645 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
646 {
647 xdr_destroy(&outxdr);
648 return -1;
649 }
650
651 datalen = 0;
652 lookup_buf = NULL;
653
654 if (_lookup_all(_lu_port, proc, (unit *)namebuf,
655 xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
656 != KERN_SUCCESS)
657 {
658 xdr_destroy(&outxdr);
659 return -1;
660 }
661
662 xdr_destroy(&outxdr);
663
664 datalen *= BYTES_PER_XDR_UNIT;
665 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
666
667 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
668
669 if (!xdr_int(&inxdr, &count))
670 {
671 xdr_destroy(&inxdr);
672 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
673 return -1;
674 }
675
676 for (i = 0; i < count; i++)
677 {
678 if (!xdr_int(&inxdr, &a_group)) break;
679
680 j = 0;
681 if (dupbase != 0) j = 1;
682 for (; j < ngroups; j++)
683 {
684 if (groups[j] == a_group) break;
685 }
686
687 if (j >= ngroups)
688 {
689 groups[ngroups++] = a_group;
690 if (ngroups == *grpcnt) break;
691 }
692 }
693
694 xdr_destroy(&inxdr);
695 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
696
697 *grpcnt = ngroups;
698 return 0;
699 }
700
701 int
702 getgrouplist(const char *uname, int agroup, int *groups, int *grpcnt)
703 {
704 if (_lu_running())
705 {
706 return lu_getgrouplist(uname, agroup, groups, grpcnt, 1);
707 }
708
709 return _old_getgrouplist(uname, agroup, groups, grpcnt);
710 }
711
712 static int
713 lu_initgroups(const char *name, int basegid)
714 {
715 int status, ngroups, groups[NGROUPS];
716
717 ngroups = NGROUPS;
718 status = lu_getgrouplist(name, basegid, groups, &ngroups, 0);
719 if (status < 0) return status;
720
721 return setgroups(ngroups, groups);
722 }
723
724 static void
725 lu_endgrent(void)
726 {
727 struct lu_thread_info *tdata;
728
729 tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
730 _lu_data_free_vm_xdr(tdata);
731 }
732
733 static int
734 lu_setgrent(void)
735 {
736 lu_endgrent();
737 return 1;
738 }
739
740 static struct group *
741 lu_getgrent()
742 {
743 struct group *g;
744 static int proc = -1;
745 struct lu_thread_info *tdata;
746
747 tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
748 if (tdata == NULL)
749 {
750 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
751 _lu_data_set_key(_lu_data_key_group, tdata);
752 }
753
754 if (tdata->lu_vm == NULL)
755 {
756 if (proc < 0)
757 {
758 if (_lookup_link(_lu_port, "getgrent", &proc) != KERN_SUCCESS)
759 {
760 lu_endgrent();
761 return NULL;
762 }
763 }
764
765 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
766 {
767 lu_endgrent();
768 return NULL;
769 }
770
771 /* mig stubs measure size in words (4 bytes) */
772 tdata->lu_vm_length *= 4;
773
774 if (tdata->lu_xdr != NULL)
775 {
776 xdr_destroy(tdata->lu_xdr);
777 free(tdata->lu_xdr);
778 }
779 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
780
781 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
782 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
783 {
784 lu_endgrent();
785 return NULL;
786 }
787 }
788
789 if (tdata->lu_vm_cursor == 0)
790 {
791 lu_endgrent();
792 return NULL;
793 }
794
795 g = extract_group(tdata->lu_xdr);
796 if (g == NULL)
797 {
798 lu_endgrent();
799 return NULL;
800 }
801
802 tdata->lu_vm_cursor--;
803
804 return g;
805 }
806
807 static struct group *
808 getgr_internal(const char *name, gid_t gid, int source)
809 {
810 struct group *res = NULL;
811 int from_cache;
812
813 from_cache = 0;
814 res = NULL;
815
816 switch (source)
817 {
818 case GR_GET_NAME:
819 res = cache_getgrnam(name);
820 break;
821 case GR_GET_GID:
822 res = cache_getgrgid(gid);
823 break;
824 default: res = NULL;
825 }
826
827 if (res != NULL)
828 {
829 from_cache = 1;
830 }
831 else if (_lu_running())
832 {
833 switch (source)
834 {
835 case GR_GET_NAME:
836 res = lu_getgrnam(name);
837 break;
838 case GR_GET_GID:
839 res = lu_getgrgid(gid);
840 break;
841 case GR_GET_ENT:
842 res = lu_getgrent();
843 break;
844 default: res = NULL;
845 }
846 }
847 else
848 {
849 pthread_mutex_lock(&_group_lock);
850 switch (source)
851 {
852 case GR_GET_NAME:
853 res = copy_group(_old_getgrnam(name));
854 break;
855 case GR_GET_GID:
856 res = copy_group(_old_getgrgid(gid));
857 break;
858 case GR_GET_ENT:
859 res = copy_group(_old_getgrent());
860 break;
861 default: res = NULL;
862 }
863 pthread_mutex_unlock(&_group_lock);
864 }
865
866 if (from_cache == 0) cache_group(res);
867
868 return res;
869 }
870
871 static struct group *
872 getgr(const char *name, gid_t gid, int source)
873 {
874 struct group *res = NULL;
875 struct lu_thread_info *tdata;
876
877 tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
878 if (tdata == NULL)
879 {
880 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
881 _lu_data_set_key(_lu_data_key_group, tdata);
882 }
883
884 res = getgr_internal(name, gid, source);
885
886 recycle_group(tdata, res);
887 return (struct group *)tdata->lu_entry;
888 }
889
890 static int
891 getgr_r(const char *name, gid_t gid, int source, struct group *grp, char *buffer, size_t bufsize, struct group **result)
892 {
893 struct group *res = NULL;
894 int status;
895
896 *result = NULL;
897 errno = 0;
898
899 res = getgr_internal(name, gid, source);
900 if (res == NULL) return -1;
901
902 status = copy_group_r(res, grp, buffer, bufsize);
903 free_group(res);
904
905 if (status != 0)
906 {
907 errno = ERANGE;
908 return -1;
909 }
910
911 *result = grp;
912 return 0;
913 }
914
915 int
916 initgroups(const char *name, int basegid)
917 {
918 int res;
919
920 if (name == NULL) return -1;
921
922 if (_lu_running())
923 {
924 if ((res = lu_initgroups(name, basegid)))
925 {
926 res = _old_initgroups(name, basegid);
927 }
928 }
929 else
930 {
931 res = _old_initgroups(name, basegid);
932 }
933
934 return (res);
935 }
936
937 struct group *
938 getgrnam(const char *name)
939 {
940 return getgr(name, -2, GR_GET_NAME);
941 }
942
943 struct group *
944 getgrgid(gid_t gid)
945 {
946 return getgr(NULL, gid, GR_GET_GID);
947 }
948
949 struct group *
950 getgrent(void)
951 {
952 return getgr(NULL, -2, GR_GET_ENT);
953 }
954
955 int
956 setgrent(void)
957 {
958 if (_lu_running()) lu_setgrent();
959 else _old_setgrent();
960 return 1;
961 }
962
963 void
964 endgrent(void)
965 {
966 if (_lu_running()) lu_endgrent();
967 else _old_endgrent();
968 }
969
970 int
971 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result)
972 {
973 return getgr_r(name, -2, GR_GET_NAME, grp, buffer, bufsize, result);
974 }
975
976 int
977 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
978 {
979 return getgr_r(NULL, gid, GR_GET_GID, grp, buffer, bufsize, result);
980 }