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