/* $NetBSD: getgrent.c,v 1.54.2.3 2005/07/11 21:25:27 tron 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * 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 #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.54.2.3 2005/07/11 21:25:27 tron Exp $"); #endif #endif /* LIBC_SCCS and not lint */ #include "namespace.h" #include "reentrant.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HESIOD #include #endif #ifdef YP #include #include #include #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) { /* fail on lines that are too big */ int ch; while ((ch = getc(state->fp)) != '\n' && ch != EOF) continue; rv = NS_UNAVAIL; break; } *ep = '\0'; /* clear trailing \n */ if (filebuf[0] == '+') /* skip compat line */ continue; /* validate line */ if (! _gr_parse(filebuf, grp, buffer, buflen)) { rv = NS_UNAVAIL; break; } 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; } 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 rv = NS_UNAVAIL; 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; } 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 rv = NS_UNAVAIL; } 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(cb_data != 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") { 0 } }; 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") { 0 } }; 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") { 0 } }; _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) { /* fail on lines that are too big */ int ch; while ((ch = getc(state->fp)) != '\n' && ch != EOF) continue; rv = NS_UNAVAIL; break; } *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)) { rv = NS_UNAVAIL; break; } 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") { 0 } }; /* 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") { 0 } }; /* 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") { 0 } }; /* 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) { 0 } }; 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) { 0 } }; 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) { 0 } }; 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) { 0 } }; _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) { 0 } }; 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) { 0 } }; _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) { 0 } }; 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) { 0 } }; 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) { 0 } }; mutex_lock(&__grmutex); /* force all setgrent() methods */ (void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", __nsdefaultcompat_forceall); mutex_unlock(&__grmutex); }