1 /*
2  * rpc_prot.c
3  *
4  * Copyright (c) 2010, Oracle America, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials
15  *       provided with the distribution.
16  *     * Neither the name of the "Oracle America, 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
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * This set of routines implements the rpc message definition,
34  * its serializer and some common rpc utility routines.
35  * The routines are meant for various implementations of rpc -
36  * they are NOT for the rpc client or rpc service implementations!
37  * Because authentication stuff is easy and is part of rpc, the opaque
38  * routines are also in this program.
39  */
40 
41 #include <sys/param.h>
42 #include <rpc/rpc.h>
43 #include <shlib-compat.h>
44 
45 /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
46 
47 /*
48  * XDR an opaque authentication struct
49  * (see auth.h)
50  */
51 bool_t
xdr_opaque_auth(XDR * xdrs,struct opaque_auth * ap)52 xdr_opaque_auth (XDR *xdrs, struct opaque_auth *ap)
53 {
54 
55   if (xdr_enum (xdrs, &(ap->oa_flavor)))
56     return xdr_bytes (xdrs, &ap->oa_base,
57 		      &ap->oa_length, MAX_AUTH_BYTES);
58   return FALSE;
59 }
libc_hidden_nolink_sunrpc(xdr_opaque_auth,GLIBC_2_0)60 libc_hidden_nolink_sunrpc (xdr_opaque_auth, GLIBC_2_0)
61 
62 /*
63  * XDR a DES block
64  */
65 bool_t
66 xdr_des_block (XDR *xdrs, des_block *blkp)
67 {
68   return xdr_opaque (xdrs, (caddr_t) blkp, sizeof (des_block));
69 }
libc_hidden_nolink_sunrpc(xdr_des_block,GLIBC_2_0)70 libc_hidden_nolink_sunrpc (xdr_des_block, GLIBC_2_0)
71 
72 /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
73 
74 /*
75  * XDR the MSG_ACCEPTED part of a reply message union
76  */
77 bool_t
78 xdr_accepted_reply (XDR *xdrs, struct accepted_reply *ar)
79 {
80   /* personalized union, rather than calling xdr_union */
81   if (!xdr_opaque_auth (xdrs, &(ar->ar_verf)))
82     return FALSE;
83   if (!xdr_enum (xdrs, (enum_t *) & (ar->ar_stat)))
84     return FALSE;
85   switch (ar->ar_stat)
86     {
87     case SUCCESS:
88       return ((*(ar->ar_results.proc)) (xdrs, ar->ar_results.where));
89     case PROG_MISMATCH:
90       if (!xdr_u_long (xdrs, &(ar->ar_vers.low)))
91 	return FALSE;
92       return (xdr_u_long (xdrs, &(ar->ar_vers.high)));
93     default:
94       return TRUE;
95     }
96   return TRUE;		/* TRUE => open ended set of problems */
97 }
libc_hidden_nolink_sunrpc(xdr_accepted_reply,GLIBC_2_0)98 libc_hidden_nolink_sunrpc (xdr_accepted_reply, GLIBC_2_0)
99 
100 /*
101  * XDR the MSG_DENIED part of a reply message union
102  */
103 bool_t
104 xdr_rejected_reply (XDR *xdrs, struct rejected_reply *rr)
105 {
106   /* personalized union, rather than calling xdr_union */
107   if (!xdr_enum (xdrs, (enum_t *) & (rr->rj_stat)))
108     return FALSE;
109   switch (rr->rj_stat)
110     {
111     case RPC_MISMATCH:
112       if (!xdr_u_long (xdrs, &(rr->rj_vers.low)))
113 	return FALSE;
114       return xdr_u_long (xdrs, &(rr->rj_vers.high));
115 
116     case AUTH_ERROR:
117       return xdr_enum (xdrs, (enum_t *) & (rr->rj_why));
118     }
119   return FALSE;
120 }
121 libc_hidden_nolink_sunrpc (xdr_rejected_reply, GLIBC_2_0)
122 
123 static const struct xdr_discrim reply_dscrm[3] =
124 {
125   {(int) MSG_ACCEPTED, (xdrproc_t) xdr_accepted_reply},
126   {(int) MSG_DENIED, (xdrproc_t) xdr_rejected_reply},
127   {__dontcare__, NULL_xdrproc_t}};
128 
129 /*
130  * XDR a reply message
131  */
132 bool_t
xdr_replymsg(XDR * xdrs,struct rpc_msg * rmsg)133 xdr_replymsg (XDR *xdrs, struct rpc_msg *rmsg)
134 {
135   if (xdr_u_long (xdrs, &(rmsg->rm_xid)) &&
136       xdr_enum (xdrs, (enum_t *) & (rmsg->rm_direction)) &&
137       (rmsg->rm_direction == REPLY))
138     return xdr_union (xdrs, (enum_t *) & (rmsg->rm_reply.rp_stat),
139 		      (caddr_t) & (rmsg->rm_reply.ru), reply_dscrm,
140 		      NULL_xdrproc_t);
141   return FALSE;
142 }
libc_hidden_nolink_sunrpc(xdr_replymsg,GLIBC_2_0)143 libc_hidden_nolink_sunrpc (xdr_replymsg, GLIBC_2_0)
144 
145 
146 /*
147  * Serializes the "static part" of a call message header.
148  * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
149  * The rm_xid is not really static, but the user can easily munge on the fly.
150  */
151 bool_t
152 xdr_callhdr (XDR *xdrs, struct rpc_msg *cmsg)
153 {
154 
155   cmsg->rm_direction = CALL;
156   cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
157   if (
158        (xdrs->x_op == XDR_ENCODE) &&
159        xdr_u_long (xdrs, &(cmsg->rm_xid)) &&
160        xdr_enum (xdrs, (enum_t *) & (cmsg->rm_direction)) &&
161        xdr_u_long (xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
162        xdr_u_long (xdrs, &(cmsg->rm_call.cb_prog)))
163     return xdr_u_long (xdrs, &(cmsg->rm_call.cb_vers));
164   return FALSE;
165 }
libc_hidden_nolink_sunrpc(xdr_callhdr,GLIBC_2_0)166 libc_hidden_nolink_sunrpc (xdr_callhdr, GLIBC_2_0)
167 
168 /* ************************** Client utility routine ************* */
169 
170 static void
171 accepted (enum accept_stat acpt_stat,
172 	  struct rpc_err *error)
173 {
174   switch (acpt_stat)
175     {
176 
177     case PROG_UNAVAIL:
178       error->re_status = RPC_PROGUNAVAIL;
179       return;
180 
181     case PROG_MISMATCH:
182       error->re_status = RPC_PROGVERSMISMATCH;
183       return;
184 
185     case PROC_UNAVAIL:
186       error->re_status = RPC_PROCUNAVAIL;
187       return;
188 
189     case GARBAGE_ARGS:
190       error->re_status = RPC_CANTDECODEARGS;
191       return;
192 
193     case SYSTEM_ERR:
194       error->re_status = RPC_SYSTEMERROR;
195       return;
196 
197     case SUCCESS:
198       error->re_status = RPC_SUCCESS;
199       return;
200     }
201   /* something's wrong, but we don't know what ... */
202   error->re_status = RPC_FAILED;
203   error->re_lb.s1 = (long) MSG_ACCEPTED;
204   error->re_lb.s2 = (long) acpt_stat;
205 }
206 
207 static void
rejected(enum reject_stat rjct_stat,struct rpc_err * error)208 rejected (enum reject_stat rjct_stat,
209 	  struct rpc_err *error)
210 {
211   switch (rjct_stat)
212     {
213     case RPC_MISMATCH:
214       error->re_status = RPC_VERSMISMATCH;
215       return;
216     case AUTH_ERROR:
217       error->re_status = RPC_AUTHERROR;
218       return;
219     default:
220       /* something's wrong, but we don't know what ... */
221       error->re_status = RPC_FAILED;
222       error->re_lb.s1 = (long) MSG_DENIED;
223       error->re_lb.s2 = (long) rjct_stat;
224       return;
225     }
226 }
227 
228 /*
229  * given a reply message, fills in the error
230  */
231 void
_seterr_reply(struct rpc_msg * msg,struct rpc_err * error)232 _seterr_reply (struct rpc_msg *msg,
233 	       struct rpc_err *error)
234 {
235   /* optimized for normal, SUCCESSful case */
236   switch (msg->rm_reply.rp_stat)
237     {
238     case MSG_ACCEPTED:
239       if (msg->acpted_rply.ar_stat == SUCCESS)
240 	{
241 	  error->re_status = RPC_SUCCESS;
242 	  return;
243 	};
244       accepted (msg->acpted_rply.ar_stat, error);
245       break;
246 
247     case MSG_DENIED:
248       rejected (msg->rjcted_rply.rj_stat, error);
249       break;
250 
251     default:
252       error->re_status = RPC_FAILED;
253       error->re_lb.s1 = (long) (msg->rm_reply.rp_stat);
254       break;
255     }
256   switch (error->re_status)
257     {
258 
259     case RPC_VERSMISMATCH:
260       error->re_vers.low = msg->rjcted_rply.rj_vers.low;
261       error->re_vers.high = msg->rjcted_rply.rj_vers.high;
262       break;
263 
264     case RPC_AUTHERROR:
265       error->re_why = msg->rjcted_rply.rj_why;
266       break;
267 
268     case RPC_PROGVERSMISMATCH:
269       error->re_vers.low = msg->acpted_rply.ar_vers.low;
270       error->re_vers.high = msg->acpted_rply.ar_vers.high;
271       break;
272     default:
273       break;
274     }
275 }
276 libc_hidden_nolink_sunrpc (_seterr_reply, GLIBC_2_0)
277