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