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: stable/11/stand/libsa/rpc.c 332154 2018-04-06 21:37:25Z kevans $"); 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 */ 66332154Skevans uint32_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 { 78332154Skevans uint32_t rp_xid; /* request transaction id */ 7938451Smsmith int32_t rp_direction; /* call direction (0) */ 80332154Skevans uint32_t rp_rpcvers; /* rpc version (2) */ 81332154Skevans uint32_t rp_prog; /* program */ 82332154Skevans uint32_t rp_vers; /* version */ 83332154Skevans uint32_t rp_proc; /* procedure */ 8438451Smsmith}; 8538451Smsmith 8638451Smsmithstruct rpc_reply { 87332154Skevans uint32_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 { 91332154Skevans uint32_t rpu_errno; 9238451Smsmith struct { 9338451Smsmith struct auth_info rok_auth; 94332154Skevans uint32_t rok_status; 9538451Smsmith } rpu_rok; 9638451Smsmith } rp_u; 9738451Smsmith}; 9838451Smsmith 9938451Smsmith/* Local forwards */ 100330898Skevansstatic ssize_t recvrpc(struct iodesc *, void **, void **, time_t, void *); 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, 112329100Skevans void *sdata, size_t slen, void **rdata, void **pkt) 11338451Smsmith{ 114329100Skevans ssize_t cc, rsize; 11538451Smsmith struct auth_info *auth; 11638451Smsmith struct rpc_call *call; 11738451Smsmith struct rpc_reply *reply; 11838451Smsmith char *send_head, *send_tail; 119329100Skevans void *ptr; 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 /* Auth credentials: always auth unix (as root) */ 14938451Smsmith send_head -= sizeof(struct auth_unix); 15038451Smsmith bzero(send_head, sizeof(struct auth_unix)); 15138451Smsmith send_head -= sizeof(*auth); 15238451Smsmith auth = (struct auth_info *)send_head; 15338451Smsmith auth->authtype = htonl(RPCAUTH_UNIX); 15438451Smsmith auth->authlen = htonl(sizeof(struct auth_unix)); 15538451Smsmith 15638451Smsmith /* RPC call structure. */ 15738451Smsmith send_head -= sizeof(*call); 15838451Smsmith call = (struct rpc_call *)send_head; 15938451Smsmith rpc_xid++; 16038451Smsmith call->rp_xid = htonl(rpc_xid); 16138451Smsmith call->rp_direction = htonl(RPC_CALL); 16238451Smsmith call->rp_rpcvers = htonl(RPC_VER2); 16338451Smsmith call->rp_prog = htonl(prog); 16438451Smsmith call->rp_vers = htonl(vers); 16538451Smsmith call->rp_proc = htonl(proc); 16638451Smsmith 167329100Skevans ptr = NULL; 16838451Smsmith cc = sendrecv(d, 16938451Smsmith sendudp, send_head, send_tail - send_head, 170330898Skevans recvrpc, &ptr, (void **)&reply, NULL); 17138451Smsmith 17238451Smsmith#ifdef RPC_DEBUG 17338451Smsmith if (debug) 174329100Skevans printf("callrpc: cc=%zd\n", cc); 17538451Smsmith#endif 17638451Smsmith if (cc == -1) 17738451Smsmith return (-1); 17838451Smsmith 17938451Smsmith if (cc <= sizeof(*reply)) { 18038451Smsmith errno = EBADRPC; 181329100Skevans free(ptr); 18238451Smsmith return (-1); 18338451Smsmith } 18438451Smsmith 18538451Smsmith /* 18638451Smsmith * Check the RPC reply status. 18738451Smsmith * The xid, dir, astatus were already checked. 18838451Smsmith */ 18938451Smsmith auth = &reply->rp_u.rpu_rok.rok_auth; 19038451Smsmith x = ntohl(auth->authlen); 19138451Smsmith if (x != 0) { 19238451Smsmith#ifdef RPC_DEBUG 19338451Smsmith if (debug) 19438451Smsmith printf("callrpc: reply auth != NULL\n"); 19538451Smsmith#endif 19638451Smsmith errno = EBADRPC; 197329100Skevans free(ptr); 198329100Skevans return (-1); 19938451Smsmith } 20038451Smsmith x = ntohl(reply->rp_u.rpu_rok.rok_status); 20138451Smsmith if (x != 0) { 20238451Smsmith printf("callrpc: error = %ld\n", (long)x); 20338451Smsmith errno = EBADRPC; 204329100Skevans free(ptr); 205329100Skevans return (-1); 20638451Smsmith } 20738451Smsmith 208329100Skevans rsize = cc - sizeof(*reply); 209329100Skevans *rdata = (void *)((uintptr_t)reply + sizeof(*reply)); 210329100Skevans *pkt = ptr; 211329100Skevans return (rsize); 21238451Smsmith} 21338451Smsmith 21438451Smsmith/* 21538451Smsmith * Returns true if packet is the one we're waiting for. 21638451Smsmith * This just checks the XID, direction, acceptance. 21738451Smsmith * Remaining checks are done by callrpc 21838451Smsmith */ 21938451Smsmithstatic ssize_t 220330898Skevansrecvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra) 22138451Smsmith{ 222329100Skevans void *ptr; 22392913Sobrien struct rpc_reply *reply; 22438451Smsmith ssize_t n; 22538451Smsmith int x; 22638451Smsmith 22738451Smsmith errno = 0; 22838451Smsmith#ifdef RPC_DEBUG 22938451Smsmith if (debug) 230329100Skevans printf("recvrpc: called\n"); 23138451Smsmith#endif 23238451Smsmith 233329100Skevans ptr = NULL; 234329100Skevans n = readudp(d, &ptr, (void **)&reply, tleft); 235329100Skevans if (n <= (4 * 4)) { 236329100Skevans free(ptr); 237329100Skevans return (-1); 238329100Skevans } 23938451Smsmith 24038451Smsmith x = ntohl(reply->rp_xid); 24138451Smsmith if (x != rpc_xid) { 24238451Smsmith#ifdef RPC_DEBUG 24338451Smsmith if (debug) 24438451Smsmith printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); 24538451Smsmith#endif 246329100Skevans free(ptr); 247329100Skevans return (-1); 24838451Smsmith } 24938451Smsmith 25038451Smsmith x = ntohl(reply->rp_direction); 25138451Smsmith if (x != RPC_REPLY) { 25238451Smsmith#ifdef RPC_DEBUG 25338451Smsmith if (debug) 25438451Smsmith printf("recvrpc: rp_direction %d != REPLY\n", x); 25538451Smsmith#endif 256329100Skevans free(ptr); 257329100Skevans return (-1); 25838451Smsmith } 25938451Smsmith 26038451Smsmith x = ntohl(reply->rp_astatus); 26138451Smsmith if (x != RPC_MSGACCEPTED) { 26238451Smsmith errno = ntohl(reply->rp_u.rpu_errno); 26338451Smsmith printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); 264329100Skevans free(ptr); 265329100Skevans return (-1); 26638451Smsmith } 26738451Smsmith 268329100Skevans *pkt = ptr; 269329100Skevans *payload = reply; 27038451Smsmith /* Return data count (thus indicating success) */ 27138451Smsmith return (n); 27238451Smsmith} 27338451Smsmith 27438451Smsmith/* 27538451Smsmith * Given a pointer to a reply just received, 27638451Smsmith * dig out the IP address/port from the headers. 27738451Smsmith */ 27838451Smsmithvoid 279197178Semasterpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) 28038451Smsmith{ 28138451Smsmith struct hackhdr { 28238451Smsmith /* Tail of IP header: just IP addresses */ 28338451Smsmith n_long ip_src; 28438451Smsmith n_long ip_dst; 28538451Smsmith /* UDP header: */ 286332154Skevans uint16_t uh_sport; /* source port */ 287332154Skevans uint16_t uh_dport; /* destination port */ 28838451Smsmith int16_t uh_ulen; /* udp length */ 289332154Skevans uint16_t uh_sum; /* udp checksum */ 29038451Smsmith /* RPC reply header: */ 29138451Smsmith struct rpc_reply rpc; 29238451Smsmith } *hhdr; 29338451Smsmith 29438451Smsmith hhdr = ((struct hackhdr *)pkt) - 1; 29538451Smsmith addr->s_addr = hhdr->ip_src; 29638451Smsmith *port = hhdr->uh_sport; 29738451Smsmith} 29838451Smsmith 29938451Smsmith/* 30038451Smsmith * RPC Portmapper cache 30138451Smsmith */ 30238451Smsmith#define PMAP_NUM 8 /* need at most 5 pmap entries */ 30338451Smsmith 30438451Smsmithint rpc_pmap_num; 30538451Smsmithstruct pmap_list { 30638451Smsmith struct in_addr addr; /* server, net order */ 30738451Smsmith u_int prog; /* host order */ 30838451Smsmith u_int vers; /* host order */ 30938451Smsmith int port; /* host order */ 31038451Smsmith} rpc_pmap_list[PMAP_NUM]; 31138451Smsmith 312197178Semaste/* 313197178Semaste * return port number in host order, or -1. 314197178Semaste * arguments are: 315197178Semaste * addr .. server, net order. 316197178Semaste * prog .. host order. 317197178Semaste * vers .. host order. 318197178Semaste */ 31938451Smsmithint 320197178Semasterpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) 32138451Smsmith{ 32238451Smsmith struct pmap_list *pl; 32338451Smsmith 32438451Smsmith for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 32538451Smsmith if (pl->addr.s_addr == addr.s_addr && 32638451Smsmith pl->prog == prog && pl->vers == vers ) 32738451Smsmith { 32838451Smsmith return (pl->port); 32938451Smsmith } 33038451Smsmith } 33138451Smsmith return (-1); 33238451Smsmith} 33338451Smsmith 334197178Semaste/* 335197178Semaste * arguments are: 336197178Semaste * addr .. server, net order. 337197178Semaste * prog .. host order. 338197178Semaste * vers .. host order. 339197178Semaste * port .. host order. 340197178Semaste */ 34138451Smsmithvoid 342197178Semasterpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) 34338451Smsmith{ 34438451Smsmith struct pmap_list *pl; 34538451Smsmith 34638451Smsmith /* Don't overflow cache... */ 34738451Smsmith if (rpc_pmap_num >= PMAP_NUM) { 34838451Smsmith /* ... just re-use the last entry. */ 34938451Smsmith rpc_pmap_num = PMAP_NUM - 1; 35038451Smsmith#ifdef RPC_DEBUG 35138451Smsmith printf("rpc_pmap_putcache: cache overflow\n"); 35238451Smsmith#endif 35338451Smsmith } 35438451Smsmith 35538451Smsmith pl = &rpc_pmap_list[rpc_pmap_num]; 35638451Smsmith rpc_pmap_num++; 35738451Smsmith 35838451Smsmith /* Cache answer */ 35938451Smsmith pl->addr = addr; 36038451Smsmith pl->prog = prog; 36138451Smsmith pl->vers = vers; 36238451Smsmith pl->port = port; 36338451Smsmith} 36438451Smsmith 36538451Smsmith 36638451Smsmith/* 36738451Smsmith * Request a port number from the port mapper. 36838451Smsmith * Returns the port in host order. 369197178Semaste * prog and vers are host order. 37038451Smsmith */ 37138451Smsmithint 372197178Semasterpc_getport(struct iodesc *d, n_long prog, n_long vers) 37338451Smsmith{ 37438451Smsmith struct args { 37538451Smsmith n_long prog; /* call program */ 37638451Smsmith n_long vers; /* call version */ 37738451Smsmith n_long proto; /* call protocol */ 37838451Smsmith n_long port; /* call port (unused) */ 37938451Smsmith } *args; 38038451Smsmith struct res { 38138451Smsmith n_long port; 38238451Smsmith } *res; 38338451Smsmith struct { 38438451Smsmith n_long h[RPC_HEADER_WORDS]; 38538451Smsmith struct args d; 38638451Smsmith } sdata; 387329100Skevans void *pkt; 38838451Smsmith ssize_t cc; 38938451Smsmith int port; 39038451Smsmith 39138451Smsmith#ifdef RPC_DEBUG 39238451Smsmith if (debug) 393193109Smarcel printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); 39438451Smsmith#endif 39538451Smsmith 39638451Smsmith /* This one is fixed forever. */ 397193109Smarcel if (prog == PMAPPROG) { 398193109Smarcel port = PMAPPORT; 399193109Smarcel goto out; 400193109Smarcel } 40138451Smsmith 40238451Smsmith /* Try for cached answer first */ 40338451Smsmith port = rpc_pmap_getcache(d->destip, prog, vers); 40438451Smsmith if (port != -1) 405193109Smarcel goto out; 40638451Smsmith 40738451Smsmith args = &sdata.d; 40838451Smsmith args->prog = htonl(prog); 40938451Smsmith args->vers = htonl(vers); 41038451Smsmith args->proto = htonl(IPPROTO_UDP); 41138451Smsmith args->port = 0; 412329100Skevans pkt = NULL; 41338451Smsmith 41438451Smsmith cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 415329100Skevans args, sizeof(*args), (void **)&res, &pkt); 41638451Smsmith if (cc < sizeof(*res)) { 41738451Smsmith printf("getport: %s", strerror(errno)); 41838451Smsmith errno = EBADRPC; 419329100Skevans free(pkt); 42038451Smsmith return (-1); 42138451Smsmith } 42238451Smsmith port = (int)ntohl(res->port); 423329100Skevans free(pkt); 42438451Smsmith 42538451Smsmith rpc_pmap_putcache(d->destip, prog, vers, port); 42638451Smsmith 427193109Smarcelout: 428193109Smarcel#ifdef RPC_DEBUG 429193109Smarcel if (debug) 430193109Smarcel printf("%s: port=%u\n", __func__, port); 431193109Smarcel#endif 43238451Smsmith return (port); 43338451Smsmith} 434