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 *
bootparamproc_whoami_1(bp_whoami_arg * argp,CLIENT * cl)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 *
bootparamproc_getfile_1(bp_getfile_arg * argp,CLIENT * cl)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
getf_printres(bp_getfile_res * res)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
copydomain(char * source,char * target,int len)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