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