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