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
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * 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 /*
22*36e852a1SRaja Andra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * nis/getgrent.c -- "nis" backend for nsswitch "group" database
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <grp.h>
317c478bd9Sstevel@tonic-gate #include <pwd.h>
327c478bd9Sstevel@tonic-gate #include "nis_common.h"
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <rpc/auth.h>	/* for MAXNETNAMELEN */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static nss_status_t netid_lookup(struct nss_groupsbymem *argp);
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static nss_status_t
getbyname(be,a)417c478bd9Sstevel@tonic-gate getbyname(be, a)
427c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
437c478bd9Sstevel@tonic-gate 	void			*a;
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	return (_nss_nis_lookup(be, argp, 0,
487c478bd9Sstevel@tonic-gate 				"group.byname", argp->key.name, 0));
497c478bd9Sstevel@tonic-gate }
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static nss_status_t
getbygid(be,a)527c478bd9Sstevel@tonic-gate getbygid(be, a)
537c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
547c478bd9Sstevel@tonic-gate 	void			*a;
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
577c478bd9Sstevel@tonic-gate 	char			gidstr[12];	/* More than enough */
587c478bd9Sstevel@tonic-gate 
592b4a7802SBaban Kenkre 	if (argp->key.gid > MAXUID)
602b4a7802SBaban Kenkre 		return (NSS_NOTFOUND);
61cb5caa98Sdjl 	(void) snprintf(gidstr, 12, "%d", argp->key.gid);
627c478bd9Sstevel@tonic-gate 	return (_nss_nis_lookup(be, argp, 0, "group.bygid", gidstr, 0));
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate 
652b4a7802SBaban Kenkre /*
662b4a7802SBaban Kenkre  * Validates group entry replacing gid > MAXUID by GID_NOBODY.
672b4a7802SBaban Kenkre  */
682b4a7802SBaban Kenkre int
validate_group_ids(char ** linepp,int * linelenp,int allocbuf)692b4a7802SBaban Kenkre validate_group_ids(char **linepp, int *linelenp, int allocbuf)
702b4a7802SBaban Kenkre {
712b4a7802SBaban Kenkre 	char	*linep, *limit, *gidp, *newline;
722b4a7802SBaban Kenkre 	ulong_t	gid;
732b4a7802SBaban Kenkre 	int	oldgidlen, idlen;
742b4a7802SBaban Kenkre 	int	linelen = *linelenp, newlinelen;
752b4a7802SBaban Kenkre 
762b4a7802SBaban Kenkre 	linep = *linepp;
772b4a7802SBaban Kenkre 	limit = linep + linelen;
782b4a7802SBaban Kenkre 
792b4a7802SBaban Kenkre 	/* +/- entries valid for compat source only */
802b4a7802SBaban Kenkre 	if (linelen == 0 || *linep == '+' || *linep == '-')
812b4a7802SBaban Kenkre 		return (NSS_STR_PARSE_SUCCESS);
822b4a7802SBaban Kenkre 
832b4a7802SBaban Kenkre 	while (linep < limit && *linep++ != ':') /* skip groupname */
842b4a7802SBaban Kenkre 		continue;
852b4a7802SBaban Kenkre 	while (linep < limit && *linep++ != ':') /* skip password */
862b4a7802SBaban Kenkre 		continue;
872b4a7802SBaban Kenkre 	if (linep == limit)
882b4a7802SBaban Kenkre 		return (NSS_STR_PARSE_PARSE);
892b4a7802SBaban Kenkre 
902b4a7802SBaban Kenkre 	gidp = linep;
912b4a7802SBaban Kenkre 	gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */
922b4a7802SBaban Kenkre 	oldgidlen = linep - gidp;
932b4a7802SBaban Kenkre 	if (linep >= limit || oldgidlen == 0)
942b4a7802SBaban Kenkre 		return (NSS_STR_PARSE_PARSE);
952b4a7802SBaban Kenkre 
962b4a7802SBaban Kenkre 	if (gid <= MAXUID)
972b4a7802SBaban Kenkre 		return (NSS_STR_PARSE_SUCCESS);
982b4a7802SBaban Kenkre 
992b4a7802SBaban Kenkre 	idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
1002b4a7802SBaban Kenkre 	newlinelen = linelen + idlen - oldgidlen;
1012b4a7802SBaban Kenkre 	if (newlinelen > linelen) {
1022b4a7802SBaban Kenkre 		/* need a larger buffer */
1032b4a7802SBaban Kenkre 		if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL)
1042b4a7802SBaban Kenkre 			return (NSS_STR_PARSE_ERANGE);
1052b4a7802SBaban Kenkre 		/* Replace ephemeral ids by ID_NOBODY in the new buffer */
1062b4a7802SBaban Kenkre 		*(gidp - 1) = '\0';
1072b4a7802SBaban Kenkre 		(void) snprintf(newline, newlinelen + 1, "%s:%u%s",
1082b4a7802SBaban Kenkre 		    *linepp, GID_NOBODY, linep);
1092b4a7802SBaban Kenkre 		free(*linepp);
1102b4a7802SBaban Kenkre 		*linepp = newline;
1112b4a7802SBaban Kenkre 		*linelenp = newlinelen;
1122b4a7802SBaban Kenkre 		return (NSS_STR_PARSE_SUCCESS);
1132b4a7802SBaban Kenkre 	}
1142b4a7802SBaban Kenkre 
1152b4a7802SBaban Kenkre 	/* Replace ephemeral gid by GID_NOBODY in the same buffer */
1162b4a7802SBaban Kenkre 	(void) bcopy(linep, gidp + idlen, limit - linep + 1);
1172b4a7802SBaban Kenkre 	(void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
1182b4a7802SBaban Kenkre 	*(gidp + idlen) = ':';
1192b4a7802SBaban Kenkre 	*linelenp = newlinelen;
1202b4a7802SBaban Kenkre 	return (NSS_STR_PARSE_SUCCESS);
1212b4a7802SBaban Kenkre }
1222b4a7802SBaban Kenkre 
1237c478bd9Sstevel@tonic-gate static nss_status_t
getbymember(be,a)1247c478bd9Sstevel@tonic-gate getbymember(be, a)
1257c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
1267c478bd9Sstevel@tonic-gate 	void			*a;
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	struct nss_groupsbymem	*argp = (struct nss_groupsbymem *)a;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	if (strcmp(argp->username, "root") == 0) {
1317c478bd9Sstevel@tonic-gate 		/*
1327c478bd9Sstevel@tonic-gate 		 * Assume that "root" can only sensibly be in /etc/group,
133*36e852a1SRaja Andra 		 *   not in NIS
1347c478bd9Sstevel@tonic-gate 		 * If we don't do this, a hung name-service may cause
1357c478bd9Sstevel@tonic-gate 		 *   a root login or su to hang.
1367c478bd9Sstevel@tonic-gate 		 */
1377c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (argp->force_slow_way != 1) {
1417c478bd9Sstevel@tonic-gate 		switch (netid_lookup(argp)) {
1427c478bd9Sstevel@tonic-gate 		case NSS_SUCCESS:
1437c478bd9Sstevel@tonic-gate 			/*
1447c478bd9Sstevel@tonic-gate 			 * Return SUCESS only if array is full. Explained
1457c478bd9Sstevel@tonic-gate 			 * in <nss_dbdefs.h>.
1467c478bd9Sstevel@tonic-gate 			 */
1477c478bd9Sstevel@tonic-gate 			return ((argp->numgids == argp->maxgids)
1487c478bd9Sstevel@tonic-gate 			    ? NSS_SUCCESS
1497c478bd9Sstevel@tonic-gate 			    : NSS_NOTFOUND);
1507c478bd9Sstevel@tonic-gate 		case NSS_NOTFOUND:
1517c478bd9Sstevel@tonic-gate 		case NSS_UNAVAIL:
1527c478bd9Sstevel@tonic-gate 			/*
1537c478bd9Sstevel@tonic-gate 			 * Failover to group map search if no luck with netid.
1547c478bd9Sstevel@tonic-gate 			 */
1557c478bd9Sstevel@tonic-gate 			break;
1567c478bd9Sstevel@tonic-gate 		case NSS_TRYAGAIN:
1577c478bd9Sstevel@tonic-gate 			return (NSS_TRYAGAIN);
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	return (_nss_nis_do_all(be, argp, argp->username,
1627c478bd9Sstevel@tonic-gate 				(nis_do_all_func_t)argp->process_cstr));
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static nis_backend_op_t group_ops[] = {
1667c478bd9Sstevel@tonic-gate 	_nss_nis_destr,
1677c478bd9Sstevel@tonic-gate 	_nss_nis_endent,
1687c478bd9Sstevel@tonic-gate 	_nss_nis_setent,
1697c478bd9Sstevel@tonic-gate 	_nss_nis_getent_rigid,
1707c478bd9Sstevel@tonic-gate 	getbyname,
1717c478bd9Sstevel@tonic-gate 	getbygid,
1727c478bd9Sstevel@tonic-gate 	getbymember
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1767c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_nis_group_constr(dummy1,dummy2,dummy3)1777c478bd9Sstevel@tonic-gate _nss_nis_group_constr(dummy1, dummy2, dummy3)
1787c478bd9Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	return (_nss_nis_constr(group_ops,
1817c478bd9Sstevel@tonic-gate 				sizeof (group_ops) / sizeof (group_ops[0]),
1827c478bd9Sstevel@tonic-gate 				"group.byname"));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * Add gid to gid_array if it's not already there. gid_array must have room
1877c478bd9Sstevel@tonic-gate  * for one more entry.  Return new size of array.
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static int
add_gid(gid_t gid_array[],int numgids,gid_t gid)1907c478bd9Sstevel@tonic-gate add_gid(gid_t gid_array[], int numgids, gid_t gid)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	int i = 0;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	for (i = 0; i < numgids; i++) {
1957c478bd9Sstevel@tonic-gate 		if (gid_array[i] == gid) {
1967c478bd9Sstevel@tonic-gate 			return (numgids);
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	gid_array[numgids++] = gid;
2007c478bd9Sstevel@tonic-gate 	return (numgids);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate  * Given buf, a null-terminated string containing the result of a successful
2057c478bd9Sstevel@tonic-gate  * netid lookup, add the gids to the gid_array.  The string may contain extra
2067c478bd9Sstevel@tonic-gate  * whitesapce.  On parse error, the valid portion of the gid_array is not
2077c478bd9Sstevel@tonic-gate  * modified.
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate static int
parse_netid(const char * buf,gid_t gid_array[],int maxgids,int * numgids_ptr)2107c478bd9Sstevel@tonic-gate parse_netid(const char *buf, gid_t gid_array[], int maxgids, int *numgids_ptr)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	int	numgids = *numgids_ptr;
2137c478bd9Sstevel@tonic-gate 	char	*buf_next;
2147c478bd9Sstevel@tonic-gate 	gid_t	gid;
2157c478bd9Sstevel@tonic-gate 	long	value;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/* Scan past "<uid>:" */
2187c478bd9Sstevel@tonic-gate 	while (isspace(*buf) || isdigit(*buf)) {
2197c478bd9Sstevel@tonic-gate 		buf++;
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if (*buf++ != ':') {
2237c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/* buf should now point to a comma-separated list of gids */
2277c478bd9Sstevel@tonic-gate 	while (*buf != '\0' && *buf != '\n') {
2287c478bd9Sstevel@tonic-gate 		errno = 0;
2297c478bd9Sstevel@tonic-gate 		value = strtol(buf, &buf_next, 10);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		if (buf == buf_next) {
2327c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
2337c478bd9Sstevel@tonic-gate 		} else if ((value == LONG_MAX && errno == ERANGE) ||
2347c478bd9Sstevel@tonic-gate 		    (ulong_t)value > INT_MAX) {
2357c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		gid = (gid_t)value;
2397c478bd9Sstevel@tonic-gate 		if (numgids < maxgids) {
2407c478bd9Sstevel@tonic-gate 			numgids = add_gid(gid_array, numgids, gid);
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 		buf = buf_next;
2437c478bd9Sstevel@tonic-gate 		if (*buf == ',') {
2447c478bd9Sstevel@tonic-gate 			buf++;
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	*numgids_ptr = numgids;
2487c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * Perform a lookup in the netid map.  Fill in the gid_array if successful.
2547c478bd9Sstevel@tonic-gate  * Return values are like those for _nss_nis_lookup().
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static nss_status_t
netid_lookup(struct nss_groupsbymem * argp)2577c478bd9Sstevel@tonic-gate netid_lookup(struct nss_groupsbymem *argp)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	const char	*domain = _nss_nis_domain();
2607c478bd9Sstevel@tonic-gate 	struct passwd	pw;
2617c478bd9Sstevel@tonic-gate 	char		pwbuf[NSS_BUFLEN_PASSWD];
2627c478bd9Sstevel@tonic-gate 	char		netname[MAXNETNAMELEN + 1];
2637c478bd9Sstevel@tonic-gate 	nss_status_t	res;
2647c478bd9Sstevel@tonic-gate 	char		*val;
2657c478bd9Sstevel@tonic-gate 	int		vallen;
2667c478bd9Sstevel@tonic-gate 	int		parse_res;
2677c478bd9Sstevel@tonic-gate 	char		*lasts;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/*
2707c478bd9Sstevel@tonic-gate 	 * Need to build up the netname for the user manually. Can't use
2717c478bd9Sstevel@tonic-gate 	 * user2netname() rpc library call, since that does all sorts of
2727c478bd9Sstevel@tonic-gate 	 * extra stuff based upon its own private name-service switch.
2737c478bd9Sstevel@tonic-gate 	 *
2747c478bd9Sstevel@tonic-gate 	 * Note that "root" has no user netname so return in error.
2757c478bd9Sstevel@tonic-gate 	 */
2767c478bd9Sstevel@tonic-gate 	if ((getpwnam_r(argp->username, &pw, pwbuf, sizeof (pwbuf)) == NULL) ||
2777c478bd9Sstevel@tonic-gate 	    (pw.pw_uid == 0)) {
2787c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 	if (snprintf(netname, MAXNETNAMELEN + 1, "unix.%d@%s",
2817c478bd9Sstevel@tonic-gate 	    pw.pw_uid, domain) < 0) {
2827c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if ((res = _nss_nis_ypmatch(domain, "netid.byname", netname,
2862b4a7802SBaban Kenkre 	    &val, &vallen, 0)) != NSS_SUCCESS) {
2877c478bd9Sstevel@tonic-gate 		return (res);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
290cb5caa98Sdjl 	(void) strtok_r(val, "#", &lasts);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	parse_res = parse_netid(val, argp->gid_array, argp->maxgids,
2932b4a7802SBaban Kenkre 	    &argp->numgids);
2947c478bd9Sstevel@tonic-gate 	free(val);
2957c478bd9Sstevel@tonic-gate 	return ((parse_res == NSS_STR_PARSE_SUCCESS)
2962b4a7802SBaban Kenkre 	    ? NSS_SUCCESS : NSS_NOTFOUND);
2977c478bd9Sstevel@tonic-gate }
298