xref: /illumos-gate/usr/src/lib/libc/port/gen/getgrnam_r.c (revision cb5caa98562cf06753163f558cbcfe30b8f4673a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22004388ebScasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma weak endgrent = _endgrent
297c478bd9Sstevel@tonic-gate #pragma weak setgrent = _setgrent
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma weak getgrnam_r = _getgrnam_r
327c478bd9Sstevel@tonic-gate #pragma weak getgrgid_r = _getgrgid_r
337c478bd9Sstevel@tonic-gate #pragma weak getgrent_r = _getgrent_r
347c478bd9Sstevel@tonic-gate #pragma weak fgetgrent_r = _fgetgrent_r
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include "synonyms.h"
377c478bd9Sstevel@tonic-gate #include <mtlib.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <grp.h>
407c478bd9Sstevel@tonic-gate #include <memory.h>
417c478bd9Sstevel@tonic-gate #include <nsswitch.h>
427c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <synch.h>
477c478bd9Sstevel@tonic-gate #include <sys/param.h>
487c478bd9Sstevel@tonic-gate #include <sys/mman.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate extern int _getgroupsbymember(const char *, gid_t[], int, int);
51*cb5caa98Sdjl int str2group(const char *, int, void *, char *, int);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
547c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	USE_NETID_STR	"NETID_AUTHORITATIVE=TRUE"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate void
597c478bd9Sstevel@tonic-gate _nss_initf_group(nss_db_params_t *p)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_GROUP;
627c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_GROUP;
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #include <getxby_door.h>
667c478bd9Sstevel@tonic-gate #include <sys/door.h>
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate struct group *
697c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
707c478bd9Sstevel@tonic-gate     int buflen);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate struct group *
737c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function getgrnam_r.
777c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate struct group *
807c478bd9Sstevel@tonic-gate _getgrnam_r(const char *name, struct group *result, char *buffer, int buflen)
817c478bd9Sstevel@tonic-gate {
82*cb5caa98Sdjl 	nss_XbyY_args_t arg;
837c478bd9Sstevel@tonic-gate 
84*cb5caa98Sdjl 	if (name == (const char *)NULL) {
857c478bd9Sstevel@tonic-gate 		errno = ERANGE;
867c478bd9Sstevel@tonic-gate 		return (NULL);
877c478bd9Sstevel@tonic-gate 	}
88*cb5caa98Sdjl 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
89*cb5caa98Sdjl 	arg.key.name = name;
90*cb5caa98Sdjl 	(void) nss_search(&db_root, _nss_initf_group,
91*cb5caa98Sdjl 			NSS_DBOP_GROUP_BYNAME, &arg);
92*cb5caa98Sdjl 	return ((struct group *)NSS_XbyY_FINI(&arg));
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function getgrgid_r.
977c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate struct group *
1007c478bd9Sstevel@tonic-gate _getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen)
1017c478bd9Sstevel@tonic-gate {
102*cb5caa98Sdjl 	nss_XbyY_args_t arg;
1037c478bd9Sstevel@tonic-gate 
104*cb5caa98Sdjl 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
105*cb5caa98Sdjl 	arg.key.gid = gid;
106*cb5caa98Sdjl 	(void) nss_search(&db_root, _nss_initf_group,
107*cb5caa98Sdjl 				NSS_DBOP_GROUP_BYGID, &arg);
108*cb5caa98Sdjl 	return ((struct group *)NSS_XbyY_FINI(&arg));
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate struct group *
1127c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer,
1137c478bd9Sstevel@tonic-gate     int buflen)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1187c478bd9Sstevel@tonic-gate 	arg.key.gid = gid;
1197c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
1207c478bd9Sstevel@tonic-gate 				NSS_DBOP_GROUP_BYGID, &arg);
1217c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function getgrgid_r.
1267c478bd9Sstevel@tonic-gate  * User gets it via static getgrgid_r from the header file.
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate int
1297c478bd9Sstevel@tonic-gate __posix_getgrgid_r(gid_t gid, struct group *grp, char *buffer,
1307c478bd9Sstevel@tonic-gate     size_t bufsize, struct group **result)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	int nerrno = 0;
1337c478bd9Sstevel@tonic-gate 	int oerrno = errno;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	errno = 0;
1367c478bd9Sstevel@tonic-gate 	if ((*result = _getgrgid_r(gid, grp, buffer, (uintptr_t)bufsize))
1377c478bd9Sstevel@tonic-gate 		== NULL) {
1387c478bd9Sstevel@tonic-gate 			nerrno = errno;
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 	errno = oerrno;
1417c478bd9Sstevel@tonic-gate 	return (nerrno);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate extern struct group *
1457c478bd9Sstevel@tonic-gate _getgrnam_r(const char *name, struct group *result, char *buffer,
1467c478bd9Sstevel@tonic-gate 	int buflen);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate struct group *
1497c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
1507c478bd9Sstevel@tonic-gate 	int buflen)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1557c478bd9Sstevel@tonic-gate 	arg.key.name = name;
1567c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
1577c478bd9Sstevel@tonic-gate 			NSS_DBOP_GROUP_BYNAME, &arg);
1587c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function getgrnam_r.
1637c478bd9Sstevel@tonic-gate  * User gets it via static getgrnam_r from the header file.
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate int
1667c478bd9Sstevel@tonic-gate __posix_getgrnam_r(const char *name, struct group *grp, char *buffer,
1677c478bd9Sstevel@tonic-gate     size_t bufsize, struct group **result)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	int nerrno = 0;
1707c478bd9Sstevel@tonic-gate 	int oerrno = errno;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if ((*result = _getgrnam_r(name, grp, buffer, (uintptr_t)bufsize))
1737c478bd9Sstevel@tonic-gate 		== NULL) {
1747c478bd9Sstevel@tonic-gate 			nerrno = errno;
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	errno = oerrno;
1777c478bd9Sstevel@tonic-gate 	return (nerrno);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate void
1817c478bd9Sstevel@tonic-gate setgrent(void)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	nss_setent(&db_root, _nss_initf_group, &context);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate void
1877c478bd9Sstevel@tonic-gate endgrent(void)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	nss_endent(&db_root, _nss_initf_group, &context);
1907c478bd9Sstevel@tonic-gate 	nss_delete(&db_root);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate struct group *
1947c478bd9Sstevel@tonic-gate getgrent_r(struct group *result, char *buffer, int buflen)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1977c478bd9Sstevel@tonic-gate 	char		*nam;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	do {
2027c478bd9Sstevel@tonic-gate 		NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
2037c478bd9Sstevel@tonic-gate 		/* No key to fill in */
2047c478bd9Sstevel@tonic-gate 		(void) nss_getent(&db_root, _nss_initf_group, &context, &arg);
2057c478bd9Sstevel@tonic-gate 	} while (arg.returnval != 0 &&
2067c478bd9Sstevel@tonic-gate 		(nam = ((struct group *)arg.returnval)->gr_name) != 0 &&
2077c478bd9Sstevel@tonic-gate 		(*nam == '+' || *nam == '-'));
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate struct group *
2137c478bd9Sstevel@tonic-gate fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	extern void	_nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
2167c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t	arg;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	/* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/* No key to fill in */
2217c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
2227c478bd9Sstevel@tonic-gate 	_nss_XbyY_fgets(f, &arg);
2237c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate  * _getgroupsbymember(uname, gid_array, maxgids, numgids):
2287c478bd9Sstevel@tonic-gate  *	Private interface for initgroups().  It returns the group ids of
2297c478bd9Sstevel@tonic-gate  *	groups of which the specified user is a member.
2307c478bd9Sstevel@tonic-gate  *
2317c478bd9Sstevel@tonic-gate  * Arguments:
2327c478bd9Sstevel@tonic-gate  *   username	Username of the putative member
2337c478bd9Sstevel@tonic-gate  *   gid_array	Space in which to return the gids.  The first [numgids]
2347c478bd9Sstevel@tonic-gate  *		elements are assumed to already contain valid gids.
2357c478bd9Sstevel@tonic-gate  *   maxgids	Maximum number of elements in gid_array.
2367c478bd9Sstevel@tonic-gate  *   numgids	Number of elements (normally 0 or 1) that already contain
2377c478bd9Sstevel@tonic-gate  *		valid gids.
2387c478bd9Sstevel@tonic-gate  * Return value:
2397c478bd9Sstevel@tonic-gate  *   number of valid gids in gid_array (may be zero)
2407c478bd9Sstevel@tonic-gate  *	or
2417c478bd9Sstevel@tonic-gate  *   -1 (and errno set appropriately) on errors (none currently defined)
242*cb5caa98Sdjl  *
243*cb5caa98Sdjl  * NSS2 Consistency enhancements:
244*cb5caa98Sdjl  *   The "files normal" format between an application and nscd for the
245*cb5caa98Sdjl  *   NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a
246*cb5caa98Sdjl  *   processed array of numgids [up to maxgids] gid_t values.  gid_t
247*cb5caa98Sdjl  *   values in the array are unique.
2487c478bd9Sstevel@tonic-gate  */
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate int
2537c478bd9Sstevel@tonic-gate _getgroupsbymember(const char *username, gid_t gid_array[],
2547c478bd9Sstevel@tonic-gate     int maxgids, int numgids)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	struct nss_groupsbymem	arg;
2577c478bd9Sstevel@tonic-gate 	char defval[BUFSIZ];
258004388ebScasper 	FILE *defl;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	arg.username	= username;
2617c478bd9Sstevel@tonic-gate 	arg.gid_array	= gid_array;
2627c478bd9Sstevel@tonic-gate 	arg.maxgids	= maxgids;
2637c478bd9Sstevel@tonic-gate 	arg.numgids	= numgids;
264*cb5caa98Sdjl 	/*
265*cb5caa98Sdjl 	 * In backwards compatibility mode, use the old str2group &
266*cb5caa98Sdjl 	 * process_cstr interfaces.  Ditto within nscd processing.
267*cb5caa98Sdjl 	 */
2687c478bd9Sstevel@tonic-gate 	arg.str2ent	= str2group;
2697c478bd9Sstevel@tonic-gate 	arg.process_cstr = process_cstr;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/*
2727c478bd9Sstevel@tonic-gate 	 * The old value being provided here was 0, ie do the quick
2737c478bd9Sstevel@tonic-gate 	 * way.  Given that this was never actually used under NIS
2747c478bd9Sstevel@tonic-gate 	 * and had the wrong (now corrected) meaning for NIS+ we need
2757c478bd9Sstevel@tonic-gate 	 * to change the default to be 1 (TRUE) as we now need the
2767c478bd9Sstevel@tonic-gate 	 * admin to decided to use netid, setting NETID_AUTHORITATIVE
2777c478bd9Sstevel@tonic-gate 	 * in /etc/default/nss to TRUE gets us a value of 0 for
2787c478bd9Sstevel@tonic-gate 	 * force_slow_way - don't you just love double negatives ;-)
2797c478bd9Sstevel@tonic-gate 	 *
2807c478bd9Sstevel@tonic-gate 	 * We need to do this to preserve the behaviour seen when the
2817c478bd9Sstevel@tonic-gate 	 * admin makes no changes.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	arg.force_slow_way = 1;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	/*
2867c478bd9Sstevel@tonic-gate 	 * The "easy" way to do /etc/default/nss is to use the defread()
2877c478bd9Sstevel@tonic-gate 	 * stuff from libcmd, but since we are in libc we don't want to
2887c478bd9Sstevel@tonic-gate 	 * link ourselfs against libcmd, so instead we just do it by hand
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 
291004388ebScasper 	if ((defl = fopen(__NSW_DEFAULT_FILE, "rF")) != NULL) {
292004388ebScasper 		while (fgets(defval, sizeof (defval), defl) != NULL) {
2937c478bd9Sstevel@tonic-gate 			if (strncmp(USE_NETID_STR, defval,
2947c478bd9Sstevel@tonic-gate 			    sizeof (USE_NETID_STR) - 1) == 0) {
2957c478bd9Sstevel@tonic-gate 				arg.force_slow_way = 0;
2967c478bd9Sstevel@tonic-gate 				break;
2977c478bd9Sstevel@tonic-gate 			}
2987c478bd9Sstevel@tonic-gate 		}
299004388ebScasper 		(void) fclose(defl);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
3037c478bd9Sstevel@tonic-gate 			NSS_DBOP_GROUP_BYMEMBER, &arg);
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	return (arg.numgids);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static char *
3107c478bd9Sstevel@tonic-gate gettok(char **nextpp, char sep)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	char	*p = *nextpp;
3137c478bd9Sstevel@tonic-gate 	char	*q = p;
3147c478bd9Sstevel@tonic-gate 	char	c;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (p == 0)
3177c478bd9Sstevel@tonic-gate 		return (0);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	while ((c = *q) != '\0' && c != sep)
3207c478bd9Sstevel@tonic-gate 		q++;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (c == '\0')
3237c478bd9Sstevel@tonic-gate 		*nextpp = 0;
3247c478bd9Sstevel@tonic-gate 	else {
3257c478bd9Sstevel@tonic-gate 		*q++ = '\0';
3267c478bd9Sstevel@tonic-gate 		*nextpp = q;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	return (p);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
3337c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
3347c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
3357c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate int
3387c478bd9Sstevel@tonic-gate str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	struct group		*group	= (struct group *)ent;
3417c478bd9Sstevel@tonic-gate 	char			*p, *next;
3427c478bd9Sstevel@tonic-gate 	int			black_magic;	/* "+" or "-" entry */
3437c478bd9Sstevel@tonic-gate 	char			**memlist, **limit;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if (lenstr + 1 > buflen)
3467c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	/*
3497c478bd9Sstevel@tonic-gate 	 * We copy the input string into the output buffer and
3507c478bd9Sstevel@tonic-gate 	 * operate on it in place.
3517c478bd9Sstevel@tonic-gate 	 */
352*cb5caa98Sdjl 	if (instr != buffer) {
353*cb5caa98Sdjl 		/* Overlapping buffer copies are OK */
354*cb5caa98Sdjl 		(void) memmove(buffer, instr, lenstr);
3557c478bd9Sstevel@tonic-gate 		buffer[lenstr] = '\0';
356*cb5caa98Sdjl 	}
357*cb5caa98Sdjl 
358*cb5caa98Sdjl 	/* quick exit do not entry fill if not needed */
359*cb5caa98Sdjl 	if (ent == (void *)NULL)
360*cb5caa98Sdjl 		return (NSS_STR_PARSE_SUCCESS);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	next = buffer;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * Parsers for passwd and group have always been pretty rigid;
3667c478bd9Sstevel@tonic-gate 	 * we wouldn't want to buck a Unix tradition
3677c478bd9Sstevel@tonic-gate 	 */
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	group->gr_name = p = gettok(&next, ':');
3707c478bd9Sstevel@tonic-gate 	if (*p == '\0') {
3717c478bd9Sstevel@tonic-gate 		/* Empty group-name;  not allowed */
3727c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/* Always return at least an empty gr_mem list */
3767c478bd9Sstevel@tonic-gate 	memlist	= (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *));
3777c478bd9Sstevel@tonic-gate 	limit	= (char **)ROUND_DOWN(buffer + buflen, sizeof (char *));
3787c478bd9Sstevel@tonic-gate 	*memlist = 0;
3797c478bd9Sstevel@tonic-gate 	group->gr_mem = memlist;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	black_magic = (*p == '+' || *p == '-');
3827c478bd9Sstevel@tonic-gate 	if (black_magic) {
3837c478bd9Sstevel@tonic-gate 		/* Then the rest of the group entry is optional */
3847c478bd9Sstevel@tonic-gate 		group->gr_passwd = 0;
3857c478bd9Sstevel@tonic-gate 		group->gr_gid = 0;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	group->gr_passwd = p = gettok(&next, ':');
3897c478bd9Sstevel@tonic-gate 	if (p == 0) {
3907c478bd9Sstevel@tonic-gate 		if (black_magic)
3917c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
3927c478bd9Sstevel@tonic-gate 		else
3937c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	p = next;					/* gid */
3977c478bd9Sstevel@tonic-gate 	if (p == 0 || *p == '\0') {
3987c478bd9Sstevel@tonic-gate 		if (black_magic)
3997c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
4007c478bd9Sstevel@tonic-gate 		else
4017c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 	if (!black_magic) {
4047c478bd9Sstevel@tonic-gate 		group->gr_gid = (gid_t)strtol(p, &next, 10);
4057c478bd9Sstevel@tonic-gate 		if (next == p) {
4067c478bd9Sstevel@tonic-gate 			/* gid field should be nonempty */
4077c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 		/*
4107c478bd9Sstevel@tonic-gate 		 * gids should be non-negative; anything else
4117c478bd9Sstevel@tonic-gate 		 * is administrative policy.
4127c478bd9Sstevel@tonic-gate 		 */
4137c478bd9Sstevel@tonic-gate 		if (group->gr_gid < 0)
4147c478bd9Sstevel@tonic-gate 			group->gr_gid = GID_NOBODY;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	if (*next++ != ':') {
4177c478bd9Sstevel@tonic-gate 		/* Parse error, even for a '+' entry (which should have	*/
4187c478bd9Sstevel@tonic-gate 		/*   an empty gid field, since it's always overridden)	*/
4197c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* === Could check and complain if there are any extra colons */
4237c478bd9Sstevel@tonic-gate 	while (memlist < limit) {
4247c478bd9Sstevel@tonic-gate 		p = gettok(&next, ',');
4257c478bd9Sstevel@tonic-gate 		if (p == 0 || *p == '\0') {
4267c478bd9Sstevel@tonic-gate 			*memlist = 0;
4277c478bd9Sstevel@tonic-gate 			/* Successfully parsed and stored */
4287c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		*memlist++ = p;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 	/* Out of space;  error even for black_magic */
4337c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_ERANGE);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate static nss_status_t
4377c478bd9Sstevel@tonic-gate process_cstr(const char *instr, int instr_len, struct nss_groupsbymem *gbm)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	/*
4407c478bd9Sstevel@tonic-gate 	 * It's possible to do a much less inefficient version of this by
4417c478bd9Sstevel@tonic-gate 	 * selectively duplicating code from str2group().  For now,
4427c478bd9Sstevel@tonic-gate 	 * however, we'll take the easy way out and implement this on
4437c478bd9Sstevel@tonic-gate 	 * top of str2group().
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	const char		*username = gbm->username;
4477c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t		*buf;
4487c478bd9Sstevel@tonic-gate 	struct group		*grp;
4497c478bd9Sstevel@tonic-gate 	char			**memp;
4507c478bd9Sstevel@tonic-gate 	char			*mem;
4517c478bd9Sstevel@tonic-gate 	int	parsestat;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP);
4547c478bd9Sstevel@tonic-gate 	if (buf == 0)
4557c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	grp = (struct group *)buf->result;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	parsestat = (*gbm->str2ent)(instr, instr_len,
4607c478bd9Sstevel@tonic-gate 				    grp, buf->buffer, buf->buflen);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (parsestat != NSS_STR_PARSE_SUCCESS) {
4637c478bd9Sstevel@tonic-gate 		_nss_XbyY_buf_free(buf);
4647c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);	/* === ? */
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (grp->gr_mem) {
4687c478bd9Sstevel@tonic-gate 		for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0);
4697c478bd9Sstevel@tonic-gate 								memp++) {
4707c478bd9Sstevel@tonic-gate 			if (strcmp(mem, username) == 0) {
4717c478bd9Sstevel@tonic-gate 				gid_t	gid 	= grp->gr_gid;
4727c478bd9Sstevel@tonic-gate 				gid_t	*gidp	= gbm->gid_array;
4737c478bd9Sstevel@tonic-gate 				int	numgids	= gbm->numgids;
4747c478bd9Sstevel@tonic-gate 				int	i;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 				_nss_XbyY_buf_free(buf);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 				for (i = 0; i < numgids && *gidp != gid; i++,
4797c478bd9Sstevel@tonic-gate 								gidp++) {
4807c478bd9Sstevel@tonic-gate 					;
4817c478bd9Sstevel@tonic-gate 				}
4827c478bd9Sstevel@tonic-gate 				if (i >= numgids) {
4837c478bd9Sstevel@tonic-gate 					if (i >= gbm->maxgids) {
4847c478bd9Sstevel@tonic-gate 					/* Filled the array;  stop searching */
4857c478bd9Sstevel@tonic-gate 						return (NSS_SUCCESS);
4867c478bd9Sstevel@tonic-gate 					}
4877c478bd9Sstevel@tonic-gate 					*gidp = gid;
4887c478bd9Sstevel@tonic-gate 					gbm->numgids = numgids + 1;
4897c478bd9Sstevel@tonic-gate 				}
4907c478bd9Sstevel@tonic-gate 				return (NSS_NOTFOUND);	/* Explained in   */
4917c478bd9Sstevel@tonic-gate 							/* <nss_dbdefs.h> */
4927c478bd9Sstevel@tonic-gate 			}
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	_nss_XbyY_buf_free(buf);
4967c478bd9Sstevel@tonic-gate 	return (NSS_NOTFOUND);
4977c478bd9Sstevel@tonic-gate }
498