1 /* $NetBSD: getgroupmembership.c,v 1.4 2008/04/28 20:22:59 martin Exp $ */
4 * Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.4 2008/04/28 20:22:59 martin 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>
61 #include "gr_private.h"
64 __weak_alias(getgroupmembership
,_getgroupmembership
)
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.
75 __gr_addgid(gid_t gid
, gid_t
*groups
, int maxgrp
, int *groupc
)
79 _DIAGASSERT(groupc
!= NULL
);
80 _DIAGASSERT(groups
!= NULL
);
83 for (dupc
= 0; dupc
< MIN(maxgrp
, *groupc
); dupc
++) {
84 if (groups
[dupc
] == gid
)
89 if (*groupc
< maxgrp
) /* add this gid */
90 groups
[*groupc
] = gid
;
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
;
111 char grpbuf
[_GETGR_R_SIZE_MAX
];
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
) {
126 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
127 if (strcmp(grp
.gr_mem
[i
], uname
) != 0)
129 if (! __gr_addgid(grp
.gr_gid
, groups
, maxgrp
, groupc
))
134 __grend_files(&state
);
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
;
154 char grpbuf
[_GETGR_R_SIZE_MAX
];
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
);
171 if (hesiod_init(&context
) == -1) /* setup hesiod */
174 hp
= hesiod_resolve(context
, uname
, "grplist"); /* find grplist */
176 if (errno
!= ENOENT
) { /* wasn't "not found"*/
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
) {
185 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
186 if (strcmp(grp
.gr_mem
[i
], uname
) != 0)
188 if (! __gr_addgid(grp
.gr_gid
, groups
, maxgrp
,
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 */
206 id
= strtoul(cp
, &ep
, 10); /* parse gid */
207 if (id
> GID_MAX
|| (*ep
!= ':' && *ep
!= '\0')) {
209 goto dnsgroupmembers_out
;
216 if (! __gr_addgid((gid_t
)id
, groups
, maxgrp
, groupc
))
224 hesiod_free_list(context
, hp
);
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
;
247 char grpbuf
[_GETGR_R_SIZE_MAX
];
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
) {
262 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
263 if (strcmp(grp
.gr_mem
[i
], uname
) != 0)
265 if (! __gr_addgid(grp
.gr_gid
, groups
, maxgrp
, groupc
))
281 const char *uname
; /* user to search for */
289 _compat_ggm_search(void *cookie
, struct group
**groupres
)
291 struct __compatggm
*cp
;
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")
302 *groupres
= NULL
; /* we don't care about this */
303 cp
= (struct __compatggm
*)cookie
;
305 crv
= nsdispatch(NULL
, dtab
,
306 NSDB_GROUP_COMPAT
, "getgroupmembership",
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" */
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
;
330 char grpbuf
[_GETGR_R_SIZE_MAX
];
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
)
353 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
354 if (strcmp(grp
.gr_mem
[i
], uname
) != 0)
356 if (! __gr_addgid(grp
.gr_gid
, groups
, maxgrp
, groupc
))
362 __grend_compat(&state
);
366 #endif /* _GROUP_COMPAT */
370 getgroupmembership(const char *uname
, gid_t agroup
,
371 gid_t
*groups
, int maxgrp
, int *groupc
)
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
)
383 _DIAGASSERT(uname
!= NULL
);
384 /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
385 _DIAGASSERT(groupc
!= NULL
);
389 mutex_lock(&__grmutex
);
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",
398 &rerror
, uname
, agroup
, groups
, maxgrp
, groupc
);
399 mutex_unlock(&__grmutex
);
401 if (*groupc
> maxgrp
) /* too many groups found */