10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52830Sdjl * Common Development and Distribution License (the "License"). 62830Sdjl * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*11262SRajagopal.Andra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * nis/getgrent.c -- "nis" backend for nsswitch "group" database 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <grp.h> 310Sstevel@tonic-gate #include <pwd.h> 320Sstevel@tonic-gate #include "nis_common.h" 330Sstevel@tonic-gate #include <ctype.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <rpc/auth.h> /* for MAXNETNAMELEN */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate static nss_status_t netid_lookup(struct nss_groupsbymem *argp); 390Sstevel@tonic-gate 400Sstevel@tonic-gate static nss_status_t 410Sstevel@tonic-gate getbyname(be, a) 420Sstevel@tonic-gate nis_backend_ptr_t be; 430Sstevel@tonic-gate void *a; 440Sstevel@tonic-gate { 450Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 460Sstevel@tonic-gate 470Sstevel@tonic-gate return (_nss_nis_lookup(be, argp, 0, 480Sstevel@tonic-gate "group.byname", argp->key.name, 0)); 490Sstevel@tonic-gate } 500Sstevel@tonic-gate 510Sstevel@tonic-gate static nss_status_t 520Sstevel@tonic-gate getbygid(be, a) 530Sstevel@tonic-gate nis_backend_ptr_t be; 540Sstevel@tonic-gate void *a; 550Sstevel@tonic-gate { 560Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 570Sstevel@tonic-gate char gidstr[12]; /* More than enough */ 580Sstevel@tonic-gate 598040SBaban.Kenkre@Sun.COM if (argp->key.gid > MAXUID) 608040SBaban.Kenkre@Sun.COM return (NSS_NOTFOUND); 612830Sdjl (void) snprintf(gidstr, 12, "%d", argp->key.gid); 620Sstevel@tonic-gate return (_nss_nis_lookup(be, argp, 0, "group.bygid", gidstr, 0)); 630Sstevel@tonic-gate } 640Sstevel@tonic-gate 658040SBaban.Kenkre@Sun.COM /* 668040SBaban.Kenkre@Sun.COM * Validates group entry replacing gid > MAXUID by GID_NOBODY. 678040SBaban.Kenkre@Sun.COM */ 688040SBaban.Kenkre@Sun.COM int 698040SBaban.Kenkre@Sun.COM validate_group_ids(char **linepp, int *linelenp, int allocbuf) 708040SBaban.Kenkre@Sun.COM { 718040SBaban.Kenkre@Sun.COM char *linep, *limit, *gidp, *newline; 728040SBaban.Kenkre@Sun.COM ulong_t gid; 738040SBaban.Kenkre@Sun.COM int oldgidlen, idlen; 748040SBaban.Kenkre@Sun.COM int linelen = *linelenp, newlinelen; 758040SBaban.Kenkre@Sun.COM 768040SBaban.Kenkre@Sun.COM linep = *linepp; 778040SBaban.Kenkre@Sun.COM limit = linep + linelen; 788040SBaban.Kenkre@Sun.COM 798040SBaban.Kenkre@Sun.COM /* +/- entries valid for compat source only */ 808040SBaban.Kenkre@Sun.COM if (linelen == 0 || *linep == '+' || *linep == '-') 818040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS); 828040SBaban.Kenkre@Sun.COM 838040SBaban.Kenkre@Sun.COM while (linep < limit && *linep++ != ':') /* skip groupname */ 848040SBaban.Kenkre@Sun.COM continue; 858040SBaban.Kenkre@Sun.COM while (linep < limit && *linep++ != ':') /* skip password */ 868040SBaban.Kenkre@Sun.COM continue; 878040SBaban.Kenkre@Sun.COM if (linep == limit) 888040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_PARSE); 898040SBaban.Kenkre@Sun.COM 908040SBaban.Kenkre@Sun.COM gidp = linep; 918040SBaban.Kenkre@Sun.COM gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */ 928040SBaban.Kenkre@Sun.COM oldgidlen = linep - gidp; 938040SBaban.Kenkre@Sun.COM if (linep >= limit || oldgidlen == 0) 948040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_PARSE); 958040SBaban.Kenkre@Sun.COM 968040SBaban.Kenkre@Sun.COM if (gid <= MAXUID) 978040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS); 988040SBaban.Kenkre@Sun.COM 998040SBaban.Kenkre@Sun.COM idlen = snprintf(NULL, 0, "%u", GID_NOBODY); 1008040SBaban.Kenkre@Sun.COM newlinelen = linelen + idlen - oldgidlen; 1018040SBaban.Kenkre@Sun.COM if (newlinelen > linelen) { 1028040SBaban.Kenkre@Sun.COM /* need a larger buffer */ 1038040SBaban.Kenkre@Sun.COM if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL) 1048040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_ERANGE); 1058040SBaban.Kenkre@Sun.COM /* Replace ephemeral ids by ID_NOBODY in the new buffer */ 1068040SBaban.Kenkre@Sun.COM *(gidp - 1) = '\0'; 1078040SBaban.Kenkre@Sun.COM (void) snprintf(newline, newlinelen + 1, "%s:%u%s", 1088040SBaban.Kenkre@Sun.COM *linepp, GID_NOBODY, linep); 1098040SBaban.Kenkre@Sun.COM free(*linepp); 1108040SBaban.Kenkre@Sun.COM *linepp = newline; 1118040SBaban.Kenkre@Sun.COM *linelenp = newlinelen; 1128040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS); 1138040SBaban.Kenkre@Sun.COM } 1148040SBaban.Kenkre@Sun.COM 1158040SBaban.Kenkre@Sun.COM /* Replace ephemeral gid by GID_NOBODY in the same buffer */ 1168040SBaban.Kenkre@Sun.COM (void) bcopy(linep, gidp + idlen, limit - linep + 1); 1178040SBaban.Kenkre@Sun.COM (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY); 1188040SBaban.Kenkre@Sun.COM *(gidp + idlen) = ':'; 1198040SBaban.Kenkre@Sun.COM *linelenp = newlinelen; 1208040SBaban.Kenkre@Sun.COM return (NSS_STR_PARSE_SUCCESS); 1218040SBaban.Kenkre@Sun.COM } 1228040SBaban.Kenkre@Sun.COM 1230Sstevel@tonic-gate static nss_status_t 1240Sstevel@tonic-gate getbymember(be, a) 1250Sstevel@tonic-gate nis_backend_ptr_t be; 1260Sstevel@tonic-gate void *a; 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if (strcmp(argp->username, "root") == 0) { 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * Assume that "root" can only sensibly be in /etc/group, 133*11262SRajagopal.Andra@Sun.COM * not in NIS 1340Sstevel@tonic-gate * If we don't do this, a hung name-service may cause 1350Sstevel@tonic-gate * a root login or su to hang. 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate return (NSS_NOTFOUND); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate if (argp->force_slow_way != 1) { 1410Sstevel@tonic-gate switch (netid_lookup(argp)) { 1420Sstevel@tonic-gate case NSS_SUCCESS: 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * Return SUCESS only if array is full. Explained 1450Sstevel@tonic-gate * in <nss_dbdefs.h>. 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate return ((argp->numgids == argp->maxgids) 1480Sstevel@tonic-gate ? NSS_SUCCESS 1490Sstevel@tonic-gate : NSS_NOTFOUND); 1500Sstevel@tonic-gate case NSS_NOTFOUND: 1510Sstevel@tonic-gate case NSS_UNAVAIL: 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * Failover to group map search if no luck with netid. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate break; 1560Sstevel@tonic-gate case NSS_TRYAGAIN: 1570Sstevel@tonic-gate return (NSS_TRYAGAIN); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate return (_nss_nis_do_all(be, argp, argp->username, 1620Sstevel@tonic-gate (nis_do_all_func_t)argp->process_cstr)); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static nis_backend_op_t group_ops[] = { 1660Sstevel@tonic-gate _nss_nis_destr, 1670Sstevel@tonic-gate _nss_nis_endent, 1680Sstevel@tonic-gate _nss_nis_setent, 1690Sstevel@tonic-gate _nss_nis_getent_rigid, 1700Sstevel@tonic-gate getbyname, 1710Sstevel@tonic-gate getbygid, 1720Sstevel@tonic-gate getbymember 1730Sstevel@tonic-gate }; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /*ARGSUSED*/ 1760Sstevel@tonic-gate nss_backend_t * 1770Sstevel@tonic-gate _nss_nis_group_constr(dummy1, dummy2, dummy3) 1780Sstevel@tonic-gate const char *dummy1, *dummy2, *dummy3; 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate return (_nss_nis_constr(group_ops, 1810Sstevel@tonic-gate sizeof (group_ops) / sizeof (group_ops[0]), 1820Sstevel@tonic-gate "group.byname")); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Add gid to gid_array if it's not already there. gid_array must have room 1870Sstevel@tonic-gate * for one more entry. Return new size of array. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate static int 1900Sstevel@tonic-gate add_gid(gid_t gid_array[], int numgids, gid_t gid) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate int i = 0; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate for (i = 0; i < numgids; i++) { 1950Sstevel@tonic-gate if (gid_array[i] == gid) { 1960Sstevel@tonic-gate return (numgids); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate gid_array[numgids++] = gid; 2000Sstevel@tonic-gate return (numgids); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * Given buf, a null-terminated string containing the result of a successful 2050Sstevel@tonic-gate * netid lookup, add the gids to the gid_array. The string may contain extra 2060Sstevel@tonic-gate * whitesapce. On parse error, the valid portion of the gid_array is not 2070Sstevel@tonic-gate * modified. 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate static int 2100Sstevel@tonic-gate parse_netid(const char *buf, gid_t gid_array[], int maxgids, int *numgids_ptr) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate int numgids = *numgids_ptr; 2130Sstevel@tonic-gate char *buf_next; 2140Sstevel@tonic-gate gid_t gid; 2150Sstevel@tonic-gate long value; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* Scan past "<uid>:" */ 2180Sstevel@tonic-gate while (isspace(*buf) || isdigit(*buf)) { 2190Sstevel@tonic-gate buf++; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if (*buf++ != ':') { 2230Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* buf should now point to a comma-separated list of gids */ 2270Sstevel@tonic-gate while (*buf != '\0' && *buf != '\n') { 2280Sstevel@tonic-gate errno = 0; 2290Sstevel@tonic-gate value = strtol(buf, &buf_next, 10); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (buf == buf_next) { 2320Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 2330Sstevel@tonic-gate } else if ((value == LONG_MAX && errno == ERANGE) || 2340Sstevel@tonic-gate (ulong_t)value > INT_MAX) { 2350Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate gid = (gid_t)value; 2390Sstevel@tonic-gate if (numgids < maxgids) { 2400Sstevel@tonic-gate numgids = add_gid(gid_array, numgids, gid); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate buf = buf_next; 2430Sstevel@tonic-gate if (*buf == ',') { 2440Sstevel@tonic-gate buf++; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate *numgids_ptr = numgids; 2480Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Perform a lookup in the netid map. Fill in the gid_array if successful. 2540Sstevel@tonic-gate * Return values are like those for _nss_nis_lookup(). 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate static nss_status_t 2570Sstevel@tonic-gate netid_lookup(struct nss_groupsbymem *argp) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate const char *domain = _nss_nis_domain(); 2600Sstevel@tonic-gate struct passwd pw; 2610Sstevel@tonic-gate char pwbuf[NSS_BUFLEN_PASSWD]; 2620Sstevel@tonic-gate char netname[MAXNETNAMELEN + 1]; 2630Sstevel@tonic-gate nss_status_t res; 2640Sstevel@tonic-gate char *val; 2650Sstevel@tonic-gate int vallen; 2660Sstevel@tonic-gate int parse_res; 2670Sstevel@tonic-gate char *lasts; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * Need to build up the netname for the user manually. Can't use 2710Sstevel@tonic-gate * user2netname() rpc library call, since that does all sorts of 2720Sstevel@tonic-gate * extra stuff based upon its own private name-service switch. 2730Sstevel@tonic-gate * 2740Sstevel@tonic-gate * Note that "root" has no user netname so return in error. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate if ((getpwnam_r(argp->username, &pw, pwbuf, sizeof (pwbuf)) == NULL) || 2770Sstevel@tonic-gate (pw.pw_uid == 0)) { 2780Sstevel@tonic-gate return (NSS_UNAVAIL); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate if (snprintf(netname, MAXNETNAMELEN + 1, "unix.%d@%s", 2810Sstevel@tonic-gate pw.pw_uid, domain) < 0) { 2820Sstevel@tonic-gate return (NSS_UNAVAIL); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate if ((res = _nss_nis_ypmatch(domain, "netid.byname", netname, 2868040SBaban.Kenkre@Sun.COM &val, &vallen, 0)) != NSS_SUCCESS) { 2870Sstevel@tonic-gate return (res); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2902830Sdjl (void) strtok_r(val, "#", &lasts); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate parse_res = parse_netid(val, argp->gid_array, argp->maxgids, 2938040SBaban.Kenkre@Sun.COM &argp->numgids); 2940Sstevel@tonic-gate free(val); 2950Sstevel@tonic-gate return ((parse_res == NSS_STR_PARSE_SUCCESS) 2968040SBaban.Kenkre@Sun.COM ? NSS_SUCCESS : NSS_NOTFOUND); 2970Sstevel@tonic-gate } 298