Implement getgroupmembership(3). This is similar to getgrouplist(3), except

that the "int maxgroups" and "int *ngroups" parameters are separated into
two separate parameters which makes it possible to call multiple nsswitch
back-ends and have the results correctly merged.
getgrouplist(3) is now implemented using getgroupmembership(3).

Proposed on tech-userlevel on December 1, 2004.
This commit is contained in:
lukem 2005-01-06 15:10:45 +00:00
parent 337d8d731d
commit a3665ef9cf
6 changed files with 478 additions and 195 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: getgrent.c,v 1.8 2003/10/13 15:36:33 agc Exp $ */
/* $NetBSD: getgrent.c,v 1.9 2005/01/06 15:10:45 lukem Exp $ */
/*
* Copyright (c) 1989, 1993
* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -69,6 +69,7 @@
#define getgrnam _getgrnam
#define setgrent _setgrent
#define setgroupent _setgroupent
#define getgroupmembership _getgroupmembership
__weak_alias(endgrent,_endgrent)
__weak_alias(getgrent,_getgrent)
@ -76,9 +77,10 @@ __weak_alias(getgrgid,_getgrgid)
__weak_alias(getgrnam,_getgrnam)
__weak_alias(setgrent,_setgrent)
__weak_alias(setgroupent,_setgroupent)
__weak_alias(getgroupmembership,_getgroupmembership)
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <grp.h>
#include <limits.h>
@ -86,8 +88,6 @@ __weak_alias(setgroupent,_setgroupent)
#include <stdlib.h>
#include <string.h>
struct group *_getgrent_user(const char *);
static FILE *_gr_fp;
static struct group _gr_group;
static int _gr_stayopen;
@ -112,21 +112,6 @@ getgrent(void)
return &_gr_group;
}
/*
* _getgrent_user() is designed only to be called by getgrouplist(3) and
* hence makes no guarantees about filling the entire structure that it
* returns. It may only fill in the group name and gid fields.
*/
struct group *
_getgrent_user(const char *user)
{
if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, user))
return (NULL);
return &_gr_group;
}
struct group *
getgrnam(const char *name)
{
@ -193,6 +178,53 @@ endgrent(void)
}
}
int
getgroupmembership(const char *uname, gid_t agroup,
gid_t *groups, int maxgroups, int *grpcnt)
{
struct group *grp;
int i, ngroups, ret;
ret = 0;
ngroups = 0;
/*
* install primary group
*/
if (ngroups < maxgroups)
groups[ngroups] = agroup;
else
ret = -1;
ngroups++;
/*
* Scan the group file to find additional groups.
*/
setgrent();
nextgroup:
while ((grp = getgrent()) != NULL) {
if (grp->gr_gid == agroup)
continue;
for (i = 0; grp->gr_mem[i]; i++) {
if (strcmp(grp->gr_mem[i], uname) != 0)
continue;
for (i = 0; i < MIN(ngroups, maxgroups); i++) {
if (grp->gr_gid == groups[i])
goto nextgroup;
}
if (ngroups < maxgroups)
groups[ngroups] = grp->gr_gid;
else
ret = -1;
ngroups++;
break;
}
}
endgrent();
*grpcnt = ngroups;
return ret;
}
static int
grscan(int search, gid_t gid, const char *name, const char *user)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: unistd.h,v 1.99 2004/06/01 16:10:29 kleink Exp $ */
/* $NetBSD: unistd.h,v 1.100 2005/01/06 15:10:45 lukem Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@ -311,6 +311,7 @@ int fchroot __P((int));
int fsync_range __P((int, int, off_t, off_t));
int getdomainname __P((char *, size_t));
int getgrouplist __P((const char *, gid_t, gid_t *, int *));
int getgroupmembership __P((const char *, gid_t, gid_t *, int, int *));
mode_t getmode __P((const void *, mode_t));
int getsubopt __P((char **, char * const *, char **));
__aconst char *getusershell __P((void));

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.inc,v 1.138 2005/01/02 16:43:26 thorpej Exp $
# $NetBSD: Makefile.inc,v 1.139 2005/01/06 15:10:45 lukem Exp $
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
# gen sources
@ -10,8 +10,8 @@ SRCS+= _errno.c alarm.c arc4random.c assert.c basename.c clock.c closedir.c \
execle.c execlp.c execv.c execvp.c extattr.c \
fmtcheck.c fmtmsg.c fnmatch.c \
fstab.c ftok.c __fts13.c fts.c getbsize.c getcap.c getcwd.c \
getdevmajor.c \
getdomainname.c getgrent.c getgrouplist.c gethostname.c \
getdevmajor.c getdomainname.c getgrent.c \
getgrouplist.c getgroupmembership.c gethostname.c \
getloadavg.c getlogin.c getmntinfo.c __getmntinfo13.c \
getnetgrent.c getpagesize.c \
getpass.c getprogname.c getpwent.c getttyent.c \

View File

@ -1,7 +1,7 @@
/* $NetBSD: getgrouplist.c,v 1.20 2004/09/28 10:46:19 lukem Exp $ */
/* $NetBSD: getgrouplist.c,v 1.21 2005/01/06 15:10:45 lukem Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -36,41 +36,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)getgrouplist.c 8.2 (Berkeley) 12/8/94";
#else
__RCSID("$NetBSD: getgrouplist.c,v 1.20 2004/09/28 10:46:19 lukem Exp $");
__RCSID("$NetBSD: getgrouplist.c,v 1.21 2005/01/06 15:10:45 lukem Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@ -82,158 +53,25 @@ __RCSID("$NetBSD: getgrouplist.c,v 1.20 2004/09/28 10:46:19 lukem Exp $");
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <nsswitch.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HESIOD
#include <hesiod.h>
#endif
#ifdef __weak_alias
__weak_alias(getgrouplist,_getgrouplist)
#endif
#ifdef HESIOD
/*ARGSUSED*/
static int
_nss_dns_getgrouplist(void *retval, void *cb_data, va_list ap)
{
int *result = va_arg(ap, int *);
const char *uname = va_arg(ap, const char *);
gid_t agroup = va_arg(ap, gid_t);
gid_t *groups = va_arg(ap, gid_t *);
int *grpcnt = va_arg(ap, int *);
unsigned long id;
void *context;
char **hp, *cp, *ep;
int rv, ret, ngroups, maxgroups;
hp = NULL;
rv = NS_NOTFOUND;
ret = 0;
if (hesiod_init(&context) == -1) /* setup hesiod */
return NS_UNAVAIL;
hp = hesiod_resolve(context, uname, "grplist"); /* find grplist */
if (hp == NULL) {
if (errno != ENOENT)
rv = NS_NOTFOUND;
goto dnsgrouplist_out;
}
if ((ep = strchr(hp[0], '\n')) != NULL)
*ep = '\0'; /* clear trailing \n */
ret = 0;
ngroups = 0;
maxgroups = *grpcnt;
if (ngroups < maxgroups) /* add primary gid */
groups[ngroups] = agroup;
else
ret = -1;
ngroups++;
for (cp = hp[0]; *cp != '\0'; ) { /* parse grplist */
if ((cp = strchr(cp, ':')) == NULL) /* skip grpname */
break;
cp++;
id = strtoul(cp, &ep, 10); /* parse gid */
if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
rv = NS_UNAVAIL;
goto dnsgrouplist_out;
}
cp = ep;
if (*cp == ':')
cp++;
if (ngroups < maxgroups) /* add this gid */
groups[ngroups] = (gid_t)id;
else
ret = -1;
ngroups++;
}
*result = ret;
*grpcnt = ngroups;
rv = NS_SUCCESS;
dnsgrouplist_out:
if (hp)
hesiod_free_list(context, hp);
hesiod_end(context);
return rv;
}
#endif /* HESIOD */
int
getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
{
struct group *grp;
int i, ngroups, maxgroups, ret;
static const ns_dtab dtab[] = {
NS_DNS_CB(_nss_dns_getgrouplist, NULL)
{ 0 }
};
int rv, groupc;
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with *grpcnt = 0 */
_DIAGASSERT(grpcnt != NULL);
/* first, try source-specific optimized getgrouplist */
i = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrouplist",
__nsdefaultsrc,
&ret, uname, agroup, groups, grpcnt);
if (i == NS_SUCCESS)
return ret;
/* fallback to scan the group(5) database */
ret = 0;
ngroups = 0;
maxgroups = *grpcnt;
/*
* install primary group
*/
if (ngroups < maxgroups)
groups[ngroups] = agroup;
else
ret = -1;
ngroups++;
/*
* Scan the group file to find additional groups.
*/
setgrent();
nextgroup:
while ((grp = getgrent()) != NULL) {
if (grp->gr_gid == agroup)
continue;
for (i = 0; grp->gr_mem[i]; i++) {
if (strcmp(grp->gr_mem[i], uname) != 0)
continue;
for (i = 0; i < MIN(ngroups, maxgroups); i++) {
if (grp->gr_gid == groups[i])
goto nextgroup;
}
if (ngroups < maxgroups)
groups[ngroups] = grp->gr_gid;
else
ret = -1;
ngroups++;
break;
}
}
endgrent();
*grpcnt = ngroups;
return ret;
groupc = 0;
rv = getgroupmembership(uname, agroup, groups, *grpcnt, &groupc);
*grpcnt = groupc; /* set groupc to the actual # of groups */
return rv;
}

