root/nfs/krpc_subr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. krpc_portmap
  2. krpc_call
  3. xdr_string_encode
  4. xdr_string_decode
  5. xdr_inaddr_encode
  6. xdr_inaddr_decode

    1 /*      $OpenBSD: krpc_subr.c,v 1.14 2007/02/27 19:09:56 deraadt Exp $  */
    2 /*      $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1995 Gordon Ross, Adam Glass
    6  * Copyright (c) 1992 Regents of the University of California.
    7  * All rights reserved.
    8  *
    9  * This software was developed by the Computer Systems Engineering group
   10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   11  * contributed to Berkeley.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. All advertising materials mentioning features or use of this software
   22  *    must display the following acknowledgement:
   23  *      This product includes software developed by the University of
   24  *      California, Lawrence Berkeley Laboratory and its contributors.
   25  * 4. Neither the name of the University nor the names of its contributors
   26  *    may be used to endorse or promote products derived from this software
   27  *    without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   39  * SUCH DAMAGE.
   40  *
   41  * partially based on:
   42  *      libnetboot/rpc.c
   43  *               @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/conf.h>
   49 #include <sys/ioctl.h>
   50 #include <sys/proc.h>
   51 #include <sys/mount.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/reboot.h>
   54 #include <sys/socket.h>
   55 #include <sys/socketvar.h>
   56 
   57 #include <net/if.h>
   58 #include <netinet/in.h>
   59 
   60 #include <nfs/rpcv2.h>
   61 #include <nfs/krpc.h>
   62 #include <nfs/xdr_subs.h>
   63 #include <dev/rndvar.h>
   64 
   65 /*
   66  * Kernel support for Sun RPC
   67  *
   68  * Used currently for bootstrapping in nfs diskless configurations.
   69  */
   70 
   71 /*
   72  * Generic RPC headers
   73  */
   74 
   75 struct auth_info {
   76         u_int32_t       authtype;       /* auth type */
   77         u_int32_t       authlen;        /* auth length */
   78 };
   79 
   80 struct auth_unix {
   81         int32_t   ua_time;
   82         int32_t   ua_hostname;  /* null */
   83         int32_t   ua_uid;
   84         int32_t   ua_gid;
   85         int32_t   ua_gidlist;   /* null */
   86 };
   87 
   88 struct rpc_call {
   89         u_int32_t       rp_xid;         /* request transaction id */
   90         int32_t         rp_direction;   /* call direction (0) */
   91         u_int32_t       rp_rpcvers;     /* rpc version (2) */
   92         u_int32_t       rp_prog;        /* program */
   93         u_int32_t       rp_vers;        /* version */
   94         u_int32_t       rp_proc;        /* procedure */
   95         struct  auth_info rpc_auth;
   96         struct  auth_unix rpc_unix;
   97         struct  auth_info rpc_verf;
   98 };
   99 
  100 struct rpc_reply {
  101         u_int32_t rp_xid;               /* request transaction id */
  102         int32_t   rp_direction;         /* call direction (1) */
  103         int32_t   rp_astatus;           /* accept status (0: accepted) */
  104         union {
  105                 u_int32_t rpu_errno;
  106                 struct {
  107                         struct auth_info rok_auth;
  108                         u_int32_t       rok_status;
  109                 } rpu_rok;
  110         } rp_u;
  111 };
  112 #define rp_errno  rp_u.rpu_errno
  113 #define rp_auth   rp_u.rpu_rok.rok_auth
  114 #define rp_status rp_u.rpu_rok.rok_status
  115 
  116 #define MIN_REPLY_HDR 16        /* xid, dir, astat, errno */
  117 
  118 /*
  119  * What is the longest we will wait before re-sending a request?
  120  * Note this is also the frequency of "RPC timeout" messages.
  121  * The re-send loop count sup linearly to this maximum, so the
  122  * first complaint will happen after (1+2+3+4+5)=15 seconds.
  123  */
  124 #define MAX_RESEND_DELAY 5      /* seconds */
  125 
  126 /*
  127  * Call portmap to lookup a port number for a particular rpc program
  128  * Returns non-zero error on failure.
  129  */
  130 int
  131 krpc_portmap(sin,  prog, vers, portp)
  132         struct sockaddr_in *sin;                /* server address */
  133         u_int prog, vers;       /* host order */
  134         u_int16_t *portp;       /* network order */
  135 {
  136         struct sdata {
  137                 u_int32_t prog;         /* call program */
  138                 u_int32_t vers;         /* call version */
  139                 u_int32_t proto;        /* call protocol */
  140                 u_int32_t port;         /* call port (unused) */
  141         } *sdata;
  142         struct rdata {
  143                 u_int16_t pad;
  144                 u_int16_t port;
  145         } *rdata;
  146         struct mbuf *m;
  147         int error;
  148 
  149         /* The portmapper port is fixed. */
  150         if (prog == PMAPPROG) {
  151                 *portp = htons(PMAPPORT);
  152                 return 0;
  153         }
  154 
  155         m = m_get(M_WAIT, MT_DATA);
  156         sdata = mtod(m, struct sdata *);
  157         m->m_len = sizeof(*sdata);
  158 
  159         /* Do the RPC to get it. */
  160         sdata->prog = txdr_unsigned(prog);
  161         sdata->vers = txdr_unsigned(vers);
  162         sdata->proto = txdr_unsigned(IPPROTO_UDP);
  163         sdata->port = 0;
  164 
  165         sin->sin_port = htons(PMAPPORT);
  166         error = krpc_call(sin, PMAPPROG, PMAPVERS,
  167             PMAPPROC_GETPORT, &m, NULL, -1);
  168         if (error) 
  169                 return error;
  170 
  171         if (m->m_len < sizeof(*rdata)) {
  172                 m = m_pullup(m, sizeof(*rdata));
  173                 if (m == NULL)
  174                         return ENOBUFS;
  175         }
  176         rdata = mtod(m, struct rdata *);
  177         *portp = rdata->port;
  178 
  179         m_freem(m);
  180         return 0;
  181 }
  182 
  183 /*
  184  * Do a remote procedure call (RPC) and wait for its reply.
  185  * If from_p is non-null, then we are doing broadcast, and
  186  * the address from whence the response came is saved there.
  187  */
  188 int
  189 krpc_call(sa, prog, vers, func, data, from_p, retries)
  190         struct sockaddr_in *sa;
  191         u_int prog, vers, func;
  192         struct mbuf **data;     /* input/output */
  193         struct mbuf **from_p;   /* output */
  194         int retries;
  195 {
  196         struct socket *so;
  197         struct sockaddr_in *sin;
  198         struct mbuf *m, *nam, *mhead, *from, *mopt;
  199         struct rpc_call *call;
  200         struct rpc_reply *reply;
  201         struct uio auio;
  202         int error, rcvflg, timo, secs, len;
  203         static u_int32_t xid = 0;
  204         u_int32_t newxid;
  205         int *ip;
  206         struct timeval *tv;
  207 
  208         /*
  209          * Validate address family.
  210          * Sorry, this is INET specific...
  211          */
  212         if (sa->sin_family != AF_INET)
  213                 return (EAFNOSUPPORT);
  214 
  215         /* Free at end if not null. */
  216         nam = mhead = NULL;
  217         from = NULL;
  218 
  219         /*
  220          * Create socket and set its receive timeout.
  221          */
  222         if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
  223                 goto out;
  224 
  225         m = m_get(M_WAIT, MT_SOOPTS);
  226         tv = mtod(m, struct timeval *);
  227         m->m_len = sizeof(*tv);
  228         tv->tv_sec = 1;
  229         tv->tv_usec = 0;
  230         if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
  231                 goto out;
  232 
  233         /*
  234          * Enable broadcast if necessary.
  235          */
  236         if (from_p) {
  237                 int32_t *on;
  238                 m = m_get(M_WAIT, MT_SOOPTS);
  239                 on = mtod(m, int32_t *);
  240                 m->m_len = sizeof(*on);
  241                 *on = 1;
  242                 if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
  243                         goto out;
  244         }
  245 
  246         /*
  247          * Bind the local endpoint to a reserved port,
  248          * because some NFS servers refuse requests from
  249          * non-reserved (non-privileged) ports.
  250          */
  251         m = m_getclr(M_WAIT, MT_SONAME);
  252         sin = mtod(m, struct sockaddr_in *);
  253         sin->sin_len = m->m_len = sizeof(*sin);
  254         sin->sin_family = AF_INET;
  255         sin->sin_addr.s_addr = INADDR_ANY;
  256 
  257         MGET(mopt, M_WAIT, MT_SOOPTS);
  258         mopt->m_len = sizeof(int);
  259         ip = mtod(mopt, int *);
  260         *ip = IP_PORTRANGE_LOW;
  261         error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
  262         if (error)
  263                 goto out;
  264 
  265         MGET(m, M_WAIT, MT_SONAME);
  266         sin = mtod(m, struct sockaddr_in *);
  267         sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
  268         sin->sin_family = AF_INET;
  269         sin->sin_addr.s_addr = INADDR_ANY;
  270         sin->sin_port = htons(0);
  271         error = sobind(so, m);
  272         m_freem(m);
  273         if (error) {
  274                 printf("bind failed\n");
  275                 goto out;
  276         }
  277 
  278         MGET(mopt, M_WAIT, MT_SOOPTS);
  279         mopt->m_len = sizeof(int);
  280         ip = mtod(mopt, int *);
  281         *ip = IP_PORTRANGE_DEFAULT;
  282         error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
  283         if (error)
  284                 goto out;
  285 
  286         /*
  287          * Setup socket address for the server.
  288          */
  289         nam = m_get(M_WAIT, MT_SONAME);
  290         sin = mtod(nam, struct sockaddr_in *);
  291         bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len));
  292 
  293         /*
  294          * Prepend RPC message header.
  295          */
  296         mhead = m_gethdr(M_WAIT, MT_DATA);
  297         mhead->m_next = *data;
  298         call = mtod(mhead, struct rpc_call *);
  299         mhead->m_len = sizeof(*call);
  300         bzero((caddr_t)call, sizeof(*call));
  301         /* rpc_call part */
  302         while ((newxid = arc4random()) == xid);
  303         xid = newxid;
  304         call->rp_xid = txdr_unsigned(xid);
  305         /* call->rp_direction = 0; */
  306         call->rp_rpcvers = txdr_unsigned(2);
  307         call->rp_prog = txdr_unsigned(prog);
  308         call->rp_vers = txdr_unsigned(vers);
  309         call->rp_proc = txdr_unsigned(func);
  310         /* rpc_auth part (auth_unix as root) */
  311         call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX);
  312         call->rpc_auth.authlen  = txdr_unsigned(sizeof(struct auth_unix));
  313         /* rpc_verf part (auth_null) */
  314         call->rpc_verf.authtype = 0;
  315         call->rpc_verf.authlen  = 0;
  316 
  317         /*
  318          * Setup packet header
  319          */
  320         len = 0;
  321         m = mhead;
  322         while (m) {
  323                 len += m->m_len;
  324                 m = m->m_next;
  325         }
  326         mhead->m_pkthdr.len = len;
  327         mhead->m_pkthdr.rcvif = NULL;
  328 
  329         /*
  330          * Send it, repeatedly, until a reply is received,
  331          * but delay each re-send by an increasing amount.
  332          * If the delay hits the maximum, start complaining.
  333          */
  334         for (timo = 0; retries; retries--) {
  335                 /* Send RPC request (or re-send). */
  336                 m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
  337                 if (m == NULL) {
  338                         error = ENOBUFS;
  339                         goto out;
  340                 }
  341                 error = sosend(so, nam, NULL, m, NULL, 0);
  342                 if (error) {
  343                         printf("krpc_call: sosend: %d\n", error);
  344                         goto out;
  345                 }
  346                 m = NULL;
  347 
  348                 /* Determine new timeout. */
  349                 if (timo < MAX_RESEND_DELAY)
  350                         timo++;
  351                 else
  352                         printf("RPC timeout for server %s (0x%x) prog %u\n",
  353                             inet_ntoa(sin->sin_addr),
  354                             ntohl(sin->sin_addr.s_addr), prog);
  355 
  356                 /*
  357                  * Wait for up to timo seconds for a reply.
  358                  * The socket receive timeout was set to 1 second.
  359                  */
  360                 secs = timo;
  361                 while (secs > 0) {
  362                         if (from) {
  363                                 m_freem(from);
  364                                 from = NULL;
  365                         }
  366                         if (m) {
  367                                 m_freem(m);
  368                                 m = NULL;
  369                         }
  370                         auio.uio_resid = len = 1<<16;
  371                         auio.uio_procp = NULL;
  372                         rcvflg = 0;
  373                         error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
  374                         if (error == EWOULDBLOCK) {
  375                                 secs--;
  376                                 continue;
  377                         }
  378                         if (error)
  379                                 goto out;
  380                         len -= auio.uio_resid;
  381 
  382                         /* Does the reply contain at least a header? */
  383                         if (len < MIN_REPLY_HDR)
  384                                 continue;
  385                         if (m->m_len < MIN_REPLY_HDR)
  386                                 continue;
  387                         reply = mtod(m, struct rpc_reply *);
  388 
  389                         /* Is it the right reply? */
  390                         if (reply->rp_direction != txdr_unsigned(RPC_REPLY))
  391                                 continue;
  392 
  393                         if (reply->rp_xid != txdr_unsigned(xid))
  394                                 continue;
  395 
  396                         /* Was RPC accepted? (authorization OK) */
  397                         if (reply->rp_astatus != 0) {
  398                                 error = fxdr_unsigned(u_int32_t, reply->rp_errno);
  399                                 printf("rpc denied, error=%d\n", error);
  400                                 continue;
  401                         }
  402 
  403                         /* Did the call succeed? */
  404                         if (reply->rp_status != 0) {
  405                                 error = fxdr_unsigned(u_int32_t, reply->rp_status);
  406                                 printf("rpc denied, status=%d\n", error);
  407                                 continue;
  408                         }
  409 
  410                         goto gotreply;  /* break two levels */
  411 
  412                 } /* while secs */
  413         } /* forever send/receive */
  414 
  415         error = ETIMEDOUT;
  416         goto out;
  417 
  418  gotreply:
  419 
  420         /*
  421          * Get RPC reply header into first mbuf,
  422          * get its length, then strip it off.
  423          */
  424         len = sizeof(*reply);
  425         if (m->m_len < len) {
  426                 m = m_pullup(m, len);
  427                 if (m == NULL) {
  428                         error = ENOBUFS;
  429                         goto out;
  430                 }
  431         }
  432         reply = mtod(m, struct rpc_reply *);
  433         if (reply->rp_auth.authtype != 0) {
  434                 len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
  435                 len = (len + 3) & ~3; /* XXX? */
  436         }
  437         m_adj(m, len);
  438 
  439         /* result */
  440         *data = m;
  441         if (from_p) {
  442                 *from_p = from;
  443                 from = NULL;
  444         }
  445 
  446  out:
  447         if (nam) m_freem(nam);
  448         if (mhead) m_freem(mhead);
  449         if (from) m_freem(from);
  450         soclose(so);
  451         return error;
  452 }
  453 
  454 /*
  455  * eXternal Data Representation routines.
  456  * (but with non-standard args...)
  457  */
  458 
  459 /*
  460  * String representation for RPC.
  461  */
  462 struct xdr_string {
  463         u_int32_t len;          /* length without null or padding */
  464         char data[4];   /* data (longer, of course) */
  465     /* data is padded to a long-word boundary */
  466 };
  467 
  468 struct mbuf *
  469 xdr_string_encode(str, len)
  470         char *str;
  471         int len;
  472 {
  473         struct mbuf *m;
  474         struct xdr_string *xs;
  475         int dlen;       /* padded string length */
  476         int mlen;       /* message length */
  477 
  478         dlen = (len + 3) & ~3;
  479         mlen = dlen + 4;
  480 
  481         if (mlen > MCLBYTES)            /* If too big, we just can't do it. */
  482                 return (NULL);
  483 
  484         m = m_get(M_WAIT, MT_DATA);
  485         if (mlen > MLEN) {
  486                 MCLGET(m, M_WAIT);
  487                 if ((m->m_flags & M_EXT) == 0) {
  488                         (void) m_free(m);       /* There can be only one. */
  489                         return (NULL);
  490                 }
  491         }
  492         xs = mtod(m, struct xdr_string *);
  493         m->m_len = mlen;
  494         xs->len = txdr_unsigned(len);
  495         bcopy(str, xs->data, len);
  496         return (m);
  497 }
  498 
  499 struct mbuf *
  500 xdr_string_decode(m, str, len_p)
  501         struct mbuf *m;
  502         char *str;
  503         int *len_p;             /* bufsize - 1 */
  504 {
  505         struct xdr_string *xs;
  506         int mlen;       /* message length */
  507         int slen;       /* string length */
  508 
  509         if (m->m_len < 4) {
  510                 m = m_pullup(m, 4);
  511                 if (m == NULL)
  512                         return (NULL);
  513         }
  514         xs = mtod(m, struct xdr_string *);
  515         slen = fxdr_unsigned(u_int32_t, xs->len);
  516         mlen = 4 + ((slen + 3) & ~3);
  517 
  518         if (slen > *len_p)
  519                 slen = *len_p;
  520         if (slen > m->m_pkthdr.len) {
  521                 m_freem(m);
  522                 return (NULL);
  523         }
  524         m_copydata(m, 4, slen, str);
  525         m_adj(m, mlen);
  526 
  527         str[slen] = '\0';
  528         *len_p = slen;
  529 
  530         return (m);
  531 }
  532 
  533 
  534 /*
  535  * Inet address in RPC messages
  536  * (Note, really four ints, NOT chars.  Blech.)
  537  */
  538 struct xdr_inaddr {
  539         u_int32_t atype;
  540         u_int32_t addr[4];
  541 };
  542 
  543 struct mbuf *
  544 xdr_inaddr_encode(ia)
  545         struct in_addr *ia;             /* already in network order */
  546 {
  547         struct mbuf *m;
  548         struct xdr_inaddr *xi;
  549         u_int8_t *cp;
  550         u_int32_t *ip;
  551 
  552         m = m_get(M_WAIT, MT_DATA);
  553         xi = mtod(m, struct xdr_inaddr *);
  554         m->m_len = sizeof(*xi);
  555         xi->atype = txdr_unsigned(1);
  556         ip = xi->addr;
  557         cp = (u_int8_t *)&ia->s_addr;
  558         *ip++ = txdr_unsigned(*cp++);
  559         *ip++ = txdr_unsigned(*cp++);
  560         *ip++ = txdr_unsigned(*cp++);
  561         *ip++ = txdr_unsigned(*cp++);
  562 
  563         return (m);
  564 }
  565 
  566 struct mbuf *
  567 xdr_inaddr_decode(m, ia)
  568         struct mbuf *m;
  569         struct in_addr *ia;             /* already in network order */
  570 {
  571         struct xdr_inaddr *xi;
  572         u_int8_t *cp;
  573         u_int32_t *ip;
  574 
  575         if (m->m_len < sizeof(*xi)) {
  576                 m = m_pullup(m, sizeof(*xi));
  577                 if (m == NULL)
  578                         return (NULL);
  579         }
  580         xi = mtod(m, struct xdr_inaddr *);
  581         if (xi->atype != txdr_unsigned(1)) {
  582                 ia->s_addr = INADDR_ANY;
  583                 goto out;
  584         }
  585         ip = xi->addr;
  586         cp = (u_int8_t *)&ia->s_addr;
  587         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  588         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  589         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  590         *cp++ = fxdr_unsigned(u_int8_t, *ip++);
  591 
  592 out:
  593         m_adj(m, sizeof(*xi));
  594         return (m);
  595 }

/* [<][>][^][v][top][bottom][index][help] */