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