getgroupmembership.c revision 1.1 1 1.1 lukem /* $NetBSD: getgroupmembership.c,v 1.1 2005/01/06 15:10:45 lukem Exp $ */
2 1.1 lukem
3 1.1 lukem /*-
4 1.1 lukem * Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
5 1.1 lukem * All rights reserved.
6 1.1 lukem *
7 1.1 lukem * This code is derived from software contributed to The NetBSD Foundation
8 1.1 lukem * by Luke Mewburn.
9 1.1 lukem *
10 1.1 lukem * Redistribution and use in source and binary forms, with or without
11 1.1 lukem * modification, are permitted provided that the following conditions
12 1.1 lukem * are met:
13 1.1 lukem * 1. Redistributions of source code must retain the above copyright
14 1.1 lukem * notice, this list of conditions and the following disclaimer.
15 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 lukem * notice, this list of conditions and the following disclaimer in the
17 1.1 lukem * documentation and/or other materials provided with the distribution.
18 1.1 lukem * 3. All advertising materials mentioning features or use of this software
19 1.1 lukem * must display the following acknowledgement:
20 1.1 lukem * This product includes software developed by the NetBSD
21 1.1 lukem * Foundation, Inc. and its contributors.
22 1.1 lukem * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 lukem * contributors may be used to endorse or promote products derived
24 1.1 lukem * from this software without specific prior written permission.
25 1.1 lukem *
26 1.1 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 lukem * POSSIBILITY OF SUCH DAMAGE.
37 1.1 lukem */
38 1.1 lukem
39 1.1 lukem #include <sys/cdefs.h>
40 1.1 lukem #if defined(LIBC_SCCS) && !defined(lint)
41 1.1 lukem __RCSID("$NetBSD: getgroupmembership.c,v 1.1 2005/01/06 15:10:45 lukem Exp $");
42 1.1 lukem #endif /* LIBC_SCCS and not lint */
43 1.1 lukem
44 1.1 lukem /*
45 1.1 lukem * calculate group access list
46 1.1 lukem */
47 1.1 lukem
48 1.1 lukem #include "namespace.h"
49 1.1 lukem #include "reentrant.h"
50 1.1 lukem
51 1.1 lukem #include <sys/param.h>
52 1.1 lukem
53 1.1 lukem #include <assert.h>
54 1.1 lukem #include <errno.h>
55 1.1 lukem #include <grp.h>
56 1.1 lukem #include <limits.h>
57 1.1 lukem #include <nsswitch.h>
58 1.1 lukem #include <stdarg.h>
59 1.1 lukem #include <stdio.h>
60 1.1 lukem #include <stdlib.h>
61 1.1 lukem #include <string.h>
62 1.1 lukem #include <unistd.h>
63 1.1 lukem
64 1.1 lukem #ifdef HESIOD
65 1.1 lukem #include <hesiod.h>
66 1.1 lukem #endif
67 1.1 lukem
68 1.1 lukem #include "gr_private.h"
69 1.1 lukem
70 1.1 lukem #ifdef __weak_alias
71 1.1 lukem __weak_alias(getgroupmembership,_getgroupmembership)
72 1.1 lukem #endif
73 1.1 lukem
74 1.1 lukem /*
75 1.1 lukem * __gr_addgid
76 1.1 lukem * Add gid to the groups array (of maxgrp size) at the position
77 1.1 lukem * indicated by *groupc, unless it already exists or *groupc is
78 1.1 lukem * past &groups[maxgrp].
79 1.1 lukem * Returns 1 upon success (including duplicate suppression), 0 otherwise.
80 1.1 lukem */
81 1.1 lukem static int
82 1.1 lukem __gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *groupc)
83 1.1 lukem {
84 1.1 lukem int ret, dupc;
85 1.1 lukem
86 1.1 lukem _DIAGASSERT(grpcnt != NULL);
87 1.1 lukem
88 1.1 lukem /* skip duplicates */
89 1.1 lukem for (dupc = 0; dupc < MIN(maxgrp, *groupc); dupc++) {
90 1.1 lukem if (groups[dupc] == gid)
91 1.1 lukem return 1;
92 1.1 lukem }
93 1.1 lukem
94 1.1 lukem ret = 1;
95 1.1 lukem if (*groupc < maxgrp) /* add this gid */
96 1.1 lukem groups[*groupc] = gid;
97 1.1 lukem else
98 1.1 lukem ret = 0;
99 1.1 lukem (*groupc)++;
100 1.1 lukem return ret;
101 1.1 lukem }
102 1.1 lukem
103 1.1 lukem
104 1.1 lukem /*ARGSUSED*/
105 1.1 lukem static int
106 1.1 lukem _files_getgroupmembership(void *retval, void *cb_data, va_list ap)
107 1.1 lukem {
108 1.1 lukem int *result = va_arg(ap, int *);
109 1.1 lukem const char *uname = va_arg(ap, const char *);
110 1.1 lukem gid_t agroup = va_arg(ap, gid_t);
111 1.1 lukem gid_t *groups = va_arg(ap, gid_t *);
112 1.1 lukem int maxgrp = va_arg(ap, int);
113 1.1 lukem int *groupc = va_arg(ap, int *);
114 1.1 lukem
115 1.1 lukem struct __grstate_files state;
116 1.1 lukem struct group grp;
117 1.1 lukem char grpbuf[_GETGR_R_SIZE_MAX];
118 1.1 lukem int rv, i;
119 1.1 lukem
120 1.1 lukem _DIAGASSERT(result != NULL);
121 1.1 lukem _DIAGASSERT(uname != NULL);
122 1.1 lukem /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
123 1.1 lukem _DIAGASSERT(groupc != NULL);
124 1.1 lukem
125 1.1 lukem /* install primary group */
126 1.1 lukem (void) __gr_addgid(agroup, groups, maxgrp, groupc);
127 1.1 lukem
128 1.1 lukem memset(&state, 0, sizeof(state));
129 1.1 lukem while (__grscan_files(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
130 1.1 lukem 0, NULL, 0) == NS_SUCCESS) {
131 1.1 lukem /* scan members */
132 1.1 lukem for (i = 0; grp.gr_mem[i]; i++) {
133 1.1 lukem if (strcmp(grp.gr_mem[i], uname) != 0)
134 1.1 lukem continue;
135 1.1 lukem if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
136 1.1 lukem *result = -1;
137 1.1 lukem break;
138 1.1 lukem }
139 1.1 lukem }
140 1.1 lukem __grend_files(&state);
141 1.1 lukem return NS_NOTFOUND;
142 1.1 lukem }
143 1.1 lukem
144 1.1 lukem
145 1.1 lukem #ifdef HESIOD
146 1.1 lukem
147 1.1 lukem /*ARGSUSED*/
148 1.1 lukem static int
149 1.1 lukem _dns_getgroupmembership(void *retval, void *cb_data, va_list ap)
150 1.1 lukem {
151 1.1 lukem int *result = va_arg(ap, int *);
152 1.1 lukem const char *uname = va_arg(ap, const char *);
153 1.1 lukem gid_t agroup = va_arg(ap, gid_t);
154 1.1 lukem gid_t *groups = va_arg(ap, gid_t *);
155 1.1 lukem int maxgrp = va_arg(ap, int);
156 1.1 lukem int *groupc = va_arg(ap, int *);
157 1.1 lukem
158 1.1 lukem struct __grstate_dns state;
159 1.1 lukem struct group grp;
160 1.1 lukem char grpbuf[_GETGR_R_SIZE_MAX];
161 1.1 lukem unsigned long id;
162 1.1 lukem void *context;
163 1.1 lukem char **hp, *cp, *ep;
164 1.1 lukem int rv, i;
165 1.1 lukem
166 1.1 lukem _DIAGASSERT(result != NULL);
167 1.1 lukem _DIAGASSERT(uname != NULL);
168 1.1 lukem /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
169 1.1 lukem _DIAGASSERT(groupc != NULL);
170 1.1 lukem
171 1.1 lukem /* install primary group */
172 1.1 lukem (void) __gr_addgid(agroup, groups, maxgrp, groupc);
173 1.1 lukem
174 1.1 lukem hp = NULL;
175 1.1 lukem rv = NS_NOTFOUND;
176 1.1 lukem
177 1.1 lukem if (hesiod_init(&context) == -1) /* setup hesiod */
178 1.1 lukem return NS_UNAVAIL;
179 1.1 lukem
180 1.1 lukem hp = hesiod_resolve(context, uname, "grplist"); /* find grplist */
181 1.1 lukem if (hp == NULL) {
182 1.1 lukem if (errno != ENOENT) { /* wasn't "not found"*/
183 1.1 lukem rv = NS_UNAVAIL;
184 1.1 lukem goto dnsgroupmembers_out;
185 1.1 lukem }
186 1.1 lukem /* grplist not found, fallback to _dns_grscan */
187 1.1 lukem memset(&state, 0, sizeof(state));
188 1.1 lukem while (__grscan_dns(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
189 1.1 lukem 0, NULL, 0) == NS_SUCCESS) {
190 1.1 lukem /* scan members */
191 1.1 lukem for (i = 0; grp.gr_mem[i]; i++) {
192 1.1 lukem if (strcmp(grp.gr_mem[i], uname) != 0)
193 1.1 lukem continue;
194 1.1 lukem if (! __gr_addgid(grp.gr_gid, groups, maxgrp,
195 1.1 lukem groupc))
196 1.1 lukem *result = -1;
197 1.1 lukem break;
198 1.1 lukem }
199 1.1 lukem }
200 1.1 lukem __grend_dns(&state);
201 1.1 lukem rv = NS_NOTFOUND;
202 1.1 lukem goto dnsgroupmembers_out;
203 1.1 lukem }
204 1.1 lukem
205 1.1 lukem if ((ep = strchr(hp[0], '\n')) != NULL)
206 1.1 lukem *ep = '\0'; /* clear trailing \n */
207 1.1 lukem
208 1.1 lukem for (cp = hp[0]; *cp != '\0'; ) { /* parse grplist */
209 1.1 lukem if ((cp = strchr(cp, ':')) == NULL) /* skip grpname */
210 1.1 lukem break;
211 1.1 lukem cp++;
212 1.1 lukem id = strtoul(cp, &ep, 10); /* parse gid */
213 1.1 lukem if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
214 1.1 lukem rv = NS_UNAVAIL;
215 1.1 lukem goto dnsgroupmembers_out;
216 1.1 lukem }
217 1.1 lukem cp = ep;
218 1.1 lukem if (*cp == ':')
219 1.1 lukem cp++;
220 1.1 lukem
221 1.1 lukem /* add gid */
222 1.1 lukem if (! __gr_addgid((gid_t)id, groups, maxgrp, groupc))
223 1.1 lukem *result = -1;
224 1.1 lukem }
225 1.1 lukem
226 1.1 lukem rv = NS_NOTFOUND;
227 1.1 lukem
228 1.1 lukem dnsgroupmembers_out:
229 1.1 lukem if (hp)
230 1.1 lukem hesiod_free_list(context, hp);
231 1.1 lukem hesiod_end(context);
232 1.1 lukem return rv;
233 1.1 lukem }
234 1.1 lukem
235 1.1 lukem #endif /* HESIOD */
236 1.1 lukem
237 1.1 lukem
238 1.1 lukem #ifdef YP
239 1.1 lukem
240 1.1 lukem /*ARGSUSED*/
241 1.1 lukem static int
242 1.1 lukem _nis_getgroupmembership(void *retval, void *cb_data, va_list ap)
243 1.1 lukem {
244 1.1 lukem int *result = va_arg(ap, int *);
245 1.1 lukem const char *uname = va_arg(ap, const char *);
246 1.1 lukem gid_t agroup = va_arg(ap, gid_t);
247 1.1 lukem gid_t *groups = va_arg(ap, gid_t *);
248 1.1 lukem int maxgrp = va_arg(ap, int);
249 1.1 lukem int *groupc = va_arg(ap, int *);
250 1.1 lukem
251 1.1 lukem struct __grstate_nis state;
252 1.1 lukem struct group grp;
253 1.1 lukem char grpbuf[_GETGR_R_SIZE_MAX];
254 1.1 lukem int rv, i;
255 1.1 lukem
256 1.1 lukem _DIAGASSERT(result != NULL);
257 1.1 lukem _DIAGASSERT(uname != NULL);
258 1.1 lukem /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
259 1.1 lukem _DIAGASSERT(groupc != NULL);
260 1.1 lukem
261 1.1 lukem /* install primary group */
262 1.1 lukem (void) __gr_addgid(agroup, groups, maxgrp, groupc);
263 1.1 lukem
264 1.1 lukem memset(&state, 0, sizeof(state));
265 1.1 lukem while (__grscan_nis(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
266 1.1 lukem 0, NULL, 0) == NS_SUCCESS) {
267 1.1 lukem /* scan members */
268 1.1 lukem for (i = 0; grp.gr_mem[i]; i++) {
269 1.1 lukem if (strcmp(grp.gr_mem[i], uname) != 0)
270 1.1 lukem continue;
271 1.1 lukem if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
272 1.1 lukem *result = -1;
273 1.1 lukem break;
274 1.1 lukem }
275 1.1 lukem }
276 1.1 lukem __grend_nis(&state);
277 1.1 lukem
278 1.1 lukem return NS_NOTFOUND;
279 1.1 lukem }
280 1.1 lukem
281 1.1 lukem #endif /* YP */
282 1.1 lukem
283 1.1 lukem
284 1.1 lukem #ifdef _GROUP_COMPAT
285 1.1 lukem
286 1.1 lukem struct __compatggm {
287 1.1 lukem const char *uname; /* user to search for */
288 1.1 lukem gid_t *groups;
289 1.1 lukem gid_t agroup;
290 1.1 lukem int maxgrp;
291 1.1 lukem int *groupc;
292 1.1 lukem };
293 1.1 lukem
294 1.1 lukem static int
295 1.1 lukem _compat_ggm_search(void *cookie, struct group **groupres)
296 1.1 lukem {
297 1.1 lukem struct __compatggm *cp;
298 1.1 lukem int rerror, crv;
299 1.1 lukem
300 1.1 lukem static const ns_dtab dtab[] = {
301 1.1 lukem NS_FILES_CB(__grbad_compat, "files")
302 1.1 lukem NS_DNS_CB(_dns_getgroupmembership, NULL)
303 1.1 lukem NS_NIS_CB(_nis_getgroupmembership, NULL)
304 1.1 lukem NS_COMPAT_CB(__grbad_compat, "compat")
305 1.1 lukem { 0 }
306 1.1 lukem };
307 1.1 lukem
308 1.1 lukem *groupres = NULL; /* we don't care about this */
309 1.1 lukem cp = (struct __compatggm *)cookie;
310 1.1 lukem
311 1.1 lukem crv = nsdispatch(NULL, dtab,
312 1.1 lukem NSDB_GROUP_COMPAT, "getgroupmembership",
313 1.1 lukem __nsdefaultnis,
314 1.1 lukem &rerror, cp->uname, cp->agroup, cp->groups, cp->maxgrp, cp->groupc);
315 1.1 lukem
316 1.1 lukem if (crv == NS_SUCCESS)
317 1.1 lukem crv = NS_NOTFOUND; /* indicate "no more +: entries" */
318 1.1 lukem
319 1.1 lukem return crv;
320 1.1 lukem }
321 1.1 lukem
322 1.1 lukem /* ARGSUSED */
323 1.1 lukem static int
324 1.1 lukem _compat_getgroupmembership(void *retval, void *cb_data, va_list ap)
325 1.1 lukem {
326 1.1 lukem int *result = va_arg(ap, int *);
327 1.1 lukem const char *uname = va_arg(ap, const char *);
328 1.1 lukem gid_t agroup = va_arg(ap, gid_t);
329 1.1 lukem gid_t *groups = va_arg(ap, gid_t *);
330 1.1 lukem int maxgrp = va_arg(ap, int);
331 1.1 lukem int *groupc = va_arg(ap, int *);
332 1.1 lukem
333 1.1 lukem struct __grstate_compat state;
334 1.1 lukem struct __compatggm ggmstate;
335 1.1 lukem struct group grp;
336 1.1 lukem char grpbuf[_GETGR_R_SIZE_MAX];
337 1.1 lukem int rv, i;
338 1.1 lukem
339 1.1 lukem _DIAGASSERT(result != NULL);
340 1.1 lukem _DIAGASSERT(uname != NULL);
341 1.1 lukem /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
342 1.1 lukem _DIAGASSERT(groupc != NULL);
343 1.1 lukem
344 1.1 lukem /* install primary group */
345 1.1 lukem (void) __gr_addgid(agroup, groups, maxgrp, groupc);
346 1.1 lukem
347 1.1 lukem memset(&state, 0, sizeof(state));
348 1.1 lukem memset(&ggmstate, 0, sizeof(ggmstate));
349 1.1 lukem ggmstate.uname = uname;
350 1.1 lukem ggmstate.groups = groups;
351 1.1 lukem ggmstate.agroup = agroup;
352 1.1 lukem ggmstate.maxgrp = maxgrp;
353 1.1 lukem ggmstate.groupc = groupc;
354 1.1 lukem
355 1.1 lukem while (__grscan_compat(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
356 1.1 lukem 0, NULL, 0, _compat_ggm_search, &ggmstate)
357 1.1 lukem == NS_SUCCESS) {
358 1.1 lukem /* scan members */
359 1.1 lukem for (i = 0; grp.gr_mem[i]; i++) {
360 1.1 lukem if (strcmp(grp.gr_mem[i], uname) != 0)
361 1.1 lukem continue;
362 1.1 lukem if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
363 1.1 lukem *result = -1;
364 1.1 lukem break;
365 1.1 lukem }
366 1.1 lukem }
367 1.1 lukem
368 1.1 lukem __grend_compat(&state);
369 1.1 lukem return NS_NOTFOUND;
370 1.1 lukem }
371 1.1 lukem
372 1.1 lukem #endif /* _GROUP_COMPAT */
373 1.1 lukem
374 1.1 lukem
375 1.1 lukem int
376 1.1 lukem getgroupmembership(const char *uname, gid_t agroup,
377 1.1 lukem gid_t *groups, int maxgrp, int *groupc)
378 1.1 lukem {
379 1.1 lukem int rerror;
380 1.1 lukem
381 1.1 lukem static const ns_dtab dtab[] = {
382 1.1 lukem NS_FILES_CB(_files_getgroupmembership, NULL)
383 1.1 lukem NS_DNS_CB(_dns_getgroupmembership, NULL)
384 1.1 lukem NS_NIS_CB(_nis_getgroupmembership, NULL)
385 1.1 lukem NS_COMPAT_CB(_compat_getgroupmembership, NULL)
386 1.1 lukem { 0 }
387 1.1 lukem };
388 1.1 lukem
389 1.1 lukem _DIAGASSERT(uname != NULL);
390 1.1 lukem /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
391 1.1 lukem _DIAGASSERT(groupc != NULL);
392 1.1 lukem
393 1.1 lukem *groupc = 0;
394 1.1 lukem
395 1.1 lukem mutex_lock(&__grmutex);
396 1.1 lukem /*
397 1.1 lukem * Call each backend.
398 1.1 lukem * For compatibility with getgrent(3) semantics,
399 1.1 lukem * a backend should return NS_NOTFOUND even upon
400 1.1 lukem * completion, to allow result merging to occur.
401 1.1 lukem */
402 1.1 lukem (void) nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
403 1.1 lukem __nsdefaultcompat,
404 1.1 lukem &rerror, uname, agroup, groups, maxgrp, groupc);
405 1.1 lukem mutex_unlock(&__grmutex);
406 1.1 lukem
407 1.1 lukem if (*groupc > maxgrp) /* too many groups found */
408 1.1 lukem return -1;
409 1.1 lukem else
410 1.1 lukem return 0;
411 1.1 lukem }
412