Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libc / gen / getgroupmembership.c
blobf8b901e52e62b908b6450144c926176c7e7db254
1 /* $NetBSD: getgroupmembership.c,v 1.3 2007/02/03 16:17:15 christos Exp $ */
3 /*-
4 * Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
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.
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.
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 __RCSID("$NetBSD: getgroupmembership.c,v 1.3 2007/02/03 16:17:15 christos Exp $");
35 #endif /* LIBC_SCCS and not lint */
38 * calculate group access list
41 #include "namespace.h"
42 #include "reentrant.h"
44 #include <sys/param.h>
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>
57 #ifdef HESIOD
58 #include <hesiod.h>
59 #endif
61 #include "gr_private.h"
63 #ifdef __weak_alias
64 __weak_alias(getgroupmembership,_getgroupmembership)
65 #endif
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.
74 static int
75 __gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *groupc)
77 int ret, dupc;
79 _DIAGASSERT(groupc != NULL);
80 _DIAGASSERT(groups != NULL);
82 /* skip duplicates */
83 for (dupc = 0; dupc < MIN(maxgrp, *groupc); dupc++) {
84 if (groups[dupc] == gid)
85 return 1;
88 ret = 1;
89 if (*groupc < maxgrp) /* add this gid */
90 groups[*groupc] = gid;
91 else
92 ret = 0;
93 (*groupc)++;
94 return ret;
98 /*ARGSUSED*/
99 static int
100 _files_getgroupmembership(void *retval, void *cb_data, va_list ap)
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 *);
109 struct __grstate_files state;
110 struct group grp;
111 char grpbuf[_GETGR_R_SIZE_MAX];
112 int rv, i;
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);
119 /* install primary group */
120 (void) __gr_addgid(agroup, groups, maxgrp, groupc);
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;
134 __grend_files(&state);
135 return NS_NOTFOUND;
139 #ifdef HESIOD
141 /*ARGSUSED*/
142 static int
143 _dns_getgroupmembership(void *retval, void *cb_data, va_list ap)
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 *);
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;
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);
165 /* install primary group */
166 (void) __gr_addgid(agroup, groups, maxgrp, groupc);
168 hp = NULL;
169 rv = NS_NOTFOUND;
171 if (hesiod_init(&context) == -1) /* setup hesiod */
172 return NS_UNAVAIL;
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;
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;
194 __grend_dns(&state);
195 rv = NS_NOTFOUND;
196 goto dnsgroupmembers_out;
199 if ((ep = strchr(hp[0], '\n')) != NULL)
200 *ep = '\0'; /* clear trailing \n */
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;
211 cp = ep;
212 if (*cp == ':')
213 cp++;
215 /* add gid */
216 if (! __gr_addgid((gid_t)id, groups, maxgrp, groupc))
217 *result = -1;
220 rv = NS_NOTFOUND;
222 dnsgroupmembers_out:
223 if (hp)
224 hesiod_free_list(context, hp);
225 hesiod_end(context);
226 return rv;
229 #endif /* HESIOD */
232 #ifdef YP
234 /*ARGSUSED*/
235 static int
236 _nis_getgroupmembership(void *retval, void *cb_data, va_list ap)
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 *);
245 struct __grstate_nis state;
246 struct group grp;
247 char grpbuf[_GETGR_R_SIZE_MAX];
248 int rv, i;
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);
255 /* install primary group */
256 (void) __gr_addgid(agroup, groups, maxgrp, groupc);
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;
270 __grend_nis(&state);
272 return NS_NOTFOUND;
275 #endif /* YP */
278 #ifdef _GROUP_COMPAT
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;
288 static int
289 _compat_ggm_search(void *cookie, struct group **groupres)
291 struct __compatggm *cp;
292 int rerror, crv;
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")
299 NS_NULL_CB
302 *groupres = NULL; /* we don't care about this */
303 cp = (struct __compatggm *)cookie;
305 crv = nsdispatch(NULL, dtab,
306 NSDB_GROUP_COMPAT, "getgroupmembership",
307 __nsdefaultnis,
308 &rerror, cp->uname, cp->agroup, cp->groups, cp->maxgrp, cp->groupc);
310 if (crv == NS_SUCCESS)
311 crv = NS_NOTFOUND; /* indicate "no more +: entries" */
313 return crv;
316 /* ARGSUSED */
317 static int
318 _compat_getgroupmembership(void *retval, void *cb_data, va_list ap)
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 *);
327 struct __grstate_compat state;
328 struct __compatggm ggmstate;
329 struct group grp;
330 char grpbuf[_GETGR_R_SIZE_MAX];
331 int rv, i;
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);
338 /* install primary group */
339 (void) __gr_addgid(agroup, groups, maxgrp, groupc);
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;
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;
362 __grend_compat(&state);
363 return NS_NOTFOUND;
366 #endif /* _GROUP_COMPAT */
370 getgroupmembership(const char *uname, gid_t agroup,
371 gid_t *groups, int maxgrp, int *groupc)
373 int rerror;
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)
380 NS_NULL_CB
383 _DIAGASSERT(uname != NULL);
384 /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
385 _DIAGASSERT(groupc != NULL);
387 *groupc = 0;
389 mutex_lock(&__grmutex);
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.
396 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
397 __nsdefaultcompat,
398 &rerror, uname, agroup, groups, maxgrp, groupc);
399 mutex_unlock(&__grmutex);
401 if (*groupc > maxgrp) /* too many groups found */
402 return -1;
403 else
404 return 0;