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