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