138451Smsmith/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ 238451Smsmith 338451Smsmith/* 438451Smsmith * Copyright (c) 1992 Regents of the University of California. 538451Smsmith * All rights reserved. 638451Smsmith * 738451Smsmith * This software was developed by the Computer Systems Engineering group 838451Smsmith * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 938451Smsmith * contributed to Berkeley. 1038451Smsmith * 1138451Smsmith * Redistribution and use in source and binary forms, with or without 1238451Smsmith * modification, are permitted provided that the following conditions 1338451Smsmith * are met: 1438451Smsmith * 1. Redistributions of source code must retain the above copyright 1538451Smsmith * notice, this list of conditions and the following disclaimer. 1638451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1738451Smsmith * notice, this list of conditions and the following disclaimer in the 1838451Smsmith * documentation and/or other materials provided with the distribution. 1938451Smsmith * 4. Neither the name of the University nor the names of its contributors 2038451Smsmith * may be used to endorse or promote products derived from this software 2138451Smsmith * without specific prior written permission. 2238451Smsmith * 2338451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338451Smsmith * SUCH DAMAGE. 3438451Smsmith * 3538451Smsmith * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 3638451Smsmith */ 3738451Smsmith 3884221Sdillon#include <sys/cdefs.h> 3984221Sdillon__FBSDID("$FreeBSD$"); 4084221Sdillon 4138451Smsmith/* 4238451Smsmith * RPC functions used by NFS and bootparams. 4338451Smsmith * Note that bootparams requires the ability to find out the 4438451Smsmith * address of the server from which its response has come. 4538451Smsmith * This is supported by keeping the IP/UDP headers in the 4638451Smsmith * buffer space provided by the caller. (See rpc_fromaddr) 4738451Smsmith */ 4838451Smsmith 4938451Smsmith#include <sys/param.h> 5038451Smsmith#include <sys/socket.h> 5138451Smsmith 5238451Smsmith#include <netinet/in.h> 5338451Smsmith#include <netinet/in_systm.h> 5438451Smsmith 5538451Smsmith#include <string.h> 5638451Smsmith 5738451Smsmith#include "rpcv2.h" 5838451Smsmith 5938451Smsmith#include "stand.h" 6038451Smsmith#include "net.h" 6138451Smsmith#include "netif.h" 6238451Smsmith#include "rpc.h" 6338451Smsmith 6438451Smsmithstruct auth_info { 6538451Smsmith int32_t authtype; /* auth type */ 6638451Smsmith u_int32_t authlen; /* auth length */ 6738451Smsmith}; 6838451Smsmith 6938451Smsmithstruct auth_unix { 7038451Smsmith int32_t ua_time; 7138451Smsmith int32_t ua_hostname; /* null */ 7238451Smsmith int32_t ua_uid; 7338451Smsmith int32_t ua_gid; 7438451Smsmith int32_t ua_gidlist; /* null */ 7538451Smsmith}; 7638451Smsmith 7738451Smsmithstruct rpc_call { 7838451Smsmith u_int32_t rp_xid; /* request transaction id */ 7938451Smsmith int32_t rp_direction; /* call direction (0) */ 8038451Smsmith u_int32_t rp_rpcvers; /* rpc version (2) */ 8138451Smsmith u_int32_t rp_prog; /* program */ 8238451Smsmith u_int32_t rp_vers; /* version */ 8338451Smsmith u_int32_t rp_proc; /* procedure */ 8438451Smsmith}; 8538451Smsmith 8638451Smsmithstruct rpc_reply { 8738451Smsmith u_int32_t rp_xid; /* request transaction id */ 8838451Smsmith int32_t rp_direction; /* call direction (1) */ 8938451Smsmith int32_t rp_astatus; /* accept status (0: accepted) */ 9038451Smsmith union { 9138451Smsmith u_int32_t rpu_errno; 9238451Smsmith struct { 9338451Smsmith struct auth_info rok_auth; 9438451Smsmith u_int32_t rok_status; 9538451Smsmith } rpu_rok; 9638451Smsmith } rp_u; 9738451Smsmith}; 9838451Smsmith 9938451Smsmith/* Local forwards */ 10038451Smsmithstatic ssize_t recvrpc(struct iodesc *, void *, size_t, time_t); 10138451Smsmithstatic int rpc_getport(struct iodesc *, n_long, n_long); 10238451Smsmith 10338451Smsmithint rpc_xid; 10438451Smsmithint rpc_port = 0x400; /* predecrement */ 10538451Smsmith 10638451Smsmith/* 10738451Smsmith * Make a rpc call; return length of answer 10838451Smsmith * Note: Caller must leave room for headers. 10938451Smsmith */ 11038451Smsmithssize_t 111197178Semasterpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, 112197178Semaste void *sdata, size_t slen, void *rdata, size_t rlen) 11338451Smsmith{ 11492913Sobrien ssize_t cc; 11538451Smsmith struct auth_info *auth; 11638451Smsmith struct rpc_call *call; 11738451Smsmith struct rpc_reply *reply; 11838451Smsmith char *send_head, *send_tail; 11938451Smsmith char *recv_head, *recv_tail; 12038451Smsmith n_long x; 12138451Smsmith int port; /* host order */ 12238451Smsmith 12338451Smsmith#ifdef RPC_DEBUG 12438451Smsmith if (debug) 12538451Smsmith printf("rpc_call: prog=0x%x vers=%d proc=%d\n", 12638451Smsmith prog, vers, proc); 12738451Smsmith#endif 12838451Smsmith 12938451Smsmith port = rpc_getport(d, prog, vers); 13038451Smsmith if (port == -1) 13138451Smsmith return (-1); 13238451Smsmith 13338451Smsmith d->destport = htons(port); 13438451Smsmith 13538451Smsmith /* 13638451Smsmith * Prepend authorization stuff and headers. 13738451Smsmith * Note, must prepend things in reverse order. 13838451Smsmith */ 13938451Smsmith send_head = sdata; 14038451Smsmith send_tail = (char *)sdata + slen; 14138451Smsmith 14238451Smsmith /* Auth verifier is always auth_null */ 14338451Smsmith send_head -= sizeof(*auth); 14438451Smsmith auth = (struct auth_info *)send_head; 14538451Smsmith auth->authtype = htonl(RPCAUTH_NULL); 14638451Smsmith auth->authlen = 0; 14738451Smsmith 14838451Smsmith#if 1 14938451Smsmith /* Auth credentials: always auth unix (as root) */ 15038451Smsmith send_head -= sizeof(struct auth_unix); 15138451Smsmith bzero(send_head, sizeof(struct auth_unix)); 15238451Smsmith send_head -= sizeof(*auth); 15338451Smsmith auth = (struct auth_info *)send_head; 15438451Smsmith auth->authtype = htonl(RPCAUTH_UNIX); 15538451Smsmith auth->authlen = htonl(sizeof(struct auth_unix)); 15638451Smsmith#else 15738451Smsmith /* Auth credentials: always auth_null (XXX OK?) */ 15838451Smsmith send_head -= sizeof(*auth); 15938451Smsmith auth = send_head; 16038451Smsmith auth->authtype = htonl(RPCAUTH_NULL); 16138451Smsmith auth->authlen = 0; 16238451Smsmith#endif 16338451Smsmith 16438451Smsmith /* RPC call structure. */ 16538451Smsmith send_head -= sizeof(*call); 16638451Smsmith call = (struct rpc_call *)send_head; 16738451Smsmith rpc_xid++; 16838451Smsmith call->rp_xid = htonl(rpc_xid); 16938451Smsmith call->rp_direction = htonl(RPC_CALL); 17038451Smsmith call->rp_rpcvers = htonl(RPC_VER2); 17138451Smsmith call->rp_prog = htonl(prog); 17238451Smsmith call->rp_vers = htonl(vers); 17338451Smsmith call->rp_proc = htonl(proc); 17438451Smsmith 17538451Smsmith /* Make room for the rpc_reply header. */ 17638451Smsmith recv_head = rdata; 17738451Smsmith recv_tail = (char *)rdata + rlen; 17838451Smsmith recv_head -= sizeof(*reply); 17938451Smsmith 18038451Smsmith cc = sendrecv(d, 18138451Smsmith sendudp, send_head, send_tail - send_head, 18238451Smsmith recvrpc, recv_head, recv_tail - recv_head); 18338451Smsmith 18438451Smsmith#ifdef RPC_DEBUG 18538451Smsmith if (debug) 18638451Smsmith printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); 18738451Smsmith#endif 18838451Smsmith if (cc == -1) 18938451Smsmith return (-1); 19038451Smsmith 19138451Smsmith if (cc <= sizeof(*reply)) { 19238451Smsmith errno = EBADRPC; 19338451Smsmith return (-1); 19438451Smsmith } 19538451Smsmith 19638451Smsmith recv_tail = recv_head + cc; 19738451Smsmith 19838451Smsmith /* 19938451Smsmith * Check the RPC reply status. 20038451Smsmith * The xid, dir, astatus were already checked. 20138451Smsmith */ 20238451Smsmith reply = (struct rpc_reply *)recv_head; 20338451Smsmith auth = &reply->rp_u.rpu_rok.rok_auth; 20438451Smsmith x = ntohl(auth->authlen); 20538451Smsmith if (x != 0) { 20638451Smsmith#ifdef RPC_DEBUG 20738451Smsmith if (debug) 20838451Smsmith printf("callrpc: reply auth != NULL\n"); 20938451Smsmith#endif 21038451Smsmith errno = EBADRPC; 21138451Smsmith return(-1); 21238451Smsmith } 21338451Smsmith x = ntohl(reply->rp_u.rpu_rok.rok_status); 21438451Smsmith if (x != 0) { 21538451Smsmith printf("callrpc: error = %ld\n", (long)x); 21638451Smsmith errno = EBADRPC; 21738451Smsmith return(-1); 21838451Smsmith } 21938451Smsmith recv_head += sizeof(*reply); 22038451Smsmith 22138451Smsmith return (ssize_t)(recv_tail - recv_head); 22238451Smsmith} 22338451Smsmith 22438451Smsmith/* 22538451Smsmith * Returns true if packet is the one we're waiting for. 22638451Smsmith * This just checks the XID, direction, acceptance. 22738451Smsmith * Remaining checks are done by callrpc 22838451Smsmith */ 22938451Smsmithstatic ssize_t 230197178Semasterecvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) 23138451Smsmith{ 23292913Sobrien struct rpc_reply *reply; 23338451Smsmith ssize_t n; 23438451Smsmith int x; 23538451Smsmith 23638451Smsmith errno = 0; 23738451Smsmith#ifdef RPC_DEBUG 23838451Smsmith if (debug) 23938451Smsmith printf("recvrpc: called len=%lu\n", (u_long)len); 24038451Smsmith#endif 24138451Smsmith 24238451Smsmith n = readudp(d, pkt, len, tleft); 24338451Smsmith if (n <= (4 * 4)) 24438451Smsmith return -1; 24538451Smsmith 24638451Smsmith reply = (struct rpc_reply *)pkt; 24738451Smsmith 24838451Smsmith x = ntohl(reply->rp_xid); 24938451Smsmith if (x != rpc_xid) { 25038451Smsmith#ifdef RPC_DEBUG 25138451Smsmith if (debug) 25238451Smsmith printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); 25338451Smsmith#endif 25438451Smsmith return -1; 25538451Smsmith } 25638451Smsmith 25738451Smsmith x = ntohl(reply->rp_direction); 25838451Smsmith if (x != RPC_REPLY) { 25938451Smsmith#ifdef RPC_DEBUG 26038451Smsmith if (debug) 26138451Smsmith printf("recvrpc: rp_direction %d != REPLY\n", x); 26238451Smsmith#endif 26338451Smsmith return -1; 26438451Smsmith } 26538451Smsmith 26638451Smsmith x = ntohl(reply->rp_astatus); 26738451Smsmith if (x != RPC_MSGACCEPTED) { 26838451Smsmith errno = ntohl(reply->rp_u.rpu_errno); 26938451Smsmith printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); 27038451Smsmith return -1; 27138451Smsmith } 27238451Smsmith 27338451Smsmith /* Return data count (thus indicating success) */ 27438451Smsmith return (n); 27538451Smsmith} 27638451Smsmith 27738451Smsmith/* 27838451Smsmith * Given a pointer to a reply just received, 27938451Smsmith * dig out the IP address/port from the headers. 28038451Smsmith */ 28138451Smsmithvoid 282197178Semasterpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) 28338451Smsmith{ 28438451Smsmith struct hackhdr { 28538451Smsmith /* Tail of IP header: just IP addresses */ 28638451Smsmith n_long ip_src; 28738451Smsmith n_long ip_dst; 28838451Smsmith /* UDP header: */ 28938451Smsmith u_int16_t uh_sport; /* source port */ 29038451Smsmith u_int16_t uh_dport; /* destination port */ 29138451Smsmith int16_t uh_ulen; /* udp length */ 29238451Smsmith u_int16_t uh_sum; /* udp checksum */ 29338451Smsmith /* RPC reply header: */ 29438451Smsmith struct rpc_reply rpc; 29538451Smsmith } *hhdr; 29638451Smsmith 29738451Smsmith hhdr = ((struct hackhdr *)pkt) - 1; 29838451Smsmith addr->s_addr = hhdr->ip_src; 29938451Smsmith *port = hhdr->uh_sport; 30038451Smsmith} 30138451Smsmith 30238451Smsmith/* 30338451Smsmith * RPC Portmapper cache 30438451Smsmith */ 30538451Smsmith#define PMAP_NUM 8 /* need at most 5 pmap entries */ 30638451Smsmith 30738451Smsmithint rpc_pmap_num; 30838451Smsmithstruct pmap_list { 30938451Smsmith struct in_addr addr; /* server, net order */ 31038451Smsmith u_int prog; /* host order */ 31138451Smsmith u_int vers; /* host order */ 31238451Smsmith int port; /* host order */ 31338451Smsmith} rpc_pmap_list[PMAP_NUM]; 31438451Smsmith 315197178Semaste/* 316197178Semaste * return port number in host order, or -1. 317197178Semaste * arguments are: 318197178Semaste * addr .. server, net order. 319197178Semaste * prog .. host order. 320197178Semaste * vers .. host order. 321197178Semaste */ 32238451Smsmithint 323197178Semasterpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) 32438451Smsmith{ 32538451Smsmith struct pmap_list *pl; 32638451Smsmith 32738451Smsmith for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 32838451Smsmith if (pl->addr.s_addr == addr.s_addr && 32938451Smsmith pl->prog == prog && pl->vers == vers ) 33038451Smsmith { 33138451Smsmith return (pl->port); 33238451Smsmith } 33338451Smsmith } 33438451Smsmith return (-1); 33538451Smsmith} 33638451Smsmith 337197178Semaste/* 338197178Semaste * arguments are: 339197178Semaste * addr .. server, net order. 340197178Semaste * prog .. host order. 341197178Semaste * vers .. host order. 342197178Semaste * port .. host order. 343197178Semaste */ 34438451Smsmithvoid 345197178Semasterpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) 34638451Smsmith{ 34738451Smsmith struct pmap_list *pl; 34838451Smsmith 34938451Smsmith /* Don't overflow cache... */ 35038451Smsmith if (rpc_pmap_num >= PMAP_NUM) { 35138451Smsmith /* ... just re-use the last entry. */ 35238451Smsmith rpc_pmap_num = PMAP_NUM - 1; 35338451Smsmith#ifdef RPC_DEBUG 35438451Smsmith printf("rpc_pmap_putcache: cache overflow\n"); 35538451Smsmith#endif 35638451Smsmith } 35738451Smsmith 35838451Smsmith pl = &rpc_pmap_list[rpc_pmap_num]; 35938451Smsmith rpc_pmap_num++; 36038451Smsmith 36138451Smsmith /* Cache answer */ 36238451Smsmith pl->addr = addr; 36338451Smsmith pl->prog = prog; 36438451Smsmith pl->vers = vers; 36538451Smsmith pl->port = port; 36638451Smsmith} 36738451Smsmith 36838451Smsmith 36938451Smsmith/* 37038451Smsmith * Request a port number from the port mapper. 37138451Smsmith * Returns the port in host order. 372197178Semaste * prog and vers are host order. 37338451Smsmith */ 37438451Smsmithint 375197178Semasterpc_getport(struct iodesc *d, n_long prog, n_long vers) 37638451Smsmith{ 37738451Smsmith struct args { 37838451Smsmith n_long prog; /* call program */ 37938451Smsmith n_long vers; /* call version */ 38038451Smsmith n_long proto; /* call protocol */ 38138451Smsmith n_long port; /* call port (unused) */ 38238451Smsmith } *args; 38338451Smsmith struct res { 38438451Smsmith n_long port; 38538451Smsmith } *res; 38638451Smsmith struct { 38738451Smsmith n_long h[RPC_HEADER_WORDS]; 38838451Smsmith struct args d; 38938451Smsmith } sdata; 39038451Smsmith struct { 39138451Smsmith n_long h[RPC_HEADER_WORDS]; 39238451Smsmith struct res d; 39338451Smsmith n_long pad; 39438451Smsmith } rdata; 39538451Smsmith ssize_t cc; 39638451Smsmith int port; 39738451Smsmith 39838451Smsmith#ifdef RPC_DEBUG 39938451Smsmith if (debug) 400193109Smarcel printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); 40138451Smsmith#endif 40238451Smsmith 40338451Smsmith /* This one is fixed forever. */ 404193109Smarcel if (prog == PMAPPROG) { 405193109Smarcel port = PMAPPORT; 406193109Smarcel goto out; 407193109Smarcel } 40838451Smsmith 40938451Smsmith /* Try for cached answer first */ 41038451Smsmith port = rpc_pmap_getcache(d->destip, prog, vers); 41138451Smsmith if (port != -1) 412193109Smarcel goto out; 41338451Smsmith 41438451Smsmith args = &sdata.d; 41538451Smsmith args->prog = htonl(prog); 41638451Smsmith args->vers = htonl(vers); 41738451Smsmith args->proto = htonl(IPPROTO_UDP); 41838451Smsmith args->port = 0; 41938451Smsmith res = &rdata.d; 42038451Smsmith 42138451Smsmith cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 42238451Smsmith args, sizeof(*args), res, sizeof(*res)); 42338451Smsmith if (cc < sizeof(*res)) { 42438451Smsmith printf("getport: %s", strerror(errno)); 42538451Smsmith errno = EBADRPC; 42638451Smsmith return (-1); 42738451Smsmith } 42838451Smsmith port = (int)ntohl(res->port); 42938451Smsmith 43038451Smsmith rpc_pmap_putcache(d->destip, prog, vers, port); 43138451Smsmith 432193109Smarcelout: 433193109Smarcel#ifdef RPC_DEBUG 434193109Smarcel if (debug) 435193109Smarcel printf("%s: port=%u\n", __func__, port); 436193109Smarcel#endif 43738451Smsmith return (port); 43838451Smsmith} 439