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