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: releng/10.2/lib/libstand/bootparam.c 84221 2001-09-30 22:28:01Z dillon $"); 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