1 /* $OpenBSD: rpc_prot.c,v 1.17 2024/09/20 02:00:46 jsg 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 /* 50 * XDR an opaque authentication struct 51 * (see auth.h) 52 */ 53 bool_t 54 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 55 { 56 57 if (xdr_enum(xdrs, &(ap->oa_flavor))) 58 return (xdr_bytes(xdrs, &ap->oa_base, 59 &ap->oa_length, MAX_AUTH_BYTES)); 60 return (FALSE); 61 } 62 DEF_WEAK(xdr_opaque_auth); 63 64 /* 65 * XDR a DES block 66 */ 67 bool_t 68 xdr_des_block(XDR *xdrs, des_block *blkp) 69 { 70 return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); 71 } 72 73 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 74 75 /* 76 * XDR the MSG_ACCEPTED part of a reply message union 77 */ 78 bool_t 79 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 80 { 81 82 /* personalized union, rather than calling xdr_union */ 83 if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) 84 return (FALSE); 85 if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) 86 return (FALSE); 87 88 switch (ar->ar_stat) { 89 case SUCCESS: 90 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 91 case PROG_MISMATCH: 92 if (!xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) 93 return (FALSE); 94 return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); 95 default: 96 return (TRUE); /* TRUE => open ended set of problems */ 97 } 98 } 99 DEF_WEAK(xdr_accepted_reply); 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 DEF_WEAK(xdr_rejected_reply); 123 124 static struct xdr_discrim reply_dscrm[3] = { 125 { (int)MSG_ACCEPTED, xdr_accepted_reply }, 126 { (int)MSG_DENIED, xdr_rejected_reply }, 127 { __dontcare__, NULL } }; 128 129 /* 130 * XDR a reply message 131 */ 132 bool_t 133 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 134 { 135 if (xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && 136 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && 137 rmsg->rm_direction == REPLY) 138 return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), 139 (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL)); 140 return (FALSE); 141 } 142 DEF_WEAK(xdr_replymsg); 143 144 /* 145 * Serializes the "static part" of a call message header. 146 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 147 * The rm_xid is not really static, but the user can easily munge on the fly. 148 */ 149 bool_t 150 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 151 { 152 153 cmsg->rm_direction = CALL; 154 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 155 if (xdrs->x_op == XDR_ENCODE && 156 xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && 157 xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && 158 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 159 xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog))) 160 return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); 161 return (FALSE); 162 } 163 DEF_WEAK(xdr_callhdr); 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 default: 267 break; 268 } 269 } 270 DEF_STRONG(_seterr_reply); 271