xref: /illumos-gate/usr/src/uts/common/rpc/rpc_prot.c (revision a38ddfee9c8c6b6c5a2947ff52fd2338362a4444)
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