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*2b4a7802SBaban Kenkre * Copyright 2008 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 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 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 59*2b4a7802SBaban Kenkre if (argp->key.gid > MAXUID) 60*2b4a7802SBaban 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 65*2b4a7802SBaban Kenkre /* 66*2b4a7802SBaban Kenkre * Validates group entry replacing gid > MAXUID by GID_NOBODY. 67*2b4a7802SBaban Kenkre */ 68*2b4a7802SBaban Kenkre int 69*2b4a7802SBaban Kenkre validate_group_ids(char **linepp, int *linelenp, int allocbuf) 70*2b4a7802SBaban Kenkre { 71*2b4a7802SBaban Kenkre char *linep, *limit, *gidp, *newline; 72*2b4a7802SBaban Kenkre ulong_t gid; 73*2b4a7802SBaban Kenkre int oldgidlen, idlen; 74*2b4a7802SBaban Kenkre int linelen = *linelenp, newlinelen; 75*2b4a7802SBaban Kenkre 76*2b4a7802SBaban Kenkre linep = *linepp; 77*2b4a7802SBaban Kenkre limit = linep + linelen; 78*2b4a7802SBaban Kenkre 79*2b4a7802SBaban Kenkre /* +/- entries valid for compat source only */ 80*2b4a7802SBaban Kenkre if (linelen == 0 || *linep == '+' || *linep == '-') 81*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_SUCCESS); 82*2b4a7802SBaban Kenkre 83*2b4a7802SBaban Kenkre while (linep < limit && *linep++ != ':') /* skip groupname */ 84*2b4a7802SBaban Kenkre continue; 85*2b4a7802SBaban Kenkre while (linep < limit && *linep++ != ':') /* skip password */ 86*2b4a7802SBaban Kenkre continue; 87*2b4a7802SBaban Kenkre if (linep == limit) 88*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_PARSE); 89*2b4a7802SBaban Kenkre 90*2b4a7802SBaban Kenkre gidp = linep; 91*2b4a7802SBaban Kenkre gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */ 92*2b4a7802SBaban Kenkre oldgidlen = linep - gidp; 93*2b4a7802SBaban Kenkre if (linep >= limit || oldgidlen == 0) 94*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_PARSE); 95*2b4a7802SBaban Kenkre 96*2b4a7802SBaban Kenkre if (gid <= MAXUID) 97*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_SUCCESS); 98*2b4a7802SBaban Kenkre 99*2b4a7802SBaban Kenkre idlen = snprintf(NULL, 0, "%u", GID_NOBODY); 100*2b4a7802SBaban Kenkre newlinelen = linelen + idlen - oldgidlen; 101*2b4a7802SBaban Kenkre if (newlinelen > linelen) { 102*2b4a7802SBaban Kenkre /* need a larger buffer */ 103*2b4a7802SBaban Kenkre if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL) 104*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_ERANGE); 105*2b4a7802SBaban Kenkre /* Replace ephemeral ids by ID_NOBODY in the new buffer */ 106*2b4a7802SBaban Kenkre *(gidp - 1) = '\0'; 107*2b4a7802SBaban Kenkre (void) snprintf(newline, newlinelen + 1, "%s:%u%s", 108*2b4a7802SBaban Kenkre *linepp, GID_NOBODY, linep); 109*2b4a7802SBaban Kenkre free(*linepp); 110*2b4a7802SBaban Kenkre *linepp = newline; 111*2b4a7802SBaban Kenkre *linelenp = newlinelen; 112*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_SUCCESS); 113*2b4a7802SBaban Kenkre } 114*2b4a7802SBaban Kenkre 115*2b4a7802SBaban Kenkre /* Replace ephemeral gid by GID_NOBODY in the same buffer */ 116*2b4a7802SBaban Kenkre (void) bcopy(linep, gidp + idlen, limit - linep + 1); 117*2b4a7802SBaban Kenkre (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY); 118*2b4a7802SBaban Kenkre *(gidp + idlen) = ':'; 119*2b4a7802SBaban Kenkre *linelenp = newlinelen; 120*2b4a7802SBaban Kenkre return (NSS_STR_PARSE_SUCCESS); 121*2b4a7802SBaban Kenkre } 122*2b4a7802SBaban Kenkre 1237c478bd9Sstevel@tonic-gate static nss_status_t 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, 1337c478bd9Sstevel@tonic-gate * not in NIS or 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 * 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 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 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 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, 286*2b4a7802SBaban 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, 293*2b4a7802SBaban Kenkre &argp->numgids); 2947c478bd9Sstevel@tonic-gate free(val); 2957c478bd9Sstevel@tonic-gate return ((parse_res == NSS_STR_PARSE_SUCCESS) 296*2b4a7802SBaban Kenkre ? NSS_SUCCESS : NSS_NOTFOUND); 2977c478bd9Sstevel@tonic-gate } 298