1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #include <alloca.h>
20: #include <assert.h>
21: #include <errno.h>
22: #include <grp.h>
23: #include <limits.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <unistd.h>
27: #include <sys/param.h>
28: #include <sys/types.h>
29: #include <nsswitch.h>
30:
31: #include "../nscd/nscd-client.h"
32: #include "../nscd/nscd_proto.h"
33:
34:
35:
36: typedef enum nss_status (*initgroups_dyn_function) (const char *, gid_t,
37: long int *, long int *,
38: gid_t **, long int, int *);
39:
40:
41: extern int __nss_group_lookup (service_user **nip, const char *name,
42: void **fctp);
43: extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
44:
45: extern service_user *__nss_group_database attribute_hidden;
46:
47:
48: #include "compat-initgroups.c"
49:
50:
51: static int
52: internal_getgrouplist (const char *user, gid_t group, long int *size,
53: gid_t **groupsp, long int limit)
54: {
55: #ifdef USE_NSCD
56: if (__nss_not_use_nscd_group > 0
57: && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
58: __nss_not_use_nscd_group = 0;
59: if (!__nss_not_use_nscd_group)
60: {
61: int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
62: if (n >= 0)
63: return n;
64:
65:
66: __nss_not_use_nscd_group = 1;
67: }
68: #endif
69:
70: service_user *nip = NULL;
71: initgroups_dyn_function fct;
72: enum nss_status status = NSS_STATUS_UNAVAIL;
73: int no_more;
74:
75: long int start = 1;
76:
77:
78: assert (*size > 0);
79: (*groupsp)[0] = group;
80:
81: if (__nss_group_database != NULL)
82: {
83: no_more = 0;
84: nip = __nss_group_database;
85: }
86: else
87: no_more = __nss_database_lookup ("group", NULL,
88: "compat [NOTFOUND=return] files", &nip);
89:
90: while (! no_more)
91: {
92: long int prev_start = start;
93:
94: fct = __nss_lookup_function (nip, "initgroups_dyn");
95:
96: if (fct == NULL)
97: {
98: status = compat_call (nip, user, group, &start, size, groupsp,
99: limit, &errno);
100:
101: if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
102: break;
103: }
104: else
105: status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
106: limit, &errno));
107:
108:
109: long int cnt = prev_start;
110: while (cnt < start)
111: {
112: long int inner;
113: for (inner = 0; inner < prev_start; ++inner)
114: if ((*groupsp)[inner] == (*groupsp)[cnt])
115: break;
116:
117: if (inner < prev_start)
118: (*groupsp)[cnt] = (*groupsp)[--start];
119: else
120: ++cnt;
121: }
122:
123:
124: if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
125: __libc_fatal ("illegal status in internal_getgrouplist");
126:
127: if (status != NSS_STATUS_SUCCESS
128: && nss_next_action (nip, status) == NSS_ACTION_RETURN)
129: break;
130:
131: if (nip->next == NULL)
132: no_more = -1;
133: else
134: nip = nip->next;
135: }
136:
137: return start;
138: }
139:
140:
141:
142:
143: int
144: getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
145: {
146: long int size = MAX (1, *ngroups);
147:
148: gid_t *newgroups = (gid_t *) malloc (size * sizeof (gid_t));
149: if (__builtin_expect (newgroups == NULL, 0))
150:
151:
152:
153:
154:
155: return -1;
156:
157: int total = internal_getgrouplist (user, group, &size, &newgroups, -1);
158:
159: memcpy (groups, newgroups, MIN (*ngroups, total) * sizeof (gid_t));
160:
161: free (newgroups);
162:
163: int retval = total > *ngroups ? -1 : total;
164: *ngroups = total;
165:
166: return retval;
167: }
168:
169: static_link_warning (getgrouplist)
170:
171:
172:
173:
174: int
175: initgroups (const char *user, gid_t group)
176: {
177: #if defined NGROUPS_MAX && NGROUPS_MAX == 0
178:
179:
180: return 0;
181:
182: #else
183:
184: long int size;
185: gid_t *groups;
186: int ngroups;
187: int result;
188:
189:
190:
191:
192: long int limit = __sysconf (_SC_NGROUPS_MAX);
193:
194: if (limit > 0)
195:
196: size = MIN (limit, 64);
197: else
198:
199: size = 16;
200:
201: groups = (gid_t *) malloc (size * sizeof (gid_t));
202: if (__builtin_expect (groups == NULL, 0))
203:
204: return -1;
205:
206: ngroups = internal_getgrouplist (user, group, &size, &groups, limit);
207:
208:
209: do
210: result = setgroups (ngroups, groups);
211: while (result == -1 && errno == EINVAL && --ngroups > 0);
212:
213: free (groups);
214:
215: return result;
216: #endif
217: }
218:
219: static_link_warning (initgroups)