1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1986-1995, 1997, 2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
31 *
32 * $Header:
33 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi_misc.c,v
34 * 1.10 1994/10/27 12:39:23 jik Exp $
35 */
36
37 #include <stdlib.h>
38 #include <gssapi/gssapi.h>
39 #include <rpc/rpc.h>
40 #include <rpc/rpcsec_defs.h>
41
42 /*
43 * Miscellaneous XDR routines.
44 */
45 bool_t
__xdr_gss_buf(xdrs,buf)46 __xdr_gss_buf(xdrs, buf)
47 XDR *xdrs;
48 gss_buffer_t buf;
49 {
50 u_int cast_len, bound_len;
51
52 /*
53 * We go through this contortion because size_t is a now a ulong,
54 * GSS-API uses ulongs.
55 */
56
57 if (xdrs->x_op != XDR_DECODE) {
58 bound_len = cast_len = (u_int) buf->length;
59 } else {
60 bound_len = (u_int)-1;
61 }
62
63 if (xdr_bytes(xdrs, (char **)&buf->value, &cast_len,
64 bound_len) == TRUE) {
65 if (xdrs->x_op == XDR_DECODE)
66 buf->length = cast_len;
67
68 return (TRUE);
69 }
70
71 return (FALSE);
72 }
73
74 bool_t
__xdr_rpc_gss_creds(xdrs,creds)75 __xdr_rpc_gss_creds(xdrs, creds)
76 XDR *xdrs;
77 rpc_gss_creds *creds;
78 {
79 if (!xdr_u_int(xdrs, &creds->version) ||
80 !xdr_u_int(xdrs, &creds->gss_proc) ||
81 !xdr_u_int(xdrs, &creds->seq_num) ||
82 !xdr_u_int(xdrs, (u_int *)&creds->service) ||
83 !__xdr_gss_buf(xdrs, &creds->ctx_handle))
84 return (FALSE);
85 return (TRUE);
86 }
87
88 bool_t
__xdr_rpc_gss_init_arg(xdrs,init_arg)89 __xdr_rpc_gss_init_arg(xdrs, init_arg)
90 XDR *xdrs;
91 rpc_gss_init_arg *init_arg;
92 {
93 if (!__xdr_gss_buf(xdrs, init_arg))
94 return (FALSE);
95 return (TRUE);
96 }
97
98 bool_t
__xdr_rpc_gss_init_res(xdrs,init_res)99 __xdr_rpc_gss_init_res(xdrs, init_res)
100 XDR *xdrs;
101 rpc_gss_init_res *init_res;
102 {
103 if (!__xdr_gss_buf(xdrs, &init_res->ctx_handle) ||
104 !xdr_u_int(xdrs, (u_int *)&init_res->gss_major) ||
105 !xdr_u_int(xdrs, (u_int *)&init_res->gss_minor) ||
106 !xdr_u_int(xdrs, (u_int *)&init_res->seq_window) ||
107 !__xdr_gss_buf(xdrs, &init_res->token))
108 return (FALSE);
109 return (TRUE);
110 }
111
112 /*
113 * Generic routine to wrap data used by client and server sides.
114 */
115 bool_t
__rpc_gss_wrap_data(service,qop,context,seq_num,out_xdrs,xdr_func,xdr_ptr)116 __rpc_gss_wrap_data(service, qop, context, seq_num, out_xdrs, xdr_func,
117 xdr_ptr)
118 OM_uint32 qop;
119 rpc_gss_service_t service;
120 gss_ctx_id_t context;
121 u_int seq_num;
122 XDR *out_xdrs;
123 bool_t (*xdr_func)();
124 caddr_t xdr_ptr;
125 {
126 OM_uint32 minor;
127 gss_buffer_desc in_buf, out_buf;
128 XDR temp_xdrs;
129 bool_t conf_state;
130 bool_t ret = FALSE;
131 u_int bufsiz;
132 char *buf;
133
134 /*
135 * Create a temporary XDR/buffer to hold the data to be wrapped.
136 */
137 out_buf.length = 0;
138 bufsiz = xdr_sizeof(xdr_func, xdr_ptr) +
139 xdr_sizeof(xdr_u_int, &seq_num);
140 if ((buf = (char *)malloc(bufsiz)) == NULL) {
141 fprintf(stderr, dgettext(TEXT_DOMAIN, "malloc failed in "
142 "__rpc_gss_wrap_data\n"));
143 return (FALSE);
144 }
145 xdrmem_create(&temp_xdrs, buf, bufsiz, XDR_ENCODE);
146
147 /*
148 * serialize the sequence number into tmp memory
149 */
150 if (!xdr_u_int(&temp_xdrs, &seq_num))
151 goto fail;
152
153 /*
154 * serialize the arguments into tmp memory
155 */
156 if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
157 goto fail;
158
159 /*
160 * Data to be wrapped goes in in_buf. If privacy is used,
161 * out_buf will have wrapped data (in_buf will no longer be
162 * needed). If integrity is used, out_buf will have checksum
163 * which will follow the data in in_buf.
164 */
165 in_buf.length = xdr_getpos(&temp_xdrs);
166 in_buf.value = temp_xdrs.x_base;
167
168 switch (service) {
169 case rpc_gss_svc_privacy:
170 if (gss_seal(&minor, context, TRUE, qop, &in_buf,
171 &conf_state, &out_buf) != GSS_S_COMPLETE)
172 goto fail;
173 in_buf.length = 0; /* in_buf not needed */
174 if (!conf_state)
175 goto fail;
176 break;
177 case rpc_gss_svc_integrity:
178 if (gss_sign(&minor, context, qop, &in_buf,
179 &out_buf) != GSS_S_COMPLETE)
180 goto fail;
181 break;
182 default:
183 goto fail;
184 }
185
186 /*
187 * write out in_buf and out_buf as needed
188 */
189 if (in_buf.length != 0) {
190 if (!__xdr_gss_buf(out_xdrs, &in_buf))
191 goto fail;
192 }
193
194 if (!__xdr_gss_buf(out_xdrs, &out_buf))
195 goto fail;
196 ret = TRUE;
197 fail:
198 XDR_DESTROY(&temp_xdrs);
199 if (buf)
200 (void) free(buf);
201 if (out_buf.length != 0)
202 (void) gss_release_buffer(&minor, &out_buf);
203 return (ret);
204 }
205
206 /*
207 * Generic routine to unwrap data used by client and server sides.
208 */
209 bool_t
__rpc_gss_unwrap_data(service,context,seq_num,qop_check,in_xdrs,xdr_func,xdr_ptr)210 __rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, xdr_func,
211 xdr_ptr)
212 rpc_gss_service_t service;
213 gss_ctx_id_t context;
214 u_int seq_num;
215 OM_uint32 qop_check;
216 XDR *in_xdrs;
217 bool_t (*xdr_func)();
218 caddr_t xdr_ptr;
219 {
220 gss_buffer_desc in_buf, out_buf;
221 XDR temp_xdrs;
222 u_int seq_num2;
223 bool_t conf;
224 OM_uint32 major = GSS_S_COMPLETE, minor = 0;
225 int qop;
226
227 in_buf.value = NULL;
228 out_buf.value = NULL;
229
230 /*
231 * Pull out wrapped data. For privacy service, this is the
232 * encrypted data. For integrity service, this is the data
233 * followed by a checksum.
234 */
235 if (!__xdr_gss_buf(in_xdrs, &in_buf))
236 return (FALSE);
237
238 if (service == rpc_gss_svc_privacy) {
239 major = gss_unseal(&minor, context, &in_buf, &out_buf, &conf,
240 &qop);
241 free(in_buf.value);
242 if (major != GSS_S_COMPLETE)
243 return (FALSE);
244 /*
245 * Keep the returned token (unencrypted data) in in_buf.
246 */
247 in_buf.length = out_buf.length;
248 in_buf.value = out_buf.value;
249
250 /*
251 * If privacy was not used, or if QOP is not what we are
252 * expecting, fail.
253 */
254 if (!conf || qop != qop_check)
255 goto fail;
256
257 } else if (service == rpc_gss_svc_integrity) {
258 if (!__xdr_gss_buf(in_xdrs, &out_buf))
259 return (FALSE);
260 major = gss_verify(&minor, context, &in_buf, &out_buf, &qop);
261 free(out_buf.value);
262 if (major != GSS_S_COMPLETE) {
263 free(in_buf.value);
264 return (FALSE);
265 }
266
267 /*
268 * If QOP is not what we are expecting, fail.
269 */
270 if (qop != qop_check)
271 goto fail;
272 }
273
274 xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE);
275
276 /*
277 * The data consists of the sequence number followed by the
278 * arguments. Make sure sequence number is what we are
279 * expecting (i.e., the value in the header).
280 */
281 if (!xdr_u_int(&temp_xdrs, &seq_num2))
282 goto fail;
283 if (seq_num2 != seq_num)
284 goto fail;
285
286 /*
287 * Deserialize the arguments into xdr_ptr, and release in_buf.
288 */
289 if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
290 goto fail;
291
292 if (service == rpc_gss_svc_privacy)
293 (void) gss_release_buffer(&minor, &in_buf);
294 else
295 free(in_buf.value);
296 XDR_DESTROY(&temp_xdrs);
297 return (TRUE);
298 fail:
299 XDR_DESTROY(&temp_xdrs);
300 if (service == rpc_gss_svc_privacy)
301 (void) gss_release_buffer(&minor, &in_buf);
302 else
303 free(in_buf.value);
304 return (FALSE);
305 }
306
307 /*ARGSUSED*/
308 int
__find_max_data_length(service,context,qop,max_tp_unit_len)309 __find_max_data_length(service, context, qop, max_tp_unit_len)
310 rpc_gss_service_t service;
311 gss_ctx_id_t context;
312 OM_uint32 qop;
313 int max_tp_unit_len;
314 {
315 int conf;
316 OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
317 OM_uint32 max_input_size;
318 int ret_val = 0;
319
320 if (service == rpc_gss_svc_integrity || service == rpc_gss_svc_default)
321 conf = 0;
322 else if (service == rpc_gss_svc_privacy)
323 conf = 1;
324 else if (service == rpc_gss_svc_none)
325 return (max_tp_unit_len);
326
327 maj_stat = gss_wrap_size_limit(&min_stat,
328 context, conf, qop,
329 max_tp_unit_len, &max_input_size);
330
331 /*
332 * max_input_size may result in negative value
333 */
334 if (maj_stat == GSS_S_COMPLETE) {
335 if ((int)max_input_size <= 0)
336 ret_val = 0;
337 else
338 ret_val = (int)(max_input_size);
339 } else {
340 fprintf(stderr, dgettext(TEXT_DOMAIN,
341 "gss_wrap_size_limit failed in "
342 "__find_max_data_length\n"));
343 }
344
345 return (ret_val);
346 }
347