[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     ! 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