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