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