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