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