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