1 /* $OpenBSD: rpc_prot.c,v 1.11 2010/09/01 14:43:34 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * rpc_prot.c 36 * 37 * This set of routines implements the rpc message definition, 38 * its serializer and some common rpc utility routines. 39 * The routines are meant for various implementations of rpc - 40 * they are NOT for the rpc client or rpc service implementations! 41 * Because authentication stuff is easy and is part of rpc, the opaque 42 * routines are also in this program. 43 */ 44 45 #include <sys/param.h> 46 47 #include <rpc/rpc.h> 48 49 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ 50 51 struct opaque_auth _null_auth; 52 53 /* 54 * XDR an opaque authentication struct 55 * (see auth.h) 56 */ 57 bool_t 58 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 59 { 60 61 if (xdr_enum(xdrs, &(ap->oa_flavor))) 62 return (xdr_bytes(xdrs, &ap->oa_base, 63 &ap->oa_length, MAX_AUTH_BYTES)); 64 return (FALSE); 65 } 66 67 /* 68 * XDR a DES block 69 */ 70 bool_t 71 xdr_des_block(XDR *xdrs, des_block *blkp) 72 { 73 return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); 74 } 75 76 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 77 78 /* 79 * XDR the MSG_ACCEPTED part of a reply message union 80 */ 81 bool_t 82 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 83 { 84 85 /* personalized union, rather than calling xdr_union */ 86 if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) 87 return (FALSE); 88 if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) 89 return (FALSE); 90 91 switch (ar->ar_stat) { 92 case SUCCESS: 93 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 94 case PROG_MISMATCH: 95 if (!xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) 96 return (FALSE); 97 return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); 98 default: 99 return (TRUE); /* TRUE => open ended set of problems */ 100 } 101 } 102 103 /* 104 * XDR the MSG_DENIED part of a reply message union 105 */ 106 bool_t 107 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr) 108 { 109 110 /* personalized union, rather than calling xdr_union */ 111 if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) 112 return (FALSE); 113 114 switch (rr->rj_stat) { 115 case RPC_MISMATCH: 116 if (!xdr_u_int32_t(xdrs, &(rr->rj_vers.low))) 117 return (FALSE); 118 return (xdr_u_int32_t(xdrs, &(rr->rj_vers.high))); 119 case AUTH_ERROR: 120 return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); 121 } 122 return (FALSE); 123 } 124 125 static struct xdr_discrim reply_dscrm[3] = { 126 { (int)MSG_ACCEPTED, xdr_accepted_reply }, 127 { (int)MSG_DENIED, xdr_rejected_reply }, 128 { __dontcare__, NULL } }; 129 130 /* 131 * XDR a reply message 132 */ 133 bool_t 134 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 135 { 136 if (xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && 137 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && 138 rmsg->rm_direction == REPLY) 139 return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), 140 (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL)); 141 return (FALSE); 142 } 143 144 145 /* 146 * Serializes the "static part" of a call message header. 147 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 148 * The rm_xid is not really static, but the user can easily munge on the fly. 149 */ 150 bool_t 151 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 152 { 153 154 cmsg->rm_direction = CALL; 155 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 156 if (xdrs->x_op == XDR_ENCODE && 157 xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && 158 xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && 159 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 160 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog))) 161 return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); 162 return (FALSE); 163 } 164 165 /* ************************** Client utility routine ************* */ 166 167 static void 168 accepted(enum accept_stat acpt_stat, struct rpc_err *error) 169 { 170 171 switch (acpt_stat) { 172 173 case PROG_UNAVAIL: 174 error->re_status = RPC_PROGUNAVAIL; 175 return; 176 177 case PROG_MISMATCH: 178 error->re_status = RPC_PROGVERSMISMATCH; 179 return; 180 181 case PROC_UNAVAIL: 182 error->re_status = RPC_PROCUNAVAIL; 183 return; 184 185 case GARBAGE_ARGS: 186 error->re_status = RPC_CANTDECODEARGS; 187 return; 188 189 case SYSTEM_ERR: 190 error->re_status = RPC_SYSTEMERROR; 191 return; 192 193 case SUCCESS: 194 error->re_status = RPC_SUCCESS; 195 return; 196 } 197 /* something's wrong, but we don't know what ... */ 198 error->re_status = RPC_FAILED; 199 error->re_lb.s1 = (long)MSG_ACCEPTED; 200 error->re_lb.s2 = (long)acpt_stat; 201 } 202 203 static void 204 rejected(enum reject_stat rjct_stat, struct rpc_err *error) 205 { 206 207 switch (rjct_stat) { 208 209 case RPC_MISMATCH: 210 error->re_status = RPC_VERSMISMATCH; 211 return; 212 213 case AUTH_ERROR: 214 error->re_status = RPC_AUTHERROR; 215 return; 216 } 217 /* something's wrong, but we don't know what ... */ 218 error->re_status = RPC_FAILED; 219 error->re_lb.s1 = (long)MSG_DENIED; 220 error->re_lb.s2 = (long)rjct_stat; 221 } 222 223 /* 224 * given a reply message, fills in the error 225 */ 226 void 227 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) 228 { 229 230 /* optimized for normal, SUCCESSful case */ 231 switch (msg->rm_reply.rp_stat) { 232 233 case MSG_ACCEPTED: 234 if (msg->acpted_rply.ar_stat == SUCCESS) { 235 error->re_status = RPC_SUCCESS; 236 return; 237 }; 238 accepted(msg->acpted_rply.ar_stat, error); 239 break; 240 241 case MSG_DENIED: 242 rejected(msg->rjcted_rply.rj_stat, error); 243 break; 244 245 default: 246 error->re_status = RPC_FAILED; 247 error->re_lb.s1 = (long)(msg->rm_reply.rp_stat); 248 break; 249 } 250 switch (error->re_status) { 251 252 case RPC_VERSMISMATCH: 253 error->re_vers.low = msg->rjcted_rply.rj_vers.low; 254 error->re_vers.high = msg->rjcted_rply.rj_vers.high; 255 break; 256 257 case RPC_AUTHERROR: 258 error->re_why = msg->rjcted_rply.rj_why; 259 break; 260 261 case RPC_PROGVERSMISMATCH: 262 error->re_vers.low = msg->acpted_rply.ar_vers.low; 263 error->re_vers.high = msg->acpted_rply.ar_vers.high; 264 break; 265 } 266 } 267