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