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