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 1999-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Subroutines that implement the bootparam services. 31 */ 32 33 #include <rpcsvc/bootparam_prot.h> 34 #include <netdb.h> 35 #include <nlist.h> 36 #include <stdio.h> 37 #include <ctype.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <nsswitch.h> 41 #include <sys/types.h> 42 #include <sys/file.h> 43 #include <sys/socket.h> 44 #define KERNEL /* to get RTHASHSIZ */ 45 #include <sys/stream.h> 46 #include <net/route.h> 47 #undef KERNEL 48 #include <net/if.h> /* for structs ifnet and ifaddr */ 49 #include <netinet/in.h> 50 #include <netinet/in_var.h> /* for struct in_ifaddr */ 51 #include <arpa/inet.h> 52 53 #include "bootparam_private.h" 54 55 #define LINESIZE 1024 56 57 extern int getdomainname(char *, int); 58 extern int bootparams_getbyname(char *, char *, int); 59 60 static char *wildcard = "*"; 61 static char domainkey[] = "domain="; 62 static void getf_printres(bp_getfile_res *); 63 static void copydomain(char *, char *, int); 64 65 /* 66 * Whoami turns a client address into a client name 67 * and suggested route machine. 68 */ 69 /*ARGSUSED1*/ 70 bp_whoami_res * 71 bootparamproc_whoami_1(bp_whoami_arg *argp, CLIENT *cl) 72 { 73 static bp_whoami_res res; 74 struct in_addr clnt_addr; 75 struct in_addr route_addr; 76 struct hostent *hp; 77 static char clnt_entry[LINESIZE]; 78 static char domain[MAX_MACHINE_NAME]; 79 char *cp; 80 81 if (argp->client_address.address_type != IP_ADDR_TYPE) { 82 if (debug) { 83 msgout("Whoami failed: unknown address type %d", 84 argp->client_address.address_type); 85 } 86 return (NULL); 87 } 88 (void) memcpy(&clnt_addr, &argp->client_address.bp_address_u.ip_addr, 89 sizeof (clnt_addr)); 90 hp = gethostbyaddr((char *)&clnt_addr, sizeof (clnt_addr), AF_INET); 91 if (hp == NULL) { 92 if (debug) { 93 msgout("Whoami failed: gethostbyaddr for %s.", 94 inet_ntoa(clnt_addr)); 95 } 96 return (NULL); 97 } 98 99 /* 100 * We only answer requests from clients listed in the database. 101 */ 102 if ((bootparams_getbyname(hp->h_name, clnt_entry, 103 sizeof (clnt_entry)) != __NSW_SUCCESS) && 104 (bootparams_getbyname(wildcard, clnt_entry, 105 sizeof (clnt_entry)) != __NSW_SUCCESS)) 106 return (NULL); 107 108 res.client_name = hp->h_name; 109 110 /* 111 * The algorithm for determining the client's domain name is: 112 * 1) look for "domain=" in the client's bootparams line. 113 * If found, use its value. 114 * 2) look for a "domain=" entry in the wildcard bootparams 115 * line (if any). If found, use its value. Otherwise, 116 * 3) return the domain name of the server answering the 117 * request. 118 */ 119 if (cp = strstr(clnt_entry, domainkey)) { 120 copydomain(cp + sizeof (domainkey) - 1, domain, 121 sizeof (domain)); 122 } else { 123 /* "domain=" not found - try for wildcard */ 124 if ((bootparams_getbyname(wildcard, clnt_entry, 125 sizeof (clnt_entry)) == __NSW_SUCCESS) && 126 (cp = strstr(clnt_entry, domainkey))) { 127 copydomain(cp + sizeof (domainkey) - 1, domain, 128 sizeof (domain)); 129 } else { 130 (void) getdomainname(domain, sizeof (domain)); 131 } 132 } 133 res.domain_name = domain; 134 135 res.router_address.address_type = IP_ADDR_TYPE; 136 route_addr.s_addr = get_ip_route(clnt_addr); 137 (void) memcpy(&res.router_address.bp_address_u.ip_addr, 138 &route_addr, 139 sizeof (res.router_address.bp_address_u.ip_addr)); 140 141 if (debug) { 142 struct in_addr in; 143 144 (void) memcpy(&in.s_addr, 145 &res.router_address.bp_address_u.ip_addr, 146 sizeof (in.s_addr)); 147 msgout("Whoami returning name = %s, router address = %s", 148 res.client_name, 149 inet_ntoa(in)); 150 } 151 return (&res); 152 } 153 154 /* 155 * Getfile gets the client name and the key and returns its server 156 * and the pathname for that key. 157 */ 158 /*ARGSUSED1*/ 159 bp_getfile_res * 160 bootparamproc_getfile_1(bp_getfile_arg *argp, CLIENT *cl) 161 { 162 static bp_getfile_res res; 163 static char clnt_entry[LINESIZE]; 164 struct hostent *hp; 165 char *cp; 166 char filekey[LINESIZE]; 167 char *server_hostname; 168 char *path_on_server; 169 int do_wildcard = 0; 170 static char *zero_len_string = ""; 171 172 /* 173 * The bootparams_getbyname() library function looks up a 174 * "client entry" using using the client's hostname as the 175 * key. A client entry consists of a string of "file entries" 176 * separated by white space. Each file entry is of the form: 177 * 178 * file_key=server_hostname:path_on_server 179 * 180 * In the getfile RPC call, the client gives us his hostname 181 * and a file_key. We lookup his client entry, then locate a 182 * file entry matching that file_key. We then parse out the 183 * server_hostname and path_on_server from the file entry, map 184 * the server_hostname to an IP address, and return both the 185 * IP address and path_on_server back to the client. 186 */ 187 188 /* make the client's file key int a string we can use for matching */ 189 (void) strncpy(filekey, argp->file_id, sizeof (filekey) - 2); 190 filekey[sizeof (filekey) - 2] = '\0'; 191 (void) strcat(filekey, "="); 192 193 if (bootparams_getbyname(argp->client_name, clnt_entry, 194 sizeof (clnt_entry)) == __NSW_SUCCESS) { 195 /* locate the file_key in the client's entry */ 196 cp = strstr(clnt_entry, filekey); 197 if (cp == NULL) 198 do_wildcard++; 199 200 } else 201 do_wildcard++; 202 203 if (do_wildcard) { 204 if (bootparams_getbyname(wildcard, clnt_entry, 205 sizeof (clnt_entry)) != __NSW_SUCCESS) 206 return (NULL); 207 208 /* locate the file_key in the client's entry */ 209 cp = strstr(clnt_entry, filekey); 210 if (cp == NULL) 211 return (NULL); 212 } 213 214 /* locate the "data" part of file entry (r.h.s. of "=") */ 215 cp = strchr(cp, '='); 216 if (cp == NULL) 217 return (NULL); 218 cp++; 219 if (*cp == '\0') 220 return (NULL); 221 server_hostname = cp; 222 223 /* null-terminate server_hostname and parse path_on_server */ 224 cp = strchr(server_hostname, ':'); 225 if (cp == NULL) 226 return (NULL); 227 *cp = '\0'; 228 cp++; 229 /* strtok() will null-terminate path_on_server */ 230 path_on_server = strtok(cp, "\t\n "); 231 if (path_on_server == NULL) 232 path_on_server = zero_len_string; 233 234 res.server_name = server_hostname; 235 res.server_path = path_on_server; 236 if (*res.server_name == 0) { 237 res.server_address.address_type = IP_ADDR_TYPE; 238 (void) memset(&res.server_address.bp_address_u.ip_addr, 0, 239 sizeof (res.server_address.bp_address_u.ip_addr)); 240 } else { 241 in_addr_t addr; 242 243 if ((hp = gethostbyname(server_hostname)) != NULL) { 244 addr = find_best_server_int(hp->h_addr_list, 245 argp->client_name); 246 } else { 247 addr = inet_addr(server_hostname); 248 if (addr == INADDR_BROADCAST) { 249 if (debug) { 250 msgout("getfile_1: gethostbyname(%s) " 251 "failed", res.server_name); 252 } 253 return (NULL); 254 } 255 } 256 res.server_address.address_type = IP_ADDR_TYPE; 257 (void) memcpy(&res.server_address.bp_address_u.ip_addr, 258 &addr, sizeof (res.server_address.bp_address_u.ip_addr)); 259 } 260 if (debug) { 261 getf_printres(&res); 262 } 263 return (&res); 264 } 265 266 void 267 getf_printres(bp_getfile_res *res) 268 { 269 struct in_addr in; 270 271 (void) memcpy(&in.s_addr, &res->server_address.bp_address_u.ip_addr, 272 sizeof (in.s_addr)); 273 msgout("getfile_1: file is \"%s\" %s \"%s\"", 274 res->server_name, 275 inet_ntoa(in), 276 res->server_path); 277 } 278 279 /* 280 * Used when we've found a "domain=" key, this function copies characters 281 * from source to target until we come upon either a NULL or whitespace is 282 * found in the source string, or we run out of room in the target. 283 * 284 */ 285 void 286 copydomain(char *source, char *target, int len) 287 { 288 int n; /* number of characters copies */; 289 290 len--; /* leave room for terminating '\0' */ 291 if (source) 292 for (n = 0; *source != '\0' && n < len; n++) 293 if (isspace((int)*source)) 294 break; 295 else 296 *target++ = *source++; 297 298 *target = '\0'; 299 } 300