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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 /* 29 * Portions of this source code were derived from Berkeley 30 * 4.3 BSD under license from the Regents of the University of 31 * California. 32 */ 33 /* 34 * ==== hack-attack: possibly MT-safe but definitely not MT-hot. 35 * ==== turn this into a real switch frontend and backends 36 * 37 * Well, at least the API doesn't involve pointers-to-static. 38 */ 39 40 41 /* 42 * netname utility routines (getnetname, user2netname, host2netname). 43 * 44 * Convert from unix names (uid, gid) to network wide names. 45 * This module is operating system dependent! 46 * What we define here will work with any unix system that has adopted 47 * the Sun NIS domain architecture. 48 */ 49 50 #undef NIS 51 52 #include "mt.h" 53 #include "rpc_mt.h" 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 #include <sys/types.h> 58 #include <ctype.h> 59 #include <string.h> 60 #include <syslog.h> 61 #include <sys/param.h> 62 #include <rpc/rpc.h> 63 #include <rpcsvc/nis.h> 64 #include <rpcsvc/nis_dhext.h> 65 #include <nsswitch.h> 66 #include <syslog.h> 67 #include <errno.h> 68 69 #ifndef MAXHOSTNAMELEN 70 #define MAXHOSTNAMELEN 256 71 #endif 72 #ifndef NGROUPS 73 #define NGROUPS 16 74 #endif 75 76 /* 77 * the value for NOBODY_UID is set by the SVID. The following define also 78 * appears in netnamer.c 79 */ 80 81 #define NOBODY_UID 60001 82 83 extern int getdomainname(); 84 extern int key_call(); 85 #define OPSYS_LEN 4 86 static const char *OPSYS = "unix"; 87 88 /* 89 * default publickey policy: 90 * publickey: nis [NOTFOUND = return] files 91 */ 92 93 94 /* NSW_NOTSUCCESS NSW_NOTFOUND NSW_UNAVAIL NSW_TRYAGAIN */ 95 #define DEF_ACTION {__NSW_RETURN, __NSW_RETURN, __NSW_CONTINUE, __NSW_CONTINUE} 96 97 static struct __nsw_lookup lookup_files = {"files", DEF_ACTION, NULL, NULL}, 98 lookup_nis = {"nis", DEF_ACTION, NULL, &lookup_files}; 99 static struct __nsw_switchconfig publickey_default = 100 {0, "publickey", 2, &lookup_nis}; 101 102 static mutex_t serialize_netname = ERRORCHECKMUTEX; 103 104 105 #define MAXIPRINT (11) /* max length of printed integer */ 106 107 /* 108 * Convert unix cred to network-name by concatenating the 109 * 3 pieces of information <opsys type> <uid> <domain>. 110 */ 111 112 static int 113 user2netname_nis(int *err, char netname[MAXNETNAMELEN + 1], uid_t uid, 114 char *domain) 115 { 116 int i; 117 char *dfltdom; 118 if (domain == NULL) { 119 if (__rpc_get_default_domain(&dfltdom) != 0) { 120 *err = __NSW_UNAVAIL; 121 return (0); 122 } 123 domain = dfltdom; 124 } 125 if ((strlen(domain) + OPSYS_LEN + 3 + MAXIPRINT) > 126 (size_t)MAXNETNAMELEN) { 127 *err = __NSW_UNAVAIL; 128 return (0); 129 } 130 (void) snprintf(netname, MAXNETNAMELEN + 1, 131 "%s.%d@%s", OPSYS, (int)uid, domain); 132 i = strlen(netname); 133 if (netname[i-1] == '.') 134 netname[i-1] = '\0'; 135 *err = __NSW_SUCCESS; 136 return (1); 137 } 138 139 /* 140 * Figure out my fully qualified network name 141 */ 142 int 143 getnetname(char name[MAXNETNAMELEN + 1]) 144 { 145 uid_t uid; 146 147 uid = geteuid(); 148 if (uid == 0) 149 return (host2netname(name, NULL, NULL)); 150 return (user2netname(name, uid, NULL)); 151 } 152 153 154 /* 155 * Figure out the fully qualified network name for the given uid. 156 * This is a private interface. 157 */ 158 int 159 __getnetnamebyuid(char name[MAXNETNAMELEN + 1], uid_t uid) 160 { 161 if (uid == 0) 162 return (host2netname(name, NULL, NULL)); 163 return (user2netname(name, uid, NULL)); 164 } 165 166 /* 167 * Convert unix cred to network-name 168 * 169 * It uses the publickey policy in the /etc/nsswitch.conf file 170 * (Unless the netname is "nobody", which is special cased). 171 * If there is no publickey policy in /etc/nsswitch.conf, 172 * the default publickey policy is used, which is 173 * publickey: nis [NOTFOUND=return] files 174 * Note that for the non-nisplus case, there is no failover 175 * so only the first entry would be relevant for those cases. 176 */ 177 int 178 user2netname(char netname[MAXNETNAMELEN + 1], const uid_t uid, 179 const char *domain) 180 { 181 struct __nsw_switchconfig *conf; 182 struct __nsw_lookup *look; 183 int needfree = 1, res = 0; 184 enum __nsw_parse_err perr; 185 int err; 186 187 /* 188 * Take care of the special case of "nobody". If the uid is 189 * the value assigned by the SVID for nobody, return the string 190 * "nobody". 191 */ 192 193 if (uid == NOBODY_UID) { 194 (void) strlcpy(netname, "nobody", sizeof (netname)); 195 return (1); 196 } 197 198 netname[0] = '\0'; /* make null first (no need for memset) */ 199 200 if (mutex_lock(&serialize_netname) == EDEADLK) { 201 /* 202 * This thread already holds this lock. This scenario 203 * occurs when a process requires a netname which 204 * itself requires a netname to look up. As we clearly 205 * can't continue like this we return 'nobody'. 206 */ 207 (void) strlcpy(netname, "nobody", sizeof (netname)); 208 return (1); 209 } 210 211 conf = __nsw_getconfig("publickey", &perr); 212 if (!conf) { 213 conf = &publickey_default; 214 needfree = 0; 215 } 216 217 for (look = conf->lookups; look; look = look->next) { 218 /* ldap, nis, and files all do the same thing. */ 219 if (strcmp(look->service_name, "ldap") == 0 || 220 strcmp(look->service_name, "nis") == 0 || 221 strcmp(look->service_name, "files") == 0) 222 res = user2netname_nis(&err, 223 netname, uid, (char *)domain); 224 else { 225 syslog(LOG_INFO, 226 "user2netname: unknown nameservice \ 227 for publickey info '%s'\n", 228 look->service_name); 229 err = __NSW_UNAVAIL; 230 } 231 switch (look->actions[err]) { 232 case __NSW_CONTINUE : 233 break; 234 case __NSW_RETURN : 235 if (needfree) 236 __nsw_freeconfig(conf); 237 (void) mutex_unlock(&serialize_netname); 238 return (res); 239 default : 240 syslog(LOG_ERR, 241 "user2netname: Unknown action for nameservice '%s'", 242 look->service_name); 243 } 244 } 245 if (needfree) 246 __nsw_freeconfig(conf); 247 (void) mutex_unlock(&serialize_netname); 248 return (0); 249 } 250 251 252 /* 253 * Convert host to network-name 254 * This routine returns following netnames given the host and domain 255 * arguments defined below: (domainname=y.z) 256 * Arguments 257 * host domain netname 258 * ---- ------ ------- 259 * - - unix.m@y.z (hostname=m) 260 * - a.b unix.m@a.b (hostname=m) 261 * - - unix.m@y.z (hostname=m.w.x) 262 * - a.b unix.m@a.b (hostname=m.w.x) 263 * h - unix.h@y.z 264 * h a.b unix.h@a.b 265 * h.w.x - unix.h@w.x 266 * h.w.x a.b unix.h@a.b 267 */ 268 int 269 host2netname(char netname[MAXNETNAMELEN + 1], const char *host, 270 const char *domain) 271 { 272 char *p; 273 char hostname[MAXHOSTNAMELEN + 1]; 274 char domainname[MAXHOSTNAMELEN + 1]; 275 char *dot_in_host; 276 int i; 277 size_t len; 278 279 netname[0] = '\0'; /* make null first (no need for memset) */ 280 281 if (host == NULL) { 282 (void) strncpy(hostname, nis_local_host(), sizeof (hostname)); 283 p = (char *)strchr(hostname, '.'); 284 if (p) { 285 *p++ = '\0'; 286 /* if no domain passed, use tail of nis_local_host() */ 287 if (domain == NULL) { 288 domain = p; 289 } 290 } 291 } else { 292 len = strlen(host); 293 if (len >= sizeof (hostname)) { 294 return (0); 295 } 296 (void) strcpy(hostname, host); 297 } 298 299 dot_in_host = (char *)strchr(hostname, '.'); 300 if (domain == NULL) { 301 p = dot_in_host; 302 if (p) { 303 p = (char *)nis_domain_of(hostname); 304 len = strlen(p); 305 if (len >= sizeof (domainname)) { 306 return (0); 307 } 308 (void) strcpy(domainname, p); 309 } else { 310 domainname[0] = NULL; 311 if (getdomainname(domainname, MAXHOSTNAMELEN) < 0) 312 return (0); 313 } 314 } else { 315 len = strlen(domain); 316 if (len >= sizeof (domainname)) { 317 return (0); 318 } 319 (void) strcpy(domainname, domain); 320 } 321 322 i = strlen(domainname); 323 if (i == 0) 324 /* No domainname */ 325 return (0); 326 if (domainname[i - 1] == '.') 327 domainname[i - 1] = 0; 328 329 if (dot_in_host) { /* strip off rest of name */ 330 *dot_in_host = '\0'; 331 } 332 333 if ((strlen(domainname) + strlen(hostname) + OPSYS_LEN + 3) 334 > (size_t)MAXNETNAMELEN) { 335 return (0); 336 } 337 338 (void) snprintf(netname, MAXNETNAMELEN + 1, 339 "%s.%s@%s", OPSYS, hostname, domainname); 340 return (1); 341 } 342