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