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