root/lib/libsa/rpc.c

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

DEFINITIONS

This source file includes following definitions.
  1. rpc_call
  2. recvrpc
  3. rpc_fromaddr
  4. rpc_pmap_getcache
  5. rpc_pmap_putcache
  6. rpc_getport

    1 /*      $OpenBSD: rpc.c,v 1.13 2003/08/11 06:23:09 deraadt Exp $        */
    2 /*      $NetBSD: rpc.c,v 1.16 1996/10/13 02:29:06 christos Exp $        */
    3 
    4 /*
    5  * Copyright (c) 1992 Regents of the University of California.
    6  * All rights reserved.
    7  *
    8  * This software was developed by the Computer Systems Engineering group
    9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   10  * contributed to Berkeley.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the University of
   23  *      California, Lawrence Berkeley Laboratory and its contributors.
   24  * 4. Neither the name of the University nor the names of its contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   38  * SUCH DAMAGE.
   39  *
   40  * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
   41  */
   42 
   43 /*
   44  * RPC functions used by NFS and bootparams.
   45  * Note that bootparams requires the ability to find out the
   46  * address of the server from which its response has come.
   47  * This is supported by keeping the IP/UDP headers in the
   48  * buffer space provided by the caller.  (See rpc_fromaddr)
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/socket.h>
   53 
   54 #include <netinet/in.h>
   55 #include <netinet/in_systm.h>
   56 
   57 #include <nfs/rpcv2.h>
   58 
   59 #include "stand.h"
   60 #include "net.h"
   61 #include "netif.h"
   62 #include "rpc.h"
   63 
   64 struct auth_info {
   65         int32_t         authtype;       /* auth type */
   66         u_int32_t       authlen;        /* auth length */
   67 };
   68 
   69 struct auth_unix {
   70         int32_t   ua_time;
   71         int32_t   ua_hostname;  /* null */
   72         int32_t   ua_uid;
   73         int32_t   ua_gid;
   74         int32_t   ua_gidlist;   /* null */
   75 };
   76 
   77 struct rpc_call {
   78         u_int32_t       rp_xid;         /* request transaction id */
   79         int32_t         rp_direction;   /* call direction (0) */
   80         u_int32_t       rp_rpcvers;     /* rpc version (2) */
   81         u_int32_t       rp_prog;        /* program */
   82         u_int32_t       rp_vers;        /* version */
   83         u_int32_t       rp_proc;        /* procedure */
   84 };
   85 
   86 struct rpc_reply {
   87         u_int32_t       rp_xid;         /* request transaction id */
   88         int32_t         rp_direction;   /* call direction (1) */
   89         int32_t         rp_astatus;     /* accept status (0: accepted) */
   90         union {
   91                 u_int32_t       rpu_errno;
   92                 struct {
   93                         struct auth_info rok_auth;
   94                         u_int32_t       rok_status;
   95                 } rpu_rok;
   96         } rp_u;
   97 };
   98 
   99 /* Local forwards */
  100 static  ssize_t recvrpc(struct iodesc *, void *, size_t, time_t);
  101 static  int rpc_getport(struct iodesc *, n_long, n_long);
  102 
  103 int rpc_xid;
  104 int rpc_port = 0x400;   /* predecrement */
  105 
  106 /*
  107  * Make a rpc call; return length of answer
  108  * Note: Caller must leave room for headers.
  109  */
  110 ssize_t
  111 rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, void *sdata,
  112     size_t slen, void *rdata, size_t rlen)
  113 {
  114         ssize_t cc;
  115         struct auth_info *auth;
  116         struct rpc_call *call;
  117         struct rpc_reply *reply;
  118         char *send_head, *send_tail;
  119         char *recv_head, *recv_tail;
  120         n_long x;
  121         int port;       /* host order */
  122 
  123 #ifdef RPC_DEBUG
  124         if (debug)
  125                 printf("rpc_call: prog=0x%x vers=%d proc=%d\n",
  126                     prog, vers, proc);
  127 #endif
  128 
  129         port = rpc_getport(d, prog, vers);
  130         if (port == -1)
  131                 return (-1);
  132 
  133         d->destport = htons(port);
  134 
  135         /*
  136          * Prepend authorization stuff and headers.
  137          * Note, must prepend things in reverse order.
  138          */
  139         send_head = sdata;
  140         send_tail = (char *)sdata + slen;
  141 
  142         /* Auth verifier is always auth_null */
  143         send_head -= sizeof(*auth);
  144         auth = (struct auth_info *)send_head;
  145         auth->authtype = htonl(RPCAUTH_NULL);
  146         auth->authlen = 0;
  147 
  148 #if 1
  149         /* Auth credentials: always auth unix (as root) */
  150         send_head -= sizeof(struct auth_unix);
  151         bzero(send_head, sizeof(struct auth_unix));
  152         send_head -= sizeof(*auth);
  153         auth = (struct auth_info *)send_head;
  154         auth->authtype = htonl(RPCAUTH_UNIX);
  155         auth->authlen = htonl(sizeof(struct auth_unix));
  156 #else
  157         /* Auth credentials: always auth_null (XXX OK?) */
  158         send_head -= sizeof(*auth);
  159         auth = send_head;
  160         auth->authtype = htonl(RPCAUTH_NULL);
  161         auth->authlen = 0;
  162 #endif
  163 
  164         /* RPC call structure. */
  165         send_head -= sizeof(*call);
  166         call = (struct rpc_call *)send_head;
  167         rpc_xid++;
  168         call->rp_xid       = htonl(rpc_xid);
  169         call->rp_direction = htonl(RPC_CALL);
  170         call->rp_rpcvers   = htonl(RPC_VER2);
  171         call->rp_prog = htonl(prog);
  172         call->rp_vers = htonl(vers);
  173         call->rp_proc = htonl(proc);
  174 
  175         /* Make room for the rpc_reply header. */
  176         recv_head = rdata;
  177         recv_tail = (char *)rdata + rlen;
  178         recv_head -= sizeof(*reply);
  179 
  180         cc = sendrecv(d,
  181             sendudp, send_head, send_tail - send_head,
  182             recvrpc, recv_head, recv_tail - recv_head);
  183 
  184 #ifdef RPC_DEBUG
  185         if (debug)
  186                 printf("callrpc: cc=%d rlen=%d\n", cc, rlen);
  187 #endif
  188         if (cc < -1)
  189                 return (-1);
  190 
  191         if ((size_t)cc <= sizeof(*reply)) {
  192                 errno = EBADRPC;
  193                 return (-1);
  194         }
  195 
  196         recv_tail = recv_head + cc;
  197 
  198         /*
  199          * Check the RPC reply status.
  200          * The xid, dir, astatus were already checked.
  201          */
  202         reply = (struct rpc_reply *)recv_head;
  203         auth = &reply->rp_u.rpu_rok.rok_auth;
  204         x = ntohl(auth->authlen);
  205         if (x != 0) {
  206 #ifdef RPC_DEBUG
  207                 if (debug)
  208                         printf("callrpc: reply auth != NULL\n");
  209 #endif
  210                 errno = EBADRPC;
  211                 return(-1);
  212         }
  213         x = ntohl(reply->rp_u.rpu_rok.rok_status);
  214         if (x != 0) {
  215                 printf("callrpc: error = %d\n", x);
  216                 errno = EBADRPC;
  217                 return(-1);
  218         }
  219         recv_head += sizeof(*reply);
  220 
  221         return (ssize_t)(recv_tail - recv_head);
  222 }
  223 
  224 /*
  225  * Returns true if packet is the one we're waiting for.
  226  * This just checks the XID, direction, acceptance.
  227  * Remaining checks are done by callrpc
  228  */
  229 static ssize_t
  230 recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
  231 {
  232         struct rpc_reply *reply;
  233         ssize_t n;
  234         int     x;
  235 
  236         errno = 0;
  237 #ifdef RPC_DEBUG
  238         if (debug)
  239                 printf("recvrpc: called len=%d\n", len);
  240 #endif
  241 
  242         n = readudp(d, pkt, len, tleft);
  243         if (n <= (4 * 4))
  244                 return -1;
  245 
  246         reply = (struct rpc_reply *)pkt;
  247 
  248         x = ntohl(reply->rp_xid);
  249         if (x != rpc_xid) {
  250 #ifdef RPC_DEBUG
  251                 if (debug)
  252                         printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
  253 #endif
  254                 return -1;
  255         }
  256 
  257         x = ntohl(reply->rp_direction);
  258         if (x != RPC_REPLY) {
  259 #ifdef RPC_DEBUG
  260                 if (debug)
  261                         printf("recvrpc: rp_direction %d != REPLY\n", x);
  262 #endif
  263                 return -1;
  264         }
  265 
  266         x = ntohl(reply->rp_astatus);
  267         if (x != RPC_MSGACCEPTED) {
  268                 errno = ntohl(reply->rp_u.rpu_errno);
  269                 printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
  270                 return -1;
  271         }
  272 
  273         /* Return data count (thus indicating success) */
  274         return (n);
  275 }
  276 
  277 /*
  278  * Given a pointer to a reply just received,
  279  * dig out the IP address/port from the headers.
  280  */
  281 void
  282 rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port)
  283 {
  284         struct hackhdr {
  285                 /* Tail of IP header: just IP addresses */
  286                 n_long ip_src;
  287                 n_long ip_dst;
  288                 /* UDP header: */
  289                 u_int16_t uh_sport;             /* source port */
  290                 u_int16_t uh_dport;             /* destination port */
  291                 int16_t   uh_ulen;              /* udp length */
  292                 u_int16_t uh_sum;               /* udp checksum */
  293                 /* RPC reply header: */
  294                 struct rpc_reply rpc;
  295         } *hhdr;
  296 
  297         hhdr = ((struct hackhdr *)pkt) - 1;
  298         addr->s_addr = hhdr->ip_src;
  299         *port = hhdr->uh_sport;
  300 }
  301 
  302 /*
  303  * RPC Portmapper cache
  304  */
  305 #define PMAP_NUM 8                      /* need at most 5 pmap entries */
  306 
  307 int rpc_pmap_num;
  308 struct pmap_list {
  309         struct in_addr  addr;   /* server, net order */
  310         u_int   prog;           /* host order */
  311         u_int   vers;           /* host order */
  312         int     port;           /* host order */
  313 } rpc_pmap_list[PMAP_NUM];
  314 
  315 /* return port number in host order, or -1 */
  316 int
  317 rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers)
  318 {
  319         struct pmap_list *pl;
  320 
  321         for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) {
  322                 if (pl->addr.s_addr == addr.s_addr &&
  323                     pl->prog == prog && pl->vers == vers)
  324                         return (pl->port);
  325         }
  326         return (-1);
  327 }
  328 
  329 void
  330 rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port)
  331 {
  332         struct pmap_list *pl;
  333 
  334         /* Don't overflow cache... */
  335         if (rpc_pmap_num >= PMAP_NUM) {
  336                 /* ... just re-use the last entry. */
  337                 rpc_pmap_num = PMAP_NUM - 1;
  338 #ifdef  RPC_DEBUG
  339                 printf("rpc_pmap_putcache: cache overflow\n");
  340 #endif
  341         }
  342 
  343         pl = &rpc_pmap_list[rpc_pmap_num];
  344         rpc_pmap_num++;
  345 
  346         /* Cache answer */
  347         pl->addr = addr;
  348         pl->prog = prog;
  349         pl->vers = vers;
  350         pl->port = port;
  351 }
  352 
  353 
  354 /*
  355  * Request a port number from the port mapper.
  356  * Returns the port in host order.
  357  */
  358 int
  359 rpc_getport(struct iodesc *d, n_long prog, n_long vers)
  360 {
  361         struct args {
  362                 n_long  prog;           /* call program */
  363                 n_long  vers;           /* call version */
  364                 n_long  proto;          /* call protocol */
  365                 n_long  port;           /* call port (unused) */
  366         } *args;
  367         struct res {
  368                 n_long port;
  369         } *res;
  370         struct {
  371                 n_long  h[RPC_HEADER_WORDS];
  372                 struct args d;
  373         } sdata;
  374         struct {
  375                 n_long  h[RPC_HEADER_WORDS];
  376                 struct res d;
  377                 n_long  pad;
  378         } rdata;
  379         ssize_t cc;
  380         int port;
  381 
  382 #ifdef RPC_DEBUG
  383         if (debug)
  384                 printf("getport: prog=0x%x vers=%d\n", prog, vers);
  385 #endif
  386 
  387         /* This one is fixed forever. */
  388         if (prog == PMAPPROG)
  389                 return (PMAPPORT);
  390 
  391         /* Try for cached answer first */
  392         port = rpc_pmap_getcache(d->destip, prog, vers);
  393         if (port != -1)
  394                 return (port);
  395 
  396         args = &sdata.d;
  397         args->prog = htonl(prog);
  398         args->vers = htonl(vers);
  399         args->proto = htonl(IPPROTO_UDP);
  400         args->port = 0;
  401         res = &rdata.d;
  402 
  403         cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
  404                 args, sizeof(*args), res, sizeof(*res));
  405         if (cc < 0 || (size_t)cc < sizeof(*res)) {
  406                 printf("getport: %s", strerror(errno));
  407                 errno = EBADRPC;
  408                 return (-1);
  409         }
  410         port = (int)ntohl(res->port);
  411 
  412         rpc_pmap_putcache(d->destip, prog, vers, port);
  413 
  414         return (port);
  415 }

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