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