xref: /freebsd/lib/libc/rpc/rpc_prot.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1 /*	$NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2009, Sun Microsystems, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * - Redistributions of source code must retain the above copyright notice,
12  *   this list of conditions and the following disclaimer.
13  * - Redistributions in binary form must reproduce the above copyright notice,
14  *   this list of conditions and the following disclaimer in the documentation
15  *   and/or other materials provided with the distribution.
16  * - Neither the name of Sun Microsystems, Inc. nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #if defined(LIBC_SCCS) && !defined(lint)
34 static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
35 static char *sccsid = "@(#)rpc_prot.c	2.3 88/08/07 4.0 RPCSRC";
36 #endif
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 /*
41  * rpc_prot.c
42  *
43  * Copyright (C) 1984, Sun Microsystems, Inc.
44  *
45  * This set of routines implements the rpc message definition,
46  * its serializer and some common rpc utility routines.
47  * The routines are meant for various implementations of rpc -
48  * they are NOT for the rpc client or rpc service implementations!
49  * Because authentication stuff is easy and is part of rpc, the opaque
50  * routines are also in this program.
51  */
52 
53 #include "namespace.h"
54 #include <sys/param.h>
55 
56 #include <assert.h>
57 
58 #include <rpc/rpc.h>
59 #include "un-namespace.h"
60 
61 static void accepted(enum accept_stat, struct rpc_err *);
62 static void rejected(enum reject_stat, struct rpc_err *);
63 
64 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
65 
66 extern struct opaque_auth _null_auth;
67 
68 /*
69  * XDR an opaque authentication struct
70  * (see auth.h)
71  */
72 bool_t
73 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
74 {
75 
76 	assert(xdrs != NULL);
77 	assert(ap != NULL);
78 
79 	if (xdr_enum(xdrs, &(ap->oa_flavor)))
80 		return (xdr_bytes(xdrs, &ap->oa_base,
81 			&ap->oa_length, MAX_AUTH_BYTES));
82 	return (FALSE);
83 }
84 
85 /*
86  * XDR a DES block
87  */
88 bool_t
89 xdr_des_block(XDR *xdrs, des_block *blkp)
90 {
91 
92 	assert(xdrs != NULL);
93 	assert(blkp != NULL);
94 
95 	return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block)));
96 }
97 
98 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
99 
100 /*
101  * XDR the MSG_ACCEPTED part of a reply message union
102  */
103 bool_t
104 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
105 {
106 	enum accept_stat *par_stat;
107 
108 	assert(xdrs != NULL);
109 	assert(ar != NULL);
110 
111 	par_stat = &ar->ar_stat;
112 
113 	/* personalized union, rather than calling xdr_union */
114 	if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
115 		return (FALSE);
116 	if (! xdr_enum(xdrs, (enum_t *) par_stat))
117 		return (FALSE);
118 	switch (ar->ar_stat) {
119 
120 	case SUCCESS:
121 		return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
122 
123 	case PROG_MISMATCH:
124 		if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low)))
125 			return (FALSE);
126 		return (xdr_rpcvers(xdrs, &(ar->ar_vers.high)));
127 
128 	case GARBAGE_ARGS:
129 	case SYSTEM_ERR:
130 	case PROC_UNAVAIL:
131 	case PROG_UNAVAIL:
132 		break;
133 	}
134 	return (TRUE);  /* TRUE => open ended set of problems */
135 }
136 
137 /*
138  * XDR the MSG_DENIED part of a reply message union
139  */
140 bool_t
141 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
142 {
143 	enum reject_stat *prj_stat;
144 	enum auth_stat *prj_why;
145 
146 	assert(xdrs != NULL);
147 	assert(rr != NULL);
148 
149 	prj_stat = &rr->rj_stat;
150 
151 	/* personalized union, rather than calling xdr_union */
152 	if (! xdr_enum(xdrs, (enum_t *) prj_stat))
153 		return (FALSE);
154 	switch (rr->rj_stat) {
155 
156 	case RPC_MISMATCH:
157 		if (! xdr_rpcvers(xdrs, &(rr->rj_vers.low)))
158 			return (FALSE);
159 		return (xdr_rpcvers(xdrs, &(rr->rj_vers.high)));
160 
161 	case AUTH_ERROR:
162 		prj_why = &rr->rj_why;
163 		return (xdr_enum(xdrs, (enum_t *) prj_why));
164 	}
165 	/* NOTREACHED */
166 	assert(0);
167 	return (FALSE);
168 }
169 
170 static const struct xdr_discrim reply_dscrm[3] = {
171 	{ (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
172 	{ (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
173 	{ __dontcare__, NULL_xdrproc_t } };
174 
175 /*
176  * XDR a reply message
177  */
178 bool_t
179 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
180 {
181 	enum msg_type *prm_direction;
182 	enum reply_stat *prp_stat;
183 
184 	assert(xdrs != NULL);
185 	assert(rmsg != NULL);
186 
187 	prm_direction = &rmsg->rm_direction;
188 	prp_stat = &rmsg->rm_reply.rp_stat;
189 
190 	if (
191 	    xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) &&
192 	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
193 	    (rmsg->rm_direction == REPLY) )
194 		return (xdr_union(xdrs, (enum_t *) prp_stat,
195 		   (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
196 		   NULL_xdrproc_t));
197 	return (FALSE);
198 }
199 
200 
201 /*
202  * Serializes the "static part" of a call message header.
203  * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
204  * The rm_xid is not really static, but the user can easily munge on the fly.
205  */
206 bool_t
207 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
208 {
209 	enum msg_type *prm_direction;
210 
211 	assert(xdrs != NULL);
212 	assert(cmsg != NULL);
213 
214 	prm_direction = &cmsg->rm_direction;
215 
216 	cmsg->rm_direction = CALL;
217 	cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
218 	if (
219 	    (xdrs->x_op == XDR_ENCODE) &&
220 	    xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
221 	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
222 	    xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
223 	    xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) )
224 		return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)));
225 	return (FALSE);
226 }
227 
228 /* ************************** Client utility routine ************* */
229 
230 static void
231 accepted(enum accept_stat acpt_stat, struct rpc_err *error)
232 {
233 
234 	assert(error != NULL);
235 
236 	switch (acpt_stat) {
237 
238 	case PROG_UNAVAIL:
239 		error->re_status = RPC_PROGUNAVAIL;
240 		return;
241 
242 	case PROG_MISMATCH:
243 		error->re_status = RPC_PROGVERSMISMATCH;
244 		return;
245 
246 	case PROC_UNAVAIL:
247 		error->re_status = RPC_PROCUNAVAIL;
248 		return;
249 
250 	case GARBAGE_ARGS:
251 		error->re_status = RPC_CANTDECODEARGS;
252 		return;
253 
254 	case SYSTEM_ERR:
255 		error->re_status = RPC_SYSTEMERROR;
256 		return;
257 
258 	case SUCCESS:
259 		error->re_status = RPC_SUCCESS;
260 		return;
261 	}
262 	/* NOTREACHED */
263 	/* something's wrong, but we don't know what ... */
264 	error->re_status = RPC_FAILED;
265 	error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
266 	error->re_lb.s2 = (int32_t)acpt_stat;
267 }
268 
269 static void
270 rejected(enum reject_stat rjct_stat, struct rpc_err *error)
271 {
272 
273 	assert(error != NULL);
274 
275 	switch (rjct_stat) {
276 	case RPC_MISMATCH:
277 		error->re_status = RPC_VERSMISMATCH;
278 		return;
279 
280 	case AUTH_ERROR:
281 		error->re_status = RPC_AUTHERROR;
282 		return;
283 	}
284 	/* something's wrong, but we don't know what ... */
285 	/* NOTREACHED */
286 	error->re_status = RPC_FAILED;
287 	error->re_lb.s1 = (int32_t)MSG_DENIED;
288 	error->re_lb.s2 = (int32_t)rjct_stat;
289 }
290 
291 /*
292  * given a reply message, fills in the error
293  */
294 void
295 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
296 {
297 
298 	assert(msg != NULL);
299 	assert(error != NULL);
300 
301 	/* optimized for normal, SUCCESSful case */
302 	switch (msg->rm_reply.rp_stat) {
303 
304 	case MSG_ACCEPTED:
305 		if (msg->acpted_rply.ar_stat == SUCCESS) {
306 			error->re_status = RPC_SUCCESS;
307 			return;
308 		}
309 		accepted(msg->acpted_rply.ar_stat, error);
310 		break;
311 
312 	case MSG_DENIED:
313 		rejected(msg->rjcted_rply.rj_stat, error);
314 		break;
315 
316 	default:
317 		error->re_status = RPC_FAILED;
318 		error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
319 		break;
320 	}
321 	switch (error->re_status) {
322 
323 	case RPC_VERSMISMATCH:
324 		error->re_vers.low = msg->rjcted_rply.rj_vers.low;
325 		error->re_vers.high = msg->rjcted_rply.rj_vers.high;
326 		break;
327 
328 	case RPC_AUTHERROR:
329 		error->re_why = msg->rjcted_rply.rj_why;
330 		break;
331 
332 	case RPC_PROGVERSMISMATCH:
333 		error->re_vers.low = msg->acpted_rply.ar_vers.low;
334 		error->re_vers.high = msg->acpted_rply.ar_vers.high;
335 		break;
336 
337 	case RPC_FAILED:
338 	case RPC_SUCCESS:
339 	case RPC_PROGNOTREGISTERED:
340 	case RPC_PMAPFAILURE:
341 	case RPC_UNKNOWNPROTO:
342 	case RPC_UNKNOWNHOST:
343 	case RPC_SYSTEMERROR:
344 	case RPC_CANTDECODEARGS:
345 	case RPC_PROCUNAVAIL:
346 	case RPC_PROGUNAVAIL:
347 	case RPC_TIMEDOUT:
348 	case RPC_CANTRECV:
349 	case RPC_CANTSEND:
350 	case RPC_CANTDECODERES:
351 	case RPC_CANTENCODEARGS:
352 	default:
353 		break;
354 	}
355 }
356