1 /* $OpenBSD: rpc_prot.c,v 1.13 2015/09/13 15:36:56 guenther 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 <rpc/rpc.h> 46 47 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ 48 49 struct opaque_auth _null_auth; 50 51 /* 52 * XDR an opaque authentication struct 53 * (see auth.h) 54 */ 55 bool_t 56 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 57 { 58 59 if (xdr_enum(xdrs, &(ap->oa_flavor))) 60 return (xdr_bytes(xdrs, &ap->oa_base, 61 &ap->oa_length, MAX_AUTH_BYTES)); 62 return (FALSE); 63 } 64 DEF_WEAK(xdr_opaque_auth); 65 66 /* 67 * XDR a DES block 68 */ 69 bool_t 70 xdr_des_block(XDR *xdrs, des_block *blkp) 71 { 72 return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); 73 } 74 75 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 76 77 /* 78 * XDR the MSG_ACCEPTED part of a reply message union 79 */ 80 bool_t 81 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 82 { 83 84 /* personalized union, rather than calling xdr_union */ 85 if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) 86 return (FALSE); 87 if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) 88 return (FALSE); 89 90 switch (ar->ar_stat) { 91 case SUCCESS: 92 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 93 case PROG_MISMATCH: 94 if (!xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) 95 return (FALSE); 96 return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); 97 default: 98 return (TRUE); /* TRUE => open ended set of problems */ 99 } 100 } 101 DEF_WEAK(xdr_accepted_reply); 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 DEF_WEAK(xdr_rejected_reply); 125 126 static struct xdr_discrim reply_dscrm[3] = { 127 { (int)MSG_ACCEPTED, xdr_accepted_reply }, 128 { (int)MSG_DENIED, xdr_rejected_reply }, 129 { __dontcare__, NULL } }; 130 131 /* 132 * XDR a reply message 133 */ 134 bool_t 135 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 136 { 137 if (xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && 138 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && 139 rmsg->rm_direction == REPLY) 140 return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), 141 (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL)); 142 return (FALSE); 143 } 144 DEF_WEAK(xdr_replymsg); 145 146 /* 147 * Serializes the "static part" of a call message header. 148 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 149 * The rm_xid is not really static, but the user can easily munge on the fly. 150 */ 151 bool_t 152 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 153 { 154 155 cmsg->rm_direction = CALL; 156 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 157 if (xdrs->x_op == XDR_ENCODE && 158 xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && 159 xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && 160 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 161 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog))) 162 return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); 163 return (FALSE); 164 } 165 DEF_WEAK(xdr_callhdr); 166 167 /* ************************** Client utility routine ************* */ 168 169 static void 170 accepted(enum accept_stat acpt_stat, struct rpc_err *error) 171 { 172 173 switch (acpt_stat) { 174 175 case PROG_UNAVAIL: 176 error->re_status = RPC_PROGUNAVAIL; 177 return; 178 179 case PROG_MISMATCH: 180 error->re_status = RPC_PROGVERSMISMATCH; 181 return; 182 183 case PROC_UNAVAIL: 184 error->re_status = RPC_PROCUNAVAIL; 185 return; 186 187 case GARBAGE_ARGS: 188 error->re_status = RPC_CANTDECODEARGS; 189 return; 190 191 case SYSTEM_ERR: 192 error->re_status = RPC_SYSTEMERROR; 193 return; 194 195 case SUCCESS: 196 error->re_status = RPC_SUCCESS; 197 return; 198 } 199 /* something's wrong, but we don't know what ... */ 200 error->re_status = RPC_FAILED; 201 error->re_lb.s1 = (long)MSG_ACCEPTED; 202 error->re_lb.s2 = (long)acpt_stat; 203 } 204 205 static void 206 rejected(enum reject_stat rjct_stat, struct rpc_err *error) 207 { 208 209 switch (rjct_stat) { 210 211 case RPC_MISMATCH: 212 error->re_status = RPC_VERSMISMATCH; 213 return; 214 215 case AUTH_ERROR: 216 error->re_status = RPC_AUTHERROR; 217 return; 218 } 219 /* something's wrong, but we don't know what ... */ 220 error->re_status = RPC_FAILED; 221 error->re_lb.s1 = (long)MSG_DENIED; 222 error->re_lb.s2 = (long)rjct_stat; 223 } 224 225 /* 226 * given a reply message, fills in the error 227 */ 228 void 229 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) 230 { 231 232 /* optimized for normal, SUCCESSful case */ 233 switch (msg->rm_reply.rp_stat) { 234 235 case MSG_ACCEPTED: 236 if (msg->acpted_rply.ar_stat == SUCCESS) { 237 error->re_status = RPC_SUCCESS; 238 return; 239 }; 240 accepted(msg->acpted_rply.ar_stat, error); 241 break; 242 243 case MSG_DENIED: 244 rejected(msg->rjcted_rply.rj_stat, error); 245 break; 246 247 default: 248 error->re_status = RPC_FAILED; 249 error->re_lb.s1 = (long)(msg->rm_reply.rp_stat); 250 break; 251 } 252 switch (error->re_status) { 253 254 case RPC_VERSMISMATCH: 255 error->re_vers.low = msg->rjcted_rply.rj_vers.low; 256 error->re_vers.high = msg->rjcted_rply.rj_vers.high; 257 break; 258 259 case RPC_AUTHERROR: 260 error->re_why = msg->rjcted_rply.rj_why; 261 break; 262 263 case RPC_PROGVERSMISMATCH: 264 error->re_vers.low = msg->acpted_rply.ar_vers.low; 265 error->re_vers.high = msg->acpted_rply.ar_vers.high; 266 break; 267 } 268 } 269 DEF_STRONG(_seterr_reply); 270