Home | History | Annotate | Download | only in rpc
      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