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 #include <sys/cdefs.h> 34 /* 35 * rpc_prot.c 36 * 37 * Copyright (C) 1984, Sun Microsystems, Inc. 38 * 39 * This set of routines implements the rpc message definition, 40 * its serializer and some common rpc utility routines. 41 * The routines are meant for various implementations of rpc - 42 * they are NOT for the rpc client or rpc service implementations! 43 * Because authentication stuff is easy and is part of rpc, the opaque 44 * routines are also in this program. 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 52 #include <rpc/types.h> 53 #include <rpc/xdr.h> 54 #include <rpc/auth.h> 55 #include <rpc/clnt.h> 56 #include <rpc/rpc_msg.h> 57 58 #define assert(exp) KASSERT(exp, ("bad arguments")) 59 60 static enum clnt_stat accepted(enum accept_stat, struct rpc_err *); 61 static enum clnt_stat rejected(enum reject_stat, struct rpc_err *); 62 63 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ 64 65 struct opaque_auth _null_auth; 66 67 /* 68 * XDR an opaque authentication struct 69 * (see auth.h) 70 */ 71 bool_t 72 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 73 { 74 75 assert(xdrs != NULL); 76 assert(ap != NULL); 77 78 if (xdr_enum(xdrs, &(ap->oa_flavor))) 79 return (xdr_bytes(xdrs, &ap->oa_base, 80 &ap->oa_length, MAX_AUTH_BYTES)); 81 return (FALSE); 82 } 83 84 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 85 86 /* 87 * XDR the MSG_ACCEPTED part of a reply message union 88 */ 89 bool_t 90 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 91 { 92 enum accept_stat *par_stat; 93 94 assert(xdrs != NULL); 95 assert(ar != NULL); 96 97 par_stat = &ar->ar_stat; 98 99 /* personalized union, rather than calling xdr_union */ 100 if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) 101 return (FALSE); 102 if (! xdr_enum(xdrs, (enum_t *) par_stat)) 103 return (FALSE); 104 switch (ar->ar_stat) { 105 106 case SUCCESS: 107 if (ar->ar_results.proc != (xdrproc_t) xdr_void) 108 return ((*(ar->ar_results.proc))(xdrs, 109 ar->ar_results.where)); 110 else 111 return (TRUE); 112 113 case PROG_MISMATCH: 114 if (! xdr_uint32_t(xdrs, &(ar->ar_vers.low))) 115 return (FALSE); 116 return (xdr_uint32_t(xdrs, &(ar->ar_vers.high))); 117 118 case GARBAGE_ARGS: 119 case SYSTEM_ERR: 120 case PROC_UNAVAIL: 121 case PROG_UNAVAIL: 122 break; 123 } 124 return (TRUE); /* TRUE => open ended set of problems */ 125 } 126 127 /* 128 * XDR the MSG_DENIED part of a reply message union 129 */ 130 bool_t 131 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr) 132 { 133 enum reject_stat *prj_stat; 134 enum auth_stat *prj_why; 135 136 assert(xdrs != NULL); 137 assert(rr != NULL); 138 139 prj_stat = &rr->rj_stat; 140 141 /* personalized union, rather than calling xdr_union */ 142 if (! xdr_enum(xdrs, (enum_t *) prj_stat)) 143 return (FALSE); 144 switch (rr->rj_stat) { 145 146 case RPC_MISMATCH: 147 if (! xdr_uint32_t(xdrs, &(rr->rj_vers.low))) 148 return (FALSE); 149 return (xdr_uint32_t(xdrs, &(rr->rj_vers.high))); 150 151 case AUTH_ERROR: 152 prj_why = &rr->rj_why; 153 return (xdr_enum(xdrs, (enum_t *) prj_why)); 154 } 155 /* NOTREACHED */ 156 assert(0); 157 return (FALSE); 158 } 159 160 static const struct xdr_discrim reply_dscrm[3] = { 161 { (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply }, 162 { (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply }, 163 { __dontcare__, NULL_xdrproc_t } }; 164 165 /* 166 * XDR a reply message 167 */ 168 bool_t 169 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 170 { 171 int32_t *buf; 172 enum msg_type *prm_direction; 173 enum reply_stat *prp_stat; 174 175 assert(xdrs != NULL); 176 assert(rmsg != NULL); 177 178 if (xdrs->x_op == XDR_DECODE) { 179 buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT); 180 if (buf != NULL) { 181 rmsg->rm_xid = IXDR_GET_UINT32(buf); 182 rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); 183 if (rmsg->rm_direction != REPLY) { 184 return (FALSE); 185 } 186 rmsg->rm_reply.rp_stat = 187 IXDR_GET_ENUM(buf, enum reply_stat); 188 if (rmsg->rm_reply.rp_stat == MSG_ACCEPTED) 189 return (xdr_accepted_reply(xdrs, 190 &rmsg->acpted_rply)); 191 else if (rmsg->rm_reply.rp_stat == MSG_DENIED) 192 return (xdr_rejected_reply(xdrs, 193 &rmsg->rjcted_rply)); 194 else 195 return (FALSE); 196 } 197 } 198 199 prm_direction = &rmsg->rm_direction; 200 prp_stat = &rmsg->rm_reply.rp_stat; 201 202 if ( 203 xdr_uint32_t(xdrs, &(rmsg->rm_xid)) && 204 xdr_enum(xdrs, (enum_t *) prm_direction) && 205 (rmsg->rm_direction == REPLY) ) 206 return (xdr_union(xdrs, (enum_t *) prp_stat, 207 (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, 208 NULL_xdrproc_t)); 209 return (FALSE); 210 } 211 212 213 /* 214 * Serializes the "static part" of a call message header. 215 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 216 * The rm_xid is not really static, but the user can easily munge on the fly. 217 */ 218 bool_t 219 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 220 { 221 enum msg_type *prm_direction; 222 223 assert(xdrs != NULL); 224 assert(cmsg != NULL); 225 226 prm_direction = &cmsg->rm_direction; 227 228 cmsg->rm_direction = CALL; 229 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 230 if ( 231 (xdrs->x_op == XDR_ENCODE) && 232 xdr_uint32_t(xdrs, &(cmsg->rm_xid)) && 233 xdr_enum(xdrs, (enum_t *) prm_direction) && 234 xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 235 xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) ) 236 return (xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers))); 237 return (FALSE); 238 } 239 240 /* ************************** Client utility routine ************* */ 241 242 static enum clnt_stat 243 accepted(enum accept_stat acpt_stat, struct rpc_err *error) 244 { 245 246 assert(error != NULL); 247 248 switch (acpt_stat) { 249 250 case PROG_UNAVAIL: 251 error->re_status = RPC_PROGUNAVAIL; 252 return (RPC_PROGUNAVAIL); 253 254 case PROG_MISMATCH: 255 error->re_status = RPC_PROGVERSMISMATCH; 256 return (RPC_PROGVERSMISMATCH); 257 258 case PROC_UNAVAIL: 259 return (RPC_PROCUNAVAIL); 260 261 case GARBAGE_ARGS: 262 return (RPC_CANTDECODEARGS); 263 264 case SYSTEM_ERR: 265 return (RPC_SYSTEMERROR); 266 267 case SUCCESS: 268 return (RPC_SUCCESS); 269 } 270 /* NOTREACHED */ 271 /* something's wrong, but we don't know what ... */ 272 error->re_lb.s1 = (int32_t)MSG_ACCEPTED; 273 error->re_lb.s2 = (int32_t)acpt_stat; 274 return (RPC_FAILED); 275 } 276 277 static enum clnt_stat 278 rejected(enum reject_stat rjct_stat, struct rpc_err *error) 279 { 280 281 assert(error != NULL); 282 283 switch (rjct_stat) { 284 case RPC_MISMATCH: 285 return (RPC_VERSMISMATCH); 286 287 case AUTH_ERROR: 288 return (RPC_AUTHERROR); 289 } 290 /* something's wrong, but we don't know what ... */ 291 /* NOTREACHED */ 292 error->re_lb.s1 = (int32_t)MSG_DENIED; 293 error->re_lb.s2 = (int32_t)rjct_stat; 294 return (RPC_FAILED); 295 } 296 297 /* 298 * given a reply message, fills in the error 299 */ 300 enum clnt_stat 301 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) 302 { 303 enum clnt_stat stat; 304 305 assert(msg != NULL); 306 assert(error != NULL); 307 308 /* optimized for normal, SUCCESSful case */ 309 switch (msg->rm_reply.rp_stat) { 310 311 case MSG_ACCEPTED: 312 if (msg->acpted_rply.ar_stat == SUCCESS) { 313 stat = RPC_SUCCESS; 314 return (stat); 315 } 316 stat = accepted(msg->acpted_rply.ar_stat, error); 317 break; 318 319 case MSG_DENIED: 320 stat = rejected(msg->rjcted_rply.rj_stat, error); 321 break; 322 323 default: 324 stat = RPC_FAILED; 325 error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); 326 break; 327 } 328 error->re_status = stat; 329 330 switch (stat) { 331 332 case RPC_VERSMISMATCH: 333 error->re_vers.low = msg->rjcted_rply.rj_vers.low; 334 error->re_vers.high = msg->rjcted_rply.rj_vers.high; 335 break; 336 337 case RPC_AUTHERROR: 338 error->re_why = msg->rjcted_rply.rj_why; 339 break; 340 341 case RPC_PROGVERSMISMATCH: 342 error->re_vers.low = msg->acpted_rply.ar_vers.low; 343 error->re_vers.high = msg->acpted_rply.ar_vers.high; 344 break; 345 346 case RPC_FAILED: 347 case RPC_SUCCESS: 348 case RPC_PROGNOTREGISTERED: 349 case RPC_PMAPFAILURE: 350 case RPC_UNKNOWNPROTO: 351 case RPC_UNKNOWNHOST: 352 case RPC_SYSTEMERROR: 353 case RPC_CANTDECODEARGS: 354 case RPC_PROCUNAVAIL: 355 case RPC_PROGUNAVAIL: 356 case RPC_TIMEDOUT: 357 case RPC_CANTRECV: 358 case RPC_CANTSEND: 359 case RPC_CANTDECODERES: 360 case RPC_CANTENCODEARGS: 361 default: 362 break; 363 } 364 365 return (stat); 366 } 367