1936 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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);
 | |
| }
 | 
