Commit | Line | Data |
---|---|---|
73dcdb9f PE |
1 | /* provide consistent interface to getgroups for systems that don't allow N==0 |
2 | ||
ba318903 | 3 | Copyright (C) 1996, 1999, 2003, 2006-2014 Free Software Foundation, Inc. |
73dcdb9f PE |
4 | |
5 | This program is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | /* written by Jim Meyering */ | |
19 | ||
20 | #include <config.h> | |
21 | ||
22 | #include <unistd.h> | |
23 | ||
24 | #include <errno.h> | |
25 | #include <stdlib.h> | |
26 | #include <stdint.h> | |
27 | ||
28 | #if !HAVE_GETGROUPS | |
29 | ||
30 | /* Provide a stub that fails with ENOSYS, since there is no group | |
31 | information available on mingw. */ | |
32 | int | |
33 | getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED) | |
34 | { | |
35 | errno = ENOSYS; | |
36 | return -1; | |
37 | } | |
38 | ||
39 | #else /* HAVE_GETGROUPS */ | |
40 | ||
41 | # undef getgroups | |
42 | # ifndef GETGROUPS_ZERO_BUG | |
43 | # define GETGROUPS_ZERO_BUG 0 | |
44 | # endif | |
45 | ||
de27f8ab PE |
46 | /* On OS X 10.6 and later, use the usual getgroups, not the one |
47 | supplied when _DARWIN_C_SOURCE is defined. _DARWIN_C_SOURCE is | |
48 | normally defined, since it means "conform to POSIX, but add | |
49 | non-POSIX extensions even if that violates the POSIX namespace | |
50 | rules", which is what we normally want. But with getgroups there | |
51 | is an inconsistency, and _DARWIN_C_SOURCE means "change getgroups() | |
52 | so that it no longer works right". The BUGS section of compat(5) | |
53 | says that the behavior is dubious if you compile different sections | |
54 | of a program with different _DARWIN_C_SOURCE settings, so fix only | |
55 | the offending symbol. */ | |
56 | # ifdef __APPLE__ | |
57 | int posix_getgroups (int, gid_t []) __asm ("_getgroups"); | |
58 | # define getgroups posix_getgroups | |
59 | # endif | |
60 | ||
73dcdb9f PE |
61 | /* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always |
62 | fails. On other systems, it returns the number of supplemental | |
63 | groups for the process. This function handles that special case | |
64 | and lets the system-provided function handle all others. However, | |
65 | it can fail with ENOMEM if memory is tight. It is unspecified | |
66 | whether the effective group id is included in the list. */ | |
67 | ||
68 | int | |
69 | rpl_getgroups (int n, gid_t *group) | |
70 | { | |
71 | int n_groups; | |
72 | GETGROUPS_T *gbuf; | |
73 | int saved_errno; | |
74 | ||
75 | if (n < 0) | |
76 | { | |
77 | errno = EINVAL; | |
78 | return -1; | |
79 | } | |
80 | ||
81 | if (n != 0 || !GETGROUPS_ZERO_BUG) | |
82 | { | |
83 | int result; | |
84 | if (sizeof *group == sizeof *gbuf) | |
85 | return getgroups (n, (GETGROUPS_T *) group); | |
86 | ||
87 | if (SIZE_MAX / sizeof *gbuf <= n) | |
88 | { | |
89 | errno = ENOMEM; | |
90 | return -1; | |
91 | } | |
92 | gbuf = malloc (n * sizeof *gbuf); | |
93 | if (!gbuf) | |
94 | return -1; | |
95 | result = getgroups (n, gbuf); | |
96 | if (0 <= result) | |
97 | { | |
98 | n = result; | |
99 | while (n--) | |
100 | group[n] = gbuf[n]; | |
101 | } | |
102 | saved_errno = errno; | |
103 | free (gbuf); | |
230fe2a5 | 104 | errno = saved_errno; |
73dcdb9f PE |
105 | return result; |
106 | } | |
107 | ||
108 | n = 20; | |
109 | while (1) | |
110 | { | |
111 | /* No need to worry about address arithmetic overflow here, | |
112 | since the ancient systems that we're running on have low | |
113 | limits on the number of secondary groups. */ | |
114 | gbuf = malloc (n * sizeof *gbuf); | |
115 | if (!gbuf) | |
116 | return -1; | |
117 | n_groups = getgroups (n, gbuf); | |
118 | if (n_groups == -1 ? errno != EINVAL : n_groups < n) | |
119 | break; | |
120 | free (gbuf); | |
121 | n *= 2; | |
122 | } | |
123 | ||
124 | saved_errno = errno; | |
125 | free (gbuf); | |
126 | errno = saved_errno; | |
127 | ||
128 | return n_groups; | |
129 | } | |
130 | ||
131 | #endif /* HAVE_GETGROUPS */ |