1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* 28*0Sstevel@tonic-gate * nis/getgrent.c -- "nis" backend for nsswitch "group" database 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <grp.h> 34*0Sstevel@tonic-gate #include <pwd.h> 35*0Sstevel@tonic-gate #include "nis_common.h" 36*0Sstevel@tonic-gate #include <ctype.h> 37*0Sstevel@tonic-gate #include <stdlib.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate #include <rpc/auth.h> /* for MAXNETNAMELEN */ 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate static nss_status_t netid_lookup(struct nss_groupsbymem *argp); 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate static nss_status_t 44*0Sstevel@tonic-gate getbyname(be, a) 45*0Sstevel@tonic-gate nis_backend_ptr_t be; 46*0Sstevel@tonic-gate void *a; 47*0Sstevel@tonic-gate { 48*0Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate return (_nss_nis_lookup(be, argp, 0, 51*0Sstevel@tonic-gate "group.byname", argp->key.name, 0)); 52*0Sstevel@tonic-gate } 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static nss_status_t 55*0Sstevel@tonic-gate getbygid(be, a) 56*0Sstevel@tonic-gate nis_backend_ptr_t be; 57*0Sstevel@tonic-gate void *a; 58*0Sstevel@tonic-gate { 59*0Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 60*0Sstevel@tonic-gate char gidstr[12]; /* More than enough */ 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate sprintf(gidstr, "%d", argp->key.gid); 63*0Sstevel@tonic-gate return (_nss_nis_lookup(be, argp, 0, "group.bygid", gidstr, 0)); 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate static nss_status_t 67*0Sstevel@tonic-gate getbymember(be, a) 68*0Sstevel@tonic-gate nis_backend_ptr_t be; 69*0Sstevel@tonic-gate void *a; 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate if (strcmp(argp->username, "root") == 0) { 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * Assume that "root" can only sensibly be in /etc/group, 76*0Sstevel@tonic-gate * not in NIS or NIS+ 77*0Sstevel@tonic-gate * If we don't do this, a hung name-service may cause 78*0Sstevel@tonic-gate * a root login or su to hang. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate return (NSS_NOTFOUND); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate if (argp->force_slow_way != 1) { 84*0Sstevel@tonic-gate switch (netid_lookup(argp)) { 85*0Sstevel@tonic-gate case NSS_SUCCESS: 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * Return SUCESS only if array is full. Explained 88*0Sstevel@tonic-gate * in <nss_dbdefs.h>. 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate return ((argp->numgids == argp->maxgids) 91*0Sstevel@tonic-gate ? NSS_SUCCESS 92*0Sstevel@tonic-gate : NSS_NOTFOUND); 93*0Sstevel@tonic-gate case NSS_NOTFOUND: 94*0Sstevel@tonic-gate case NSS_UNAVAIL: 95*0Sstevel@tonic-gate /* 96*0Sstevel@tonic-gate * Failover to group map search if no luck with netid. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate break; 99*0Sstevel@tonic-gate case NSS_TRYAGAIN: 100*0Sstevel@tonic-gate return (NSS_TRYAGAIN); 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate return (_nss_nis_do_all(be, argp, argp->username, 105*0Sstevel@tonic-gate (nis_do_all_func_t)argp->process_cstr)); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static nis_backend_op_t group_ops[] = { 109*0Sstevel@tonic-gate _nss_nis_destr, 110*0Sstevel@tonic-gate _nss_nis_endent, 111*0Sstevel@tonic-gate _nss_nis_setent, 112*0Sstevel@tonic-gate _nss_nis_getent_rigid, 113*0Sstevel@tonic-gate getbyname, 114*0Sstevel@tonic-gate getbygid, 115*0Sstevel@tonic-gate getbymember 116*0Sstevel@tonic-gate }; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /*ARGSUSED*/ 119*0Sstevel@tonic-gate nss_backend_t * 120*0Sstevel@tonic-gate _nss_nis_group_constr(dummy1, dummy2, dummy3) 121*0Sstevel@tonic-gate const char *dummy1, *dummy2, *dummy3; 122*0Sstevel@tonic-gate { 123*0Sstevel@tonic-gate return (_nss_nis_constr(group_ops, 124*0Sstevel@tonic-gate sizeof (group_ops) / sizeof (group_ops[0]), 125*0Sstevel@tonic-gate "group.byname")); 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * Add gid to gid_array if it's not already there. gid_array must have room 130*0Sstevel@tonic-gate * for one more entry. Return new size of array. 131*0Sstevel@tonic-gate */ 132*0Sstevel@tonic-gate static int 133*0Sstevel@tonic-gate add_gid(gid_t gid_array[], int numgids, gid_t gid) 134*0Sstevel@tonic-gate { 135*0Sstevel@tonic-gate int i = 0; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate for (i = 0; i < numgids; i++) { 138*0Sstevel@tonic-gate if (gid_array[i] == gid) { 139*0Sstevel@tonic-gate return (numgids); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate gid_array[numgids++] = gid; 143*0Sstevel@tonic-gate return (numgids); 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Given buf, a null-terminated string containing the result of a successful 148*0Sstevel@tonic-gate * netid lookup, add the gids to the gid_array. The string may contain extra 149*0Sstevel@tonic-gate * whitesapce. On parse error, the valid portion of the gid_array is not 150*0Sstevel@tonic-gate * modified. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate static int 153*0Sstevel@tonic-gate parse_netid(const char *buf, gid_t gid_array[], int maxgids, int *numgids_ptr) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate int numgids = *numgids_ptr; 156*0Sstevel@tonic-gate char *buf_next; 157*0Sstevel@tonic-gate int buflen = strlen(buf); 158*0Sstevel@tonic-gate gid_t gid; 159*0Sstevel@tonic-gate long value; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* Scan past "<uid>:" */ 162*0Sstevel@tonic-gate while (isspace(*buf) || isdigit(*buf)) { 163*0Sstevel@tonic-gate buf++; 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if (*buf++ != ':') { 167*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* buf should now point to a comma-separated list of gids */ 171*0Sstevel@tonic-gate while (*buf != '\0' && *buf != '\n') { 172*0Sstevel@tonic-gate errno = 0; 173*0Sstevel@tonic-gate value = strtol(buf, &buf_next, 10); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if (buf == buf_next) { 176*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 177*0Sstevel@tonic-gate } else if ((value == LONG_MAX && errno == ERANGE) || 178*0Sstevel@tonic-gate (ulong_t)value > INT_MAX) { 179*0Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate gid = (gid_t)value; 183*0Sstevel@tonic-gate if (numgids < maxgids) { 184*0Sstevel@tonic-gate numgids = add_gid(gid_array, numgids, gid); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate buf = buf_next; 187*0Sstevel@tonic-gate if (*buf == ',') { 188*0Sstevel@tonic-gate buf++; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate *numgids_ptr = numgids; 192*0Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * Perform a lookup in the netid map. Fill in the gid_array if successful. 198*0Sstevel@tonic-gate * Return values are like those for _nss_nis_lookup(). 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate static nss_status_t 201*0Sstevel@tonic-gate netid_lookup(struct nss_groupsbymem *argp) 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate const char *domain = _nss_nis_domain(); 204*0Sstevel@tonic-gate struct passwd pw; 205*0Sstevel@tonic-gate char pwbuf[NSS_BUFLEN_PASSWD]; 206*0Sstevel@tonic-gate char netname[MAXNETNAMELEN + 1]; 207*0Sstevel@tonic-gate nss_status_t res; 208*0Sstevel@tonic-gate char *val; 209*0Sstevel@tonic-gate int vallen; 210*0Sstevel@tonic-gate char *comment; 211*0Sstevel@tonic-gate int parse_res; 212*0Sstevel@tonic-gate char *lasts; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * Need to build up the netname for the user manually. Can't use 216*0Sstevel@tonic-gate * user2netname() rpc library call, since that does all sorts of 217*0Sstevel@tonic-gate * extra stuff based upon its own private name-service switch. 218*0Sstevel@tonic-gate * 219*0Sstevel@tonic-gate * Note that "root" has no user netname so return in error. 220*0Sstevel@tonic-gate */ 221*0Sstevel@tonic-gate if ((getpwnam_r(argp->username, &pw, pwbuf, sizeof (pwbuf)) == NULL) || 222*0Sstevel@tonic-gate (pw.pw_uid == 0)) { 223*0Sstevel@tonic-gate return (NSS_UNAVAIL); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate if (snprintf(netname, MAXNETNAMELEN + 1, "unix.%d@%s", 226*0Sstevel@tonic-gate pw.pw_uid, domain) < 0) { 227*0Sstevel@tonic-gate return (NSS_UNAVAIL); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if ((res = _nss_nis_ypmatch(domain, "netid.byname", netname, 231*0Sstevel@tonic-gate &val, &vallen, 0)) != NSS_SUCCESS) { 232*0Sstevel@tonic-gate return (res); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate strtok_r(val, "#", &lasts); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate parse_res = parse_netid(val, argp->gid_array, argp->maxgids, 238*0Sstevel@tonic-gate &argp->numgids); 239*0Sstevel@tonic-gate free(val); 240*0Sstevel@tonic-gate return ((parse_res == NSS_STR_PARSE_SUCCESS) 241*0Sstevel@tonic-gate ? NSS_SUCCESS 242*0Sstevel@tonic-gate : NSS_NOTFOUND); 243*0Sstevel@tonic-gate } 244