xref: /illumos-gate/usr/src/lib/libc/port/gen/getgrnam_r.c (revision 2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f)
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  */
2106e1a714Sraf 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277257d1b4Sraf #include "lint.h"
287c478bd9Sstevel@tonic-gate #include <mtlib.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <grp.h>
317c478bd9Sstevel@tonic-gate #include <memory.h>
3206e1a714Sraf #include <deflt.h>
337c478bd9Sstevel@tonic-gate #include <nsswitch.h>
347c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <synch.h>
397c478bd9Sstevel@tonic-gate #include <sys/param.h>
407c478bd9Sstevel@tonic-gate #include <sys/mman.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate extern int _getgroupsbymember(const char *, gid_t[], int, int);
43cb5caa98Sdjl int str2group(const char *, int, void *, char *, int);
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
467c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context);
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	USE_NETID_STR	"NETID_AUTHORITATIVE=TRUE"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate void
517c478bd9Sstevel@tonic-gate _nss_initf_group(nss_db_params_t *p)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_GROUP;
547c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_GROUP;
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include <getxby_door.h>
587c478bd9Sstevel@tonic-gate #include <sys/door.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate struct group *
617c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
627c478bd9Sstevel@tonic-gate     int buflen);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate struct group *
657c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function getgrnam_r.
697c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate struct group *
727257d1b4Sraf getgrnam_r(const char *name, struct group *result, char *buffer, int buflen)
737c478bd9Sstevel@tonic-gate {
74cb5caa98Sdjl 	nss_XbyY_args_t arg;
757c478bd9Sstevel@tonic-gate 
76cb5caa98Sdjl 	if (name == (const char *)NULL) {
777c478bd9Sstevel@tonic-gate 		errno = ERANGE;
787c478bd9Sstevel@tonic-gate 		return (NULL);
797c478bd9Sstevel@tonic-gate 	}
80cb5caa98Sdjl 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
81cb5caa98Sdjl 	arg.key.name = name;
82cb5caa98Sdjl 	(void) nss_search(&db_root, _nss_initf_group,
83cb5caa98Sdjl 	    NSS_DBOP_GROUP_BYNAME, &arg);
84cb5caa98Sdjl 	return ((struct group *)NSS_XbyY_FINI(&arg));
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function getgrgid_r.
897c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate struct group *
927257d1b4Sraf getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen)
937c478bd9Sstevel@tonic-gate {
94cb5caa98Sdjl 	nss_XbyY_args_t arg;
957c478bd9Sstevel@tonic-gate 
96cb5caa98Sdjl 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
97cb5caa98Sdjl 	arg.key.gid = gid;
98cb5caa98Sdjl 	(void) nss_search(&db_root, _nss_initf_group,
99cb5caa98Sdjl 	    NSS_DBOP_GROUP_BYGID, &arg);
100cb5caa98Sdjl 	return ((struct group *)NSS_XbyY_FINI(&arg));
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate struct group *
1047c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer,
1057c478bd9Sstevel@tonic-gate     int buflen)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1107c478bd9Sstevel@tonic-gate 	arg.key.gid = gid;
1117c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
1127c478bd9Sstevel@tonic-gate 	    NSS_DBOP_GROUP_BYGID, &arg);
1137c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function getgrgid_r.
1187c478bd9Sstevel@tonic-gate  * User gets it via static getgrgid_r from the header file.
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate int
1217c478bd9Sstevel@tonic-gate __posix_getgrgid_r(gid_t gid, struct group *grp, char *buffer,
1227c478bd9Sstevel@tonic-gate     size_t bufsize, struct group **result)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	int nerrno = 0;
1257c478bd9Sstevel@tonic-gate 	int oerrno = errno;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	errno = 0;
1287257d1b4Sraf 	if ((*result = getgrgid_r(gid, grp, buffer, (uintptr_t)bufsize))
1297c478bd9Sstevel@tonic-gate 	    == NULL) {
1307c478bd9Sstevel@tonic-gate 			nerrno = errno;
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 	errno = oerrno;
1337c478bd9Sstevel@tonic-gate 	return (nerrno);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate struct group *
1377c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
1387c478bd9Sstevel@tonic-gate 	int buflen)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1437c478bd9Sstevel@tonic-gate 	arg.key.name = name;
1447c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
1457c478bd9Sstevel@tonic-gate 	    NSS_DBOP_GROUP_BYNAME, &arg);
1467c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function getgrnam_r.
1517c478bd9Sstevel@tonic-gate  * User gets it via static getgrnam_r from the header file.
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate int
1547c478bd9Sstevel@tonic-gate __posix_getgrnam_r(const char *name, struct group *grp, char *buffer,
1557c478bd9Sstevel@tonic-gate     size_t bufsize, struct group **result)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	int nerrno = 0;
1587c478bd9Sstevel@tonic-gate 	int oerrno = errno;
1597c478bd9Sstevel@tonic-gate 
1607257d1b4Sraf 	if ((*result = getgrnam_r(name, grp, buffer, (uintptr_t)bufsize))
1617c478bd9Sstevel@tonic-gate 	    == NULL) {
1627c478bd9Sstevel@tonic-gate 			nerrno = errno;
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	errno = oerrno;
1657c478bd9Sstevel@tonic-gate 	return (nerrno);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate void
1697c478bd9Sstevel@tonic-gate setgrent(void)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	nss_setent(&db_root, _nss_initf_group, &context);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate void
1757c478bd9Sstevel@tonic-gate endgrent(void)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	nss_endent(&db_root, _nss_initf_group, &context);
1787c478bd9Sstevel@tonic-gate 	nss_delete(&db_root);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate struct group *
1827c478bd9Sstevel@tonic-gate getgrent_r(struct group *result, char *buffer, int buflen)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1857c478bd9Sstevel@tonic-gate 	char		*nam;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	do {
1907c478bd9Sstevel@tonic-gate 		NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1917c478bd9Sstevel@tonic-gate 		/* No key to fill in */
1927c478bd9Sstevel@tonic-gate 		(void) nss_getent(&db_root, _nss_initf_group, &context, &arg);
1937c478bd9Sstevel@tonic-gate 	} while (arg.returnval != 0 &&
1947c478bd9Sstevel@tonic-gate 	    (nam = ((struct group *)arg.returnval)->gr_name) != 0 &&
1957c478bd9Sstevel@tonic-gate 	    (*nam == '+' || *nam == '-'));
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate struct group *
2017c478bd9Sstevel@tonic-gate fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	extern void	_nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
2047c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t	arg;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* No key to fill in */
2097c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
2107c478bd9Sstevel@tonic-gate 	_nss_XbyY_fgets(f, &arg);
2117c478bd9Sstevel@tonic-gate 	return ((struct group *)NSS_XbyY_FINI(&arg));
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * _getgroupsbymember(uname, gid_array, maxgids, numgids):
2167c478bd9Sstevel@tonic-gate  *	Private interface for initgroups().  It returns the group ids of
2177c478bd9Sstevel@tonic-gate  *	groups of which the specified user is a member.
2187c478bd9Sstevel@tonic-gate  *
2197c478bd9Sstevel@tonic-gate  * Arguments:
2207c478bd9Sstevel@tonic-gate  *   username	Username of the putative member
2217c478bd9Sstevel@tonic-gate  *   gid_array	Space in which to return the gids.  The first [numgids]
2227c478bd9Sstevel@tonic-gate  *		elements are assumed to already contain valid gids.
2237c478bd9Sstevel@tonic-gate  *   maxgids	Maximum number of elements in gid_array.
2247c478bd9Sstevel@tonic-gate  *   numgids	Number of elements (normally 0 or 1) that already contain
2257c478bd9Sstevel@tonic-gate  *		valid gids.
2267c478bd9Sstevel@tonic-gate  * Return value:
2277c478bd9Sstevel@tonic-gate  *   number of valid gids in gid_array (may be zero)
2287c478bd9Sstevel@tonic-gate  *	or
2297c478bd9Sstevel@tonic-gate  *   -1 (and errno set appropriately) on errors (none currently defined)
230cb5caa98Sdjl  *
231cb5caa98Sdjl  * NSS2 Consistency enhancements:
232cb5caa98Sdjl  *   The "files normal" format between an application and nscd for the
233cb5caa98Sdjl  *   NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a
234cb5caa98Sdjl  *   processed array of numgids [up to maxgids] gid_t values.  gid_t
235cb5caa98Sdjl  *   values in the array are unique.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate 
238e37190e5Smichen extern nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate int
2417c478bd9Sstevel@tonic-gate _getgroupsbymember(const char *username, gid_t gid_array[],
2427c478bd9Sstevel@tonic-gate     int maxgids, int numgids)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	struct nss_groupsbymem	arg;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	arg.username	= username;
2477c478bd9Sstevel@tonic-gate 	arg.gid_array	= gid_array;
2487c478bd9Sstevel@tonic-gate 	arg.maxgids	= maxgids;
2497c478bd9Sstevel@tonic-gate 	arg.numgids	= numgids;
250cb5caa98Sdjl 	/*
251cb5caa98Sdjl 	 * In backwards compatibility mode, use the old str2group &
252cb5caa98Sdjl 	 * process_cstr interfaces.  Ditto within nscd processing.
253cb5caa98Sdjl 	 */
2547c478bd9Sstevel@tonic-gate 	arg.str2ent	= str2group;
2557c478bd9Sstevel@tonic-gate 	arg.process_cstr = process_cstr;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * The old value being provided here was 0, ie do the quick
2597c478bd9Sstevel@tonic-gate 	 * way.  Given that this was never actually used under NIS
2607c478bd9Sstevel@tonic-gate 	 * and had the wrong (now corrected) meaning for NIS+ we need
2617c478bd9Sstevel@tonic-gate 	 * to change the default to be 1 (TRUE) as we now need the
2627c478bd9Sstevel@tonic-gate 	 * admin to decided to use netid, setting NETID_AUTHORITATIVE
2637c478bd9Sstevel@tonic-gate 	 * in /etc/default/nss to TRUE gets us a value of 0 for
2647c478bd9Sstevel@tonic-gate 	 * force_slow_way - don't you just love double negatives ;-)
2657c478bd9Sstevel@tonic-gate 	 *
2667c478bd9Sstevel@tonic-gate 	 * We need to do this to preserve the behaviour seen when the
2677c478bd9Sstevel@tonic-gate 	 * admin makes no changes.
2687c478bd9Sstevel@tonic-gate 	 */
2697c478bd9Sstevel@tonic-gate 	arg.force_slow_way = 1;
2707c478bd9Sstevel@tonic-gate 
27106e1a714Sraf 	if (defopen(__NSW_DEFAULT_FILE) == 0) {
27206e1a714Sraf 		if (defread(USE_NETID_STR) != NULL)
2737c478bd9Sstevel@tonic-gate 			arg.force_slow_way = 0;
27406e1a714Sraf 		(void) defopen(NULL);
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	(void) nss_search(&db_root, _nss_initf_group,
2787c478bd9Sstevel@tonic-gate 	    NSS_DBOP_GROUP_BYMEMBER, &arg);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	return (arg.numgids);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static char *
2857c478bd9Sstevel@tonic-gate gettok(char **nextpp, char sep)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	char	*p = *nextpp;
2887c478bd9Sstevel@tonic-gate 	char	*q = p;
2897c478bd9Sstevel@tonic-gate 	char	c;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (p == 0)
2927c478bd9Sstevel@tonic-gate 		return (0);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	while ((c = *q) != '\0' && c != sep)
2957c478bd9Sstevel@tonic-gate 		q++;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (c == '\0')
2987c478bd9Sstevel@tonic-gate 		*nextpp = 0;
2997c478bd9Sstevel@tonic-gate 	else {
3007c478bd9Sstevel@tonic-gate 		*q++ = '\0';
3017c478bd9Sstevel@tonic-gate 		*nextpp = q;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	return (p);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
3087c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
3097c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
3107c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate int
3137c478bd9Sstevel@tonic-gate str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	struct group		*group	= (struct group *)ent;
3167c478bd9Sstevel@tonic-gate 	char			*p, *next;
3177c478bd9Sstevel@tonic-gate 	int			black_magic;	/* "+" or "-" entry */
3187c478bd9Sstevel@tonic-gate 	char			**memlist, **limit;
319*2b4a7802SBaban Kenkre 	ulong_t			tmp;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (lenstr + 1 > buflen)
3227c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/*
3257c478bd9Sstevel@tonic-gate 	 * We copy the input string into the output buffer and
3267c478bd9Sstevel@tonic-gate 	 * operate on it in place.
3277c478bd9Sstevel@tonic-gate 	 */
328cb5caa98Sdjl 	if (instr != buffer) {
329cb5caa98Sdjl 		/* Overlapping buffer copies are OK */
330cb5caa98Sdjl 		(void) memmove(buffer, instr, lenstr);
3317c478bd9Sstevel@tonic-gate 		buffer[lenstr] = '\0';
332cb5caa98Sdjl 	}
333cb5caa98Sdjl 
334cb5caa98Sdjl 	/* quick exit do not entry fill if not needed */
335cb5caa98Sdjl 	if (ent == (void *)NULL)
336cb5caa98Sdjl 		return (NSS_STR_PARSE_SUCCESS);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	next = buffer;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * Parsers for passwd and group have always been pretty rigid;
3427c478bd9Sstevel@tonic-gate 	 * we wouldn't want to buck a Unix tradition
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	group->gr_name = p = gettok(&next, ':');
3467c478bd9Sstevel@tonic-gate 	if (*p == '\0') {
3477c478bd9Sstevel@tonic-gate 		/* Empty group-name;  not allowed */
3487c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/* Always return at least an empty gr_mem list */
3527c478bd9Sstevel@tonic-gate 	memlist	= (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *));
3537c478bd9Sstevel@tonic-gate 	limit	= (char **)ROUND_DOWN(buffer + buflen, sizeof (char *));
3547c478bd9Sstevel@tonic-gate 	*memlist = 0;
3557c478bd9Sstevel@tonic-gate 	group->gr_mem = memlist;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	black_magic = (*p == '+' || *p == '-');
3587c478bd9Sstevel@tonic-gate 	if (black_magic) {
3597c478bd9Sstevel@tonic-gate 		/* Then the rest of the group entry is optional */
3607c478bd9Sstevel@tonic-gate 		group->gr_passwd = 0;
3617c478bd9Sstevel@tonic-gate 		group->gr_gid = 0;
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	group->gr_passwd = p = gettok(&next, ':');
3657c478bd9Sstevel@tonic-gate 	if (p == 0) {
3667c478bd9Sstevel@tonic-gate 		if (black_magic)
3677c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
3687c478bd9Sstevel@tonic-gate 		else
3697c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	p = next;					/* gid */
3737c478bd9Sstevel@tonic-gate 	if (p == 0 || *p == '\0') {
3747c478bd9Sstevel@tonic-gate 		if (black_magic)
3757c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
3767c478bd9Sstevel@tonic-gate 		else
3777c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	if (!black_magic) {
380*2b4a7802SBaban Kenkre 		tmp = strtoul(p, &next, 10);
3817c478bd9Sstevel@tonic-gate 		if (next == p) {
3827c478bd9Sstevel@tonic-gate 			/* gid field should be nonempty */
3837c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
3847c478bd9Sstevel@tonic-gate 		}
385*2b4a7802SBaban Kenkre 		if (group->gr_gid >= UINT32_MAX)
3867c478bd9Sstevel@tonic-gate 			group->gr_gid = GID_NOBODY;
387*2b4a7802SBaban Kenkre 		else
388*2b4a7802SBaban Kenkre 			group->gr_gid = (gid_t)tmp;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	if (*next++ != ':') {
3917c478bd9Sstevel@tonic-gate 		/* Parse error, even for a '+' entry (which should have	*/
3927c478bd9Sstevel@tonic-gate 		/*   an empty gid field, since it's always overridden)	*/
3937c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	/* === Could check and complain if there are any extra colons */
3977c478bd9Sstevel@tonic-gate 	while (memlist < limit) {
3987c478bd9Sstevel@tonic-gate 		p = gettok(&next, ',');
3997c478bd9Sstevel@tonic-gate 		if (p == 0 || *p == '\0') {
4007c478bd9Sstevel@tonic-gate 			*memlist = 0;
4017c478bd9Sstevel@tonic-gate 			/* Successfully parsed and stored */
4027c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		*memlist++ = p;
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	/* Out of space;  error even for black_magic */
4077c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_ERANGE);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
410e37190e5Smichen nss_status_t
4117c478bd9Sstevel@tonic-gate process_cstr(const char *instr, int instr_len, struct nss_groupsbymem *gbm)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * It's possible to do a much less inefficient version of this by
4157c478bd9Sstevel@tonic-gate 	 * selectively duplicating code from str2group().  For now,
4167c478bd9Sstevel@tonic-gate 	 * however, we'll take the easy way out and implement this on
4177c478bd9Sstevel@tonic-gate 	 * top of str2group().
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	const char		*username = gbm->username;
4217c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t		*buf;
4227c478bd9Sstevel@tonic-gate 	struct group		*grp;
4237c478bd9Sstevel@tonic-gate 	char			**memp;
4247c478bd9Sstevel@tonic-gate 	char			*mem;
4257c478bd9Sstevel@tonic-gate 	int	parsestat;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP);
4287c478bd9Sstevel@tonic-gate 	if (buf == 0)
4297c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	grp = (struct group *)buf->result;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	parsestat = (*gbm->str2ent)(instr, instr_len,
4347c478bd9Sstevel@tonic-gate 	    grp, buf->buffer, buf->buflen);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	if (parsestat != NSS_STR_PARSE_SUCCESS) {
4377c478bd9Sstevel@tonic-gate 		_nss_XbyY_buf_free(buf);
4387c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);	/* === ? */
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if (grp->gr_mem) {
4427c478bd9Sstevel@tonic-gate 		for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0);
4437c478bd9Sstevel@tonic-gate 		    memp++) {
4447c478bd9Sstevel@tonic-gate 			if (strcmp(mem, username) == 0) {
4457c478bd9Sstevel@tonic-gate 				gid_t	gid 	= grp->gr_gid;
4467c478bd9Sstevel@tonic-gate 				gid_t	*gidp	= gbm->gid_array;
4477c478bd9Sstevel@tonic-gate 				int	numgids	= gbm->numgids;
4487c478bd9Sstevel@tonic-gate 				int	i;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 				_nss_XbyY_buf_free(buf);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 				for (i = 0; i < numgids && *gidp != gid; i++,
4537c478bd9Sstevel@tonic-gate 				    gidp++) {
4547c478bd9Sstevel@tonic-gate 					;
4557c478bd9Sstevel@tonic-gate 				}
4567c478bd9Sstevel@tonic-gate 				if (i >= numgids) {
4577c478bd9Sstevel@tonic-gate 					if (i >= gbm->maxgids) {
4587c478bd9Sstevel@tonic-gate 					/* Filled the array;  stop searching */
4597c478bd9Sstevel@tonic-gate 						return (NSS_SUCCESS);
4607c478bd9Sstevel@tonic-gate 					}
4617c478bd9Sstevel@tonic-gate 					*gidp = gid;
4627c478bd9Sstevel@tonic-gate 					gbm->numgids = numgids + 1;
4637c478bd9Sstevel@tonic-gate 				}
4647c478bd9Sstevel@tonic-gate 				return (NSS_NOTFOUND);	/* Explained in   */
4657c478bd9Sstevel@tonic-gate 							/* <nss_dbdefs.h> */
4667c478bd9Sstevel@tonic-gate 			}
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 	_nss_XbyY_buf_free(buf);
4707c478bd9Sstevel@tonic-gate 	return (NSS_NOTFOUND);
4717c478bd9Sstevel@tonic-gate }
472