1 /* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 2009, Sun Microsystems, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * - Neither the name of Sun Microsystems, 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 "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 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 "namespace.h" 47 #include <sys/param.h> 48 49 #include <assert.h> 50 51 #include <rpc/rpc.h> 52 #include "un-namespace.h" 53 54 static void accepted(enum accept_stat, struct rpc_err *); 55 static void rejected(enum reject_stat, struct rpc_err *); 56 57 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ 58 59 extern struct opaque_auth _null_auth; 60 61 /* 62 * XDR an opaque authentication struct 63 * (see auth.h) 64 */ 65 bool_t 66 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 67 { 68 69 assert(xdrs != NULL); 70 assert(ap != NULL); 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 block 80 */ 81 bool_t 82 xdr_des_block(XDR *xdrs, des_block *blkp) 83 { 84 85 assert(xdrs != NULL); 86 assert(blkp != NULL); 87 88 return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block))); 89 } 90 91 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 92 93 /* 94 * XDR the MSG_ACCEPTED part of a reply message union 95 */ 96 bool_t 97 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 98 { 99 enum accept_stat *par_stat; 100 101 assert(xdrs != NULL); 102 assert(ar != NULL); 103 104 par_stat = &ar->ar_stat; 105 106 /* personalized union, rather than calling xdr_union */ 107 if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) 108 return (FALSE); 109 if (! xdr_enum(xdrs, (enum_t *) par_stat)) 110 return (FALSE); 111 switch (ar->ar_stat) { 112 113 case SUCCESS: 114 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 115 116 case PROG_MISMATCH: 117 if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low))) 118 return (FALSE); 119 return (xdr_rpcvers(xdrs, &(ar->ar_vers.high))); 120 121 case GARBAGE_ARGS: 122 case SYSTEM_ERR: 123 case PROC_UNAVAIL: 124 case PROG_UNAVAIL: 125 break; 126 } 127 return (TRUE); /* TRUE => open ended set of problems */ 128 } 129 130 /* 131 * XDR the MSG_DENIED part of a reply message union 132 */ 133 bool_t 134 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr) 135 { 136 enum reject_stat *prj_stat; 137 enum auth_stat *prj_why; 138 139 assert(xdrs != NULL); 140 assert(rr != NULL); 141 142 prj_stat = &rr->rj_stat; 143 144 /* personalized union, rather than calling xdr_union */ 145 if (! xdr_enum(xdrs, (enum_t *) prj_stat)) 146 return (FALSE); 147 switch (rr->rj_stat) { 148 149 case RPC_MISMATCH: 150 if (! xdr_rpcvers(xdrs, &(rr->rj_vers.low))) 151 return (FALSE); 152 return (xdr_rpcvers(xdrs, &(rr->rj_vers.high))); 153 154 case AUTH_ERROR: 155 prj_why = &rr->rj_why; 156 return (xdr_enum(xdrs, (enum_t *) prj_why)); 157 } 158 /* NOTREACHED */ 159 assert(0); 160 return (FALSE); 161 } 162 163 static const struct xdr_discrim reply_dscrm[3] = { 164 { (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply }, 165 { (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply }, 166 { __dontcare__, NULL_xdrproc_t } }; 167 168 /* 169 * XDR a reply message 170 */ 171 bool_t 172 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 173 { 174 enum msg_type *prm_direction; 175 enum reply_stat *prp_stat; 176 177 assert(xdrs != NULL); 178 assert(rmsg != NULL); 179 180 prm_direction = &rmsg->rm_direction; 181 prp_stat = &rmsg->rm_reply.rp_stat; 182 183 if ( 184 xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && 185 xdr_enum(xdrs, (enum_t *) prm_direction) && 186 (rmsg->rm_direction == REPLY) ) 187 return (xdr_union(xdrs, (enum_t *) prp_stat, 188 (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, 189 NULL_xdrproc_t)); 190 return (FALSE); 191 } 192 193 194 /* 195 * Serializes the "static part" of a call message header. 196 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 197 * The rm_xid is not really static, but the user can easily munge on the fly. 198 */ 199 bool_t 200 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 201 { 202 enum msg_type *prm_direction; 203 204 assert(xdrs != NULL); 205 assert(cmsg != NULL); 206 207 prm_direction = &cmsg->rm_direction; 208 209 cmsg->rm_direction = CALL; 210 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 211 if ( 212 (xdrs->x_op == XDR_ENCODE) && 213 xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && 214 xdr_enum(xdrs, (enum_t *) prm_direction) && 215 xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 216 xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) ) 217 return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); 218 return (FALSE); 219 } 220 221 /* ************************** Client utility routine ************* */ 222 223 static void 224 accepted(enum accept_stat acpt_stat, struct rpc_err *error) 225 { 226 227 assert(error != NULL); 228 229 switch (acpt_stat) { 230 231 case PROG_UNAVAIL: 232 error->re_status = RPC_PROGUNAVAIL; 233 return; 234 235 case PROG_MISMATCH: 236 error->re_status = RPC_PROGVERSMISMATCH; 237 return; 238 239 case PROC_UNAVAIL: 240 error->re_status = RPC_PROCUNAVAIL; 241 return; 242 243 case GARBAGE_ARGS: 244 error->re_status = RPC_CANTDECODEARGS; 245 return; 246 247 case SYSTEM_ERR: 248 error->re_status = RPC_SYSTEMERROR; 249 return; 250 251 case SUCCESS: 252 error->re_status = RPC_SUCCESS; 253 return; 254 } 255 /* NOTREACHED */ 256 /* something's wrong, but we don't know what ... */ 257 error->re_status = RPC_FAILED; 258 error->re_lb.s1 = (int32_t)MSG_ACCEPTED; 259 error->re_lb.s2 = (int32_t)acpt_stat; 260 } 261 262 static void 263 rejected(enum reject_stat rjct_stat, struct rpc_err *error) 264 { 265 266 assert(error != NULL); 267 268 switch (rjct_stat) { 269 case RPC_MISMATCH: 270 error->re_status = RPC_VERSMISMATCH; 271 return; 272 273 case AUTH_ERROR: 274 error->re_status = RPC_AUTHERROR; 275 return; 276 } 277 /* something's wrong, but we don't know what ... */ 278 /* NOTREACHED */ 279 error->re_status = RPC_FAILED; 280 error->re_lb.s1 = (int32_t)MSG_DENIED; 281 error->re_lb.s2 = (int32_t)rjct_stat; 282 } 283 284 /* 285 * given a reply message, fills in the error 286 */ 287 void 288 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) 289 { 290 291 assert(msg != NULL); 292 assert(error != NULL); 293 294 /* optimized for normal, SUCCESSful case */ 295 switch (msg->rm_reply.rp_stat) { 296 297 case MSG_ACCEPTED: 298 if (msg->acpted_rply.ar_stat == SUCCESS) { 299 error->re_status = RPC_SUCCESS; 300 return; 301 } 302 accepted(msg->acpted_rply.ar_stat, error); 303 break; 304 305 case MSG_DENIED: 306 rejected(msg->rjcted_rply.rj_stat, error); 307 break; 308 309 default: 310 error->re_status = RPC_FAILED; 311 error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); 312 break; 313 } 314 switch (error->re_status) { 315 316 case RPC_VERSMISMATCH: 317 error->re_vers.low = msg->rjcted_rply.rj_vers.low; 318 error->re_vers.high = msg->rjcted_rply.rj_vers.high; 319 break; 320 321 case RPC_AUTHERROR: 322 error->re_why = msg->rjcted_rply.rj_why; 323 break; 324 325 case RPC_PROGVERSMISMATCH: 326 error->re_vers.low = msg->acpted_rply.ar_vers.low; 327 error->re_vers.high = msg->acpted_rply.ar_vers.high; 328 break; 329 330 case RPC_FAILED: 331 case RPC_SUCCESS: 332 case RPC_PROGNOTREGISTERED: 333 case RPC_PMAPFAILURE: 334 case RPC_UNKNOWNPROTO: 335 case RPC_UNKNOWNHOST: 336 case RPC_SYSTEMERROR: 337 case RPC_CANTDECODEARGS: 338 case RPC_PROCUNAVAIL: 339 case RPC_PROGUNAVAIL: 340 case RPC_TIMEDOUT: 341 case RPC_CANTRECV: 342 case RPC_CANTSEND: 343 case RPC_CANTDECODERES: 344 case RPC_CANTENCODEARGS: 345 default: 346 break; 347 } 348 } 349