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