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) 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, const uid_t uid, const char *domain) 178 { 179 struct __nsw_switchconfig *conf; 180 struct __nsw_lookup *look; 181 int needfree = 1, res = 0; 182 enum __nsw_parse_err perr; 183 int err; 184 185 /* 186 * Take care of the special case of "nobody". If the uid is 187 * the value assigned by the SVID for nobody, return the string 188 * "nobody". 189 */ 190 191 if (uid == NOBODY_UID) { 192 (void) strlcpy(netname, "nobody", MAXNETNAMELEN + 1); 193 return (1); 194 } 195 196 netname[0] = '\0'; /* make null first (no need for memset) */ 197 198 if (mutex_lock(&serialize_netname) == EDEADLK) { 199 /* 200 * This thread already holds this lock. This scenario 201 * occurs when a process requires a netname which 202 * itself requires a netname to look up. As we clearly 203 * can't continue like this we return 'nobody'. 204 */ 205 (void) strlcpy(netname, "nobody", MAXNETNAMELEN + 1); 206 return (1); 207 } 208 209 conf = __nsw_getconfig("publickey", &perr); 210 if (!conf) { 211 conf = &publickey_default; 212 needfree = 0; 213 } 214 215 for (look = conf->lookups; look; look = look->next) { 216 /* ldap, nis, and files all do the same thing. */ 217 if (strcmp(look->service_name, "ldap") == 0 || 218 strcmp(look->service_name, "nis") == 0 || 219 strcmp(look->service_name, "files") == 0) 220 res = user2netname_nis(&err, 221 netname, uid, (char *)domain); 222 else { 223 syslog(LOG_INFO, 224 "user2netname: unknown nameservice \ 225 for publickey info '%s'\n", 226 look->service_name); 227 err = __NSW_UNAVAIL; 228 } 229 switch (look->actions[err]) { 230 case __NSW_CONTINUE : 231 break; 232 case __NSW_RETURN : 233 if (needfree) 234 (void) __nsw_freeconfig(conf); 235 (void) mutex_unlock(&serialize_netname); 236 return (res); 237 default : 238 syslog(LOG_ERR, 239 "user2netname: Unknown action for nameservice '%s'", 240 look->service_name); 241 } 242 } 243 if (needfree) 244 (void) __nsw_freeconfig(conf); 245 (void) mutex_unlock(&serialize_netname); 246 return (0); 247 } 248 249 250 /* 251 * Convert host to network-name 252 * This routine returns following netnames given the host and domain 253 * arguments defined below: (domainname=y.z) 254 * Arguments 255 * host domain netname 256 * ---- ------ ------- 257 * - - unix.m@y.z (hostname=m) 258 * - a.b unix.m@a.b (hostname=m) 259 * - - unix.m@y.z (hostname=m.w.x) 260 * - a.b unix.m@a.b (hostname=m.w.x) 261 * h - unix.h@y.z 262 * h a.b unix.h@a.b 263 * h.w.x - unix.h@w.x 264 * h.w.x a.b unix.h@a.b 265 */ 266 int 267 host2netname(char *netname, const char *host, const char *domain) 268 { 269 char *p; 270 char hostname[MAXHOSTNAMELEN + 1]; 271 char domainname[MAXHOSTNAMELEN + 1]; 272 char *dot_in_host; 273 int i; 274 size_t len; 275 276 netname[0] = '\0'; /* make null first (no need for memset) */ 277 278 if (host == NULL) { 279 (void) strncpy(hostname, nis_local_host(), sizeof (hostname)); 280 p = (char *)strchr(hostname, '.'); 281 if (p) { 282 *p++ = '\0'; 283 /* if no domain passed, use tail of nis_local_host() */ 284 if (domain == NULL) { 285 domain = p; 286 } 287 } 288 } else { 289 len = strlen(host); 290 if (len >= sizeof (hostname)) { 291 return (0); 292 } 293 (void) strcpy(hostname, host); 294 } 295 296 dot_in_host = (char *)strchr(hostname, '.'); 297 if (domain == NULL) { 298 p = dot_in_host; 299 if (p) { 300 p = (char *)nis_domain_of(hostname); 301 len = strlen(p); 302 if (len >= sizeof (domainname)) { 303 return (0); 304 } 305 (void) strcpy(domainname, p); 306 } else { 307 domainname[0] = '\0'; 308 if (getdomainname(domainname, MAXHOSTNAMELEN) < 0) 309 return (0); 310 } 311 } else { 312 len = strlen(domain); 313 if (len >= sizeof (domainname)) { 314 return (0); 315 } 316 (void) strcpy(domainname, domain); 317 } 318 319 i = strlen(domainname); 320 if (i == 0) 321 /* No domainname */ 322 return (0); 323 if (domainname[i - 1] == '.') 324 domainname[i - 1] = 0; 325 326 if (dot_in_host) { /* strip off rest of name */ 327 *dot_in_host = '\0'; 328 } 329 330 if ((strlen(domainname) + strlen(hostname) + OPSYS_LEN + 3) 331 > (size_t)MAXNETNAMELEN) { 332 return (0); 333 } 334 335 (void) snprintf(netname, MAXNETNAMELEN + 1, 336 "%s.%s@%s", OPSYS, hostname, domainname); 337 return (1); 338 } 339