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 |
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 | } |
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 | } |
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, ap: &(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 | } |
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 |
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 | } |
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 | } |
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 |
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 |
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 (acpt_stat: msg->acpted_rply.ar_stat, error); |
245 | break; |
246 | |
247 | case MSG_DENIED: |
248 | rejected (rjct_stat: 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 | |