xref: /freebsd/sys/rpc/rpc_prot.c (revision a03411e84728e9b267056fd31c7d1d9d1dc1b01e)
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 #include <sys/cdefs.h>
34 /*
35  * rpc_prot.c
36  *
37  * Copyright (C) 1984, Sun Microsystems, Inc.
38  *
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 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 
52 #include <rpc/types.h>
53 #include <rpc/xdr.h>
54 #include <rpc/auth.h>
55 #include <rpc/clnt.h>
56 #include <rpc/rpc_msg.h>
57 
58 #define assert(exp)	KASSERT(exp, ("bad arguments"))
59 
60 static enum clnt_stat accepted(enum accept_stat, struct rpc_err *);
61 static enum clnt_stat rejected(enum reject_stat, struct rpc_err *);
62 
63 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
64 
65 struct opaque_auth _null_auth;
66 
67 /*
68  * XDR an opaque authentication struct
69  * (see auth.h)
70  */
71 bool_t
72 xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
73 {
74 
75 	assert(xdrs != NULL);
76 	assert(ap != NULL);
77 
78 	if (xdr_enum(xdrs, &(ap->oa_flavor)))
79 		return (xdr_bytes(xdrs, &ap->oa_base,
80 			&ap->oa_length, MAX_AUTH_BYTES));
81 	return (FALSE);
82 }
83 
84 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
85 
86 /*
87  * XDR the MSG_ACCEPTED part of a reply message union
88  */
89 bool_t
90 xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
91 {
92 	enum accept_stat *par_stat;
93 
94 	assert(xdrs != NULL);
95 	assert(ar != NULL);
96 
97 	par_stat = &ar->ar_stat;
98 
99 	/* personalized union, rather than calling xdr_union */
100 	if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
101 		return (FALSE);
102 	if (! xdr_enum(xdrs, (enum_t *) par_stat))
103 		return (FALSE);
104 	switch (ar->ar_stat) {
105 
106 	case SUCCESS:
107 		if (ar->ar_results.proc != (xdrproc_t) xdr_void)
108 			return ((*(ar->ar_results.proc))(xdrs,
109 				ar->ar_results.where));
110 		else
111 			return (TRUE);
112 
113 	case PROG_MISMATCH:
114 		if (! xdr_uint32_t(xdrs, &(ar->ar_vers.low)))
115 			return (FALSE);
116 		return (xdr_uint32_t(xdrs, &(ar->ar_vers.high)));
117 
118 	case GARBAGE_ARGS:
119 	case SYSTEM_ERR:
120 	case PROC_UNAVAIL:
121 	case PROG_UNAVAIL:
122 		break;
123 	}
124 	return (TRUE);  /* TRUE => open ended set of problems */
125 }
126 
127 /*
128  * XDR the MSG_DENIED part of a reply message union
129  */
130 bool_t
131 xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
132 {
133 	enum reject_stat *prj_stat;
134 	enum auth_stat *prj_why;
135 
136 	assert(xdrs != NULL);
137 	assert(rr != NULL);
138 
139 	prj_stat = &rr->rj_stat;
140 
141 	/* personalized union, rather than calling xdr_union */
142 	if (! xdr_enum(xdrs, (enum_t *) prj_stat))
143 		return (FALSE);
144 	switch (rr->rj_stat) {
145 
146 	case RPC_MISMATCH:
147 		if (! xdr_uint32_t(xdrs, &(rr->rj_vers.low)))
148 			return (FALSE);
149 		return (xdr_uint32_t(xdrs, &(rr->rj_vers.high)));
150 
151 	case AUTH_ERROR:
152 		prj_why = &rr->rj_why;
153 		return (xdr_enum(xdrs, (enum_t *) prj_why));
154 	}
155 	/* NOTREACHED */
156 	assert(0);
157 	return (FALSE);
158 }
159 
160 static const struct xdr_discrim reply_dscrm[3] = {
161 	{ (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
162 	{ (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
163 	{ __dontcare__, NULL_xdrproc_t } };
164 
165 /*
166  * XDR a reply message
167  */
168 bool_t
169 xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
170 {
171 	int32_t *buf;
172 	enum msg_type *prm_direction;
173 	enum reply_stat *prp_stat;
174 
175 	assert(xdrs != NULL);
176 	assert(rmsg != NULL);
177 
178 	if (xdrs->x_op == XDR_DECODE) {
179 		buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT);
180 		if (buf != NULL) {
181 			rmsg->rm_xid = IXDR_GET_UINT32(buf);
182 			rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
183 			if (rmsg->rm_direction != REPLY) {
184 				return (FALSE);
185 			}
186 			rmsg->rm_reply.rp_stat =
187 				IXDR_GET_ENUM(buf, enum reply_stat);
188 			if (rmsg->rm_reply.rp_stat == MSG_ACCEPTED)
189 				return (xdr_accepted_reply(xdrs,
190 					&rmsg->acpted_rply));
191 			else if (rmsg->rm_reply.rp_stat == MSG_DENIED)
192 				return (xdr_rejected_reply(xdrs,
193 					&rmsg->rjcted_rply));
194 			else
195 				return (FALSE);
196 		}
197 	}
198 
199 	prm_direction = &rmsg->rm_direction;
200 	prp_stat = &rmsg->rm_reply.rp_stat;
201 
202 	if (
203 	    xdr_uint32_t(xdrs, &(rmsg->rm_xid)) &&
204 	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
205 	    (rmsg->rm_direction == REPLY) )
206 		return (xdr_union(xdrs, (enum_t *) prp_stat,
207 		   (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
208 		   NULL_xdrproc_t));
209 	return (FALSE);
210 }
211 
212 
213 /*
214  * Serializes the "static part" of a call message header.
215  * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
216  * The rm_xid is not really static, but the user can easily munge on the fly.
217  */
218 bool_t
219 xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
220 {
221 	enum msg_type *prm_direction;
222 
223 	assert(xdrs != NULL);
224 	assert(cmsg != NULL);
225 
226 	prm_direction = &cmsg->rm_direction;
227 
228 	cmsg->rm_direction = CALL;
229 	cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
230 	if (
231 	    (xdrs->x_op == XDR_ENCODE) &&
232 	    xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
233 	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
234 	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
235 	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) )
236 		return (xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)));
237 	return (FALSE);
238 }
239 
240 /* ************************** Client utility routine ************* */
241 
242 static enum clnt_stat
243 accepted(enum accept_stat acpt_stat, struct rpc_err *error)
244 {
245 
246 	assert(error != NULL);
247 
248 	switch (acpt_stat) {
249 
250 	case PROG_UNAVAIL:
251 		error->re_status = RPC_PROGUNAVAIL;
252 		return (RPC_PROGUNAVAIL);
253 
254 	case PROG_MISMATCH:
255 		error->re_status = RPC_PROGVERSMISMATCH;
256 		return (RPC_PROGVERSMISMATCH);
257 
258 	case PROC_UNAVAIL:
259 		return (RPC_PROCUNAVAIL);
260 
261 	case GARBAGE_ARGS:
262 		return (RPC_CANTDECODEARGS);
263 
264 	case SYSTEM_ERR:
265 		return (RPC_SYSTEMERROR);
266 
267 	case SUCCESS:
268 		return (RPC_SUCCESS);
269 	}
270 	/* NOTREACHED */
271 	/* something's wrong, but we don't know what ... */
272 	error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
273 	error->re_lb.s2 = (int32_t)acpt_stat;
274 	return (RPC_FAILED);
275 }
276 
277 static enum clnt_stat
278 rejected(enum reject_stat rjct_stat, struct rpc_err *error)
279 {
280 
281 	assert(error != NULL);
282 
283 	switch (rjct_stat) {
284 	case RPC_MISMATCH:
285 		return (RPC_VERSMISMATCH);
286 
287 	case AUTH_ERROR:
288 		return (RPC_AUTHERROR);
289 	}
290 	/* something's wrong, but we don't know what ... */
291 	/* NOTREACHED */
292 	error->re_lb.s1 = (int32_t)MSG_DENIED;
293 	error->re_lb.s2 = (int32_t)rjct_stat;
294 	return (RPC_FAILED);
295 }
296 
297 /*
298  * given a reply message, fills in the error
299  */
300 enum clnt_stat
301 _seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
302 {
303 	enum clnt_stat stat;
304 
305 	assert(msg != NULL);
306 	assert(error != NULL);
307 
308 	/* optimized for normal, SUCCESSful case */
309 	switch (msg->rm_reply.rp_stat) {
310 
311 	case MSG_ACCEPTED:
312 		if (msg->acpted_rply.ar_stat == SUCCESS) {
313 			stat = RPC_SUCCESS;
314 			return (stat);
315 		}
316 		stat = accepted(msg->acpted_rply.ar_stat, error);
317 		break;
318 
319 	case MSG_DENIED:
320 		stat = rejected(msg->rjcted_rply.rj_stat, error);
321 		break;
322 
323 	default:
324 		stat = RPC_FAILED;
325 		error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
326 		break;
327 	}
328 	error->re_status = stat;
329 
330 	switch (stat) {
331 
332 	case RPC_VERSMISMATCH:
333 		error->re_vers.low = msg->rjcted_rply.rj_vers.low;
334 		error->re_vers.high = msg->rjcted_rply.rj_vers.high;
335 		break;
336 
337 	case RPC_AUTHERROR:
338 		error->re_why = msg->rjcted_rply.rj_why;
339 		break;
340 
341 	case RPC_PROGVERSMISMATCH:
342 		error->re_vers.low = msg->acpted_rply.ar_vers.low;
343 		error->re_vers.high = msg->acpted_rply.ar_vers.high;
344 		break;
345 
346 	case RPC_FAILED:
347 	case RPC_SUCCESS:
348 	case RPC_PROGNOTREGISTERED:
349 	case RPC_PMAPFAILURE:
350 	case RPC_UNKNOWNPROTO:
351 	case RPC_UNKNOWNHOST:
352 	case RPC_SYSTEMERROR:
353 	case RPC_CANTDECODEARGS:
354 	case RPC_PROCUNAVAIL:
355 	case RPC_PROGUNAVAIL:
356 	case RPC_TIMEDOUT:
357 	case RPC_CANTRECV:
358 	case RPC_CANTSEND:
359 	case RPC_CANTDECODERES:
360 	case RPC_CANTENCODEARGS:
361 	default:
362 		break;
363 	}
364 
365 	return (stat);
366 }
367