1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 /* 35 * rpc_prot.c 36 * This set of routines implements the rpc message definition, 37 * its serializer and some common rpc utility routines. 38 * The routines are meant for various implementations of rpc - 39 * they are NOT for the rpc client or rpc service implementations! 40 * Because authentication stuff is easy and is part of rpc, the opaque 41 * routines are also in this program. 42 */ 43 44 #include <sys/param.h> 45 46 #include <sys/types.h> 47 #include <sys/t_lock.h> 48 #include <sys/systm.h> 49 50 #include <rpc/types.h> 51 #include <rpc/xdr.h> 52 #include <rpc/auth.h> 53 #include <rpc/clnt.h> 54 #include <rpc/rpc_msg.h> 55 56 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ 57 58 struct opaque_auth _null_auth; 59 60 /* 61 * XDR an opaque authentication struct 62 * (see auth.h) 63 */ 64 bool_t 65 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) 66 { 67 if (xdr_enum(xdrs, &(ap->oa_flavor))) { 68 return (xdr_bytes(xdrs, &ap->oa_base, 69 &ap->oa_length, MAX_AUTH_BYTES)); 70 } 71 return (FALSE); 72 } 73 74 /* 75 * XDR a DES block 76 */ 77 bool_t 78 xdr_des_block(XDR *xdrs, des_block *blkp) 79 { 80 return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof (des_block))); 81 } 82 83 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ 84 85 /* 86 * XDR the MSG_ACCEPTED part of a reply message union 87 */ 88 bool_t 89 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) 90 { 91 /* personalized union, rather than calling xdr_union */ 92 if (!xdr_opaque_auth(xdrs, &(ar->ar_verf))) 93 return (FALSE); 94 if (!xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) 95 return (FALSE); 96 97 switch (ar->ar_stat) { 98 case SUCCESS: 99 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 100 101 case PROG_MISMATCH: 102 if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low))) 103 return (FALSE); 104 return (xdr_rpcvers(xdrs, &(ar->ar_vers.high))); 105 } 106 return (TRUE); /* TRUE => open ended set of problems */ 107 } 108 109 /* 110 * XDR the MSG_DENIED part of a reply message union 111 */ 112 bool_t 113 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr) 114 { 115 /* personalized union, rather than calling xdr_union */ 116 if (!xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) 117 return (FALSE); 118 switch (rr->rj_stat) { 119 120 case RPC_MISMATCH: 121 if (!xdr_rpcvers(xdrs, &(rr->rj_vers.low))) 122 return (FALSE); 123 return (xdr_rpcvers(xdrs, &(rr->rj_vers.high))); 124 125 case AUTH_ERROR: 126 return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); 127 } 128 return (FALSE); 129 } 130 131 static struct xdr_discrim reply_dscrm[3] = { 132 { MSG_ACCEPTED, xdr_accepted_reply }, 133 { MSG_DENIED, xdr_rejected_reply }, 134 { __dontcare__, NULL_xdrproc_t } 135 }; 136 137 /* 138 * XDR a reply message 139 */ 140 bool_t 141 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) 142 { 143 int32_t *buf; 144 struct accepted_reply *ar; 145 struct opaque_auth *oa; 146 uint_t rndup; 147 148 if (xdrs->x_op == XDR_ENCODE && 149 rmsg->rm_reply.rp_stat == MSG_ACCEPTED && 150 rmsg->rm_direction == REPLY && 151 (buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT + (rndup = 152 RNDUP(rmsg->rm_reply.rp_acpt.ar_verf.oa_length)))) != NULL) { 153 IXDR_PUT_INT32(buf, rmsg->rm_xid); 154 IXDR_PUT_ENUM(buf, rmsg->rm_direction); 155 IXDR_PUT_ENUM(buf, rmsg->rm_reply.rp_stat); 156 ar = &rmsg->rm_reply.rp_acpt; 157 oa = &ar->ar_verf; 158 IXDR_PUT_ENUM(buf, oa->oa_flavor); 159 IXDR_PUT_INT32(buf, oa->oa_length); 160 if (oa->oa_length) { 161 bcopy(oa->oa_base, buf, oa->oa_length); 162 buf = (int32_t *)(((caddr_t)buf) + oa->oa_length); 163 if ((rndup = (rndup - oa->oa_length)) > 0) { 164 bzero(buf, rndup); 165 buf = (int32_t *)(((caddr_t)buf) + rndup); 166 } 167 } 168 /* 169 * stat and rest of reply, copied from xdr_accepted_reply 170 */ 171 IXDR_PUT_ENUM(buf, ar->ar_stat); 172 switch (ar->ar_stat) { 173 case SUCCESS: 174 return ((*(ar->ar_results.proc))(xdrs, 175 ar->ar_results.where)); 176 177 case PROG_MISMATCH: 178 if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low))) 179 return (FALSE); 180 return (xdr_rpcvers(xdrs, &(ar->ar_vers.high))); 181 } 182 return (TRUE); 183 } 184 if (xdrs->x_op == XDR_DECODE && 185 (buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT)) != NULL) { 186 rmsg->rm_xid = IXDR_GET_INT32(buf); 187 rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); 188 if (rmsg->rm_direction != REPLY) 189 return (FALSE); 190 rmsg->rm_reply.rp_stat = IXDR_GET_ENUM(buf, enum reply_stat); 191 if (rmsg->rm_reply.rp_stat != MSG_ACCEPTED) { 192 if (rmsg->rm_reply.rp_stat == MSG_DENIED) 193 return (xdr_rejected_reply(xdrs, 194 &rmsg->rm_reply.rp_rjct)); 195 return (FALSE); 196 } 197 ar = &rmsg->rm_reply.rp_acpt; 198 oa = &ar->ar_verf; 199 buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); 200 if (buf != NULL) { 201 oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); 202 oa->oa_length = IXDR_GET_INT32(buf); 203 } else { 204 if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || 205 xdr_u_int(xdrs, &oa->oa_length) == FALSE) 206 return (FALSE); 207 } 208 if (oa->oa_length) { 209 if (oa->oa_length > MAX_AUTH_BYTES) 210 return (FALSE); 211 if (oa->oa_base == NULL) { 212 oa->oa_base = (caddr_t) 213 mem_alloc(oa->oa_length); 214 } 215 buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); 216 if (buf == NULL) { 217 if (xdr_opaque(xdrs, oa->oa_base, 218 oa->oa_length) == FALSE) 219 return (FALSE); 220 } else { 221 bcopy(buf, oa->oa_base, oa->oa_length); 222 } 223 } 224 /* 225 * stat and rest of reply, copied from 226 * xdr_accepted_reply 227 */ 228 if (!xdr_enum(xdrs, (enum_t *)&ar->ar_stat)) 229 return (FALSE); 230 switch (ar->ar_stat) { 231 case SUCCESS: 232 return ((*(ar->ar_results.proc))(xdrs, 233 ar->ar_results.where)); 234 235 case PROG_MISMATCH: 236 if (!xdr_rpcvers(xdrs, &ar->ar_vers.low)) 237 return (FALSE); 238 return (xdr_rpcvers(xdrs, &ar->ar_vers.high)); 239 } 240 return (TRUE); 241 } 242 243 if (xdr_u_int(xdrs, &(rmsg->rm_xid)) && 244 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && 245 (rmsg->rm_direction == REPLY)) 246 return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), 247 (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, 248 NULL_xdrproc_t)); 249 return (FALSE); 250 } 251 252 /* 253 * XDR a reply message header (encode only) 254 */ 255 bool_t 256 xdr_replymsg_hdr(XDR *xdrs, struct rpc_msg *rmsg) 257 { 258 int32_t *buf; 259 struct accepted_reply *ar; 260 struct opaque_auth *oa; 261 uint_t rndup; 262 263 if (xdrs->x_op != XDR_ENCODE || 264 rmsg->rm_reply.rp_stat != MSG_ACCEPTED || 265 rmsg->rm_direction != REPLY) 266 return (FALSE); 267 268 if ((buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT + (rndup = 269 RNDUP(rmsg->rm_reply.rp_acpt.ar_verf.oa_length)))) != NULL) { 270 IXDR_PUT_INT32(buf, rmsg->rm_xid); 271 IXDR_PUT_ENUM(buf, rmsg->rm_direction); 272 IXDR_PUT_ENUM(buf, rmsg->rm_reply.rp_stat); 273 ar = &rmsg->rm_reply.rp_acpt; 274 oa = &ar->ar_verf; 275 IXDR_PUT_ENUM(buf, oa->oa_flavor); 276 IXDR_PUT_INT32(buf, oa->oa_length); 277 if (oa->oa_length) { 278 bcopy(oa->oa_base, buf, oa->oa_length); 279 buf = (int32_t *)(((caddr_t)buf) + oa->oa_length); 280 if ((rndup = (rndup - oa->oa_length)) > 0) { 281 bzero(buf, rndup); 282 buf = (int32_t *)(((caddr_t)buf) + rndup); 283 } 284 } 285 /* 286 * stat and rest of reply, copied from xdr_accepted_reply 287 */ 288 IXDR_PUT_ENUM(buf, ar->ar_stat); 289 return (TRUE); 290 } 291 292 if (xdr_u_int(xdrs, &(rmsg->rm_xid)) && 293 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && 294 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat)) && 295 xdr_opaque_auth(xdrs, &rmsg->rm_reply.rp_acpt.ar_verf) && 296 xdr_enum(xdrs, (enum_t *)&(rmsg->rm_reply.rp_acpt.ar_stat))) 297 return (TRUE); 298 return (FALSE); 299 } 300 301 /* 302 * XDR a reply message body (encode only) 303 */ 304 bool_t 305 xdr_replymsg_body(XDR *xdrs, struct rpc_msg *rmsg) 306 { 307 struct accepted_reply *ar; 308 309 if (xdrs->x_op != XDR_ENCODE) 310 return (FALSE); 311 312 ar = &rmsg->rm_reply.rp_acpt; 313 314 if (ar->ar_results.proc == NULL) 315 return (TRUE); 316 return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); 317 } 318 319 /* 320 * Serializes the "static part" of a call message header. 321 * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. 322 * The rm_xid is not really static, but the user can easily munge on the fly. 323 */ 324 bool_t 325 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) 326 { 327 cmsg->rm_direction = CALL; 328 cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; 329 if (xdrs->x_op == XDR_ENCODE && 330 xdr_u_int(xdrs, &(cmsg->rm_xid)) && 331 xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && 332 xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) && 333 xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog))) 334 return (xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_vers))); 335 return (FALSE); 336 } 337 338 /* ************************** Client utility routine ************* */ 339 340 static void 341 accepted(enum accept_stat acpt_stat, struct rpc_err *error) 342 { 343 switch (acpt_stat) { 344 case PROG_UNAVAIL: 345 error->re_status = RPC_PROGUNAVAIL; 346 return; 347 348 case PROG_MISMATCH: 349 error->re_status = RPC_PROGVERSMISMATCH; 350 return; 351 352 case PROC_UNAVAIL: 353 error->re_status = RPC_PROCUNAVAIL; 354 return; 355 356 case GARBAGE_ARGS: 357 error->re_status = RPC_CANTDECODEARGS; 358 return; 359 360 case SYSTEM_ERR: 361 error->re_status = RPC_SYSTEMERROR; 362 return; 363 364 case SUCCESS: 365 error->re_status = RPC_SUCCESS; 366 return; 367 } 368 /* something's wrong, but we don't know what ... */ 369 error->re_status = RPC_FAILED; 370 error->re_lb.s1 = (int32_t)MSG_ACCEPTED; 371 error->re_lb.s2 = (int32_t)acpt_stat; 372 } 373 374 static void 375 rejected(enum reject_stat rjct_stat, struct rpc_err *error) 376 { 377 switch (rjct_stat) { 378 case RPC_VERSMISMATCH: 379 error->re_status = RPC_VERSMISMATCH; 380 return; 381 382 case AUTH_ERROR: 383 error->re_status = RPC_AUTHERROR; 384 return; 385 } 386 /* something's wrong, but we don't know what ... */ 387 error->re_status = RPC_FAILED; 388 error->re_lb.s1 = (int32_t)MSG_DENIED; 389 error->re_lb.s2 = (int32_t)rjct_stat; 390 } 391 392 /* 393 * given a reply message, fills in the error 394 */ 395 void 396 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) 397 { 398 /* optimized for normal, SUCCESSful case */ 399 switch (msg->rm_reply.rp_stat) { 400 case MSG_ACCEPTED: 401 if (msg->acpted_rply.ar_stat == SUCCESS) { 402 error->re_status = RPC_SUCCESS; 403 return; 404 }; 405 accepted(msg->acpted_rply.ar_stat, error); 406 break; 407 408 case MSG_DENIED: 409 rejected(msg->rjcted_rply.rj_stat, error); 410 break; 411 412 default: 413 error->re_status = RPC_FAILED; 414 error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); 415 break; 416 } 417 418 switch (error->re_status) { 419 case RPC_VERSMISMATCH: 420 error->re_vers.low = msg->rjcted_rply.rj_vers.low; 421 error->re_vers.high = msg->rjcted_rply.rj_vers.high; 422 break; 423 424 case RPC_AUTHERROR: 425 error->re_why = msg->rjcted_rply.rj_why; 426 break; 427 428 case RPC_PROGVERSMISMATCH: 429 error->re_vers.low = msg->acpted_rply.ar_vers.low; 430 error->re_vers.high = msg->acpted_rply.ar_vers.high; 431 break; 432 } 433 } 434 435 /* 436 * given a reply message, frees the accepted verifier 437 */ 438 bool_t 439 xdr_rpc_free_verifier(XDR *xdrs, struct rpc_msg *msg) 440 { 441 if (msg->rm_direction == REPLY && 442 msg->rm_reply.rp_stat == MSG_ACCEPTED && 443 msg->acpted_rply.ar_verf.oa_base != NULL) { 444 xdrs->x_op = XDR_FREE; 445 return (xdr_opaque_auth(xdrs, &(msg->acpted_rply.ar_verf))); 446 } 447 return (TRUE); 448 } 449