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