NetBSD/sys/lib/libsa/bootparam.c
drochner 3906113e15 Move global variables which are used only by bootparam here.
("domainname" is useless and could be removed, but adding code to
skip this in the RPC reply would probably be more expensive than leaving
it as a dummy variable.)
2003-03-19 17:18:07 +00:00

457 lines
10 KiB
C

/* $NetBSD: bootparam.c,v 1.15 2003/03/19 17:18:07 drochner Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* 4. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Gordon W. Ross
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* RPC/bootparams
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#ifdef _STANDALONE
#include <lib/libkern/libkern.h>
#else
#include <string.h>
#endif
#include "rpcv2.h"
#include "stand.h"
#include "net.h"
#include "rpc.h"
#include "bootparam.h"
#ifdef DEBUG_RPC
#define RPC_PRINTF(a) printf a
#else
#define RPC_PRINTF(a)
#endif
struct in_addr bp_server_addr; /* net order */
n_short bp_server_port; /* net order */
int hostnamelen;
char domainname[FNAME_SIZE]; /* our DNS domain */
int domainnamelen;
/*
* RPC definitions for bootparamd
*/
#define BOOTPARAM_PROG 100026
#define BOOTPARAM_VERS 1
#define BOOTPARAM_WHOAMI 1
#define BOOTPARAM_GETFILE 2
/*
* Inet address in RPC messages
* (Note, really four ints, NOT chars. Blech.)
*/
struct xdr_inaddr {
u_int32_t atype;
int32_t addr[4];
};
int xdr_inaddr_encode __P((char **p, struct in_addr ia));
int xdr_inaddr_decode __P((char **p, struct in_addr *ia));
int xdr_string_encode __P((char **p, char *str, int len));
int xdr_string_decode __P((char **p, char *str, int *len_p));
/*
* RPC: bootparam/whoami
* Given client IP address, get:
* client name (hostname)
* domain name (domainname)
* gateway address
*
* The hostname and domainname are set here for convenience.
*
* Note - bpsin is initialized to the broadcast address,
* and will be replaced with the bootparam server address
* after this call is complete. Have to use PMAP_PROC_CALL
* to make sure we get responses only from a servers that
* know about us (don't want to broadcast a getport call).
*/
int
bp_whoami(sockfd)
int sockfd;
{
/* RPC structures for PMAPPROC_CALLIT */
struct args {
u_int32_t prog;
u_int32_t vers;
u_int32_t proc;
u_int32_t arglen;
struct xdr_inaddr xina;
} *args;
struct repl {
u_int16_t _pad;
u_int16_t port;
u_int32_t encap_len;
/* encapsulated data here */
n_long capsule[64];
} *repl;
struct {
n_long h[RPC_HEADER_WORDS];
struct args d;
} sdata;
struct {
n_long h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
char *send_tail, *recv_head;
struct iodesc *d;
int len, x;
RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
return (-1);
}
args = &sdata.d;
repl = &rdata.d;
/*
* Build request args for PMAPPROC_CALLIT.
*/
args->prog = htonl(BOOTPARAM_PROG);
args->vers = htonl(BOOTPARAM_VERS);
args->proc = htonl(BOOTPARAM_WHOAMI);
args->arglen = htonl(sizeof(struct xdr_inaddr));
send_tail = (char*) &args->xina;
/*
* append encapsulated data (client IP address)
*/
if (xdr_inaddr_encode(&send_tail, myip))
return (-1);
/* RPC: portmap/callit */
d->myport = htons(--rpc_port);
d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
/* rpc_call will set d->destport */
len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
args, send_tail - (char*)args,
repl, sizeof(*repl));
if (len < 8) {
printf("bootparamd: 'whoami' call failed\n");
return (-1);
}
/* Save bootparam server address (from IP header). */
rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
/*
* Note that bp_server_port is now 111 due to the
* indirect call (using PMAPPROC_CALLIT), so get the
* actual port number from the reply data.
*/
bp_server_port = repl->port;
RPC_PRINTF(("bp_whoami: server at %s:%d\n",
inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
/* We have just done a portmap call, so cache the portnum. */
rpc_pmap_putcache(bp_server_addr,
BOOTPARAM_PROG,
BOOTPARAM_VERS,
(int)ntohs(bp_server_port));
/*
* Parse the encapsulated results from bootparam/whoami
*/
x = ntohl(repl->encap_len);
if (len < x) {
printf("bp_whoami: short reply, %d < %d\n", len, x);
return (-1);
}
recv_head = (char*) repl->capsule;
/* client name */
hostnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
RPC_PRINTF(("bp_whoami: bad hostname\n"));
return (-1);
}
/* domain name */
domainnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
RPC_PRINTF(("bp_whoami: bad domainname\n"));
return (-1);
}
/* gateway address */
if (xdr_inaddr_decode(&recv_head, &gateip)) {
RPC_PRINTF(("bp_whoami: bad gateway\n"));
return (-1);
}
/* success */
return(0);
}
/*
* RPC: bootparam/getfile
* Given client name and file "key", get:
* server name
* server IP address
* server pathname
*/
int
bp_getfile(sockfd, key, serv_addr, pathname)
int sockfd;
char *key;
char *pathname;
struct in_addr *serv_addr;
{
struct {
n_long h[RPC_HEADER_WORDS];
n_long d[64];
} sdata;
struct {
n_long h[RPC_HEADER_WORDS];
n_long d[128];
} rdata;
char serv_name[FNAME_SIZE];
char *send_tail, *recv_head;
/* misc... */
struct iodesc *d;
int sn_len, path_len, rlen;
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
return (-1);
}
send_tail = (char*) sdata.d;
recv_head = (char*) rdata.d;
/*
* Build request message.
*/
/* client name (hostname) */
if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
RPC_PRINTF(("bp_getfile: bad client\n"));
return (-1);
}
/* key name (root or swap) */
if (xdr_string_encode(&send_tail, key, strlen(key))) {
RPC_PRINTF(("bp_getfile: bad key\n"));
return (-1);
}
/* RPC: bootparam/getfile */
d->myport = htons(--rpc_port);
d->destip = bp_server_addr;
/* rpc_call will set d->destport */
rlen = rpc_call(d,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
sdata.d, send_tail - (char*)sdata.d,
rdata.d, sizeof(rdata.d));
if (rlen < 4) {
RPC_PRINTF(("bp_getfile: short reply\n"));
errno = EBADRPC;
return (-1);
}
recv_head = (char*) rdata.d;
/*
* Parse result message.
*/
/* server name */
sn_len = FNAME_SIZE-1;
if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
RPC_PRINTF(("bp_getfile: bad server name\n"));
return (-1);
}
/* server IP address (mountd/NFS) */
if (xdr_inaddr_decode(&recv_head, serv_addr)) {
RPC_PRINTF(("bp_getfile: bad server addr\n"));
return (-1);
}
/* server pathname */
path_len = MAXPATHLEN-1;
if (xdr_string_decode(&recv_head, pathname, &path_len)) {
RPC_PRINTF(("bp_getfile: bad server path\n"));
return (-1);
}
/* success */
return(0);
}
/*
* eXternal Data Representation routines.
* (but with non-standard args...)
*/
int
xdr_string_encode(pkt, str, len)
char **pkt;
char *str;
int len;
{
u_int32_t *lenp;
char *datap;
int padlen = (len + 3) & ~3; /* padded length */
/* The data will be int aligned. */
lenp = (u_int32_t*) *pkt;
*pkt += sizeof(*lenp);
*lenp = htonl(len);
datap = *pkt;
*pkt += padlen;
bcopy(str, datap, len);
return (0);
}
int
xdr_string_decode(pkt, str, len_p)
char **pkt;
char *str;
int *len_p; /* bufsize - 1 */
{
u_int32_t *lenp;
char *datap;
int slen; /* string length */
int plen; /* padded length */
/* The data will be int aligned. */
lenp = (u_int32_t*) *pkt;
*pkt += sizeof(*lenp);
slen = ntohl(*lenp);
plen = (slen + 3) & ~3;
if (slen > *len_p)
slen = *len_p;
datap = *pkt;
*pkt += plen;
bcopy(datap, str, slen);
str[slen] = '\0';
*len_p = slen;
return (0);
}
int
xdr_inaddr_encode(pkt, ia)
char **pkt;
struct in_addr ia; /* network order */
{
struct xdr_inaddr *xi;
u_char *cp;
int32_t *ip;
union {
n_long l; /* network order */
u_char c[4];
} uia;
/* The data will be int aligned. */
xi = (struct xdr_inaddr *) *pkt;
*pkt += sizeof(*xi);
xi->atype = htonl(1);
uia.l = ia.s_addr;
cp = uia.c;
ip = xi->addr;
/*
* Note: the htonl() calls below DO NOT
* imply that uia.l is in host order.
* In fact this needs it in net order.
*/
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
return (0);
}
int
xdr_inaddr_decode(pkt, ia)
char **pkt;
struct in_addr *ia; /* network order */
{
struct xdr_inaddr *xi;
u_char *cp;
int32_t *ip;
union {
n_long l; /* network order */
u_char c[4];
} uia;
/* The data will be int aligned. */
xi = (struct xdr_inaddr *) *pkt;
*pkt += sizeof(*xi);
if (xi->atype != htonl(1)) {
RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
ntohl(xi->atype)));
return(-1);
}
cp = uia.c;
ip = xi->addr;
/*
* Note: the ntohl() calls below DO NOT
* imply that uia.l is in host order.
* In fact this needs it in net order.
*/
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
ia->s_addr = uia.l;
return (0);
}