/*
* 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.
*
* 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.
*/
/*
* Inet address in RPC messages
* (Note, really four ints, NOT chars. Blech.)
*/
struct xdr_inaddr {
uint32_t atype;
int32_t addr[4];
};
int xdr_inaddr_encode(char **, struct in_addr);
int xdr_inaddr_decode(char **, struct in_addr *);
int xdr_string_encode(char **, char *, uint32_t);
int xdr_string_decode(char **, char *, uint32_t *);
/*
* 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(int sockfd)
{
/* RPC structures for PMAPPROC_CALLIT */
struct args {
uint32_t prog;
uint32_t vers;
uint32_t proc;
uint32_t arglen;
struct xdr_inaddr xina;
} *args;
struct repl {
uint16_t _pad;
uint16_t port;
uint32_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;
uint32_t x;
ssize_t len;
/* 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(("%s: server at %s:%d\n", __func__,
inet_ntoa(bp_server_addr), ntohs((uint16_t)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((uint16_t)bp_server_port));
/*
* Parse the encapsulated results from bootparam/whoami
*/
x = ntohl((uint32_t)repl->encap_len);
if (len < x) {
printf("%s: short reply, %zd < %d\n", __func__, len, x);
return -1;
}
recv_head = (char *)repl->capsule;
/* client name */
hostnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
RPC_PRINTF(("%s: bad hostname\n", __func__));
return -1;
}
/* domain name */
domainnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
RPC_PRINTF(("%s: bad domainname\n", __func__));
return -1;
}
/* gateway address */
if (xdr_inaddr_decode(&recv_head, &gateip)) {
RPC_PRINTF(("%s: bad gateway\n", __func__));
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(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
{
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;
uint32_t sn_len, path_len;
ssize_t rlen;
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("%s: bad socket. %d\n", __func__, sockfd));
return -1;
}
/* server name */
sn_len = FNAME_SIZE - 1;
if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
RPC_PRINTF(("%s: bad server name\n", __func__));
return -1;
}
/* server IP address (mountd/NFS) */
if (xdr_inaddr_decode(&recv_head, serv_addr)) {
RPC_PRINTF(("%s: bad server addr\n", __func__));
return -1;
}
/* server pathname */
path_len = MAXPATHLEN - 1;
if (xdr_string_decode(&recv_head, pathname, &path_len)) {
RPC_PRINTF(("%s: bad server path\n", __func__));
return -1;
}
/* success */
return 0;
}
/*
* eXternal Data Representation routines.
* (but with non-standard args...)
*/
/* ia: network order */
int
xdr_inaddr_encode(char **pkt, struct in_addr ia)
{
struct xdr_inaddr *xi;
u_char *cp;
uint32_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 = (uint32_t *)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((uint32_t)*cp++);
*ip++ = htonl((uint32_t)*cp++);
*ip++ = htonl((uint32_t)*cp++);
*ip++ = htonl((uint32_t)*cp++);
return 0;
}
/* ia: network order */
int
xdr_inaddr_decode(char **pkt, struct in_addr *ia)
{
struct xdr_inaddr *xi;
u_char *cp;
uint32_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((uint32_t)1)) {
RPC_PRINTF(("%s: bad addrtype=%d\n", __func__,
ntohl((uint32_t)nxi->atype)));
return -1;
}
cp = uia.c;
ip = (uint32_t *)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++ = (u_char)ntohl(*ip++);
*cp++ = (u_char)ntohl(*ip++);
*cp++ = (u_char)ntohl(*ip++);
*cp++ = (u_char)ntohl(*ip++);
ia->s_addr = uia.l;