xref: /netbsd-src/sys/lib/libsa/bootparam.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: bootparam.c,v 1.6 1995/12/08 04:10:28 gwr 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 #include <nfs/rpcv2.h>
46 
47 #include <string.h>
48 
49 #include "stand.h"
50 #include "net.h"
51 #include "netif.h"
52 #include "rpc.h"
53 #include "bootparam.h"
54 
55 struct in_addr	bp_server_addr;	/* net order */
56 n_short		bp_server_port;	/* net order */
57 
58 /*
59  * RPC definitions for bootparamd
60  */
61 #define	BOOTPARAM_PROG		100026
62 #define	BOOTPARAM_VERS		1
63 #define BOOTPARAM_WHOAMI	1
64 #define BOOTPARAM_GETFILE	2
65 
66 /*
67  * Inet address in RPC messages
68  * (Note, really four ints, NOT chars.  Blech.)
69  */
70 struct xdr_inaddr {
71 	u_int32_t  atype;
72 	int32_t	addr[4];
73 };
74 
75 int xdr_inaddr_encode __P((char **p, struct in_addr ia));
76 int xdr_inaddr_decode __P((char **p, struct in_addr *ia));
77 
78 int xdr_string_encode __P((char **p, char *str, int len));
79 int xdr_string_decode __P((char **p, char *str, int *len_p));
80 
81 
82 /*
83  * RPC: bootparam/whoami
84  * Given client IP address, get:
85  *	client name	(hostname)
86  *	domain name (domainname)
87  *	gateway address
88  *
89  * The hostname and domainname are set here for convenience.
90  *
91  * Note - bpsin is initialized to the broadcast address,
92  * and will be replaced with the bootparam server address
93  * after this call is complete.  Have to use PMAP_PROC_CALL
94  * to make sure we get responses only from a servers that
95  * know about us (don't want to broadcast a getport call).
96  */
97 int
98 bp_whoami(sockfd)
99 	int sockfd;
100 {
101 	/* RPC structures for PMAPPROC_CALLIT */
102 	struct args {
103 		u_int32_t prog;
104 		u_int32_t vers;
105 		u_int32_t proc;
106 		u_int32_t arglen;
107 		struct xdr_inaddr xina;
108 	} *args;
109 	struct repl {
110 		u_int16_t _pad;
111 		u_int16_t port;
112 		u_int32_t encap_len;
113 		/* encapsulated data here */
114 		n_long  capsule[64];
115 	} *repl;
116 	struct {
117 		n_long	h[RPC_HEADER_WORDS];
118 		struct args d;
119 	} sdata;
120 	struct {
121 		n_long	h[RPC_HEADER_WORDS];
122 		struct repl d;
123 	} rdata;
124 	char *send_tail, *recv_head;
125 	struct iodesc *d;
126 	int len, x;
127 
128 #ifdef	RPC_DEBUG
129 	printf("bp_whoami: myip=%s\n", inet_ntoa(myip));
130 #endif
131 
132 	if (!(d = socktodesc(sockfd))) {
133 #ifdef	RPC_DEBUG
134 		printf("bp_whoami: bad socket. %d\n", sockfd);
135 #endif
136 		return (-1);
137 	}
138 	args = &sdata.d;
139 	repl = &rdata.d;
140 
141 	/*
142 	 * Build request args for PMAPPROC_CALLIT.
143 	 */
144 	args->prog = htonl(BOOTPARAM_PROG);
145 	args->vers = htonl(BOOTPARAM_VERS);
146 	args->proc = htonl(BOOTPARAM_WHOAMI);
147 	args->arglen = htonl(sizeof(struct xdr_inaddr));
148 	send_tail = (char*) &args->xina;
149 
150 	/*
151 	 * append encapsulated data (client IP address)
152 	 */
153 	if (xdr_inaddr_encode(&send_tail, myip))
154 		return (-1);
155 
156 	/* RPC: portmap/callit */
157 	d->myport = htons(--rpc_port);
158 	d->destip.s_addr = INADDR_BROADCAST;	/* XXX: subnet bcast? */
159 	/* rpc_call will set d->destport */
160 
161 	len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
162 				  args, send_tail - (char*)args,
163 				  repl, sizeof(*repl));
164 	if (len < 8) {
165 		printf("bootparamd: 'whoami' call failed\n");
166 		return (-1);
167 	}
168 
169 	/* Save bootparam server address (from IP header). */
170 	rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
171 
172 	/*
173 	 * Note that bp_server_port is now 111 due to the
174 	 * indirect call (using PMAPPROC_CALLIT), so get the
175 	 * actual port number from the reply data.
176 	 */
177 	bp_server_port = repl->port;
178 
179 #ifdef	RPC_DEBUG
180 	printf("bp_whoami: server at %s:%d\n",
181 		   inet_ntoa(bp_server_addr), ntohs(bp_server_port));
182 #endif
183 
184 	/* We have just done a portmap call, so cache the portnum. */
185 	rpc_pmap_putcache(bp_server_addr,
186 			  BOOTPARAM_PROG,
187 			  BOOTPARAM_VERS,
188 			  (int)ntohs(bp_server_port));
189 
190 	/*
191 	 * Parse the encapsulated results from bootparam/whoami
192 	 */
193 	x = ntohl(repl->encap_len);
194 	if (len < x) {
195 		printf("bp_whoami: short reply, %d < %d\n", len, x);
196 		return (-1);
197 	}
198 	recv_head = (char*) repl->capsule;
199 
200 	/* client name */
201 	hostnamelen = MAXHOSTNAMELEN-1;
202 	if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
203 #ifdef	RPC_DEBUG
204 		printf("bp_whoami: bad hostname\n");
205 #endif
206 		return (-1);
207 	}
208 
209 	/* domain name */
210 	domainnamelen = MAXHOSTNAMELEN-1;
211 	if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
212 #ifdef	RPC_DEBUG
213 		printf("bp_whoami: bad domainname\n");
214 #endif
215 		return (-1);
216 	}
217 
218 	/* gateway address */
219 	if (xdr_inaddr_decode(&recv_head, &gateip)) {
220 #ifdef	RPC_DEBUG
221 		printf("bp_whoami: bad gateway\n");
222 #endif
223 		return (-1);
224 	}
225 
226 	/* success */
227 	return(0);
228 }
229 
230 
231 /*
232  * RPC: bootparam/getfile
233  * Given client name and file "key", get:
234  *	server name
235  *	server IP address
236  *	server pathname
237  */
238 int
239 bp_getfile(sockfd, key, serv_addr, pathname)
240 	int sockfd;
241 	char *key;
242 	char *pathname;
243 	struct in_addr *serv_addr;
244 {
245 	struct {
246 		n_long	h[RPC_HEADER_WORDS];
247 		n_long  d[64];
248 	} sdata;
249 	struct {
250 		n_long	h[RPC_HEADER_WORDS];
251 		n_long  d[128];
252 	} rdata;
253 	char serv_name[FNAME_SIZE];
254 	char *send_tail, *recv_head;
255 	/* misc... */
256 	struct iodesc *d;
257 	int sn_len, path_len, rlen;
258 
259 	if (!(d = socktodesc(sockfd))) {
260 #ifdef	RPC_DEBUG
261 		printf("bp_getfile: bad socket. %d\n", sockfd);
262 #endif
263 		return (-1);
264 	}
265 
266 	send_tail = (char*) sdata.d;
267 	recv_head = (char*) rdata.d;
268 
269 	/*
270 	 * Build request message.
271 	 */
272 
273 	/* client name (hostname) */
274 	if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
275 #ifdef	RPC_DEBUG
276 		printf("bp_getfile: bad client\n");
277 #endif
278 		return (-1);
279 	}
280 
281 	/* key name (root or swap) */
282 	if (xdr_string_encode(&send_tail, key, strlen(key))) {
283 #ifdef	RPC_DEBUG
284 		printf("bp_getfile: bad key\n");
285 #endif
286 		return (-1);
287 	}
288 
289 	/* RPC: bootparam/getfile */
290 	d->myport = htons(--rpc_port);
291 	d->destip   = bp_server_addr;
292 	/* rpc_call will set d->destport */
293 
294 	rlen = rpc_call(d,
295 		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
296 		sdata.d, send_tail - (char*)sdata.d,
297 		rdata.d, sizeof(rdata.d));
298 	if (rlen < 4) {
299 #ifdef	RPC_DEBUG
300 		printf("bp_getfile: short reply\n");
301 #endif
302 		errno = EBADRPC;
303 		return (-1);
304 	}
305 	recv_head = (char*) rdata.d;
306 
307 	/*
308 	 * Parse result message.
309 	 */
310 
311 	/* server name */
312 	sn_len = FNAME_SIZE-1;
313 	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
314 #ifdef	RPC_DEBUG
315 		printf("bp_getfile: bad server name\n");
316 #endif
317 		return (-1);
318 	}
319 
320 	/* server IP address (mountd/NFS) */
321 	if (xdr_inaddr_decode(&recv_head, serv_addr)) {
322 #ifdef	RPC_DEBUG
323 		printf("bp_getfile: bad server addr\n");
324 #endif
325 		return (-1);
326 	}
327 
328 	/* server pathname */
329 	path_len = MAXPATHLEN-1;
330 	if (xdr_string_decode(&recv_head, pathname, &path_len)) {
331 #ifdef	RPC_DEBUG
332 		printf("bp_getfile: bad server path\n");
333 #endif
334 		return (-1);
335 	}
336 
337 	/* success */
338 	return(0);
339 }
340 
341 
342 /*
343  * eXternal Data Representation routines.
344  * (but with non-standard args...)
345  */
346 
347 
348 int
349 xdr_string_encode(pkt, str, len)
350 	char **pkt;
351 	char *str;
352 	int len;
353 {
354 	u_int32_t *lenp;
355 	char *datap;
356 	int padlen = (len + 3) & ~3;	/* padded length */
357 
358 	/* The data will be int aligned. */
359 	lenp = (u_int32_t*) *pkt;
360 	*pkt += sizeof(*lenp);
361 	*lenp = htonl(len);
362 
363 	datap = *pkt;
364 	*pkt += padlen;
365 	bcopy(str, datap, len);
366 
367 	return (0);
368 }
369 
370 int
371 xdr_string_decode(pkt, str, len_p)
372 	char **pkt;
373 	char *str;
374 	int *len_p;		/* bufsize - 1 */
375 {
376 	u_int32_t *lenp;
377 	char *datap;
378 	int slen;	/* string length */
379 	int plen;	/* padded length */
380 
381 	/* The data will be int aligned. */
382 	lenp = (u_int32_t*) *pkt;
383 	*pkt += sizeof(*lenp);
384 	slen = ntohl(*lenp);
385 	plen = (slen + 3) & ~3;
386 
387 	if (slen > *len_p)
388 		slen = *len_p;
389 	datap = *pkt;
390 	*pkt += plen;
391 	bcopy(datap, str, slen);
392 
393 	str[slen] = '\0';
394 	*len_p = slen;
395 
396 	return (0);
397 }
398 
399 
400 int
401 xdr_inaddr_encode(pkt, ia)
402 	char **pkt;
403 	struct in_addr ia;		/* network order */
404 {
405 	struct xdr_inaddr *xi;
406 	u_char *cp;
407 	int32_t *ip;
408 	union {
409 		n_long l;	/* network order */
410 		u_char c[4];
411 	} uia;
412 
413 	/* The data will be int aligned. */
414 	xi = (struct xdr_inaddr *) *pkt;
415 	*pkt += sizeof(*xi);
416 	xi->atype = htonl(1);
417 	uia.l = ia.s_addr;
418 	cp = uia.c;
419 	ip = xi->addr;
420 	/*
421 	 * Note: the htonl() calls below DO NOT
422 	 * imply that uia.l is in host order.
423 	 * In fact this needs it in net order.
424 	 */
425 	*ip++ = htonl((unsigned int)*cp++);
426 	*ip++ = htonl((unsigned int)*cp++);
427 	*ip++ = htonl((unsigned int)*cp++);
428 	*ip++ = htonl((unsigned int)*cp++);
429 
430 	return (0);
431 }
432 
433 int
434 xdr_inaddr_decode(pkt, ia)
435 	char **pkt;
436 	struct in_addr *ia;		/* network order */
437 {
438 	struct xdr_inaddr *xi;
439 	u_char *cp;
440 	int32_t *ip;
441 	union {
442 		n_long l;	/* network order */
443 		u_char c[4];
444 	} uia;
445 
446 	/* The data will be int aligned. */
447 	xi = (struct xdr_inaddr *) *pkt;
448 	*pkt += sizeof(*xi);
449 	if (xi->atype != htonl(1)) {
450 #ifdef	RPC_DEBUG
451 		printf("xdr_inaddr_decode: bad addrtype=%d\n",
452 			   ntohl(xi->atype));
453 #endif
454 		return(-1);
455 	}
456 
457 	cp = uia.c;
458 	ip = xi->addr;
459 	/*
460 	 * Note: the ntohl() calls below DO NOT
461 	 * imply that uia.l is in host order.
462 	 * In fact this needs it in net order.
463 	 */
464 	*cp++ = ntohl(*ip++);
465 	*cp++ = ntohl(*ip++);
466 	*cp++ = ntohl(*ip++);
467 	*cp++ = ntohl(*ip++);
468 	ia->s_addr = uia.l;
469 
470 	return (0);
471 }
472