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