[BACK]Return to rpc.c CVS log [TXT][DIR] Up to [local] / sys / lib / libsa

Annotation of sys/lib/libsa/rpc.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb