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