xref: /netbsd-src/sys/lib/libsa/bootparam.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: bootparam.c,v 1.15 2003/03/19 17:18:07 drochner Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Gordon W. Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon W. Ross
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * RPC/bootparams
35  */
36 
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 
40 #include <net/if.h>
41 
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 
45 #ifdef _STANDALONE
46 #include <lib/libkern/libkern.h>
47 #else
48 #include <string.h>
49 #endif
50 
51 #include "rpcv2.h"
52 
53 #include "stand.h"
54 #include "net.h"
55 #include "rpc.h"
56 #include "bootparam.h"
57 
58 #ifdef DEBUG_RPC
59 #define RPC_PRINTF(a)	printf a
60 #else
61 #define RPC_PRINTF(a)
62 #endif
63 
64 struct in_addr	bp_server_addr;	/* net order */
65 n_short		bp_server_port;	/* net order */
66 
67 int		hostnamelen;
68 char		domainname[FNAME_SIZE]; /* our DNS domain */
69 int		domainnamelen;
70 
71 /*
72  * RPC definitions for bootparamd
73  */
74 #define	BOOTPARAM_PROG		100026
75 #define	BOOTPARAM_VERS		1
76 #define BOOTPARAM_WHOAMI	1
77 #define BOOTPARAM_GETFILE	2
78 
79 /*
80  * Inet address in RPC messages
81  * (Note, really four ints, NOT chars.  Blech.)
82  */
83 struct xdr_inaddr {
84 	u_int32_t  atype;
85 	int32_t	addr[4];
86 };
87 
88 int xdr_inaddr_encode __P((char **p, struct in_addr ia));
89 int xdr_inaddr_decode __P((char **p, struct in_addr *ia));
90 
91 int xdr_string_encode __P((char **p, char *str, int len));
92 int xdr_string_decode __P((char **p, char *str, int *len_p));
93 
94 
95 /*
96  * RPC: bootparam/whoami
97  * Given client IP address, get:
98  *	client name	(hostname)
99  *	domain name (domainname)
100  *	gateway address
101  *
102  * The hostname and domainname are set here for convenience.
103  *
104  * Note - bpsin is initialized to the broadcast address,
105  * and will be replaced with the bootparam server address
106  * after this call is complete.  Have to use PMAP_PROC_CALL
107  * to make sure we get responses only from a servers that
108  * know about us (don't want to broadcast a getport call).
109  */
110 int
111 bp_whoami(sockfd)
112 	int sockfd;
113 {
114 	/* RPC structures for PMAPPROC_CALLIT */
115 	struct args {
116 		u_int32_t prog;
117 		u_int32_t vers;
118 		u_int32_t proc;
119 		u_int32_t arglen;
120 		struct xdr_inaddr xina;
121 	} *args;
122 	struct repl {
123 		u_int16_t _pad;
124 		u_int16_t port;
125 		u_int32_t encap_len;
126 		/* encapsulated data here */
127 		n_long  capsule[64];
128 	} *repl;
129 	struct {
130 		n_long	h[RPC_HEADER_WORDS];
131 		struct args d;
132 	} sdata;
133 	struct {
134 		n_long	h[RPC_HEADER_WORDS];
135 		struct repl d;
136 	} rdata;
137 	char *send_tail, *recv_head;
138 	struct iodesc *d;
139 	int len, x;
140 
141 	RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
142 
143 	if (!(d = socktodesc(sockfd))) {
144 		RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
145 		return (-1);
146 	}
147 	args = &sdata.d;
148 	repl = &rdata.d;
149 
150 	/*
151 	 * Build request args for PMAPPROC_CALLIT.
152 	 */
153 	args->prog = htonl(BOOTPARAM_PROG);
154 	args->vers = htonl(BOOTPARAM_VERS);
155 	args->proc = htonl(BOOTPARAM_WHOAMI);
156 	args->arglen = htonl(sizeof(struct xdr_inaddr));
157 	send_tail = (char*) &args->xina;
158 
159 	/*
160 	 * append encapsulated data (client IP address)
161 	 */
162 	if (xdr_inaddr_encode(&send_tail, myip))
163 		return (-1);
164 
165 	/* RPC: portmap/callit */
166 	d->myport = htons(--rpc_port);
167 	d->destip.s_addr = INADDR_BROADCAST;	/* XXX: subnet bcast? */
168 	/* rpc_call will set d->destport */
169 
170 	len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
171 				  args, send_tail - (char*)args,
172 				  repl, sizeof(*repl));
173 	if (len < 8) {
174 		printf("bootparamd: 'whoami' call failed\n");
175 		return (-1);
176 	}
177 
178 	/* Save bootparam server address (from IP header). */
179 	rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
180 
181 	/*
182 	 * Note that bp_server_port is now 111 due to the
183 	 * indirect call (using PMAPPROC_CALLIT), so get the
184 	 * actual port number from the reply data.
185 	 */
186 	bp_server_port = repl->port;
187 
188 	RPC_PRINTF(("bp_whoami: server at %s:%d\n",
189 	    inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
190 
191 	/* We have just done a portmap call, so cache the portnum. */
192 	rpc_pmap_putcache(bp_server_addr,
193 			  BOOTPARAM_PROG,
194 			  BOOTPARAM_VERS,
195 			  (int)ntohs(bp_server_port));
196 
197 	/*
198 	 * Parse the encapsulated results from bootparam/whoami
199 	 */
200 	x = ntohl(repl->encap_len);
201 	if (len < x) {
202 		printf("bp_whoami: short reply, %d < %d\n", len, x);
203 		return (-1);
204 	}
205 	recv_head = (char*) repl->capsule;
206 
207 	/* client name */
208 	hostnamelen = MAXHOSTNAMELEN-1;
209 	if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
210 		RPC_PRINTF(("bp_whoami: bad hostname\n"));
211 		return (-1);
212 	}
213 
214 	/* domain name */
215 	domainnamelen = MAXHOSTNAMELEN-1;
216 	if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
217 		RPC_PRINTF(("bp_whoami: bad domainname\n"));
218 		return (-1);
219 	}
220 
221 	/* gateway address */
222 	if (xdr_inaddr_decode(&recv_head, &gateip)) {
223 		RPC_PRINTF(("bp_whoami: bad gateway\n"));
224 		return (-1);
225 	}
226 
227 	/* success */
228 	return(0);
229 }
230 
231 
232 /*
233  * RPC: bootparam/getfile
234  * Given client name and file "key", get:
235  *	server name
236  *	server IP address
237  *	server pathname
238  */
239 int
240 bp_getfile(sockfd, key, serv_addr, pathname)
241 	int sockfd;
242 	char *key;
243 	char *pathname;
244 	struct in_addr *serv_addr;
245 {
246 	struct {
247 		n_long	h[RPC_HEADER_WORDS];
248 		n_long  d[64];
249 	} sdata;
250 	struct {
251 		n_long	h[RPC_HEADER_WORDS];
252 		n_long  d[128];
253 	} rdata;
254 	char serv_name[FNAME_SIZE];
255 	char *send_tail, *recv_head;
256 	/* misc... */
257 	struct iodesc *d;
258 	int sn_len, path_len, rlen;
259 
260 	if (!(d = socktodesc(sockfd))) {
261 		RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
262 		return (-1);
263 	}
264 
265 	send_tail = (char*) sdata.d;
266 	recv_head = (char*) rdata.d;
267 
268 	/*
269 	 * Build request message.
270 	 */
271 
272 	/* client name (hostname) */
273 	if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
274 		RPC_PRINTF(("bp_getfile: bad client\n"));
275 		return (-1);
276 	}
277 
278 	/* key name (root or swap) */
279 	if (xdr_string_encode(&send_tail, key, strlen(key))) {
280 		RPC_PRINTF(("bp_getfile: bad key\n"));
281 		return (-1);
282 	}
283 
284 	/* RPC: bootparam/getfile */
285 	d->myport = htons(--rpc_port);
286 	d->destip   = bp_server_addr;
287 	/* rpc_call will set d->destport */
288 
289 	rlen = rpc_call(d,
290 		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
291 		sdata.d, send_tail - (char*)sdata.d,
292 		rdata.d, sizeof(rdata.d));
293 	if (rlen < 4) {
294 		RPC_PRINTF(("bp_getfile: short reply\n"));
295 		errno = EBADRPC;
296 		return (-1);
297 	}
298 	recv_head = (char*) rdata.d;
299 
300 	/*
301 	 * Parse result message.
302 	 */
303 
304 	/* server name */
305 	sn_len = FNAME_SIZE-1;
306 	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
307 		RPC_PRINTF(("bp_getfile: bad server name\n"));
308 		return (-1);
309 	}
310 
311 	/* server IP address (mountd/NFS) */
312 	if (xdr_inaddr_decode(&recv_head, serv_addr)) {
313 		RPC_PRINTF(("bp_getfile: bad server addr\n"));
314 		return (-1);
315 	}
316 
317 	/* server pathname */
318 	path_len = MAXPATHLEN-1;
319 	if (xdr_string_decode(&recv_head, pathname, &path_len)) {
320 		RPC_PRINTF(("bp_getfile: bad server path\n"));
321 		return (-1);
322 	}
323 
324 	/* success */
325 	return(0);
326 }
327 
328 
329 /*
330  * eXternal Data Representation routines.
331  * (but with non-standard args...)
332  */
333 
334 
335 int
336 xdr_string_encode(pkt, str, len)
337 	char **pkt;
338 	char *str;
339 	int len;
340 {
341 	u_int32_t *lenp;
342 	char *datap;
343 	int padlen = (len + 3) & ~3;	/* padded length */
344 
345 	/* The data will be int aligned. */
346 	lenp = (u_int32_t*) *pkt;
347 	*pkt += sizeof(*lenp);
348 	*lenp = htonl(len);
349 
350 	datap = *pkt;
351 	*pkt += padlen;
352 	bcopy(str, datap, len);
353 
354 	return (0);
355 }
356 
357 int
358 xdr_string_decode(pkt, str, len_p)
359 	char **pkt;
360 	char *str;
361 	int *len_p;		/* bufsize - 1 */
362 {
363 	u_int32_t *lenp;
364 	char *datap;
365 	int slen;	/* string length */
366 	int plen;	/* padded length */
367 
368 	/* The data will be int aligned. */
369 	lenp = (u_int32_t*) *pkt;
370 	*pkt += sizeof(*lenp);
371 	slen = ntohl(*lenp);
372 	plen = (slen + 3) & ~3;
373 
374 	if (slen > *len_p)
375 		slen = *len_p;
376 	datap = *pkt;
377 	*pkt += plen;
378 	bcopy(datap, str, slen);
379 
380 	str[slen] = '\0';
381 	*len_p = slen;
382 
383 	return (0);
384 }
385 
386 
387 int
388 xdr_inaddr_encode(pkt, ia)
389 	char **pkt;
390 	struct in_addr ia;		/* network order */
391 {
392 	struct xdr_inaddr *xi;
393 	u_char *cp;
394 	int32_t *ip;
395 	union {
396 		n_long l;	/* network order */
397 		u_char c[4];
398 	} uia;
399 
400 	/* The data will be int aligned. */
401 	xi = (struct xdr_inaddr *) *pkt;
402 	*pkt += sizeof(*xi);
403 	xi->atype = htonl(1);
404 	uia.l = ia.s_addr;
405 	cp = uia.c;
406 	ip = xi->addr;
407 	/*
408 	 * Note: the htonl() calls below DO NOT
409 	 * imply that uia.l is in host order.
410 	 * In fact this needs it in net order.
411 	 */
412 	*ip++ = htonl((unsigned int)*cp++);
413 	*ip++ = htonl((unsigned int)*cp++);
414 	*ip++ = htonl((unsigned int)*cp++);
415 	*ip++ = htonl((unsigned int)*cp++);
416 
417 	return (0);
418 }
419 
420 int
421 xdr_inaddr_decode(pkt, ia)
422 	char **pkt;
423 	struct in_addr *ia;		/* network order */
424 {
425 	struct xdr_inaddr *xi;
426 	u_char *cp;
427 	int32_t *ip;
428 	union {
429 		n_long l;	/* network order */
430 		u_char c[4];
431 	} uia;
432 
433 	/* The data will be int aligned. */
434 	xi = (struct xdr_inaddr *) *pkt;
435 	*pkt += sizeof(*xi);
436 	if (xi->atype != htonl(1)) {
437 		RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
438 		    ntohl(xi->atype)));
439 		return(-1);
440 	}
441 
442 	cp = uia.c;
443 	ip = xi->addr;
444 	/*
445 	 * Note: the ntohl() calls below DO NOT
446 	 * imply that uia.l is in host order.
447 	 * In fact this needs it in net order.
448 	 */
449 	*cp++ = ntohl(*ip++);
450 	*cp++ = ntohl(*ip++);
451 	*cp++ = ntohl(*ip++);
452 	*cp++ = ntohl(*ip++);
453 	ia->s_addr = uia.l;
454 
455 	return (0);
456 }
457