138451Smsmith/*	$NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $	*/
238451Smsmith
338451Smsmith/*
438451Smsmith * Copyright (c) 1995 Gordon W. Ross
538451Smsmith * All rights reserved.
638451Smsmith *
738451Smsmith * Redistribution and use in source and binary forms, with or without
838451Smsmith * modification, are permitted provided that the following conditions
938451Smsmith * are met:
1038451Smsmith * 1. Redistributions of source code must retain the above copyright
1138451Smsmith *    notice, this list of conditions and the following disclaimer.
1238451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1338451Smsmith *    notice, this list of conditions and the following disclaimer in the
1438451Smsmith *    documentation and/or other materials provided with the distribution.
1538451Smsmith * 3. The name of the author may not be used to endorse or promote products
1638451Smsmith *    derived from this software without specific prior written permission.
1738451Smsmith * 4. All advertising materials mentioning features or use of this software
1838451Smsmith *    must display the following acknowledgement:
1938451Smsmith *      This product includes software developed by Gordon W. Ross
2038451Smsmith *
2138451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2238451Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2338451Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2438451Smsmith * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2538451Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2638451Smsmith * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2738451Smsmith * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2838451Smsmith * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2938451Smsmith * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3038451Smsmith * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3138451Smsmith */
3238451Smsmith
3384221Sdillon#include <sys/cdefs.h>
3484221Sdillon__FBSDID("$FreeBSD$");
3584221Sdillon
3638451Smsmith/*
3738451Smsmith * RPC/bootparams
3838451Smsmith */
3938451Smsmith
4038451Smsmith#include <sys/param.h>
4138451Smsmith#include <sys/socket.h>
4238451Smsmith
4338451Smsmith#include <net/if.h>
4438451Smsmith
4538451Smsmith#include <netinet/in.h>
4638451Smsmith#include <netinet/in_systm.h>
4738451Smsmith
4838451Smsmith#include <string.h>
4938451Smsmith
5038451Smsmith#include "rpcv2.h"
5138451Smsmith
5238451Smsmith#include "stand.h"
5338451Smsmith#include "net.h"
5438451Smsmith#include "netif.h"
5538451Smsmith#include "rpc.h"
5638451Smsmith#include "bootparam.h"
5738451Smsmith
5838451Smsmith#ifdef DEBUG_RPC
5938451Smsmith#define RPC_PRINTF(a)	printf a
6038451Smsmith#else
6138451Smsmith#define RPC_PRINTF(a)
6238451Smsmith#endif
6338451Smsmith
6438451Smsmithstruct in_addr	bp_server_addr;	/* net order */
6538451Smsmithn_short		bp_server_port;	/* net order */
6638451Smsmith
6738451Smsmith/*
6838451Smsmith * RPC definitions for bootparamd
6938451Smsmith */
7038451Smsmith#define	BOOTPARAM_PROG		100026
7138451Smsmith#define	BOOTPARAM_VERS		1
7238451Smsmith#define BOOTPARAM_WHOAMI	1
7338451Smsmith#define BOOTPARAM_GETFILE	2
7438451Smsmith
7538451Smsmith/*
7638451Smsmith * Inet address in RPC messages
7738451Smsmith * (Note, really four ints, NOT chars.  Blech.)
7838451Smsmith */
7938451Smsmithstruct xdr_inaddr {
8038451Smsmith	u_int32_t  atype;
8138451Smsmith	int32_t	addr[4];
8238451Smsmith};
8338451Smsmith
8438451Smsmithint xdr_inaddr_encode(char **p, struct in_addr ia);
8538451Smsmithint xdr_inaddr_decode(char **p, struct in_addr *ia);
8638451Smsmith
8738451Smsmithint xdr_string_encode(char **p, char *str, int len);
8838451Smsmithint xdr_string_decode(char **p, char *str, int *len_p);
8938451Smsmith
9038451Smsmith
9138451Smsmith/*
9238451Smsmith * RPC: bootparam/whoami
9338451Smsmith * Given client IP address, get:
9438451Smsmith *	client name	(hostname)
9538451Smsmith *	domain name (domainname)
9638451Smsmith *	gateway address
9738451Smsmith *
9838451Smsmith * The hostname and domainname are set here for convenience.
9938451Smsmith *
10038451Smsmith * Note - bpsin is initialized to the broadcast address,
10138451Smsmith * and will be replaced with the bootparam server address
10238451Smsmith * after this call is complete.  Have to use PMAP_PROC_CALL
10338451Smsmith * to make sure we get responses only from a servers that
10438451Smsmith * know about us (don't want to broadcast a getport call).
10538451Smsmith */
10638451Smsmithint
10738451Smsmithbp_whoami(sockfd)
10838451Smsmith	int sockfd;
10938451Smsmith{
11038451Smsmith	/* RPC structures for PMAPPROC_CALLIT */
11138451Smsmith	struct args {
11238451Smsmith		u_int32_t prog;
11338451Smsmith		u_int32_t vers;
11438451Smsmith		u_int32_t proc;
11538451Smsmith		u_int32_t arglen;
11638451Smsmith		struct xdr_inaddr xina;
11738451Smsmith	} *args;
11838451Smsmith	struct repl {
11938451Smsmith		u_int16_t _pad;
12038451Smsmith		u_int16_t port;
12138451Smsmith		u_int32_t encap_len;
12238451Smsmith		/* encapsulated data here */
12338451Smsmith		n_long  capsule[64];
12438451Smsmith	} *repl;
12538451Smsmith	struct {
12638451Smsmith		n_long	h[RPC_HEADER_WORDS];
12738451Smsmith		struct args d;
12838451Smsmith	} sdata;
12938451Smsmith	struct {
13038451Smsmith		n_long	h[RPC_HEADER_WORDS];
13138451Smsmith		struct repl d;
13238451Smsmith	} rdata;
13338451Smsmith	char *send_tail, *recv_head;
13438451Smsmith	struct iodesc *d;
13538451Smsmith	int len, x;
13638451Smsmith
13738451Smsmith	RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
13838451Smsmith
13938451Smsmith	if (!(d = socktodesc(sockfd))) {
14038451Smsmith		RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
14138451Smsmith		return (-1);
14238451Smsmith	}
14338451Smsmith	args = &sdata.d;
14438451Smsmith	repl = &rdata.d;
14538451Smsmith
14638451Smsmith	/*
14738451Smsmith	 * Build request args for PMAPPROC_CALLIT.
14838451Smsmith	 */
14938451Smsmith	args->prog = htonl(BOOTPARAM_PROG);
15038451Smsmith	args->vers = htonl(BOOTPARAM_VERS);
15138451Smsmith	args->proc = htonl(BOOTPARAM_WHOAMI);
15238451Smsmith	args->arglen = htonl(sizeof(struct xdr_inaddr));
15338451Smsmith	send_tail = (char*) &args->xina;
15438451Smsmith
15538451Smsmith	/*
15638451Smsmith	 * append encapsulated data (client IP address)
15738451Smsmith	 */
15838451Smsmith	if (xdr_inaddr_encode(&send_tail, myip))
15938451Smsmith		return (-1);
16038451Smsmith
16138451Smsmith	/* RPC: portmap/callit */
16238451Smsmith	d->myport = htons(--rpc_port);
16338451Smsmith	d->destip.s_addr = INADDR_BROADCAST;	/* XXX: subnet bcast? */
16438451Smsmith	/* rpc_call will set d->destport */
16538451Smsmith
16638451Smsmith	len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
16738451Smsmith				  args, send_tail - (char*)args,
16838451Smsmith				  repl, sizeof(*repl));
16938451Smsmith	if (len < 8) {
17038451Smsmith		printf("bootparamd: 'whoami' call failed\n");
17138451Smsmith		return (-1);
17238451Smsmith	}
17338451Smsmith
17438451Smsmith	/* Save bootparam server address (from IP header). */
17538451Smsmith	rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
17638451Smsmith
17738451Smsmith	/*
17838451Smsmith	 * Note that bp_server_port is now 111 due to the
17938451Smsmith	 * indirect call (using PMAPPROC_CALLIT), so get the
18038451Smsmith	 * actual port number from the reply data.
18138451Smsmith	 */
18238451Smsmith	bp_server_port = repl->port;
18338451Smsmith
18438451Smsmith	RPC_PRINTF(("bp_whoami: server at %s:%d\n",
18538451Smsmith	    inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
18638451Smsmith
18738451Smsmith	/* We have just done a portmap call, so cache the portnum. */
18838451Smsmith	rpc_pmap_putcache(bp_server_addr,
18938451Smsmith			  BOOTPARAM_PROG,
19038451Smsmith			  BOOTPARAM_VERS,
19138451Smsmith			  (int)ntohs(bp_server_port));
19238451Smsmith
19338451Smsmith	/*
19438451Smsmith	 * Parse the encapsulated results from bootparam/whoami
19538451Smsmith	 */
19638451Smsmith	x = ntohl(repl->encap_len);
19738451Smsmith	if (len < x) {
19838451Smsmith		printf("bp_whoami: short reply, %d < %d\n", len, x);
19938451Smsmith		return (-1);
20038451Smsmith	}
20138451Smsmith	recv_head = (char*) repl->capsule;
20238451Smsmith
20338451Smsmith	/* client name */
20438451Smsmith	hostnamelen = MAXHOSTNAMELEN-1;
20538451Smsmith	if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
20638451Smsmith		RPC_PRINTF(("bp_whoami: bad hostname\n"));
20738451Smsmith		return (-1);
20838451Smsmith	}
20938451Smsmith
21038451Smsmith	/* domain name */
21138451Smsmith	domainnamelen = MAXHOSTNAMELEN-1;
21238451Smsmith	if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
21338451Smsmith		RPC_PRINTF(("bp_whoami: bad domainname\n"));
21438451Smsmith		return (-1);
21538451Smsmith	}
21638451Smsmith
21738451Smsmith	/* gateway address */
21838451Smsmith	if (xdr_inaddr_decode(&recv_head, &gateip)) {
21938451Smsmith		RPC_PRINTF(("bp_whoami: bad gateway\n"));
22038451Smsmith		return (-1);
22138451Smsmith	}
22238451Smsmith
22338451Smsmith	/* success */
22438451Smsmith	return(0);
22538451Smsmith}
22638451Smsmith
22738451Smsmith
22838451Smsmith/*
22938451Smsmith * RPC: bootparam/getfile
23038451Smsmith * Given client name and file "key", get:
23138451Smsmith *	server name
23238451Smsmith *	server IP address
23338451Smsmith *	server pathname
23438451Smsmith */
23538451Smsmithint
23638451Smsmithbp_getfile(sockfd, key, serv_addr, pathname)
23738451Smsmith	int sockfd;
23838451Smsmith	char *key;
23938451Smsmith	char *pathname;
24038451Smsmith	struct in_addr *serv_addr;
24138451Smsmith{
24238451Smsmith	struct {
24338451Smsmith		n_long	h[RPC_HEADER_WORDS];
24438451Smsmith		n_long  d[64];
24538451Smsmith	} sdata;
24638451Smsmith	struct {
24738451Smsmith		n_long	h[RPC_HEADER_WORDS];
24838451Smsmith		n_long  d[128];
24938451Smsmith	} rdata;
25038451Smsmith	char serv_name[FNAME_SIZE];
25138451Smsmith	char *send_tail, *recv_head;
25238451Smsmith	/* misc... */
25338451Smsmith	struct iodesc *d;
25438451Smsmith	int sn_len, path_len, rlen;
25538451Smsmith
25638451Smsmith	if (!(d = socktodesc(sockfd))) {
25738451Smsmith		RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
25838451Smsmith		return (-1);
25938451Smsmith	}
26038451Smsmith
26138451Smsmith	send_tail = (char*) sdata.d;
26238451Smsmith	recv_head = (char*) rdata.d;
26338451Smsmith
26438451Smsmith	/*
26538451Smsmith	 * Build request message.
26638451Smsmith	 */
26738451Smsmith
26838451Smsmith	/* client name (hostname) */
26938451Smsmith	if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
27038451Smsmith		RPC_PRINTF(("bp_getfile: bad client\n"));
27138451Smsmith		return (-1);
27238451Smsmith	}
27338451Smsmith
27438451Smsmith	/* key name (root or swap) */
27538451Smsmith	if (xdr_string_encode(&send_tail, key, strlen(key))) {
27638451Smsmith		RPC_PRINTF(("bp_getfile: bad key\n"));
27738451Smsmith		return (-1);
27838451Smsmith	}
27938451Smsmith
28038451Smsmith	/* RPC: bootparam/getfile */
28138451Smsmith	d->myport = htons(--rpc_port);
28238451Smsmith	d->destip   = bp_server_addr;
28338451Smsmith	/* rpc_call will set d->destport */
28438451Smsmith
28538451Smsmith	rlen = rpc_call(d,
28638451Smsmith		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
28738451Smsmith		sdata.d, send_tail - (char*)sdata.d,
28838451Smsmith		rdata.d, sizeof(rdata.d));
28938451Smsmith	if (rlen < 4) {
29038451Smsmith		RPC_PRINTF(("bp_getfile: short reply\n"));
29138451Smsmith		errno = EBADRPC;
29238451Smsmith		return (-1);
29338451Smsmith	}
29438451Smsmith	recv_head = (char*) rdata.d;
29538451Smsmith
29638451Smsmith	/*
29738451Smsmith	 * Parse result message.
29838451Smsmith	 */
29938451Smsmith
30038451Smsmith	/* server name */
30138451Smsmith	sn_len = FNAME_SIZE-1;
30238451Smsmith	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
30338451Smsmith		RPC_PRINTF(("bp_getfile: bad server name\n"));
30438451Smsmith		return (-1);
30538451Smsmith	}
30638451Smsmith
30738451Smsmith	/* server IP address (mountd/NFS) */
30838451Smsmith	if (xdr_inaddr_decode(&recv_head, serv_addr)) {
30938451Smsmith		RPC_PRINTF(("bp_getfile: bad server addr\n"));
31038451Smsmith		return (-1);
31138451Smsmith	}
31238451Smsmith
31338451Smsmith	/* server pathname */
31438451Smsmith	path_len = MAXPATHLEN-1;
31538451Smsmith	if (xdr_string_decode(&recv_head, pathname, &path_len)) {
31638451Smsmith		RPC_PRINTF(("bp_getfile: bad server path\n"));
31738451Smsmith		return (-1);
31838451Smsmith	}
31938451Smsmith
32038451Smsmith	/* success */
32138451Smsmith	return(0);
32238451Smsmith}
32338451Smsmith
32438451Smsmith
32538451Smsmith/*
32638451Smsmith * eXternal Data Representation routines.
32738451Smsmith * (but with non-standard args...)
32838451Smsmith */
32938451Smsmith
33038451Smsmith
33138451Smsmithint
33238451Smsmithxdr_string_encode(pkt, str, len)
33338451Smsmith	char **pkt;
33438451Smsmith	char *str;
33538451Smsmith	int len;
33638451Smsmith{
33738451Smsmith	u_int32_t *lenp;
33838451Smsmith	char *datap;
33938451Smsmith	int padlen = (len + 3) & ~3;	/* padded length */
34038451Smsmith
34138451Smsmith	/* The data will be int aligned. */
34238451Smsmith	lenp = (u_int32_t*) *pkt;
34338451Smsmith	*pkt += sizeof(*lenp);
34438451Smsmith	*lenp = htonl(len);
34538451Smsmith
34638451Smsmith	datap = *pkt;
34738451Smsmith	*pkt += padlen;
34838451Smsmith	bcopy(str, datap, len);
34938451Smsmith
35038451Smsmith	return (0);
35138451Smsmith}
35238451Smsmith
35338451Smsmithint
35438451Smsmithxdr_string_decode(pkt, str, len_p)
35538451Smsmith	char **pkt;
35638451Smsmith	char *str;
35738451Smsmith	int *len_p;		/* bufsize - 1 */
35838451Smsmith{
35938451Smsmith	u_int32_t *lenp;
36038451Smsmith	char *datap;
36138451Smsmith	int slen;	/* string length */
36238451Smsmith	int plen;	/* padded length */
36338451Smsmith
36438451Smsmith	/* The data will be int aligned. */
36538451Smsmith	lenp = (u_int32_t*) *pkt;
36638451Smsmith	*pkt += sizeof(*lenp);
36738451Smsmith	slen = ntohl(*lenp);
36838451Smsmith	plen = (slen + 3) & ~3;
36938451Smsmith
37038451Smsmith	if (slen > *len_p)
37138451Smsmith		slen = *len_p;
37238451Smsmith	datap = *pkt;
37338451Smsmith	*pkt += plen;
37438451Smsmith	bcopy(datap, str, slen);
37538451Smsmith
37638451Smsmith	str[slen] = '\0';
37738451Smsmith	*len_p = slen;
37838451Smsmith
37938451Smsmith	return (0);
38038451Smsmith}
38138451Smsmith
38238451Smsmith
38338451Smsmithint
38438451Smsmithxdr_inaddr_encode(pkt, ia)
38538451Smsmith	char **pkt;
38638451Smsmith	struct in_addr ia;		/* network order */
38738451Smsmith{
38838451Smsmith	struct xdr_inaddr *xi;
38938451Smsmith	u_char *cp;
39038451Smsmith	int32_t *ip;
39138451Smsmith	union {
39238451Smsmith		n_long l;	/* network order */
39338451Smsmith		u_char c[4];
39438451Smsmith	} uia;
39538451Smsmith
39638451Smsmith	/* The data will be int aligned. */
39738451Smsmith	xi = (struct xdr_inaddr *) *pkt;
39838451Smsmith	*pkt += sizeof(*xi);
39938451Smsmith	xi->atype = htonl(1);
40038451Smsmith	uia.l = ia.s_addr;
40138451Smsmith	cp = uia.c;
40238451Smsmith	ip = xi->addr;
40338451Smsmith	/*
40438451Smsmith	 * Note: the htonl() calls below DO NOT
40538451Smsmith	 * imply that uia.l is in host order.
40638451Smsmith	 * In fact this needs it in net order.
40738451Smsmith	 */
40838451Smsmith	*ip++ = htonl((unsigned int)*cp++);
40938451Smsmith	*ip++ = htonl((unsigned int)*cp++);
41038451Smsmith	*ip++ = htonl((unsigned int)*cp++);
41138451Smsmith	*ip++ = htonl((unsigned int)*cp++);
41238451Smsmith
41338451Smsmith	return (0);
41438451Smsmith}
41538451Smsmith
41638451Smsmithint
41738451Smsmithxdr_inaddr_decode(pkt, ia)
41838451Smsmith	char **pkt;
41938451Smsmith	struct in_addr *ia;		/* network order */
42038451Smsmith{
42138451Smsmith	struct xdr_inaddr *xi;
42238451Smsmith	u_char *cp;
42338451Smsmith	int32_t *ip;
42438451Smsmith	union {
42538451Smsmith		n_long l;	/* network order */
42638451Smsmith		u_char c[4];
42738451Smsmith	} uia;
42838451Smsmith
42938451Smsmith	/* The data will be int aligned. */
43038451Smsmith	xi = (struct xdr_inaddr *) *pkt;
43138451Smsmith	*pkt += sizeof(*xi);
43238451Smsmith	if (xi->atype != htonl(1)) {
43338451Smsmith		RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
43438451Smsmith		    ntohl(xi->atype)));
43538451Smsmith		return(-1);
43638451Smsmith	}
43738451Smsmith
43838451Smsmith	cp = uia.c;
43938451Smsmith	ip = xi->addr;
44038451Smsmith	/*
44138451Smsmith	 * Note: the ntohl() calls below DO NOT
44238451Smsmith	 * imply that uia.l is in host order.
44338451Smsmith	 * In fact this needs it in net order.
44438451Smsmith	 */
44538451Smsmith	*cp++ = ntohl(*ip++);
44638451Smsmith	*cp++ = ntohl(*ip++);
44738451Smsmith	*cp++ = ntohl(*ip++);
44838451Smsmith	*cp++ = ntohl(*ip++);
44938451Smsmith	ia->s_addr = uia.l;
45038451Smsmith
45138451Smsmith	return (0);
45238451Smsmith}
453