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