125723Stegge/* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ 225723Stegge 3139823Simp/*- 425723Stegge * Copyright (c) 1995 Gordon Ross, Adam Glass 525723Stegge * Copyright (c) 1992 Regents of the University of California. 625723Stegge * All rights reserved. 725723Stegge * 825723Stegge * This software was developed by the Computer Systems Engineering group 925723Stegge * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 1025723Stegge * contributed to Berkeley. 1125723Stegge * 1225723Stegge * Redistribution and use in source and binary forms, with or without 1325723Stegge * modification, are permitted provided that the following conditions 1425723Stegge * are met: 1525723Stegge * 1. Redistributions of source code must retain the above copyright 1625723Stegge * notice, this list of conditions and the following disclaimer. 1725723Stegge * 2. Redistributions in binary form must reproduce the above copyright 1825723Stegge * notice, this list of conditions and the following disclaimer in the 1925723Stegge * documentation and/or other materials provided with the distribution. 2025723Stegge * 3. All advertising materials mentioning features or use of this software 2125723Stegge * must display the following acknowledgement: 2225723Stegge * This product includes software developed by the University of 2325723Stegge * California, Lawrence Berkeley Laboratory and its contributors. 2425723Stegge * 4. Neither the name of the University nor the names of its contributors 2525723Stegge * may be used to endorse or promote products derived from this software 2625723Stegge * without specific prior written permission. 2725723Stegge * 2825723Stegge * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2925723Stegge * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3025723Stegge * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3125723Stegge * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3225723Stegge * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3325723Stegge * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3425723Stegge * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3525723Stegge * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3625723Stegge * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3725723Stegge * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3825723Stegge * SUCH DAMAGE. 3925723Stegge * 4025723Stegge * partially based on: 4125723Stegge * libnetboot/rpc.c 4225723Stegge * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 4325723Stegge */ 4425723Stegge 4583651Speter#include <sys/cdefs.h> 4683651Speter__FBSDID("$FreeBSD$"); 4783651Speter 4825723Stegge#include <sys/param.h> 4925723Stegge#include <sys/systm.h> 50201044Sbz#include <sys/jail.h> 5130354Sphk#include <sys/malloc.h> 5225723Stegge#include <sys/mbuf.h> 5388743Srwatson#include <sys/proc.h> 5425723Stegge#include <sys/socket.h> 5525723Stegge#include <sys/socketvar.h> 5634924Sbde#include <sys/uio.h> 5725723Stegge 5825723Stegge#include <net/if.h> 59200471Sbz#include <net/vnet.h> 60200471Sbz 6125723Stegge#include <netinet/in.h> 6225723Stegge 63195202Sdfr#include <rpc/types.h> 64195202Sdfr#include <rpc/auth.h> 65195202Sdfr#include <rpc/rpc_msg.h> 66221032Srmacklem#include <nfs/krpc.h> 6725723Stegge#include <nfs/xdr_subs.h> 6825723Stegge 6925723Stegge/* 7025723Stegge * Kernel support for Sun RPC 7125723Stegge * 7225723Stegge * Used currently for bootstrapping in nfs diskless configurations. 7325723Stegge */ 7425723Stegge 7525723Stegge/* 7625723Stegge * Generic RPC headers 7725723Stegge */ 7825723Stegge 7925723Steggestruct auth_info { 8025723Stegge u_int32_t authtype; /* auth type */ 8125723Stegge u_int32_t authlen; /* auth length */ 8225723Stegge}; 8325723Stegge 8425723Steggestruct auth_unix { 8525723Stegge int32_t ua_time; 8625723Stegge int32_t ua_hostname; /* null */ 8725723Stegge int32_t ua_uid; 8825723Stegge int32_t ua_gid; 8925723Stegge int32_t ua_gidlist; /* null */ 9025723Stegge}; 9125723Stegge 92122719Salfredstruct krpc_call { 9325723Stegge u_int32_t rp_xid; /* request transaction id */ 9425723Stegge int32_t rp_direction; /* call direction (0) */ 9525723Stegge u_int32_t rp_rpcvers; /* rpc version (2) */ 9625723Stegge u_int32_t rp_prog; /* program */ 9725723Stegge u_int32_t rp_vers; /* version */ 9825723Stegge u_int32_t rp_proc; /* procedure */ 9925723Stegge struct auth_info rpc_auth; 10025723Stegge struct auth_unix rpc_unix; 10125723Stegge struct auth_info rpc_verf; 10225723Stegge}; 10325723Stegge 104122719Salfredstruct krpc_reply { 10525723Stegge u_int32_t rp_xid; /* request transaction id */ 10625723Stegge int32_t rp_direction; /* call direction (1) */ 10725723Stegge int32_t rp_astatus; /* accept status (0: accepted) */ 10825723Stegge union { 10925723Stegge u_int32_t rpu_errno; 11025723Stegge struct { 11125723Stegge struct auth_info rok_auth; 11225723Stegge u_int32_t rok_status; 11325723Stegge } rpu_rok; 11425723Stegge } rp_u; 11525723Stegge}; 11625723Stegge#define rp_errno rp_u.rpu_errno 11725723Stegge#define rp_auth rp_u.rpu_rok.rok_auth 11825723Stegge#define rp_status rp_u.rpu_rok.rok_status 11925723Stegge 12025723Stegge#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 12125723Stegge 12225723Stegge/* 12325723Stegge * What is the longest we will wait before re-sending a request? 12425723Stegge * Note this is also the frequency of "RPC timeout" messages. 12525723Stegge * The re-send loop count sup linearly to this maximum, so the 12625723Stegge * first complaint will happen after (1+2+3+4+5)=15 seconds. 12725723Stegge */ 12825723Stegge#define MAX_RESEND_DELAY 5 /* seconds */ 12925723Stegge 13025723Stegge/* 13125723Stegge * Call portmap to lookup a port number for a particular rpc program 13225723Stegge * Returns non-zero error on failure. 13325723Stegge */ 13425723Steggeint 13583651Speterkrpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp, 13683651Speter struct thread *td) 13725723Stegge{ 13825723Stegge struct sdata { 13925723Stegge u_int32_t prog; /* call program */ 14025723Stegge u_int32_t vers; /* call version */ 14125723Stegge u_int32_t proto; /* call protocol */ 14225723Stegge u_int32_t port; /* call port (unused) */ 14325723Stegge } *sdata; 14425723Stegge struct rdata { 14525723Stegge u_int16_t pad; 14625723Stegge u_int16_t port; 14725723Stegge } *rdata; 14825723Stegge struct mbuf *m; 14925723Stegge int error; 15025723Stegge 15125723Stegge /* The portmapper port is fixed. */ 15225723Stegge if (prog == PMAPPROG) { 15325723Stegge *portp = htons(PMAPPORT); 15425723Stegge return 0; 15525723Stegge } 15625723Stegge 157243882Sglebius m = m_get(M_WAITOK, MT_DATA); 15825723Stegge sdata = mtod(m, struct sdata *); 15925723Stegge m->m_len = sizeof(*sdata); 16025723Stegge 16125723Stegge /* Do the RPC to get it. */ 16225723Stegge sdata->prog = txdr_unsigned(prog); 16325723Stegge sdata->vers = txdr_unsigned(vers); 16425723Stegge sdata->proto = txdr_unsigned(IPPROTO_UDP); 16525723Stegge sdata->port = 0; 16625723Stegge 16725723Stegge sin->sin_port = htons(PMAPPORT); 16825723Stegge error = krpc_call(sin, PMAPPROG, PMAPVERS, 16983366Sjulian PMAPPROC_GETPORT, &m, NULL, td); 17083651Speter if (error) 17125723Stegge return error; 17225723Stegge 17325723Stegge if (m->m_len < sizeof(*rdata)) { 17425723Stegge m = m_pullup(m, sizeof(*rdata)); 17525723Stegge if (m == NULL) 17625723Stegge return ENOBUFS; 17725723Stegge } 17825723Stegge rdata = mtod(m, struct rdata *); 17925723Stegge *portp = rdata->port; 18025723Stegge 18125723Stegge m_freem(m); 18225723Stegge return 0; 18325723Stegge} 18425723Stegge 18525723Stegge/* 18625723Stegge * Do a remote procedure call (RPC) and wait for its reply. 18725723Stegge * If from_p is non-null, then we are doing broadcast, and 18825723Stegge * the address from whence the response came is saved there. 18925723Stegge */ 19025723Steggeint 19183651Speterkrpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, 19283651Speter struct mbuf **data, struct sockaddr **from_p, struct thread *td) 19325723Stegge{ 19425723Stegge struct socket *so; 19528270Swollman struct sockaddr_in *sin, ssin; 19628270Swollman struct sockaddr *from; 19728270Swollman struct mbuf *m, *nam, *mhead; 198122719Salfred struct krpc_call *call; 199122719Salfred struct krpc_reply *reply; 20038482Swollman struct sockopt sopt; 20138482Swollman struct timeval tv; 20225723Stegge struct uio auio; 20325723Stegge int error, rcvflg, timo, secs, len; 20425723Stegge static u_int32_t xid = ~0xFF; 20525723Stegge u_int16_t tport; 20667529Stegge u_int32_t saddr; 20725723Stegge 20825723Stegge /* 20925723Stegge * Validate address family. 21025723Stegge * Sorry, this is INET specific... 21125723Stegge */ 21225723Stegge if (sa->sin_family != AF_INET) 21325723Stegge return (EAFNOSUPPORT); 21425723Stegge 21525723Stegge /* Free at end if not null. */ 21625723Stegge nam = mhead = NULL; 21725723Stegge from = NULL; 21825723Stegge 21925723Stegge /* 22025723Stegge * Create socket and set its recieve timeout. 22125723Stegge */ 22291406Sjhb if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td))) 22325723Stegge goto out; 22425723Stegge 22538482Swollman tv.tv_sec = 1; 22638482Swollman tv.tv_usec = 0; 22738482Swollman bzero(&sopt, sizeof sopt); 228120755Sjeff sopt.sopt_dir = SOPT_SET; 22938482Swollman sopt.sopt_level = SOL_SOCKET; 23038482Swollman sopt.sopt_name = SO_RCVTIMEO; 23138482Swollman sopt.sopt_val = &tv; 23238482Swollman sopt.sopt_valsize = sizeof tv; 23338482Swollman 23443309Sdillon if ((error = sosetopt(so, &sopt)) != 0) 23525723Stegge goto out; 23625723Stegge 23725723Stegge /* 23825723Stegge * Enable broadcast if necessary. 23925723Stegge */ 24025723Stegge if (from_p) { 24138482Swollman int on = 1; 24238482Swollman sopt.sopt_name = SO_BROADCAST; 24338482Swollman sopt.sopt_val = &on; 24438482Swollman sopt.sopt_valsize = sizeof on; 24543309Sdillon if ((error = sosetopt(so, &sopt)) != 0) 24625723Stegge goto out; 24725723Stegge } 24825723Stegge 24925723Stegge /* 25025723Stegge * Bind the local endpoint to a reserved port, 25125723Stegge * because some NFS servers refuse requests from 25225723Stegge * non-reserved (non-privileged) ports. 25325723Stegge */ 25428270Swollman sin = &ssin; 25528270Swollman bzero(sin, sizeof *sin); 25628270Swollman sin->sin_len = sizeof(*sin); 25725723Stegge sin->sin_family = AF_INET; 25825723Stegge sin->sin_addr.s_addr = INADDR_ANY; 25925723Stegge tport = IPPORT_RESERVED; 26025723Stegge do { 26125723Stegge tport--; 26225723Stegge sin->sin_port = htons(tport); 26383366Sjulian error = sobind(so, (struct sockaddr *)sin, td); 26425723Stegge } while (error == EADDRINUSE && 26525723Stegge tport > IPPORT_RESERVED / 2); 26625723Stegge if (error) { 26725723Stegge printf("bind failed\n"); 26825723Stegge goto out; 26925723Stegge } 27025723Stegge 27125723Stegge /* 27225723Stegge * Setup socket address for the server. 27325723Stegge */ 27425723Stegge 27525723Stegge /* 27625723Stegge * Prepend RPC message header. 27725723Stegge */ 278243882Sglebius mhead = m_gethdr(M_WAITOK, MT_DATA); 27925723Stegge mhead->m_next = *data; 280122719Salfred call = mtod(mhead, struct krpc_call *); 28125723Stegge mhead->m_len = sizeof(*call); 28225723Stegge bzero((caddr_t)call, sizeof(*call)); 28325723Stegge /* rpc_call part */ 28425723Stegge xid++; 28525723Stegge call->rp_xid = txdr_unsigned(xid); 28625723Stegge /* call->rp_direction = 0; */ 28725723Stegge call->rp_rpcvers = txdr_unsigned(2); 28825723Stegge call->rp_prog = txdr_unsigned(prog); 28925723Stegge call->rp_vers = txdr_unsigned(vers); 29025723Stegge call->rp_proc = txdr_unsigned(func); 29125723Stegge /* rpc_auth part (auth_unix as root) */ 292195202Sdfr call->rpc_auth.authtype = txdr_unsigned(AUTH_UNIX); 29325723Stegge call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 29425723Stegge /* rpc_verf part (auth_null) */ 29525723Stegge call->rpc_verf.authtype = 0; 29625723Stegge call->rpc_verf.authlen = 0; 29725723Stegge 29825723Stegge /* 29925723Stegge * Setup packet header 30025723Stegge */ 301143687Sjmg m_fixhdr(mhead); 30225723Stegge mhead->m_pkthdr.rcvif = NULL; 30325723Stegge 30425723Stegge /* 30525723Stegge * Send it, repeatedly, until a reply is received, 30625723Stegge * but delay each re-send by an increasing amount. 30725723Stegge * If the delay hits the maximum, start complaining. 30825723Stegge */ 30925723Stegge timo = 0; 31025723Stegge for (;;) { 31125723Stegge /* Send RPC request (or re-send). */ 312243882Sglebius m = m_copym(mhead, 0, M_COPYALL, M_WAITOK); 31328270Swollman error = sosend(so, (struct sockaddr *)sa, NULL, m, 31483366Sjulian NULL, 0, td); 31525723Stegge if (error) { 31625723Stegge printf("krpc_call: sosend: %d\n", error); 31725723Stegge goto out; 31825723Stegge } 31925723Stegge m = NULL; 32025723Stegge 32125723Stegge /* Determine new timeout. */ 32225723Stegge if (timo < MAX_RESEND_DELAY) 32325723Stegge timo++; 32467529Stegge else { 32567529Stegge saddr = ntohl(sa->sin_addr.s_addr); 32667529Stegge printf("RPC timeout for server %d.%d.%d.%d\n", 32767529Stegge (saddr >> 24) & 255, 32867529Stegge (saddr >> 16) & 255, 32967529Stegge (saddr >> 8) & 255, 33067529Stegge saddr & 255); 33167529Stegge } 33225723Stegge 33325723Stegge /* 33425723Stegge * Wait for up to timo seconds for a reply. 33525723Stegge * The socket receive timeout was set to 1 second. 33625723Stegge */ 33725723Stegge secs = timo; 33825723Stegge while (secs > 0) { 33925723Stegge if (from) { 340184205Sdes free(from, M_SONAME); 34125723Stegge from = NULL; 34225723Stegge } 34325723Stegge if (m) { 34425723Stegge m_freem(m); 34525723Stegge m = NULL; 34625723Stegge } 34783651Speter bzero(&auio, sizeof(auio)); 34825723Stegge auio.uio_resid = len = 1<<16; 34925723Stegge rcvflg = 0; 35025723Stegge error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); 35125723Stegge if (error == EWOULDBLOCK) { 35225723Stegge secs--; 35325723Stegge continue; 35425723Stegge } 35525723Stegge if (error) 35625723Stegge goto out; 35725723Stegge len -= auio.uio_resid; 35825723Stegge 35925723Stegge /* Does the reply contain at least a header? */ 36025723Stegge if (len < MIN_REPLY_HDR) 36125723Stegge continue; 36225723Stegge if (m->m_len < MIN_REPLY_HDR) 36325723Stegge continue; 364122719Salfred reply = mtod(m, struct krpc_reply *); 36525723Stegge 36625723Stegge /* Is it the right reply? */ 367195202Sdfr if (reply->rp_direction != txdr_unsigned(REPLY)) 36825723Stegge continue; 36925723Stegge 37025723Stegge if (reply->rp_xid != txdr_unsigned(xid)) 37125723Stegge continue; 37225723Stegge 37325723Stegge /* Was RPC accepted? (authorization OK) */ 37425723Stegge if (reply->rp_astatus != 0) { 37525723Stegge error = fxdr_unsigned(u_int32_t, reply->rp_errno); 37625723Stegge printf("rpc denied, error=%d\n", error); 37725723Stegge continue; 37825723Stegge } 37925723Stegge 38025723Stegge /* Did the call succeed? */ 38125723Stegge if (reply->rp_status != 0) { 38225723Stegge error = fxdr_unsigned(u_int32_t, reply->rp_status); 383195202Sdfr if (error == PROG_MISMATCH) { 38425723Stegge error = EBADRPC; 38525723Stegge goto out; 38625723Stegge } 38725723Stegge printf("rpc denied, status=%d\n", error); 38825723Stegge continue; 38925723Stegge } 39025723Stegge 39125723Stegge goto gotreply; /* break two levels */ 39225723Stegge 39325723Stegge } /* while secs */ 39425723Stegge } /* forever send/receive */ 39525723Stegge 39625723Stegge error = ETIMEDOUT; 39725723Stegge goto out; 39825723Stegge 39925723Stegge gotreply: 40025723Stegge 40125723Stegge /* 40225723Stegge * Get RPC reply header into first mbuf, 40325723Stegge * get its length, then strip it off. 40425723Stegge */ 40525723Stegge len = sizeof(*reply); 40625723Stegge if (m->m_len < len) { 40725723Stegge m = m_pullup(m, len); 40825723Stegge if (m == NULL) { 40925723Stegge error = ENOBUFS; 41025723Stegge goto out; 41125723Stegge } 41225723Stegge } 413122719Salfred reply = mtod(m, struct krpc_reply *); 41425723Stegge if (reply->rp_auth.authtype != 0) { 41525723Stegge len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 41625723Stegge len = (len + 3) & ~3; /* XXX? */ 41725723Stegge } 41825723Stegge m_adj(m, len); 41925723Stegge 42025723Stegge /* result */ 42125723Stegge *data = m; 42225723Stegge if (from_p) { 42325723Stegge *from_p = from; 42425723Stegge from = NULL; 42525723Stegge } 42625723Stegge 42725723Stegge out: 42825723Stegge if (mhead) m_freem(mhead); 42928270Swollman if (from) free(from, M_SONAME); 43025723Stegge soclose(so); 43125723Stegge return error; 43225723Stegge} 43325723Stegge 43425723Stegge/* 43525723Stegge * eXternal Data Representation routines. 43625723Stegge * (but with non-standard args...) 43725723Stegge */ 43825723Stegge 43925723Stegge/* 44025723Stegge * String representation for RPC. 44125723Stegge */ 44225723Steggestruct xdr_string { 44325723Stegge u_int32_t len; /* length without null or padding */ 44425723Stegge char data[4]; /* data (longer, of course) */ 44525723Stegge /* data is padded to a long-word boundary */ 44625723Stegge}; 44725723Stegge 44825723Steggestruct mbuf * 44983651Speterxdr_string_encode(char *str, int len) 45025723Stegge{ 45125723Stegge struct mbuf *m; 45225723Stegge struct xdr_string *xs; 45325723Stegge int dlen; /* padded string length */ 45425723Stegge int mlen; /* message length */ 45525723Stegge 45625723Stegge dlen = (len + 3) & ~3; 45725723Stegge mlen = dlen + 4; 45825723Stegge 45925723Stegge if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 46025723Stegge return (NULL); 46125723Stegge 462248207Sglebius m = m_get2(mlen, M_WAITOK, MT_DATA, 0); 46325723Stegge xs = mtod(m, struct xdr_string *); 46425723Stegge m->m_len = mlen; 46525723Stegge xs->len = txdr_unsigned(len); 46625723Stegge bcopy(str, xs->data, len); 46725723Stegge return (m); 46825723Stegge} 469