minix/lib/libc/gen/getgrent.c
Ben Gras 2fe8fb192f Full switch to clang/ELF. Drop ack. Simplify.
There is important information about booting non-ack images in
docs/UPDATING. ack/aout-format images can't be built any more, and
booting clang/ELF-format ones is a little different. Updating to the
new boot monitor is recommended.

Changes in this commit:

	. drop boot monitor -> allowing dropping ack support
	. facility to copy ELF boot files to /boot so that old boot monitor
	  can still boot fairly easily, see UPDATING
	. no more ack-format libraries -> single-case libraries
	. some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases
	. drop several ack toolchain commands, but not all support
	  commands (e.g. aal is gone but acksize is not yet).
	. a few libc files moved to netbsd libc dir
	. new /bin/date as minix date used code in libc/
	. test compile fix
	. harmonize includes
	. /usr/lib is no longer special: without ack, /usr/lib plays no
	  kind of special bootstrapping role any more and bootstrapping
	  is done exclusively through packages, so releases depend even
	  less on the state of the machine making them now.
	. rename nbsd_lib* to lib*
	. reduce mtree
2012-02-14 14:52:02 +01:00

1936 lines
45 KiB
C

/* $NetBSD: getgrent.c,v 1.62 2008/04/28 20:22:59 martin Exp $ */
/*-
* Copyright (c) 1999-2000, 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.
*
* 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.
*/
/*
* Copyright (c) 1989, 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.
*/
/*
* Portions Copyright (c) 1994, Jason Downs. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
#else
__RCSID("$NetBSD: getgrent.c,v 1.62 2008/04/28 20:22:59 martin Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#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 <syslog.h>
#ifdef HESIOD
#include <hesiod.h>
#endif
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include "gr_private.h"
#ifdef __weak_alias
__weak_alias(endgrent,_endgrent)
__weak_alias(getgrent,_getgrent)
__weak_alias(getgrent_r,_getgrent_r)
__weak_alias(getgrgid,_getgrgid)
__weak_alias(getgrgid_r,_getgrgid_r)
__weak_alias(getgrnam,_getgrnam)
__weak_alias(getgrnam_r,_getgrnam_r)
__weak_alias(setgrent,_setgrent)
__weak_alias(setgroupent,_setgroupent)
#endif
#ifdef _REENTRANT
mutex_t __grmutex = MUTEX_INITIALIZER;
#endif
/*
* _gr_memfrombuf
* Obtain want bytes from buffer (of size buflen) and return a pointer
* to the available memory after adjusting buffer/buflen.
* Returns NULL if there is insufficient space.
*/
static char *
_gr_memfrombuf(size_t want, char **buffer, size_t *buflen)
{
char *rv;
if (want > *buflen) {
errno = ERANGE;
return NULL;
}
rv = *buffer;
*buffer += want;
*buflen -= want;
return rv;
}
/*
* _gr_parse
* Parses entry as a line per group(5) (without the trailing \n)
* and fills in grp with corresponding values; memory for strings
* and arrays will be allocated from buf (of size buflen).
* Returns 1 if parsed successfully, 0 on parse failure.
*/
static int
_gr_parse(const char *entry, struct group *grp, char *buf, size_t buflen)
{
unsigned long id;
const char *bp;
char *ep;
size_t count;
int memc;
_DIAGASSERT(entry != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buf != NULL);
#define COPYTOBUF(to) \
do { \
(to) = _gr_memfrombuf(count+1, &buf, &buflen); \
if ((to) == NULL) \
return 0; \
memmove((to), entry, count); \
to[count] = '\0'; \
} while (0) /* LINTED */
#if 0
if (*entry == '+') /* fail on compat `+' token */
return 0;
#endif
count = strcspn(entry, ":"); /* parse gr_name */
if (entry[count] == '\0')
return 0;
COPYTOBUF(grp->gr_name);
entry += count + 1;
count = strcspn(entry, ":"); /* parse gr_passwd */
if (entry[count] == '\0')
return 0;
COPYTOBUF(grp->gr_passwd);
entry += count + 1;
count = strcspn(entry, ":"); /* parse gr_gid */
if (entry[count] == '\0')
return 0;
id = strtoul(entry, &ep, 10);
if (id > GID_MAX || *ep != ':')
return 0;
grp->gr_gid = (gid_t)id;
entry += count + 1;
memc = 1; /* for final NULL */
if (*entry != '\0')
memc++; /* for first item */
for (bp = entry; *bp != '\0'; bp++) {
if (*bp == ',')
memc++;
}
/* grab ALIGNed char **gr_mem from buf */
ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
grp->gr_mem = (char **)ALIGN(ep);
if (grp->gr_mem == NULL)
return 0;
for (memc = 0; *entry != '\0'; memc++) {
count = strcspn(entry, ","); /* parse member */
COPYTOBUF(grp->gr_mem[memc]);
entry += count;
if (*entry == ',')
entry++;
}
#undef COPYTOBUF
grp->gr_mem[memc] = NULL;
return 1;
}
/*
* _gr_copy
* Copy the contents of fromgrp to grp; memory for strings
* and arrays will be allocated from buf (of size buflen).
* Returns 1 if copied successfully, 0 on copy failure.
* NOTE: fromgrp must not use buf for its own pointers.
*/
static int
_gr_copy(struct group *fromgrp, struct group *grp, char *buf, size_t buflen)
{
char *ep;
int memc;
_DIAGASSERT(fromgrp != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buf != NULL);
#define COPYSTR(to, from) \
do { \
size_t count = strlen((from)); \
(to) = _gr_memfrombuf(count+1, &buf, &buflen); \
if ((to) == NULL) \
return 0; \
memmove((to), (from), count); \
to[count] = '\0'; \
} while (0) /* LINTED */
COPYSTR(grp->gr_name, fromgrp->gr_name);
COPYSTR(grp->gr_passwd, fromgrp->gr_passwd);
grp->gr_gid = fromgrp->gr_gid;
for (memc = 0; fromgrp->gr_mem[memc]; memc++)
continue;
memc++; /* for final NULL */
/* grab ALIGNed char **gr_mem from buf */
ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
grp->gr_mem = (char **)ALIGN(ep);
if (grp->gr_mem == NULL)
return 0;
for (memc = 0; fromgrp->gr_mem[memc]; memc++) {
COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]);
}
#undef COPYSTR
grp->gr_mem[memc] = NULL;
return 1;
}
/*
* files methods
*/
int
__grstart_files(struct __grstate_files *state)
{
_DIAGASSERT(state != NULL);
if (state->fp == NULL) {
state->fp = fopen(_PATH_GROUP, "r");
if (state->fp == NULL)
return NS_UNAVAIL;
} else {
rewind(state->fp);
}
return NS_SUCCESS;
}
int
__grend_files(struct __grstate_files *state)
{
_DIAGASSERT(state != NULL);
if (state->fp) {
(void) fclose(state->fp);
state->fp = NULL;
}
return NS_SUCCESS;
}
/*
* __grscan_files
* Scan state->fp for the next desired entry.
* If search is zero, return the next entry.
* If search is non-zero, look for a specific name (if name != NULL),
* or a specific gid (if name == NULL).
* Sets *retval to the errno if the result is not NS_SUCCESS
* or NS_NOTFOUND.
*/
int
__grscan_files(int *retval, struct group *grp, char *buffer, size_t buflen,
struct __grstate_files *state, int search, const char *name, gid_t gid)
{
int rv;
char filebuf[_GETGR_R_SIZE_MAX], *ep;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(state != NULL);
/* name is NULL to indicate searching for gid */
*retval = 0;
if (state->fp == NULL) { /* only start if file not open yet */
rv = __grstart_files(state);
if (rv != NS_SUCCESS)
goto filesgrscan_out;
}
rv = NS_NOTFOUND;
/* scan line by line */
while (fgets(filebuf, sizeof(filebuf), state->fp) != NULL) {
ep = strchr(filebuf, '\n');
if (ep == NULL) { /* skip lines that are too big */
int ch;
while ((ch = getc(state->fp)) != '\n' && ch != EOF)
continue;
continue;
}
*ep = '\0'; /* clear trailing \n */
if (filebuf[0] == '+') /* skip compat line */
continue;
/* validate line */
if (! _gr_parse(filebuf, grp, buffer, buflen)) {
continue; /* skip bad lines */
}
if (! search) { /* just want this one */
rv = NS_SUCCESS;
break;
}
/* want specific */
if ((name && strcmp(name, grp->gr_name) == 0) ||
(!name && gid == grp->gr_gid)) {
rv = NS_SUCCESS;
break;
}
}
filesgrscan_out:
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
*retval = errno;
return rv;
}
static struct __grstate_files _files_state;
/* storage for non _r functions */
static struct group _files_group;
static char _files_groupbuf[_GETGR_R_SIZE_MAX];
/*ARGSUSED*/
static int
_files_setgrent(void *nsrv, void *nscb, va_list ap)
{
_files_state.stayopen = 0;
return __grstart_files(&_files_state);
}
/*ARGSUSED*/
static int
_files_setgroupent(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
int stayopen = va_arg(ap, int);
int rv;
_files_state.stayopen = stayopen;
rv = __grstart_files(&_files_state);
*retval = (rv == NS_SUCCESS);
return rv;
}
/*ARGSUSED*/
static int
_files_endgrent(void *nsrv, void *nscb, va_list ap)
{
_files_state.stayopen = 0;
return __grend_files(&_files_state);
}
/*ARGSUSED*/
static int
_files_getgrent(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grscan_files(&rerror, &_files_group,
_files_groupbuf, sizeof(_files_groupbuf),
&_files_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*retval = &_files_group;
return rv;
}
/*ARGSUSED*/
static int
_files_getgrent_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
rv = __grscan_files(retval, grp, buffer, buflen,
&_files_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*result = grp;
else
*result = NULL;
return rv;
}
/*ARGSUSED*/
static int
_files_getgrgid(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
gid_t gid = va_arg(ap, gid_t);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_files(&_files_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_files(&rerror, &_files_group,
_files_groupbuf, sizeof(_files_groupbuf),
&_files_state, 1, NULL, gid);
if (!_files_state.stayopen)
__grend_files(&_files_state);
if (rv == NS_SUCCESS)
*retval = &_files_group;
return rv;
}
/*ARGSUSED*/
static int
_files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
gid_t gid = va_arg(ap, gid_t);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_files state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid);
__grend_files(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
/*ARGSUSED*/
static int
_files_getgrnam(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
const char *name = va_arg(ap, const char *);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_files(&_files_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_files(&rerror, &_files_group,
_files_groupbuf, sizeof(_files_groupbuf),
&_files_state, 1, name, 0);
if (!_files_state.stayopen)
__grend_files(&_files_state);
if (rv == NS_SUCCESS)
*retval = &_files_group;
return rv;
}
/*ARGSUSED*/
static int
_files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
const char *name = va_arg(ap, const char *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_files state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0);
__grend_files(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
#ifdef HESIOD
/*
* dns methods
*/
int
__grstart_dns(struct __grstate_dns *state)
{
_DIAGASSERT(state != NULL);
state->num = 0;
if (state->context == NULL) { /* setup Hesiod */
if (hesiod_init(&state->context) == -1)
return NS_UNAVAIL;
}
return NS_SUCCESS;
}
int
__grend_dns(struct __grstate_dns *state)
{
_DIAGASSERT(state != NULL);
state->num = 0;
if (state->context) {
hesiod_end(state->context);
state->context = NULL;
}
return NS_SUCCESS;
}
/*
* __grscan_dns
* Search Hesiod for the next desired entry.
* If search is zero, return the next entry.
* If search is non-zero, look for a specific name (if name != NULL),
* or a specific gid (if name == NULL).
*/
int
__grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
struct __grstate_dns *state, int search, const char *name, gid_t gid)
{
const char **curzone;
char **hp, *ep;
int rv;
static const char *zones_gid_group[] = {
"gid",
"group",
NULL
};
static const char *zones_group[] = {
"group",
NULL
};
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(state != NULL);
/* name is NULL to indicate searching for gid */
*retval = 0;
if (state->context == NULL) { /* only start if Hesiod not setup */
rv = __grstart_dns(state);
if (rv != NS_SUCCESS)
return rv;
}
next_dns_entry:
hp = NULL;
rv = NS_NOTFOUND;
if (! search) { /* find next entry */
if (state->num == -1) /* exhausted search */
return NS_NOTFOUND;
/* find group-NNN */
snprintf(buffer, buflen, "group-%u", state->num);
state->num++;
curzone = zones_group;
} else if (name) { /* find group name */
snprintf(buffer, buflen, "%s", name);
curzone = zones_group;
} else { /* find gid */
snprintf(buffer, buflen, "%u", (unsigned int)gid);
curzone = zones_gid_group;
}
for (; *curzone; curzone++) { /* search zones */
hp = hesiod_resolve(state->context, buffer, *curzone);
if (hp != NULL)
break;
if (errno != ENOENT) {
rv = NS_UNAVAIL;
goto dnsgrscan_out;
}
}
if (*curzone == NULL) {
if (! search)
state->num = -1;
goto dnsgrscan_out;
}
if ((ep = strchr(hp[0], '\n')) != NULL)
*ep = '\0'; /* clear trailing \n */
if (_gr_parse(hp[0], grp, buffer, buflen)) { /* validate line */
if (! search) { /* just want this one */
rv = NS_SUCCESS;
} else if ((name && strcmp(name, grp->gr_name) == 0) ||
(!name && gid == grp->gr_gid)) { /* want specific */
rv = NS_SUCCESS;
}
} else { /* dodgy entry */
if (!search) { /* try again if ! searching */
hesiod_free_list(state->context, hp);
goto next_dns_entry;
}
}
dnsgrscan_out:
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
*retval = errno;
if (hp)
hesiod_free_list(state->context, hp);
return rv;
}
static struct __grstate_dns _dns_state;
/* storage for non _r functions */
static struct group _dns_group;
static char _dns_groupbuf[_GETGR_R_SIZE_MAX];
/*ARGSUSED*/
static int
_dns_setgrent(void *nsrv, void *nscb, va_list ap)
{
_dns_state.stayopen = 0;
return __grstart_dns(&_dns_state);
}
/*ARGSUSED*/
static int
_dns_setgroupent(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
int stayopen = va_arg(ap, int);
int rv;
_dns_state.stayopen = stayopen;
rv = __grstart_dns(&_dns_state);
*retval = (rv == NS_SUCCESS);
return rv;
}
/*ARGSUSED*/
static int
_dns_endgrent(void *nsrv, void *nscb, va_list ap)
{
_dns_state.stayopen = 0;
return __grend_dns(&_dns_state);
}
/*ARGSUSED*/
static int
_dns_getgrent(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grscan_dns(&rerror, &_dns_group,
_dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*retval = &_dns_group;
return rv;
}
/*ARGSUSED*/
static int
_dns_getgrent_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
rv = __grscan_dns(retval, grp, buffer, buflen,
&_dns_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*result = grp;
else
*result = NULL;
return rv;
}
/*ARGSUSED*/
static int
_dns_getgrgid(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
gid_t gid = va_arg(ap, gid_t);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_dns(&_dns_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_dns(&rerror, &_dns_group,
_dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid);
if (!_dns_state.stayopen)
__grend_dns(&_dns_state);
if (rv == NS_SUCCESS)
*retval = &_dns_group;
return rv;
}
/*ARGSUSED*/
static int
_dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
gid_t gid = va_arg(ap, gid_t);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_dns state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid);
__grend_dns(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
/*ARGSUSED*/
static int
_dns_getgrnam(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
const char *name = va_arg(ap, const char *);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_dns(&_dns_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_dns(&rerror, &_dns_group,
_dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0);
if (!_dns_state.stayopen)
__grend_dns(&_dns_state);
if (rv == NS_SUCCESS)
*retval = &_dns_group;
return rv;
}
/*ARGSUSED*/
static int
_dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
const char *name = va_arg(ap, const char *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_dns state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0);
__grend_dns(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
#endif /* HESIOD */
#ifdef YP
/*
* nis methods
*/
int
__grstart_nis(struct __grstate_nis *state)
{
_DIAGASSERT(state != NULL);
state->done = 0;
if (state->current) {
free(state->current);
state->current = NULL;
}
if (state->domain == NULL) { /* setup NIS */
switch (yp_get_default_domain(&state->domain)) {
case 0:
break;
case YPERR_RESRC:
return NS_TRYAGAIN;
default:
return NS_UNAVAIL;
}
}
return NS_SUCCESS;
}
int
__grend_nis(struct __grstate_nis *state)
{
_DIAGASSERT(state != NULL);
if (state->domain) {
state->domain = NULL;
}
state->done = 0;
if (state->current) {
free(state->current);
state->current = NULL;
}
return NS_SUCCESS;
}
/*
* __grscan_nis
* Search NIS for the next desired entry.
* If search is zero, return the next entry.
* If search is non-zero, look for a specific name (if name != NULL),
* or a specific gid (if name == NULL).
*/
int
__grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen,
struct __grstate_nis *state, int search, const char *name, gid_t gid)
{
const char *map;
char *key, *data;
int nisr, rv, keylen, datalen;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(state != NULL);
/* name is NULL to indicate searching for gid */
*retval = 0;
if (state->domain == NULL) { /* only start if NIS not setup */
rv = __grstart_nis(state);
if (rv != NS_SUCCESS)
return rv;
}
next_nis_entry:
key = NULL;
data = NULL;
rv = NS_SUCCESS;
if (! search) { /* find next entry */
if (state->done) /* exhausted search */
return NS_NOTFOUND;
map = "group.byname";
if (state->current) { /* already searching */
nisr = yp_next(state->domain, map,
state->current, state->currentlen,
&key, &keylen, &data, &datalen);
free(state->current);
state->current = NULL;
switch (nisr) {
case 0:
state->current = key;
state->currentlen = keylen;
key = NULL;
break;
case YPERR_NOMORE:
rv = NS_NOTFOUND;
state->done = 1;
break;
default:
rv = NS_UNAVAIL;
break;
}
} else { /* new search */
if (yp_first(state->domain, map,
&state->current, &state->currentlen,
&data, &datalen)) {
rv = NS_UNAVAIL;
}
}
} else { /* search for specific item */
if (name) { /* find group name */
snprintf(buffer, buflen, "%s", name);
map = "group.byname";
} else { /* find gid */
snprintf(buffer, buflen, "%u", (unsigned int)gid);
map = "group.bygid";
}
nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
&data, &datalen);
switch (nisr) {
case 0:
break;
case YPERR_KEY:
rv = NS_NOTFOUND;
break;
default:
rv = NS_UNAVAIL;
break;
}
}
if (rv == NS_SUCCESS) { /* validate data */
data[datalen] = '\0'; /* clear trailing \n */
if (_gr_parse(data, grp, buffer, buflen)) {
if (! search) { /* just want this one */
rv = NS_SUCCESS;
} else if ((name && strcmp(name, grp->gr_name) == 0) ||
(!name && gid == grp->gr_gid)) {
/* want specific */
rv = NS_SUCCESS;
}
} else { /* dodgy entry */
if (!search) { /* try again if ! searching */
free(data);
goto next_nis_entry;
}
}
}
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
*retval = errno;
if (key)
free(key);
if (data)
free(data);
return rv;
}
static struct __grstate_nis _nis_state;
/* storage for non _r functions */
static struct group _nis_group;
static char _nis_groupbuf[_GETGR_R_SIZE_MAX];
/*ARGSUSED*/
static int
_nis_setgrent(void *nsrv, void *nscb, va_list ap)
{
_nis_state.stayopen = 0;
return __grstart_nis(&_nis_state);
}
/*ARGSUSED*/
static int
_nis_setgroupent(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
int stayopen = va_arg(ap, int);
int rv;
_nis_state.stayopen = stayopen;
rv = __grstart_nis(&_nis_state);
*retval = (rv == NS_SUCCESS);
return rv;
}
/*ARGSUSED*/
static int
_nis_endgrent(void *nsrv, void *nscb, va_list ap)
{
return __grend_nis(&_nis_state);
}
/*ARGSUSED*/
static int
_nis_getgrent(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grscan_nis(&rerror, &_nis_group,
_nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*retval = &_nis_group;
return rv;
}
/*ARGSUSED*/
static int
_nis_getgrent_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
rv = __grscan_nis(retval, grp, buffer, buflen,
&_nis_state, 0, NULL, 0);
if (rv == NS_SUCCESS)
*result = grp;
else
*result = NULL;
return rv;
}
/*ARGSUSED*/
static int
_nis_getgrgid(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
gid_t gid = va_arg(ap, gid_t);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_nis(&_nis_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_nis(&rerror, &_nis_group,
_nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid);
if (!_nis_state.stayopen)
__grend_nis(&_nis_state);
if (rv == NS_SUCCESS)
*retval = &_nis_group;
return rv;
}
/*ARGSUSED*/
static int
_nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
gid_t gid = va_arg(ap, gid_t);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_nis state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
__grend_nis(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
/*ARGSUSED*/
static int
_nis_getgrnam(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
const char *name = va_arg(ap, const char *);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_nis(&_nis_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_nis(&rerror, &_nis_group,
_nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0);
if (!_nis_state.stayopen)
__grend_nis(&_nis_state);
if (rv == NS_SUCCESS)
*retval = &_nis_group;
return rv;
}
/*ARGSUSED*/
static int
_nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
const char *name = va_arg(ap, const char *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_nis state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
__grend_nis(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
#endif /* YP */
#ifdef _GROUP_COMPAT
/*
* compat methods
*/
int
__grstart_compat(struct __grstate_compat *state)
{
_DIAGASSERT(state != NULL);
if (state->fp == NULL) {
state->fp = fopen(_PATH_GROUP, "r");
if (state->fp == NULL)
return NS_UNAVAIL;
} else {
rewind(state->fp);
}
return NS_SUCCESS;
}
int
__grend_compat(struct __grstate_compat *state)
{
_DIAGASSERT(state != NULL);
if (state->name) {
free(state->name);
state->name = NULL;
}
if (state->fp) {
(void) fclose(state->fp);
state->fp = NULL;
}
return NS_SUCCESS;
}
/*
* __grbad_compat
* log an error if "files" or "compat" is specified in
* group_compat database
*/
/*ARGSUSED*/
int
__grbad_compat(void *nsrv, void *nscb, va_list ap)
{
static int warned;
_DIAGASSERT(nsrv != NULL);
_DIAGASSERT(nscb != NULL);
if (!warned) {
syslog(LOG_ERR,
"nsswitch.conf group_compat database can't use '%s'",
(const char *)nscb);
}
warned = 1;
return NS_UNAVAIL;
}
/*
* __grscan_compat
* Scan state->fp for the next desired entry.
* If search is zero, return the next entry.
* If search is non-zero, look for a specific name (if name != NULL),
* or a specific gid (if name == NULL).
* Sets *retval to the errno if the result is not NS_SUCCESS or
* NS_NOTFOUND.
*
* searchfunc is invoked when a compat "+" lookup is required;
* searchcookie is passed as the first argument to searchfunc,
* the second argument is the group result.
* This should return NS_NOTFOUND when "no more groups" from compat src.
* If searchfunc is NULL then nsdispatch of getgrent is used.
* This is primarily intended for getgroupmembership(3)'s compat backend.
*/
int
__grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen,
struct __grstate_compat *state, int search, const char *name, gid_t gid,
int (*searchfunc)(void *, struct group **), void *searchcookie)
{
int rv;
char filebuf[_GETGR_R_SIZE_MAX], *ep;
static const ns_dtab compatentdtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_getgrent_r, NULL)
NS_NIS_CB(_nis_getgrent_r, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
static const ns_dtab compatgiddtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_getgrgid_r, NULL)
NS_NIS_CB(_nis_getgrgid_r, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
static const ns_dtab compatnamdtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_getgrnam_r, NULL)
NS_NIS_CB(_nis_getgrnam_r, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(state != NULL);
/* name is NULL to indicate searching for gid */
*retval = 0;
if (state->fp == NULL) { /* only start if file not open yet */
rv = __grstart_compat(state);
if (rv != NS_SUCCESS)
goto compatgrscan_out;
}
rv = NS_NOTFOUND;
for (;;) { /* loop through file */
if (state->name != NULL) {
/* processing compat entry */
int crv, cretval;
struct group cgrp, *cgrpres;
if (state->name[0]) { /* specific +group: */
crv = nsdispatch(NULL, compatnamdtab,
NSDB_GROUP_COMPAT, "getgrnam_r",
__nsdefaultnis,
&cretval, state->name,
&cgrp, filebuf, sizeof(filebuf), &cgrpres);
free(state->name); /* (only check 1 grp) */
state->name = NULL;
} else if (!search) { /* any group */
if (searchfunc) {
crv = searchfunc(searchcookie,
&cgrpres);
} else {
crv = nsdispatch(NULL, compatentdtab,
NSDB_GROUP_COMPAT, "getgrent_r",
__nsdefaultnis,
&cretval, &cgrp, filebuf,
sizeof(filebuf), &cgrpres);
}
} else if (name) { /* specific group */
crv = nsdispatch(NULL, compatnamdtab,
NSDB_GROUP_COMPAT, "getgrnam_r",
__nsdefaultnis,
&cretval, name,
&cgrp, filebuf, sizeof(filebuf), &cgrpres);
} else { /* specific gid */
crv = nsdispatch(NULL, compatgiddtab,
NSDB_GROUP_COMPAT, "getgrgid_r",
__nsdefaultnis,
&cretval, gid,
&cgrp, filebuf, sizeof(filebuf), &cgrpres);
}
if (crv != NS_SUCCESS) { /* not found */
free(state->name);
state->name = NULL;
continue; /* try next line */
}
if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
rv = NS_UNAVAIL;
break;
}
goto compatgrscan_cmpgrp; /* skip to grp test */
}
/* get next file line */
if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL)
break;
ep = strchr(filebuf, '\n');
if (ep == NULL) { /* skip lines that are too big */
int ch;
while ((ch = getc(state->fp)) != '\n' && ch != EOF)
continue;
continue;
}
*ep = '\0'; /* clear trailing \n */
if (filebuf[0] == '+') { /* parse compat line */
if (state->name)
free(state->name);
state->name = NULL;
switch(filebuf[1]) {
case ':':
case '\0':
state->name = strdup("");
break;
default:
ep = strchr(filebuf + 1, ':');
if (ep == NULL)
break;
*ep = '\0';
state->name = strdup(filebuf + 1);
break;
}
if (state->name == NULL) {
rv = NS_UNAVAIL;
break;
}
continue;
}
/* validate line */
if (! _gr_parse(filebuf, grp, buffer, buflen)) {
continue; /* skip bad lines */
}
compatgrscan_cmpgrp:
if (! search) { /* just want this one */
rv = NS_SUCCESS;
break;
}
/* want specific */
if ((name && strcmp(name, grp->gr_name) == 0) ||
(!name && gid == grp->gr_gid)) {
rv = NS_SUCCESS;
break;
}
}
compatgrscan_out:
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
*retval = errno;
return rv;
}
static struct __grstate_compat _compat_state;
/* storage for non _r functions */
static struct group _compat_group;
static char _compat_groupbuf[_GETGR_R_SIZE_MAX];
/*ARGSUSED*/
static int
_compat_setgrent(void *nsrv, void *nscb, va_list ap)
{
static const ns_dtab dtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_setgrent, NULL)
NS_NIS_CB(_nis_setgrent, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
/* force group_compat setgrent() */
(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
__nsdefaultnis_forceall);
/* reset state, keep fp open */
_compat_state.stayopen = 0;
return __grstart_compat(&_compat_state);
}
/*ARGSUSED*/
static int
_compat_setgroupent(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
int stayopen = va_arg(ap, int);
int rv;
static const ns_dtab dtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_setgroupent, NULL)
NS_NIS_CB(_nis_setgroupent, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
/* force group_compat setgroupent() */
(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent",
__nsdefaultnis_forceall, &rv, stayopen);
_compat_state.stayopen = stayopen;
rv = __grstart_compat(&_compat_state);
*retval = (rv == NS_SUCCESS);
return rv;
}
/*ARGSUSED*/
static int
_compat_endgrent(void *nsrv, void *nscb, va_list ap)
{
static const ns_dtab dtab[] = {
NS_FILES_CB(__grbad_compat, "files")
NS_DNS_CB(_dns_endgrent, NULL)
NS_NIS_CB(_nis_endgrent, NULL)
NS_COMPAT_CB(__grbad_compat, "compat")
NS_NULL_CB
};
/* force group_compat endgrent() */
(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
__nsdefaultnis_forceall);
/* reset state, close fp */
_compat_state.stayopen = 0;
return __grend_compat(&_compat_state);
}
/*ARGSUSED*/
static int
_compat_getgrent(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grscan_compat(&rerror, &_compat_group,
_compat_groupbuf, sizeof(_compat_groupbuf),
&_compat_state, 0, NULL, 0, NULL, NULL);
if (rv == NS_SUCCESS)
*retval = &_compat_group;
return rv;
}
/*ARGSUSED*/
static int
_compat_getgrent_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
rv = __grscan_compat(retval, grp, buffer, buflen,
&_compat_state, 0, NULL, 0, NULL, NULL);
if (rv == NS_SUCCESS)
*result = grp;
else
*result = NULL;
return rv;
}
/*ARGSUSED*/
static int
_compat_getgrgid(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
gid_t gid = va_arg(ap, gid_t);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_compat(&_compat_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_compat(&rerror, &_compat_group,
_compat_groupbuf, sizeof(_compat_groupbuf),
&_compat_state, 1, NULL, gid, NULL, NULL);
if (!_compat_state.stayopen)
__grend_compat(&_compat_state);
if (rv == NS_SUCCESS)
*retval = &_compat_group;
return rv;
}
/*ARGSUSED*/
static int
_compat_getgrgid_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
gid_t gid = va_arg(ap, gid_t);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_compat state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_compat(retval, grp, buffer, buflen, &state,
1, NULL, gid, NULL, NULL);
__grend_compat(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
/*ARGSUSED*/
static int
_compat_getgrnam(void *nsrv, void *nscb, va_list ap)
{
struct group **retval = va_arg(ap, struct group **);
const char *name = va_arg(ap, const char *);
int rv, rerror;
_DIAGASSERT(retval != NULL);
*retval = NULL;
rv = __grstart_compat(&_compat_state);
if (rv != NS_SUCCESS)
return rv;
rv = __grscan_compat(&rerror, &_compat_group,
_compat_groupbuf, sizeof(_compat_groupbuf),
&_compat_state, 1, name, 0, NULL, NULL);
if (!_compat_state.stayopen)
__grend_compat(&_compat_state);
if (rv == NS_SUCCESS)
*retval = &_compat_group;
return rv;
}
/*ARGSUSED*/
static int
_compat_getgrnam_r(void *nsrv, void *nscb, va_list ap)
{
int *retval = va_arg(ap, int *);
const char *name = va_arg(ap, const char *);
struct group *grp = va_arg(ap, struct group *);
char *buffer = va_arg(ap, char *);
size_t buflen = va_arg(ap, size_t);
struct group **result = va_arg(ap, struct group **);
struct __grstate_compat state;
int rv;
_DIAGASSERT(retval != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
memset(&state, 0, sizeof(state));
rv = __grscan_compat(retval, grp, buffer, buflen, &state,
1, name, 0, NULL, NULL);
__grend_compat(&state);
if (rv == NS_SUCCESS)
*result = grp;
return rv;
}
#endif /* _GROUP_COMPAT */
/*
* public functions
*/
struct group *
getgrent(void)
{
int rv;
struct group *retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrent, NULL)
NS_DNS_CB(_dns_getgrent, NULL)
NS_NIS_CB(_nis_getgrent, NULL)
NS_COMPAT_CB(_compat_getgrent, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", __nsdefaultcompat,
&retval);
mutex_unlock(&__grmutex);
return (rv == NS_SUCCESS) ? retval : NULL;
}
int
getgrent_r(struct group *grp, char *buffer, size_t buflen,
struct group **result)
{
int rv, retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrent_r, NULL)
NS_DNS_CB(_dns_getgrent_r, NULL)
NS_NIS_CB(_nis_getgrent_r, NULL)
NS_COMPAT_CB(_compat_getgrent_r, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent_r", __nsdefaultcompat,
&retval, grp, buffer, buflen, result);
mutex_unlock(&__grmutex);
switch (rv) {
case NS_SUCCESS:
case NS_NOTFOUND:
return 0;
default:
return retval;
}
}
struct group *
getgrgid(gid_t gid)
{
int rv;
struct group *retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrgid, NULL)
NS_DNS_CB(_dns_getgrgid, NULL)
NS_NIS_CB(_nis_getgrgid, NULL)
NS_COMPAT_CB(_compat_getgrgid, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", __nsdefaultcompat,
&retval, gid);
mutex_unlock(&__grmutex);
return (rv == NS_SUCCESS) ? retval : NULL;
}
int
getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen,
struct group **result)
{
int rv, retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrgid_r, NULL)
NS_DNS_CB(_dns_getgrgid_r, NULL)
NS_NIS_CB(_nis_getgrgid_r, NULL)
NS_COMPAT_CB(_compat_getgrgid_r, NULL)
NS_NULL_CB
};
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
retval = 0;
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", __nsdefaultcompat,
&retval, gid, grp, buffer, buflen, result);
mutex_unlock(&__grmutex);
switch (rv) {
case NS_SUCCESS:
case NS_NOTFOUND:
return 0;
default:
return retval;
}
}
struct group *
getgrnam(const char *name)
{
int rv;
struct group *retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrnam, NULL)
NS_DNS_CB(_dns_getgrnam, NULL)
NS_NIS_CB(_nis_getgrnam, NULL)
NS_COMPAT_CB(_compat_getgrnam, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", __nsdefaultcompat,
&retval, name);
mutex_unlock(&__grmutex);
return (rv == NS_SUCCESS) ? retval : NULL;
}
int
getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen,
struct group **result)
{
int rv, retval;
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getgrnam_r, NULL)
NS_DNS_CB(_dns_getgrnam_r, NULL)
NS_NIS_CB(_nis_getgrnam_r, NULL)
NS_COMPAT_CB(_compat_getgrnam_r, NULL)
NS_NULL_CB
};
_DIAGASSERT(name != NULL);
_DIAGASSERT(grp != NULL);
_DIAGASSERT(buffer != NULL);
_DIAGASSERT(result != NULL);
*result = NULL;
retval = 0;
mutex_lock(&__grmutex);
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", __nsdefaultcompat,
&retval, name, grp, buffer, buflen, result);
mutex_unlock(&__grmutex);
switch (rv) {
case NS_SUCCESS:
case NS_NOTFOUND:
return 0;
default:
return retval;
}
}
void
endgrent(void)
{
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_endgrent, NULL)
NS_DNS_CB(_dns_endgrent, NULL)
NS_NIS_CB(_nis_endgrent, NULL)
NS_COMPAT_CB(_compat_endgrent, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
/* force all endgrent() methods */
(void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent",
__nsdefaultcompat_forceall);
mutex_unlock(&__grmutex);
}
int
setgroupent(int stayopen)
{
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_setgroupent, NULL)
NS_DNS_CB(_dns_setgroupent, NULL)
NS_NIS_CB(_nis_setgroupent, NULL)
NS_COMPAT_CB(_compat_setgroupent, NULL)
NS_NULL_CB
};
int rv, retval;
mutex_lock(&__grmutex);
/* force all setgroupent() methods */
rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent",
__nsdefaultcompat_forceall, &retval, stayopen);
mutex_unlock(&__grmutex);
return (rv == NS_SUCCESS) ? retval : 0;
}
void
setgrent(void)
{
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_setgrent, NULL)
NS_DNS_CB(_dns_setgrent, NULL)
NS_NIS_CB(_nis_setgrent, NULL)
NS_COMPAT_CB(_compat_setgrent, NULL)
NS_NULL_CB
};
mutex_lock(&__grmutex);
/* force all setgrent() methods */
(void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent",
__nsdefaultcompat_forceall);
mutex_unlock(&__grmutex);
}