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