home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / lan / soss.arj / RPC / RPC_PROT.C < prev    next >
C/C++ Source or Header  |  1991-02-22  |  15KB  |  550 lines

  1. /*
  2.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  3.  * unrestricted use provided that this legend is included on all tape
  4.  * media and as a part of the software program in whole or part.  Users
  5.  * may copy or modify Sun RPC without charge, but are not authorized
  6.  * to license or distribute it to anyone else except as part of a product or
  7.  * program developed by the user.
  8.  * 
  9.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12.  * 
  13.  * Sun RPC is provided with no support and without any obligation on the
  14.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  15.  * modification or enhancement.
  16.  * 
  17.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  19.  * OR ANY PART THEREOF.
  20.  * 
  21.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22.  * or profits or other special, indirect and consequential damages, even if
  23.  * Sun has been advised of the possibility of such damages.
  24.  * 
  25.  * Sun Microsystems, Inc.
  26.  * 2550 Garcia Avenue
  27.  * Mountain View, California  94043
  28.  */
  29. #ifndef lint
  30. static char sccsid[] = "@(#)rpc_prot.c 1.1 86/02/03 Copyr 1984 Sun Micro";
  31. #endif
  32.  
  33. /*
  34.  * rpc_prot.c
  35.  *
  36.  * Copyright (C) 1984, Sun Microsystems, Inc.
  37.  *
  38.  * This set of routines implements the rpc message definition,
  39.  * its serializer and some common rpc utility routines.
  40.  * The routines are meant for various implementations of rpc -
  41.  * they are NOT for the rpc client or rpc service implementations!
  42.  * Because authentication stuff is easy and is part of rpc, the opaque
  43.  * routines are also in this program.
  44.  */
  45.  
  46. #include <stdio.h>
  47. #include <malloc.h>            /* needed for MS C Compiler */
  48. /* #include <sys/param.h> */        /* removed by See-Mong Tan */
  49. #include "types.h"
  50. #include "xdr.h"
  51. #include "auth.h"
  52. #include "clnt.h"
  53. #include "rpc_msg.h"
  54. #include "in.h"
  55.  
  56. /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
  57.  
  58. struct opaque_auth _null_auth;
  59.  
  60. /*
  61.  * XDR an opaque authentication struct
  62.  * (see auth.h)
  63.  */
  64. bool_t
  65. xdr_opaque_auth(xdrs, ap)
  66.     register XDR *xdrs;
  67.     register struct opaque_auth *ap;
  68. {
  69.  
  70.     if (xdr_enum(xdrs, &(ap->oa_flavor)))
  71.         return (xdr_bytes(xdrs, &ap->oa_base,
  72.             &ap->oa_length, MAX_AUTH_BYTES));
  73.     return (FALSE);
  74. }
  75.  
  76. /*
  77.  * XDR a DES key.
  78.  */
  79. bool_t
  80. xdr_deskey(xdrs, blkp)
  81.     register XDR *xdrs;
  82.     register union des_block *blkp;
  83. {
  84.  
  85.     if (! xdr_u_long(xdrs, &(blkp->key.high)))
  86.         return (FALSE);
  87.     return (xdr_u_long(xdrs, &(blkp->key.low)));
  88. }
  89.  
  90. /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
  91.  
  92. /*
  93.  * XDR the MSG_ACCEPTED part of a reply message union
  94.  */
  95. bool_t 
  96. xdr_accepted_reply(xdrs, ar)
  97.     register XDR *xdrs;   
  98.     register struct accepted_reply *ar;
  99. {
  100.  
  101.     /* personalized union, rather than calling xdr_union */
  102.     if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
  103.         return (FALSE);
  104.     if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat)))
  105.         return (FALSE);
  106.     switch (ar->ar_stat) {
  107.  
  108.     case SUCCESS1:
  109.         return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
  110.     
  111.     case PROG_MISMATCH:
  112.         if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  113.             return (FALSE);
  114.         return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  115.     }
  116.     return (TRUE);  /* TRUE => open ended set of problems */
  117. }
  118.  
  119. /*
  120.  * XDR the MSG_DENIED part of a reply message union
  121.  */
  122. bool_t 
  123. xdr_rejected_reply(xdrs, rr)
  124.     register XDR *xdrs;
  125.     register struct rejected_reply *rr;
  126. {
  127.  
  128.     /* personalized union, rather than calling xdr_union */
  129.     if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat)))
  130.         return (FALSE);
  131.     switch (rr->rj_stat) {
  132.  
  133.     case RPC_MISMATCH:
  134.         if (! xdr_u_long(xdrs, &(rr->rj_vers.low)))
  135.             return (FALSE);
  136.         return (xdr_u_long(xdrs, &(rr->rj_vers.high)));
  137.  
  138.     case AUTH_ERROR:
  139.         return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why)));
  140.     }
  141.     return (FALSE);
  142. }
  143.  
  144. #define    RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
  145.            * BYTES_PER_XDR_UNIT)
  146.  
  147. static struct xdr_discrim reply_dscrm[3] = {
  148.     { (int)MSG_ACCEPTED, xdr_accepted_reply },
  149.     { (int)MSG_DENIED, xdr_rejected_reply },
  150.     { __dontcare__, NULL_xdrproc_t } };
  151.  
  152. /*
  153.  * XDR a reply message
  154.  */
  155. bool_t
  156. xdr_replymsg(xdrs, rmsg)
  157.     XDR *xdrs;
  158.     struct rpc_msg *rmsg;
  159. {
  160.     long far *buf;
  161.     struct accepted_reply *ar;
  162.     struct opaque_auth *oa;
  163.  
  164.     if (xdrs->x_op == XDR_ENCODE &&
  165.         rmsg->rm_reply.rp_stat == MSG_ACCEPTED &&
  166.         rmsg->rm_direction == REPLY &&
  167.         (buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT +
  168.         rmsg->rm_reply.rp_acpt.ar_verf.oa_length)) != NULL) {
  169.         IXDR_PUT_LONG(buf, rmsg->rm_xid);
  170.         IXDR_PUT_ENUM(buf, rmsg->rm_direction);
  171.         IXDR_PUT_ENUM(buf, rmsg->rm_reply.rp_stat);
  172.         ar = &rmsg->rm_reply.rp_acpt;
  173.         oa = &ar->ar_verf;
  174.         IXDR_PUT_ENUM(buf, oa->oa_flavor);
  175.         IXDR_PUT_LONG(buf, oa->oa_length);
  176.         if (oa->oa_length) {
  177.             bcopy_nf(oa->oa_base, buf, oa->oa_length);
  178.             buf += (oa->oa_length +
  179.                 BYTES_PER_XDR_UNIT - 1) /
  180.                 sizeof (long);
  181.         }
  182.         /*
  183.          * stat and rest of reply, copied from xdr_accepted_reply
  184.          */
  185.         IXDR_PUT_ENUM(buf, ar->ar_stat);
  186.         switch (ar->ar_stat) {
  187.  
  188.         case SUCCESS1:
  189.             return ((*(ar->ar_results.proc))
  190.                 (xdrs, ar->ar_results.where));
  191.     
  192.         case PROG_MISMATCH:
  193.             if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  194.                 return (FALSE);
  195.             return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  196.         }
  197.         return (TRUE);
  198.     }
  199.     if (xdrs->x_op == XDR_DECODE &&
  200.         (buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT)) != NULL) {
  201.         rmsg->rm_xid = IXDR_GET_LONG(buf);
  202.         rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
  203.         if (rmsg->rm_direction != REPLY) {
  204.             return (FALSE);
  205.         }
  206.         rmsg->rm_reply.rp_stat = IXDR_GET_ENUM(buf, enum reply_stat);
  207.         if (rmsg->rm_reply.rp_stat != MSG_ACCEPTED) {
  208.             if (rmsg->rm_reply.rp_stat == MSG_DENIED) {
  209.                 return (xdr_rejected_reply(xdrs,
  210.                     &rmsg->rm_reply.rp_rjct));
  211.             }
  212.             return (FALSE);
  213.         }
  214.         ar = &rmsg->rm_reply.rp_acpt;
  215.         oa = &ar->ar_verf;
  216.         buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
  217.         if (buf != NULL) {
  218.             oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  219.             oa->oa_length = IXDR_GET_LONG(buf);
  220.         } else {
  221.             if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
  222.                 xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
  223.                 return (FALSE);
  224.             }
  225.         }
  226.         if (oa->oa_length) {
  227.             if (oa->oa_length > MAX_AUTH_BYTES) {
  228.                 return (FALSE);
  229.             }
  230.             if (oa->oa_base == NULL) {
  231.                 oa->oa_base = (caddr_t)
  232.                     mem_alloc(oa->oa_length);
  233.             }
  234.             buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  235.             if (buf == NULL) {
  236.                 if (xdr_opaque(xdrs, oa->oa_base,
  237.                     oa->oa_length) == FALSE) {
  238.                     return (FALSE);
  239.                 }
  240.             } else {
  241.                 bcopy_fn(buf, oa->oa_base, oa->oa_length);
  242.                 /* no real need....
  243.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  244.                 */
  245.             }
  246.         }
  247.         /*
  248.          * stat and rest of reply, copied from
  249.          * xdr_accepted_reply
  250.          */
  251.         xdr_enum(xdrs, &ar->ar_stat);
  252.         switch (ar->ar_stat) {
  253.  
  254.         case SUCCESS1:
  255.             return ((*(ar->ar_results.proc))
  256.                 (xdrs, ar->ar_results.where));
  257.  
  258.         case PROG_MISMATCH:
  259.             if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  260.                 return (FALSE);
  261.             return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  262.         }
  263.         return (TRUE);
  264.     }
  265.     if (
  266.         xdr_u_long(xdrs, &(rmsg->rm_xid)) && 
  267.         xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) &&
  268.         (rmsg->rm_direction == REPLY) )
  269.         return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat),
  270.             (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t));
  271.     return (FALSE);
  272. }
  273.  
  274. /*
  275.  * XDR a call message
  276.  */
  277. bool_t
  278. xdr_callmsg(xdrs, cmsg)
  279.     register XDR *xdrs;
  280.     register struct rpc_msg *cmsg;
  281. {
  282.     register long far *buf;
  283.     register struct opaque_auth *oa;
  284.  
  285.     if (xdrs->x_op == XDR_ENCODE) {
  286.         if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
  287.             return (FALSE);
  288.         }
  289.         if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
  290.             return (FALSE);
  291.         }
  292.         buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
  293.             + RNDUP(cmsg->rm_call.cb_cred.oa_length)
  294.             + 2 * BYTES_PER_XDR_UNIT
  295.             + RNDUP(cmsg->rm_call.cb_verf.oa_length));
  296.         if (buf != NULL) {
  297.             IXDR_PUT_LONG(buf, cmsg->rm_xid);
  298.             IXDR_PUT_ENUM(buf, cmsg->rm_direction);
  299.             if (cmsg->rm_direction != CALL) {
  300.                 return (FALSE);
  301.             }
  302.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers);
  303.             if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
  304.                 return (FALSE);
  305.             }
  306.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog);
  307.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers);
  308.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc);
  309.             oa = &cmsg->rm_call.cb_cred;
  310.             IXDR_PUT_ENUM(buf, oa->oa_flavor);
  311.             IXDR_PUT_LONG(buf, oa->oa_length);
  312.             if (oa->oa_length) {
  313.                 bcopy_nf(oa->oa_base, buf, oa->oa_length);
  314.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  315.             }
  316.             oa = &cmsg->rm_call.cb_verf;
  317.             IXDR_PUT_ENUM(buf, oa->oa_flavor);
  318.             IXDR_PUT_LONG(buf, oa->oa_length);
  319.             if (oa->oa_length) {
  320.                 bcopy_nf(oa->oa_base, buf, oa->oa_length);
  321.                 /* no real need....
  322.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  323.                 */
  324.             }
  325.             return (TRUE);
  326.         }
  327.     }
  328.     if (xdrs->x_op == XDR_DECODE) {
  329.         buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
  330.         if (buf != NULL) {
  331.             cmsg->rm_xid = IXDR_GET_LONG(buf);
  332.             cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
  333.             if (cmsg->rm_direction != CALL) {
  334.                 return (FALSE);
  335.             }
  336.             cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf);
  337.             if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
  338.                 return (FALSE);
  339.             }
  340.             cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf);
  341.             cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf);
  342.             cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf);
  343.  
  344.             oa = &cmsg->rm_call.cb_cred;
  345.             oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  346.             oa->oa_length = IXDR_GET_LONG(buf);
  347.             if (oa->oa_length) {
  348.                 if (oa->oa_length > MAX_AUTH_BYTES) {
  349.                     return (FALSE);
  350.                 }
  351.                 if (oa->oa_base == NULL) {
  352.                     oa->oa_base = (caddr_t)
  353.                         mem_alloc(oa->oa_length);
  354.                 }
  355.                 buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  356.                 if (buf == NULL) {
  357.                     if (xdr_opaque(xdrs, oa->oa_base,
  358.                         oa->oa_length) == FALSE) {
  359.                         return (FALSE);
  360.                     }
  361.                 } else {
  362.                     bcopy_fn(buf, oa->oa_base, oa->oa_length);
  363.                     /* no real need....
  364.                     buf += RNDUP(oa->oa_length) /
  365.                         sizeof (long);
  366.                     */
  367.                 }
  368.             }
  369.             oa = &cmsg->rm_call.cb_verf;
  370.             buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
  371.             if (buf == NULL) {
  372.                 if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
  373.                     xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
  374.                     return (FALSE);
  375.                 }
  376.             } else {
  377.                 oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  378.                 oa->oa_length = IXDR_GET_LONG(buf);
  379.             }
  380.             if (oa->oa_length) {
  381.                 if (oa->oa_length > MAX_AUTH_BYTES) {
  382.                     return (FALSE);
  383.                 }
  384.                 if (oa->oa_base == NULL) {
  385.                     oa->oa_base = (caddr_t)
  386.                         mem_alloc(oa->oa_length);
  387.                 }
  388.                 buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  389.                 if (buf == NULL) {
  390.                     if (xdr_opaque(xdrs, oa->oa_base,
  391.                         oa->oa_length) == FALSE) {
  392.                         return (FALSE);
  393.                     }
  394.                 } else {
  395.                     bcopy_fn(buf, oa->oa_base, oa->oa_length);
  396.                     /* no real need...
  397.                     buf += RNDUP(oa->oa_length) /
  398.                         sizeof (long);
  399.                     */
  400.                 }
  401.             }
  402.             return (TRUE);
  403.         }
  404.     }
  405.     if (
  406.         xdr_u_long(xdrs, &(cmsg->rm_xid)) &&
  407.         xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
  408.         (cmsg->rm_direction == CALL) &&
  409.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
  410.         (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
  411.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) &&
  412.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)) &&
  413.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_proc)) &&
  414.         xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
  415.         return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
  416.     return (FALSE);
  417. }
  418.  
  419. /*
  420.  * Serializes the "static part" of a call message header.
  421.  * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
  422.  * The rm_xid is not really static, but the user can easily munge on the fly.
  423.  */
  424. bool_t
  425. xdr_callhdr(xdrs, cmsg)
  426.     register XDR *xdrs;
  427.     register struct rpc_msg *cmsg;
  428. {
  429.  
  430.     cmsg->rm_direction = CALL;
  431.     cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
  432.     if (
  433.         (xdrs->x_op == XDR_ENCODE) &&
  434.         xdr_u_long(xdrs, &(cmsg->rm_xid)) &&
  435.         xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
  436.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
  437.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) )
  438.         return (xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)));
  439.     return (FALSE);
  440. }
  441.  
  442. /* ************************** Client utility routine ************* */
  443.  
  444. static void
  445. accepted(acpt_stat, error)
  446.     register enum accept_stat acpt_stat;
  447.     register struct rpc_err *error;
  448. {
  449.  
  450.     switch (acpt_stat) {
  451.  
  452.     case PROG_UNAVAIL:
  453.         error->re_status = RPC_PROGUNAVAIL;
  454.         return;
  455.  
  456.     case PROG_MISMATCH:
  457.         error->re_status = RPC_PROGVERSMISMATCH;
  458.         return;
  459.  
  460.     case PROC_UNAVAIL:
  461.         error->re_status = RPC_PROCUNAVAIL;
  462.         return;
  463.  
  464.     case GARBAGE_ARGS:
  465.         error->re_status = RPC_CANTDECODEARGS;
  466.         return;
  467.  
  468.     case SYSTEM_ERR:
  469.         error->re_status = RPC_SYSTEMERROR;
  470.         return;
  471.  
  472.     case SUCCESS1:
  473.         error->re_status = RPC_SUCCESS;
  474.         return;
  475.     }
  476.     /* something's wrong, but we don't know what ... */
  477.     error->re_status = RPC_FAILED;
  478.     error->re_lb.s1 = (long)MSG_ACCEPTED;
  479.     error->re_lb.s2 = (long)acpt_stat;
  480. }
  481.  
  482. static void 
  483. rejected(rjct_stat, error)
  484.     register enum reject_stat rjct_stat;
  485.     register struct rpc_err *error;
  486. {
  487.  
  488.     switch (rjct_stat) {
  489.  
  490.     case RPC_VERSMISMATCH:
  491.         error->re_status = RPC_VERSMISMATCH;
  492.         return;
  493.  
  494.     case AUTH_ERROR:
  495.         error->re_status = RPC_AUTHERROR;
  496.         return;
  497.     }
  498.     /* something's wrong, but we don't know what ... */
  499.     error->re_status = RPC_FAILED;
  500.     error->re_lb.s1 = (long)MSG_DENIED;
  501.     error->re_lb.s2 = (long)rjct_stat;
  502. }
  503.  
  504. /*
  505.  * given a reply message, fills in the error
  506.  */
  507. void
  508. _seterr_reply(msg, error)
  509.     register struct rpc_msg *msg;
  510.     register struct rpc_err *error;
  511. {
  512.  
  513.     /* optimized for normal, SUCCESSful case */
  514.     switch (msg->rm_reply.rp_stat) {
  515.  
  516.     case MSG_ACCEPTED:
  517.         if (msg->acpted_rply.ar_stat == SUCCESS1) {
  518.             error->re_status = RPC_SUCCESS;
  519.             return;
  520.         };
  521.         accepted(msg->acpted_rply.ar_stat, error);
  522.         break;
  523.  
  524.     case MSG_DENIED:
  525.         rejected(msg->rjcted_rply.rj_stat, error);
  526.         break;
  527.  
  528.     default:
  529.         error->re_status = RPC_FAILED;
  530.         error->re_lb.s1 = (long)(msg->rm_reply.rp_stat);
  531.         break;
  532.     }
  533.     switch (error->re_status) {
  534.  
  535.     case RPC_VERSMISMATCH:
  536.         error->re_vers.low = msg->rjcted_rply.rj_vers.low;
  537.         error->re_vers.high = msg->rjcted_rply.rj_vers.high;
  538.         break;
  539.  
  540.     case RPC_AUTHERROR:
  541.         error->re_why = msg->rjcted_rply.rj_why;
  542.         break;
  543.  
  544.     case RPC_PROGVERSMISMATCH:
  545.         error->re_vers.low = msg->acpted_rply.ar_vers.low;
  546.         error->re_vers.high = msg->acpted_rply.ar_vers.high;
  547.         break;
  548.     }
  549. }
  550.