home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / utils / sossntr3 / src / rpc_prot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  14.8 KB  |  552 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 <winsock.h>
  50. #include "bcopy.h"
  51. #include "types.h"
  52. #include "xdr.h"
  53. #include "auth.h"
  54. #include "clnt.h"
  55. #include "rpc_msg.h"
  56. /* #include "in.h" */
  57.  
  58. /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
  59.  
  60. struct opaque_auth _null_auth;
  61.  
  62. /*
  63.  * XDR an opaque authentication struct
  64.  * (see auth.h)
  65.  */
  66. bool_t
  67. xdr_opaque_auth(xdrs, ap)
  68.     register XDR *xdrs;
  69.     register struct opaque_auth *ap;
  70. {
  71.  
  72.     if (xdr_enum(xdrs, &(ap->oa_flavor)))
  73.         return (xdr_bytes(xdrs, &ap->oa_base,
  74.             &ap->oa_length, MAX_AUTH_BYTES));
  75.     return (FALSE);
  76. }
  77.  
  78. /*
  79.  * XDR a DES key.
  80.  */
  81. bool_t
  82. xdr_deskey(xdrs, blkp)
  83.     register XDR *xdrs;
  84.     register union des_block *blkp;
  85. {
  86.  
  87.     if (! xdr_u_long(xdrs, &(blkp->key.high)))
  88.         return (FALSE);
  89.     return (xdr_u_long(xdrs, &(blkp->key.low)));
  90. }
  91.  
  92. /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
  93.  
  94. /*
  95.  * XDR the MSG_ACCEPTED part of a reply message union
  96.  */
  97. bool_t 
  98. xdr_accepted_reply(xdrs, ar)
  99.     register XDR *xdrs;   
  100.     register struct accepted_reply *ar;
  101. {
  102.  
  103.     /* personalized union, rather than calling xdr_union */
  104.     if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
  105.         return (FALSE);
  106.     if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat)))
  107.         return (FALSE);
  108.     switch (ar->ar_stat) {
  109.  
  110.     case SUCCESS1:
  111.         return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
  112.     
  113.     case PROG_MISMATCH:
  114.         if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  115.             return (FALSE);
  116.         return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  117.     }
  118.     return (TRUE);  /* TRUE => open ended set of problems */
  119. }
  120.  
  121. /*
  122.  * XDR the MSG_DENIED part of a reply message union
  123.  */
  124. bool_t 
  125. xdr_rejected_reply(xdrs, rr)
  126.     register XDR *xdrs;
  127.     register struct rejected_reply *rr;
  128. {
  129.  
  130.     /* personalized union, rather than calling xdr_union */
  131.     if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat)))
  132.         return (FALSE);
  133.     switch (rr->rj_stat) {
  134.  
  135.     case RPC_MISMATCH:
  136.         if (! xdr_u_long(xdrs, &(rr->rj_vers.low)))
  137.             return (FALSE);
  138.         return (xdr_u_long(xdrs, &(rr->rj_vers.high)));
  139.  
  140.     case AUTH_ERROR:
  141.         return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why)));
  142.     }
  143.     return (FALSE);
  144. }
  145.  
  146. #define    RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
  147.            * BYTES_PER_XDR_UNIT)
  148.  
  149. static struct xdr_discrim reply_dscrm[3] = {
  150.     { (int)MSG_ACCEPTED, xdr_accepted_reply },
  151.     { (int)MSG_DENIED, xdr_rejected_reply },
  152.     { __dontcare__, NULL_xdrproc_t } };
  153.  
  154. /*
  155.  * XDR a reply message
  156.  */
  157. bool_t
  158. xdr_replymsg(xdrs, rmsg)
  159.     XDR *xdrs;
  160.     struct rpc_msg *rmsg;
  161. {
  162.     long *buf;
  163.     struct accepted_reply *ar;
  164.     struct opaque_auth *oa;
  165.  
  166.     if (xdrs->x_op == XDR_ENCODE &&
  167.         rmsg->rm_reply.rp_stat == MSG_ACCEPTED &&
  168.         rmsg->rm_direction == REPLY &&
  169.         (buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT +
  170.         rmsg->rm_reply.rp_acpt.ar_verf.oa_length)) != NULL) {
  171.         IXDR_PUT_LONG(buf, rmsg->rm_xid);
  172.         IXDR_PUT_ENUM(buf, rmsg->rm_direction);
  173.         IXDR_PUT_ENUM(buf, rmsg->rm_reply.rp_stat);
  174.         ar = &rmsg->rm_reply.rp_acpt;
  175.         oa = &ar->ar_verf;
  176.         IXDR_PUT_ENUM(buf, oa->oa_flavor);
  177.         IXDR_PUT_LONG(buf, oa->oa_length);
  178.         if (oa->oa_length) {
  179.             bcopy_nf((char*)(oa->oa_base), (char*)buf, oa->oa_length);
  180.             buf += (oa->oa_length +
  181.                 BYTES_PER_XDR_UNIT - 1) /
  182.                 sizeof (long);
  183.         }
  184.         /*
  185.          * stat and rest of reply, copied from xdr_accepted_reply
  186.          */
  187.         IXDR_PUT_ENUM(buf, ar->ar_stat);
  188.         switch (ar->ar_stat) {
  189.  
  190.         case SUCCESS1:
  191.             return ((*(ar->ar_results.proc))
  192.                 (xdrs, ar->ar_results.where));
  193.     
  194.         case PROG_MISMATCH:
  195.             if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  196.                 return (FALSE);
  197.             return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  198.         }
  199.         return (TRUE);
  200.     }
  201.     if (xdrs->x_op == XDR_DECODE &&
  202.         (buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT)) != NULL) {
  203.         rmsg->rm_xid = IXDR_GET_LONG(buf);
  204.         rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
  205.         if (rmsg->rm_direction != REPLY) {
  206.             return (FALSE);
  207.         }
  208.         rmsg->rm_reply.rp_stat = IXDR_GET_ENUM(buf, enum reply_stat);
  209.         if (rmsg->rm_reply.rp_stat != MSG_ACCEPTED) {
  210.             if (rmsg->rm_reply.rp_stat == MSG_DENIED) {
  211.                 return (xdr_rejected_reply(xdrs,
  212.                     &rmsg->rm_reply.rp_rjct));
  213.             }
  214.             return (FALSE);
  215.         }
  216.         ar = &rmsg->rm_reply.rp_acpt;
  217.         oa = &ar->ar_verf;
  218.         buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
  219.         if (buf != NULL) {
  220.             oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  221.             oa->oa_length = IXDR_GET_LONG(buf);
  222.         } else {
  223.             if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
  224.                 xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
  225.                 return (FALSE);
  226.             }
  227.         }
  228.         if (oa->oa_length) {
  229.             if (oa->oa_length > MAX_AUTH_BYTES) {
  230.                 return (FALSE);
  231.             }
  232.             if (oa->oa_base == NULL) {
  233.                 oa->oa_base = (caddr_t)
  234.                     mem_alloc(oa->oa_length);
  235.             }
  236.             buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  237.             if (buf == NULL) {
  238.                 if (xdr_opaque(xdrs, oa->oa_base,
  239.                     oa->oa_length) == FALSE) {
  240.                     return (FALSE);
  241.                 }
  242.             } else {
  243.                 bcopy_fn((char*)buf, (char*)(oa->oa_base), oa->oa_length);
  244.                 /* no real need....
  245.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  246.                 */
  247.             }
  248.         }
  249.         /*
  250.          * stat and rest of reply, copied from
  251.          * xdr_accepted_reply
  252.          */
  253.         xdr_enum(xdrs, &ar->ar_stat);
  254.         switch (ar->ar_stat) {
  255.  
  256.         case SUCCESS1:
  257.             return ((*(ar->ar_results.proc))
  258.                 (xdrs, ar->ar_results.where));
  259.  
  260.         case PROG_MISMATCH:
  261.             if (! xdr_u_long(xdrs, &(ar->ar_vers.low)))
  262.                 return (FALSE);
  263.             return (xdr_u_long(xdrs, &(ar->ar_vers.high)));
  264.         }
  265.         return (TRUE);
  266.     }
  267.     if (
  268.         xdr_u_long(xdrs, &(rmsg->rm_xid)) && 
  269.         xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) &&
  270.         (rmsg->rm_direction == REPLY) )
  271.         return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat),
  272.             (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t));
  273.     return (FALSE);
  274. }
  275.  
  276. /*
  277.  * XDR a call message
  278.  */
  279. bool_t
  280. xdr_callmsg(xdrs, cmsg)
  281.     register XDR *xdrs;
  282.     register struct rpc_msg *cmsg;
  283. {
  284.     register long *buf;
  285.     register struct opaque_auth *oa;
  286.  
  287.     if (xdrs->x_op == XDR_ENCODE) {
  288.         if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
  289.             return (FALSE);
  290.         }
  291.         if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
  292.             return (FALSE);
  293.         }
  294.         buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
  295.             + RNDUP(cmsg->rm_call.cb_cred.oa_length)
  296.             + 2 * BYTES_PER_XDR_UNIT
  297.             + RNDUP(cmsg->rm_call.cb_verf.oa_length));
  298.         if (buf != NULL) {
  299.             IXDR_PUT_LONG(buf, cmsg->rm_xid);
  300.             IXDR_PUT_ENUM(buf, cmsg->rm_direction);
  301.             if (cmsg->rm_direction != CALL) {
  302.                 return (FALSE);
  303.             }
  304.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers);
  305.             if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
  306.                 return (FALSE);
  307.             }
  308.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog);
  309.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers);
  310.             IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc);
  311.             oa = &cmsg->rm_call.cb_cred;
  312.             IXDR_PUT_ENUM(buf, oa->oa_flavor);
  313.             IXDR_PUT_LONG(buf, oa->oa_length);
  314.             if (oa->oa_length) {
  315.                 bcopy_nf((char*)(oa->oa_base), (char*)buf, oa->oa_length);
  316.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  317.             }
  318.             oa = &cmsg->rm_call.cb_verf;
  319.             IXDR_PUT_ENUM(buf, oa->oa_flavor);
  320.             IXDR_PUT_LONG(buf, oa->oa_length);
  321.             if (oa->oa_length) {
  322.                 bcopy_nf((char*)(oa->oa_base), (char*)buf, oa->oa_length);
  323.                 /* no real need....
  324.                 buf += RNDUP(oa->oa_length) / sizeof (long);
  325.                 */
  326.             }
  327.             return (TRUE);
  328.         }
  329.     }
  330.     if (xdrs->x_op == XDR_DECODE) {
  331.         buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
  332.         if (buf != NULL) {
  333.             cmsg->rm_xid = IXDR_GET_LONG(buf);
  334.             cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
  335.             if (cmsg->rm_direction != CALL) {
  336.                 return (FALSE);
  337.             }
  338.             cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf);
  339.             if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
  340.                 return (FALSE);
  341.             }
  342.             cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf);
  343.             cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf);
  344.             cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf);
  345.  
  346.             oa = &cmsg->rm_call.cb_cred;
  347.             oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  348.             oa->oa_length = IXDR_GET_LONG(buf);
  349.             if (oa->oa_length) {
  350.                 if (oa->oa_length > MAX_AUTH_BYTES) {
  351.                     return (FALSE);
  352.                 }
  353.                 if (oa->oa_base == NULL) {
  354.                     oa->oa_base = (caddr_t)
  355.                         mem_alloc(oa->oa_length);
  356.                 }
  357.                 buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  358.                 if (buf == NULL) {
  359.                     if (xdr_opaque(xdrs, oa->oa_base,
  360.                         oa->oa_length) == FALSE) {
  361.                         return (FALSE);
  362.                     }
  363.                 } else {
  364.                     bcopy_fn((char*)buf, (char*)(oa->oa_base), oa->oa_length);
  365.                     /* no real need....
  366.                     buf += RNDUP(oa->oa_length) /
  367.                         sizeof (long);
  368.                     */
  369.                 }
  370.             }
  371.             oa = &cmsg->rm_call.cb_verf;
  372.             buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
  373.             if (buf == NULL) {
  374.                 if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
  375.                     xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
  376.                     return (FALSE);
  377.                 }
  378.             } else {
  379.                 oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
  380.                 oa->oa_length = IXDR_GET_LONG(buf);
  381.             }
  382.             if (oa->oa_length) {
  383.                 if (oa->oa_length > MAX_AUTH_BYTES) {
  384.                     return (FALSE);
  385.                 }
  386.                 if (oa->oa_base == NULL) {
  387.                     oa->oa_base = (caddr_t)
  388.                         mem_alloc(oa->oa_length);
  389.                 }
  390.                 buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
  391.                 if (buf == NULL) {
  392.                     if (xdr_opaque(xdrs, oa->oa_base,
  393.                         oa->oa_length) == FALSE) {
  394.                         return (FALSE);
  395.                     }
  396.                 } else {
  397.                     bcopy_fn((char*)buf, (char*)(oa->oa_base), oa->oa_length);
  398.                     /* no real need...
  399.                     buf += RNDUP(oa->oa_length) /
  400.                         sizeof (long);
  401.                     */
  402.                 }
  403.             }
  404.             return (TRUE);
  405.         }
  406.     }
  407.     if (
  408.         xdr_u_long(xdrs, &(cmsg->rm_xid)) &&
  409.         xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
  410.         (cmsg->rm_direction == CALL) &&
  411.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
  412.         (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
  413.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) &&
  414.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)) &&
  415.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_proc)) &&
  416.         xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
  417.         return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
  418.     return (FALSE);
  419. }
  420.  
  421. /*
  422.  * Serializes the "static part" of a call message header.
  423.  * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
  424.  * The rm_xid is not really static, but the user can easily munge on the fly.
  425.  */
  426. bool_t
  427. xdr_callhdr(xdrs, cmsg)
  428.     register XDR *xdrs;
  429.     register struct rpc_msg *cmsg;
  430. {
  431.  
  432.     cmsg->rm_direction = CALL;
  433.     cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
  434.     if (
  435.         (xdrs->x_op == XDR_ENCODE) &&
  436.         xdr_u_long(xdrs, &(cmsg->rm_xid)) &&
  437.         xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
  438.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
  439.         xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) )
  440.         return (xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)));
  441.     return (FALSE);
  442. }
  443.  
  444. /* ************************** Client utility routine ************* */
  445.  
  446. static void
  447. accepted(acpt_stat, error)
  448.     register enum accept_stat acpt_stat;
  449.     register struct rpc_err *error;
  450. {
  451.  
  452.     switch (acpt_stat) {
  453.  
  454.     case PROG_UNAVAIL:
  455.         error->re_status = RPC_PROGUNAVAIL;
  456.         return;
  457.  
  458.     case PROG_MISMATCH:
  459.         error->re_status = RPC_PROGVERSMISMATCH;
  460.         return;
  461.  
  462.     case PROC_UNAVAIL:
  463.         error->re_status = RPC_PROCUNAVAIL;
  464.         return;
  465.  
  466.     case GARBAGE_ARGS:
  467.         error->re_status = RPC_CANTDECODEARGS;
  468.         return;
  469.  
  470.     case SYSTEM_ERR:
  471.         error->re_status = RPC_SYSTEMERROR;
  472.         return;
  473.  
  474.     case SUCCESS1:
  475.         error->re_status = RPC_SUCCESS;
  476.         return;
  477.     }
  478.     /* something's wrong, but we don't know what ... */
  479.     error->re_status = RPC_FAILED;
  480.     error->re_lb.s1 = (long)MSG_ACCEPTED;
  481.     error->re_lb.s2 = (long)acpt_stat;
  482. }
  483.  
  484. static void 
  485. rejected(rjct_stat, error)
  486.     register enum reject_stat rjct_stat;
  487.     register struct rpc_err *error;
  488. {
  489.  
  490.     switch (rjct_stat) {
  491.  
  492.     case RPC_VERSMISMATCH:
  493.         error->re_status = RPC_VERSMISMATCH;
  494.         return;
  495.  
  496.     case AUTH_ERROR:
  497.         error->re_status = RPC_AUTHERROR;
  498.         return;
  499.     }
  500.     /* something's wrong, but we don't know what ... */
  501.     error->re_status = RPC_FAILED;
  502.     error->re_lb.s1 = (long)MSG_DENIED;
  503.     error->re_lb.s2 = (long)rjct_stat;
  504. }
  505.  
  506. /*
  507.  * given a reply message, fills in the error
  508.  */
  509. void
  510. _seterr_reply(msg, error)
  511.     register struct rpc_msg *msg;
  512.     register struct rpc_err *error;
  513. {
  514.  
  515.     /* optimized for normal, SUCCESSful case */
  516.     switch (msg->rm_reply.rp_stat) {
  517.  
  518.     case MSG_ACCEPTED:
  519.         if (msg->acpted_rply.ar_stat == SUCCESS1) {
  520.             error->re_status = RPC_SUCCESS;
  521.             return;
  522.         };
  523.         accepted(msg->acpted_rply.ar_stat, error);
  524.         break;
  525.  
  526.     case MSG_DENIED:
  527.         rejected(msg->rjcted_rply.rj_stat, error);
  528.         break;
  529.  
  530.     default:
  531.         error->re_status = RPC_FAILED;
  532.         error->re_lb.s1 = (long)(msg->rm_reply.rp_stat);
  533.         break;
  534.     }
  535.     switch (error->re_status) {
  536.  
  537.     case RPC_VERSMISMATCH:
  538.         error->re_vers.low = msg->rjcted_rply.rj_vers.low;
  539.         error->re_vers.high = msg->rjcted_rply.rj_vers.high;
  540.         break;
  541.  
  542.     case RPC_AUTHERROR:
  543.         error->re_why = msg->rjcted_rply.rj_why;
  544.         break;
  545.  
  546.     case RPC_PROGVERSMISMATCH:
  547.         error->re_vers.low = msg->acpted_rply.ar_vers.low;
  548.         error->re_vers.high = msg->acpted_rply.ar_vers.high;
  549.         break;
  550.     }
  551. }
  552.