xref: /titanic_50/usr/src/lib/libnsl/rpc/rpc_prot.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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