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