View File

@ -0,0 +1,411 @@
/* $NetBSD: getgroupmembership.c,v 1.1 2005/01/06 15:10:45 lukem Exp $ */
/*-
* Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: getgroupmembership.c,v 1.1 2005/01/06 15:10:45 lukem Exp $");
#endif /* LIBC_SCCS and not lint */
/*
* calculate group access list
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <nsswitch.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HESIOD
#include <hesiod.h>
#endif
#include "gr_private.h"
#ifdef __weak_alias
__weak_alias(getgroupmembership,_getgroupmembership)
#endif
/*
* __gr_addgid
* Add gid to the groups array (of maxgrp size) at the position
* indicated by *groupc, unless it already exists or *groupc is
* past &groups[maxgrp].
* Returns 1 upon success (including duplicate suppression), 0 otherwise.
*/
static int
__gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *groupc)
{
int ret, dupc;
_DIAGASSERT(grpcnt != NULL);
/* skip duplicates */
for (dupc = 0; dupc < MIN(maxgrp, *groupc); dupc++) {
if (groups[dupc] == gid)
return 1;
}
ret = 1;
if (*groupc < maxgrp) /* add this gid */
groups[*groupc] = gid;
else
ret = 0;
(*groupc)++;
return ret;
}
/*ARGSUSED*/
static int
_files_getgroupmembership(void *retval, void *cb_data, va_list ap)
{
int *result = va_arg(ap, int *);
const char *uname = va_arg(ap, const char *);
gid_t agroup = va_arg(ap, gid_t);
gid_t *groups = va_arg(ap, gid_t *);
int maxgrp = va_arg(ap, int);
int *groupc = va_arg(ap, int *);
struct __grstate_files state;
struct group grp;
char grpbuf[_GETGR_R_SIZE_MAX];
int rv, i;
_DIAGASSERT(result != NULL);
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
_DIAGASSERT(groupc != NULL);
/* install primary group */
(void) __gr_addgid(agroup, groups, maxgrp, groupc);
memset(&state, 0, sizeof(state));
while (__grscan_files(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
0, NULL, 0) == NS_SUCCESS) {
/* scan members */
for (i = 0; grp.gr_mem[i]; i++) {
if (strcmp(grp.gr_mem[i], uname) != 0)
continue;
if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
*result = -1;
break;
}
}
__grend_files(&state);
return NS_NOTFOUND;
}
#ifdef HESIOD
/*ARGSUSED*/
static int
_dns_getgroupmembership(void *retval, void *cb_data, va_list ap)
{
int *result = va_arg(ap, int *);
const char *uname = va_arg(ap, const char *);
gid_t agroup = va_arg(ap, gid_t);
gid_t *groups = va_arg(ap, gid_t *);
int maxgrp = va_arg(ap, int);
int *groupc = va_arg(ap, int *);
struct __grstate_dns state;
struct group grp;
char grpbuf[_GETGR_R_SIZE_MAX];
unsigned long id;
void *context;
char **hp, *cp, *ep;
int rv, i;
_DIAGASSERT(result != NULL);
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
_DIAGASSERT(groupc != NULL);
/* install primary group */
(void) __gr_addgid(agroup, groups, maxgrp, groupc);
hp = NULL;
rv = NS_NOTFOUND;
if (hesiod_init(&context) == -1) /* setup hesiod */
return NS_UNAVAIL;
hp = hesiod_resolve(context, uname, "grplist"); /* find grplist */
if (hp == NULL) {
if (errno != ENOENT) { /* wasn't "not found"*/
rv = NS_UNAVAIL;
goto dnsgroupmembers_out;
}
/* grplist not found, fallback to _dns_grscan */
memset(&state, 0, sizeof(state));
while (__grscan_dns(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
0, NULL, 0) == NS_SUCCESS) {
/* scan members */
for (i = 0; grp.gr_mem[i]; i++) {
if (strcmp(grp.gr_mem[i], uname) != 0)
continue;
if (! __gr_addgid(grp.gr_gid, groups, maxgrp,
groupc))
*result = -1;
break;
}
}
__grend_dns(&state);
rv = NS_NOTFOUND;
goto dnsgroupmembers_out;
}
if ((ep = strchr(hp[0], '\n')) != NULL)
*ep = '\0'; /* clear trailing \n */
for (cp = hp[0]; *cp != '\0'; ) { /* parse grplist */
if ((cp = strchr(cp, ':')) == NULL) /* skip grpname */
break;
cp++;
id = strtoul(cp, &ep, 10); /* parse gid */
if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
rv = NS_UNAVAIL;
goto dnsgroupmembers_out;
}
cp = ep;
if (*cp == ':')
cp++;
/* add gid */
if (! __gr_addgid((gid_t)id, groups, maxgrp, groupc))
*result = -1;
}
rv = NS_NOTFOUND;
dnsgroupmembers_out:
if (hp)
hesiod_free_list(context, hp);
hesiod_end(context);
return rv;
}
#endif /* HESIOD */
#ifdef YP
/*ARGSUSED*/
static int
_nis_getgroupmembership(void *retval, void *cb_data, va_list ap)
{
int *result = va_arg(ap, int *);
const char *uname = va_arg(ap, const char *);
gid_t agroup = va_arg(ap, gid_t);
gid_t *groups = va_arg(ap, gid_t *);
int maxgrp = va_arg(ap, int);
int *groupc = va_arg(ap, int *);
struct __grstate_nis state;
struct group grp;
char grpbuf[_GETGR_R_SIZE_MAX];
int rv, i;
_DIAGASSERT(result != NULL);
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
_DIAGASSERT(groupc != NULL);
/* install primary group */
(void) __gr_addgid(agroup, groups, maxgrp, groupc);
memset(&state, 0, sizeof(state));
while (__grscan_nis(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
0, NULL, 0) == NS_SUCCESS) {
/* scan members */
for (i = 0; grp.gr_mem[i]; i++) {
if (strcmp(grp.gr_mem[i], uname) != 0)
continue;
if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
*result = -1;
break;
}
}
__grend_nis(&state);
return NS_NOTFOUND;
}
#endif /* YP */
#ifdef _GROUP_COMPAT
struct __compatggm {
const char *uname; /* user to search for */
gid_t *groups;
gid_t agroup;
int maxgrp;
int *groupc;
};
static int
_compat_ggm_search(void *cookie, struct group **groupres)
{
struct __compatggm *cp;
int rerror, crv;
static const ns_dtab dtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_getgroupmembership, NULL)
NS_NIS_CB(_nis_getgroupmembership, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
{ 0 }
};
*groupres = NULL; /* we don't care about this */
cp = (struct __compatggm *)cookie;
crv = nsdispatch(NULL, dtab,
NSDB_GROUP_COMPAT, "getgroupmembership",
__nsdefaultnis,
&rerror, cp->uname, cp->agroup, cp->groups, cp->maxgrp, cp->groupc);
if (crv == NS_SUCCESS)
crv = NS_NOTFOUND; /* indicate "no more +: entries" */
return crv;
}
/* ARGSUSED */
static int
_compat_getgroupmembership(void *retval, void *cb_data, va_list ap)
{
int *result = va_arg(ap, int *);
const char *uname = va_arg(ap, const char *);
gid_t agroup = va_arg(ap, gid_t);
gid_t *groups = va_arg(ap, gid_t *);
int maxgrp = va_arg(ap, int);
int *groupc = va_arg(ap, int *);
struct __grstate_compat state;
struct __compatggm ggmstate;
struct group grp;
char grpbuf[_GETGR_R_SIZE_MAX];
int rv, i;
_DIAGASSERT(result != NULL);
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
_DIAGASSERT(groupc != NULL);
/* install primary group */
(void) __gr_addgid(agroup, groups, maxgrp, groupc);
memset(&state, 0, sizeof(state));
memset(&ggmstate, 0, sizeof(ggmstate));
ggmstate.uname = uname;
ggmstate.groups = groups;
ggmstate.agroup = agroup;
ggmstate.maxgrp = maxgrp;
ggmstate.groupc = groupc;
while (__grscan_compat(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
0, NULL, 0, _compat_ggm_search, &ggmstate)
== NS_SUCCESS) {
/* scan members */
for (i = 0; grp.gr_mem[i]; i++) {
if (strcmp(grp.gr_mem[i], uname) != 0)
continue;
if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
*result = -1;
break;
}
}
__grend_compat(&state);
return NS_NOTFOUND;
}
#endif /* _GROUP_COMPAT */
int
getgroupmembership(const char *uname, gid_t agroup,
gid_t *groups, int maxgrp, int *groupc)
{
int rerror;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgroupmembership, NULL)
NS_DNS_CB(_dns_getgroupmembership, NULL)
NS_NIS_CB(_nis_getgroupmembership, NULL)
NS_COMPAT_CB(_compat_getgroupmembership, NULL)
{ 0 }
};
_DIAGASSERT(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
_DIAGASSERT(groupc != NULL);
*groupc = 0;
mutex_lock(&__grmutex);
/*
* Call each backend.
* For compatibility with getgrent(3) semantics,
* a backend should return NS_NOTFOUND even upon
* completion, to allow result merging to occur.
*/
(void) nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
__nsdefaultcompat,
&rerror, uname, agroup, groups, maxgrp, groupc);
mutex_unlock(&__grmutex);
if (*groupc > maxgrp) /* too many groups found */
return -1;
else
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: namespace.h,v 1.96 2004/12/16 12:30:04 kleink Exp $ */
/* $NetBSD: namespace.h,v 1.97 2005/01/06 15:10:45 lukem Exp $ */
/*-
* Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
@ -226,6 +226,7 @@
#define getgrnam _getgrnam
#define getgrnam_r _getgrnam_r
#define getgrouplist _getgrouplist
#define getgroupmembership _getgroupmembership
#define gethostbyaddr _gethostbyaddr
#define gethostbyname _gethostbyname
#define gethostent _gethostent