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