1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1986-1995, 1997, 2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
32*0Sstevel@tonic-gate  *
33*0Sstevel@tonic-gate  * $Header:
34*0Sstevel@tonic-gate  * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi.c,v
35*0Sstevel@tonic-gate  * 1.14 1995/03/22 22:07:55 jik Exp $
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <stdio.h>
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate #include <strings.h>
41*0Sstevel@tonic-gate #include <errno.h>
42*0Sstevel@tonic-gate #include <pthread.h>
43*0Sstevel@tonic-gate #include <thread.h>
44*0Sstevel@tonic-gate #include <syslog.h>
45*0Sstevel@tonic-gate #include <gssapi/gssapi.h>
46*0Sstevel@tonic-gate #include <rpc/rpc.h>
47*0Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static void 	rpc_gss_nextverf();
50*0Sstevel@tonic-gate static bool_t 	rpc_gss_marshall();
51*0Sstevel@tonic-gate static bool_t	rpc_gss_validate();
52*0Sstevel@tonic-gate static bool_t	rpc_gss_refresh();
53*0Sstevel@tonic-gate static void	rpc_gss_destroy();
54*0Sstevel@tonic-gate static void	rpc_gss_destroy_pvt();
55*0Sstevel@tonic-gate static bool_t	rpc_gss_seccreate_pvt();
56*0Sstevel@tonic-gate static bool_t	validate_seqwin();
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*
59*0Sstevel@tonic-gate  * Globals that should have header files but don't.
60*0Sstevel@tonic-gate  */
61*0Sstevel@tonic-gate extern bool_t	xdr_opaque_auth(XDR *, struct opaque_auth *);
62*0Sstevel@tonic-gate extern int	_thr_main(void);
63*0Sstevel@tonic-gate extern int	_thr_getspecific(thread_key_t key, void **valuep);
64*0Sstevel@tonic-gate typedef void	(*PFrV) (void *);
65*0Sstevel@tonic-gate extern int	_thr_keycreate(thread_key_t *pkey, PFrV destructor);
66*0Sstevel@tonic-gate extern int	_thr_setspecific(unsigned int key, void *value);
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static struct auth_ops rpc_gss_ops = {
70*0Sstevel@tonic-gate 	rpc_gss_nextverf,
71*0Sstevel@tonic-gate 	rpc_gss_marshall,
72*0Sstevel@tonic-gate 	rpc_gss_validate,
73*0Sstevel@tonic-gate 	rpc_gss_refresh,
74*0Sstevel@tonic-gate 	rpc_gss_destroy
75*0Sstevel@tonic-gate };
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate /*
78*0Sstevel@tonic-gate  * Private data for RPCSEC_GSS.
79*0Sstevel@tonic-gate  */
80*0Sstevel@tonic-gate typedef struct _rpc_gss_data {
81*0Sstevel@tonic-gate 	bool_t			established;	/* TRUE when established */
82*0Sstevel@tonic-gate 	CLIENT			*clnt;		/* associated client handle */
83*0Sstevel@tonic-gate 	uint_t			version;	/* RPCSEC version */
84*0Sstevel@tonic-gate 	gss_ctx_id_t		context;	/* GSS context id */
85*0Sstevel@tonic-gate 	gss_buffer_desc		ctx_handle;	/* RPCSEC context handle */
86*0Sstevel@tonic-gate 	uint_t			seq_num;	/* last sequence number rcvd */
87*0Sstevel@tonic-gate 	gss_cred_id_t		my_cred;	/* GSS credentials */
88*0Sstevel@tonic-gate 	OM_uint32		qop;		/* requested QOP */
89*0Sstevel@tonic-gate 	rpc_gss_service_t	service;	/* requested service */
90*0Sstevel@tonic-gate 	uint_t			gss_proc;	/* GSS control procedure */
91*0Sstevel@tonic-gate 	gss_name_t		target_name;	/* target server */
92*0Sstevel@tonic-gate 	int			req_flags;	/* GSS request bits */
93*0Sstevel@tonic-gate 	gss_OID			mech_type;	/* GSS mechanism */
94*0Sstevel@tonic-gate 	OM_uint32		time_req;	/* requested cred lifetime */
95*0Sstevel@tonic-gate 	bool_t			invalid;	/* can't use this any more */
96*0Sstevel@tonic-gate 	OM_uint32		seq_window;	/* server sequence window */
97*0Sstevel@tonic-gate 	struct opaque_auth	*verifier;  /* rpc reply verifier saved for */
98*0Sstevel@tonic-gate 					    /* validating the sequence window */
99*0Sstevel@tonic-gate 	gss_channel_bindings_t	icb;
100*0Sstevel@tonic-gate } rpc_gss_data;
101*0Sstevel@tonic-gate #define	AUTH_PRIVATE(auth) ((rpc_gss_data *)auth->ah_private)
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /*
104*0Sstevel@tonic-gate  * Create a context.
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate AUTH *
107*0Sstevel@tonic-gate __rpc_gss_seccreate(clnt, server_name, mech, service, qop, options_req,
108*0Sstevel@tonic-gate 								options_ret)
109*0Sstevel@tonic-gate 	CLIENT			*clnt;		/* associated client handle */
110*0Sstevel@tonic-gate 	char			*server_name;	/* target server */
111*0Sstevel@tonic-gate 	char			*mech;		/* security mechanism */
112*0Sstevel@tonic-gate 	rpc_gss_service_t	service;	/* security service */
113*0Sstevel@tonic-gate 	char			*qop;		/* requested QOP */
114*0Sstevel@tonic-gate 	rpc_gss_options_req_t	*options_req;	/* requested options */
115*0Sstevel@tonic-gate 	rpc_gss_options_ret_t	*options_ret;	/* returned options */
116*0Sstevel@tonic-gate {
117*0Sstevel@tonic-gate 	OM_uint32		gssstat;
118*0Sstevel@tonic-gate 	OM_uint32		minor_stat;
119*0Sstevel@tonic-gate 	gss_name_t		target_name;
120*0Sstevel@tonic-gate 	gss_OID			mech_type;
121*0Sstevel@tonic-gate 	OM_uint32		ret_flags;
122*0Sstevel@tonic-gate 	OM_uint32		time_rec;
123*0Sstevel@tonic-gate 	gss_buffer_desc		input_name;
124*0Sstevel@tonic-gate 	AUTH			*auth = NULL;
125*0Sstevel@tonic-gate 	rpc_gss_data		*ap = NULL;
126*0Sstevel@tonic-gate 	OM_uint32		qop_num;
127*0Sstevel@tonic-gate 	rpc_gss_error_t		error;
128*0Sstevel@tonic-gate 	void			__rpc_gss_get_error();
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/*
131*0Sstevel@tonic-gate 	 * convert ascii strings to GSS values
132*0Sstevel@tonic-gate 	 */
133*0Sstevel@tonic-gate 	if (!__rpc_gss_qop_to_num(qop, mech, &qop_num)) {
134*0Sstevel@tonic-gate 		__rpc_gss_get_error(&error);
135*0Sstevel@tonic-gate 		return (NULL);
136*0Sstevel@tonic-gate 	}
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	if (!__rpc_gss_mech_to_oid(mech, &mech_type)) {
139*0Sstevel@tonic-gate 		__rpc_gss_get_error(&error);
140*0Sstevel@tonic-gate 		return (NULL);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	/*
144*0Sstevel@tonic-gate 	 * convert name to GSS internal type
145*0Sstevel@tonic-gate 	 */
146*0Sstevel@tonic-gate 	input_name.value = server_name;
147*0Sstevel@tonic-gate 	input_name.length = strlen(server_name);
148*0Sstevel@tonic-gate 	gssstat = gss_import_name(&minor_stat, &input_name,
149*0Sstevel@tonic-gate 				(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
150*0Sstevel@tonic-gate 				&target_name);
151*0Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
152*0Sstevel@tonic-gate 		rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
153*0Sstevel@tonic-gate 		rpc_gss_err.system_error = ENOMEM;
154*0Sstevel@tonic-gate 		return (NULL);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	/*
158*0Sstevel@tonic-gate 	 * Create AUTH handle.  Save the necessary interface information
159*0Sstevel@tonic-gate 	 * so that the client can refresh the handle later if needed.
160*0Sstevel@tonic-gate 	 */
161*0Sstevel@tonic-gate 	if ((auth = (AUTH *) malloc(sizeof (*auth))) != NULL)
162*0Sstevel@tonic-gate 		ap = (rpc_gss_data *) malloc(sizeof (*ap));
163*0Sstevel@tonic-gate 	if (auth == NULL || ap == NULL) {
164*0Sstevel@tonic-gate 		rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
165*0Sstevel@tonic-gate 		rpc_gss_err.system_error = ENOMEM;
166*0Sstevel@tonic-gate 		if (auth != NULL)
167*0Sstevel@tonic-gate 			free((char *)auth);
168*0Sstevel@tonic-gate 		(void) gss_release_name(&minor_stat, &target_name);
169*0Sstevel@tonic-gate 		return (NULL);
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	memset((char *)ap, 0, sizeof (*ap));
173*0Sstevel@tonic-gate 	ap->clnt = clnt;
174*0Sstevel@tonic-gate 	ap->version = RPCSEC_GSS_VERSION;
175*0Sstevel@tonic-gate 	if (options_req != NULL) {
176*0Sstevel@tonic-gate 		ap->my_cred = options_req->my_cred;
177*0Sstevel@tonic-gate 		ap->req_flags = options_req->req_flags;
178*0Sstevel@tonic-gate 		ap->time_req = options_req->time_req;
179*0Sstevel@tonic-gate 		ap->icb = options_req->input_channel_bindings;
180*0Sstevel@tonic-gate 	} else {
181*0Sstevel@tonic-gate 		ap->my_cred = GSS_C_NO_CREDENTIAL;
182*0Sstevel@tonic-gate 		ap->req_flags = GSS_C_MUTUAL_FLAG;
183*0Sstevel@tonic-gate 		ap->time_req = 0;
184*0Sstevel@tonic-gate 		ap->icb = NULL;
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 	if ((ap->service = service) == rpc_gss_svc_default)
187*0Sstevel@tonic-gate 		ap->service = rpc_gss_svc_integrity;
188*0Sstevel@tonic-gate 	ap->qop = qop_num;
189*0Sstevel@tonic-gate 	ap->target_name = target_name;
190*0Sstevel@tonic-gate 	ap->mech_type = mech_type;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/*
193*0Sstevel@tonic-gate 	 * Now invoke the real interface that sets up the context from
194*0Sstevel@tonic-gate 	 * the information stashed away in the private data.
195*0Sstevel@tonic-gate 	 */
196*0Sstevel@tonic-gate 	if (!rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
197*0Sstevel@tonic-gate 				&mech_type, &ret_flags, &time_rec)) {
198*0Sstevel@tonic-gate 		if (ap->target_name)
199*0Sstevel@tonic-gate 			(void) gss_release_name(&minor_stat, &ap->target_name);
200*0Sstevel@tonic-gate 		free((char *)ap);
201*0Sstevel@tonic-gate 		free((char *)auth);
202*0Sstevel@tonic-gate 		return (NULL);
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	/*
206*0Sstevel@tonic-gate 	 * Make sure that the requested service is supported.  In all
207*0Sstevel@tonic-gate 	 * cases, integrity service must be available.
208*0Sstevel@tonic-gate 	 */
209*0Sstevel@tonic-gate 	if ((ap->service == rpc_gss_svc_privacy &&
210*0Sstevel@tonic-gate 					!(ret_flags & GSS_C_CONF_FLAG)) ||
211*0Sstevel@tonic-gate 			!(ret_flags & GSS_C_INTEG_FLAG)) {
212*0Sstevel@tonic-gate 		rpc_gss_destroy(auth);
213*0Sstevel@tonic-gate 		rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
214*0Sstevel@tonic-gate 		rpc_gss_err.system_error = EPROTONOSUPPORT;
215*0Sstevel@tonic-gate 		return (NULL);
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	/*
219*0Sstevel@tonic-gate 	 * return option values if requested
220*0Sstevel@tonic-gate 	 */
221*0Sstevel@tonic-gate 	if (options_ret != NULL) {
222*0Sstevel@tonic-gate 		char	*s;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 		options_ret->major_status = gssstat;
225*0Sstevel@tonic-gate 		options_ret->minor_status = minor_stat;
226*0Sstevel@tonic-gate 		options_ret->rpcsec_version = ap->version;
227*0Sstevel@tonic-gate 		options_ret->ret_flags = ret_flags;
228*0Sstevel@tonic-gate 		options_ret->time_ret = time_rec;
229*0Sstevel@tonic-gate 		options_ret->gss_context = ap->context;
230*0Sstevel@tonic-gate 		if ((s = __rpc_gss_oid_to_mech(mech_type)) != NULL)
231*0Sstevel@tonic-gate 			strcpy(options_ret->actual_mechanism, s);
232*0Sstevel@tonic-gate 		else
233*0Sstevel@tonic-gate 			options_ret->actual_mechanism[0] = '\0';
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 	return (auth);
236*0Sstevel@tonic-gate }
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate /*
239*0Sstevel@tonic-gate  * Private interface to create a context.  This is the interface
240*0Sstevel@tonic-gate  * that's invoked when the context has to be refreshed.
241*0Sstevel@tonic-gate  */
242*0Sstevel@tonic-gate static bool_t
243*0Sstevel@tonic-gate rpc_gss_seccreate_pvt(gssstat, minor_stat, auth, ap, actual_mech_type,
244*0Sstevel@tonic-gate 						ret_flags, time_rec)
245*0Sstevel@tonic-gate 	OM_uint32		*gssstat;
246*0Sstevel@tonic-gate 	OM_uint32		*minor_stat;
247*0Sstevel@tonic-gate 	AUTH			*auth;
248*0Sstevel@tonic-gate 	rpc_gss_data		*ap;
249*0Sstevel@tonic-gate 	gss_OID			*actual_mech_type;
250*0Sstevel@tonic-gate 	OM_uint32		*ret_flags;
251*0Sstevel@tonic-gate 	OM_uint32		*time_rec;
252*0Sstevel@tonic-gate {
253*0Sstevel@tonic-gate 	CLIENT			*clnt = ap->clnt;
254*0Sstevel@tonic-gate 	AUTH			*save_auth;
255*0Sstevel@tonic-gate 	enum clnt_stat		callstat;
256*0Sstevel@tonic-gate 	rpc_gss_init_arg	call_arg;
257*0Sstevel@tonic-gate 	rpc_gss_init_res	call_res;
258*0Sstevel@tonic-gate 	gss_buffer_desc		*input_token_p, input_token;
259*0Sstevel@tonic-gate 	bool_t			free_results = FALSE;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/*
262*0Sstevel@tonic-gate 	 * initialize error
263*0Sstevel@tonic-gate 	 */
264*0Sstevel@tonic-gate 	memset(&rpc_createerr, 0, sizeof (rpc_createerr));
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	/*
267*0Sstevel@tonic-gate 	 * (re)initialize AUTH handle and private data.
268*0Sstevel@tonic-gate 	 */
269*0Sstevel@tonic-gate 	memset((char *)auth, 0, sizeof (*auth));
270*0Sstevel@tonic-gate 	auth->ah_ops = &rpc_gss_ops;
271*0Sstevel@tonic-gate 	auth->ah_private = (caddr_t)ap;
272*0Sstevel@tonic-gate 	auth->ah_cred.oa_flavor = RPCSEC_GSS;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	ap->established = FALSE;
275*0Sstevel@tonic-gate 	ap->ctx_handle.length = 0;
276*0Sstevel@tonic-gate 	ap->ctx_handle.value = NULL;
277*0Sstevel@tonic-gate 	ap->context = GSS_C_NO_CONTEXT;
278*0Sstevel@tonic-gate 	ap->seq_num = 0;
279*0Sstevel@tonic-gate 	ap->gss_proc = RPCSEC_GSS_INIT;
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	/*
282*0Sstevel@tonic-gate 	 * should not change clnt->cl_auth at this time, so save
283*0Sstevel@tonic-gate 	 * old handle
284*0Sstevel@tonic-gate 	 */
285*0Sstevel@tonic-gate 	save_auth = clnt->cl_auth;
286*0Sstevel@tonic-gate 	clnt->cl_auth = auth;
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	/*
289*0Sstevel@tonic-gate 	 * set state for starting context setup
290*0Sstevel@tonic-gate 	 */
291*0Sstevel@tonic-gate 	input_token_p = GSS_C_NO_BUFFER;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate next_token:
294*0Sstevel@tonic-gate 	*gssstat = gss_init_sec_context(minor_stat,
295*0Sstevel@tonic-gate 					ap->my_cred,
296*0Sstevel@tonic-gate 					&ap->context,
297*0Sstevel@tonic-gate 					ap->target_name,
298*0Sstevel@tonic-gate 					ap->mech_type,
299*0Sstevel@tonic-gate 					ap->req_flags,
300*0Sstevel@tonic-gate 					ap->time_req,
301*0Sstevel@tonic-gate 					NULL,
302*0Sstevel@tonic-gate 					input_token_p,
303*0Sstevel@tonic-gate 					actual_mech_type,
304*0Sstevel@tonic-gate 					&call_arg,
305*0Sstevel@tonic-gate 					ret_flags,
306*0Sstevel@tonic-gate 					time_rec);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	if (input_token_p != GSS_C_NO_BUFFER) {
309*0Sstevel@tonic-gate 		OM_uint32 minor_stat2;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 		(void) gss_release_buffer(&minor_stat2, input_token_p);
312*0Sstevel@tonic-gate 		input_token_p = GSS_C_NO_BUFFER;
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 		goto cleanup;
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	/*
321*0Sstevel@tonic-gate 	 * if we got a token, pass it on
322*0Sstevel@tonic-gate 	 */
323*0Sstevel@tonic-gate 	if (call_arg.length != 0) {
324*0Sstevel@tonic-gate 		struct timeval timeout = {30, 0};
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 		memset((char *)&call_res, 0, sizeof (call_res));
327*0Sstevel@tonic-gate 		callstat = clnt_call(clnt, NULLPROC,
328*0Sstevel@tonic-gate 				__xdr_rpc_gss_init_arg, (caddr_t)&call_arg,
329*0Sstevel@tonic-gate 				__xdr_rpc_gss_init_res, (caddr_t)&call_res,
330*0Sstevel@tonic-gate 				timeout);
331*0Sstevel@tonic-gate 		(void) gss_release_buffer(minor_stat, &call_arg);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		if (callstat != RPC_SUCCESS) {
334*0Sstevel@tonic-gate 			goto cleanup;
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 		/*
337*0Sstevel@tonic-gate 		 * we have results - note that these need to be freed
338*0Sstevel@tonic-gate 		 */
339*0Sstevel@tonic-gate 		free_results = TRUE;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 		if (call_res.gss_major != GSS_S_COMPLETE &&
342*0Sstevel@tonic-gate 			call_res.gss_major != GSS_S_CONTINUE_NEEDED)
343*0Sstevel@tonic-gate 			goto cleanup;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 		ap->gss_proc = RPCSEC_GSS_CONTINUE_INIT;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 		/*
348*0Sstevel@tonic-gate 		 * check for ctx_handle
349*0Sstevel@tonic-gate 		 */
350*0Sstevel@tonic-gate 		if (ap->ctx_handle.length == 0) {
351*0Sstevel@tonic-gate 			if (call_res.ctx_handle.length == 0)
352*0Sstevel@tonic-gate 				goto cleanup;
353*0Sstevel@tonic-gate 			GSS_DUP_BUFFER(ap->ctx_handle,
354*0Sstevel@tonic-gate 				call_res.ctx_handle);
355*0Sstevel@tonic-gate 		} else if (!GSS_BUFFERS_EQUAL(ap->ctx_handle,
356*0Sstevel@tonic-gate 						call_res.ctx_handle))
357*0Sstevel@tonic-gate 			goto cleanup;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 		/*
360*0Sstevel@tonic-gate 		 * check for token
361*0Sstevel@tonic-gate 		 */
362*0Sstevel@tonic-gate 		if (call_res.token.length != 0) {
363*0Sstevel@tonic-gate 			if (*gssstat == GSS_S_COMPLETE)
364*0Sstevel@tonic-gate 				goto cleanup;
365*0Sstevel@tonic-gate 			GSS_DUP_BUFFER(input_token, call_res.token);
366*0Sstevel@tonic-gate 			input_token_p = &input_token;
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 		} else if (*gssstat != GSS_S_COMPLETE)
369*0Sstevel@tonic-gate 			goto cleanup;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 		/* save the sequence window value; validate later */
372*0Sstevel@tonic-gate 		ap->seq_window = call_res.seq_window;
373*0Sstevel@tonic-gate 		xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
374*0Sstevel@tonic-gate 		free_results = FALSE;
375*0Sstevel@tonic-gate 	}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	/*
378*0Sstevel@tonic-gate 	 * results were okay.. continue if necessary
379*0Sstevel@tonic-gate 	 */
380*0Sstevel@tonic-gate 	if (*gssstat == GSS_S_CONTINUE_NEEDED)
381*0Sstevel@tonic-gate 		goto next_token;
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	/*
384*0Sstevel@tonic-gate 	 * Validate the sequence window - RFC 2203 section 5.2.3.1
385*0Sstevel@tonic-gate 	 */
386*0Sstevel@tonic-gate 	if (!validate_seqwin(ap)) {
387*0Sstevel@tonic-gate 		goto cleanup;
388*0Sstevel@tonic-gate 	}
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	/*
391*0Sstevel@tonic-gate 	 * Done!  Security context creation is successful.
392*0Sstevel@tonic-gate 	 * Ready for exchanging data.
393*0Sstevel@tonic-gate 	 */
394*0Sstevel@tonic-gate 	ap->established = TRUE;
395*0Sstevel@tonic-gate 	ap->seq_num = 1;
396*0Sstevel@tonic-gate 	ap->gss_proc = RPCSEC_GSS_DATA;
397*0Sstevel@tonic-gate 	ap->invalid = FALSE;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	clnt->cl_auth = save_auth;	/* restore cl_auth */
400*0Sstevel@tonic-gate 	return (TRUE);
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate cleanup:
403*0Sstevel@tonic-gate 	if (ap->context != GSS_C_NO_CONTEXT)
404*0Sstevel@tonic-gate 		rpc_gss_destroy_pvt(auth);
405*0Sstevel@tonic-gate 	if (free_results)
406*0Sstevel@tonic-gate 		xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
407*0Sstevel@tonic-gate 	clnt->cl_auth = save_auth;	/* restore cl_auth */
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate /*
410*0Sstevel@tonic-gate  *	if (rpc_createerr.cf_stat == 0)
411*0Sstevel@tonic-gate  *		rpc_createerr.cf_stat = RPC_AUTHERROR;
412*0Sstevel@tonic-gate  */
413*0Sstevel@tonic-gate 	if (rpc_createerr.cf_stat == 0) {
414*0Sstevel@tonic-gate 		rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
415*0Sstevel@tonic-gate 		rpc_gss_err.system_error = RPC_AUTHERROR;
416*0Sstevel@tonic-gate 	}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	return (FALSE);
419*0Sstevel@tonic-gate }
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate /*
422*0Sstevel@tonic-gate  * Set service defaults.
423*0Sstevel@tonic-gate  */
424*0Sstevel@tonic-gate bool_t
425*0Sstevel@tonic-gate __rpc_gss_set_defaults(auth, service, qop)
426*0Sstevel@tonic-gate 	AUTH			*auth;
427*0Sstevel@tonic-gate 	rpc_gss_service_t	service;
428*0Sstevel@tonic-gate 	char			*qop;
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate 	/*LINTED*/
431*0Sstevel@tonic-gate 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
432*0Sstevel@tonic-gate 	char			*mech;
433*0Sstevel@tonic-gate 	OM_uint32		qop_num;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	switch (service) {
436*0Sstevel@tonic-gate 	case rpc_gss_svc_integrity:
437*0Sstevel@tonic-gate 	case rpc_gss_svc_privacy:
438*0Sstevel@tonic-gate 	case rpc_gss_svc_none:
439*0Sstevel@tonic-gate 		break;
440*0Sstevel@tonic-gate 	case rpc_gss_svc_default:
441*0Sstevel@tonic-gate 		service = rpc_gss_svc_integrity;
442*0Sstevel@tonic-gate 		break;
443*0Sstevel@tonic-gate 	default:
444*0Sstevel@tonic-gate 		return (FALSE);
445*0Sstevel@tonic-gate 	}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if ((mech = __rpc_gss_oid_to_mech(ap->mech_type)) == NULL)
448*0Sstevel@tonic-gate 		return (FALSE);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	if (!__rpc_gss_qop_to_num(qop, mech, &qop_num))
451*0Sstevel@tonic-gate 		return (FALSE);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	ap->qop = qop_num;
454*0Sstevel@tonic-gate 	ap->service = service;
455*0Sstevel@tonic-gate 	return (TRUE);
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate /*
459*0Sstevel@tonic-gate  * Marshall credentials.
460*0Sstevel@tonic-gate  */
461*0Sstevel@tonic-gate static bool_t
462*0Sstevel@tonic-gate marshall_creds(ap, xdrs)
463*0Sstevel@tonic-gate 	rpc_gss_data		*ap;
464*0Sstevel@tonic-gate 	XDR			*xdrs;
465*0Sstevel@tonic-gate {
466*0Sstevel@tonic-gate 	rpc_gss_creds		ag_creds;
467*0Sstevel@tonic-gate 	char			cred_buf[MAX_AUTH_BYTES];
468*0Sstevel@tonic-gate 	struct opaque_auth	creds;
469*0Sstevel@tonic-gate 	XDR			cred_xdrs;
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	ag_creds.version = ap->version;
472*0Sstevel@tonic-gate 	ag_creds.gss_proc = ap->gss_proc;
473*0Sstevel@tonic-gate 	ag_creds.seq_num = ap->seq_num;
474*0Sstevel@tonic-gate 	ag_creds.service = ap->service;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	/*
477*0Sstevel@tonic-gate 	 * If context has not been set up yet, use NULL handle.
478*0Sstevel@tonic-gate 	 */
479*0Sstevel@tonic-gate 	if (ap->ctx_handle.length > 0)
480*0Sstevel@tonic-gate 		ag_creds.ctx_handle = ap->ctx_handle;
481*0Sstevel@tonic-gate 	else {
482*0Sstevel@tonic-gate 		ag_creds.ctx_handle.length = 0;
483*0Sstevel@tonic-gate 		ag_creds.ctx_handle.value = NULL;
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	xdrmem_create(&cred_xdrs, (caddr_t)cred_buf, MAX_AUTH_BYTES,
487*0Sstevel@tonic-gate 								XDR_ENCODE);
488*0Sstevel@tonic-gate 	if (!__xdr_rpc_gss_creds(&cred_xdrs, &ag_creds)) {
489*0Sstevel@tonic-gate 		XDR_DESTROY(&cred_xdrs);
490*0Sstevel@tonic-gate 		return (FALSE);
491*0Sstevel@tonic-gate 	}
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	creds.oa_flavor = RPCSEC_GSS;
494*0Sstevel@tonic-gate 	creds.oa_base = cred_buf;
495*0Sstevel@tonic-gate 	creds.oa_length = xdr_getpos(&cred_xdrs);
496*0Sstevel@tonic-gate 	XDR_DESTROY(&cred_xdrs);
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	if (!xdr_opaque_auth(xdrs, &creds))
499*0Sstevel@tonic-gate 		return (FALSE);
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	return (TRUE);
502*0Sstevel@tonic-gate }
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate /*
505*0Sstevel@tonic-gate  * Marshall verifier.  The verifier is the checksum of the RPC header
506*0Sstevel@tonic-gate  * up to and including the credential field.  The XDR handle that's
507*0Sstevel@tonic-gate  * passed in has the header up to and including the credential field
508*0Sstevel@tonic-gate  * encoded.  A pointer to the transmit buffer is also passed in.
509*0Sstevel@tonic-gate  */
510*0Sstevel@tonic-gate static bool_t
511*0Sstevel@tonic-gate marshall_verf(ap, xdrs, buf)
512*0Sstevel@tonic-gate 	rpc_gss_data		*ap;
513*0Sstevel@tonic-gate 	XDR			*xdrs;	/* send XDR */
514*0Sstevel@tonic-gate 	char			*buf;	/* pointer of send buffer */
515*0Sstevel@tonic-gate {
516*0Sstevel@tonic-gate 	struct opaque_auth	verf;
517*0Sstevel@tonic-gate 	OM_uint32		major, minor;
518*0Sstevel@tonic-gate 	gss_buffer_desc		in_buf, out_buf;
519*0Sstevel@tonic-gate 	bool_t			ret = FALSE;
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	/*
522*0Sstevel@tonic-gate 	 * If context is not established yet, use NULL verifier.
523*0Sstevel@tonic-gate 	 */
524*0Sstevel@tonic-gate 	if (!ap->established) {
525*0Sstevel@tonic-gate 		verf.oa_flavor = AUTH_NONE;
526*0Sstevel@tonic-gate 		verf.oa_base = NULL;
527*0Sstevel@tonic-gate 		verf.oa_length = 0;
528*0Sstevel@tonic-gate 		return (xdr_opaque_auth(xdrs, &verf));
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	verf.oa_flavor = RPCSEC_GSS;
532*0Sstevel@tonic-gate 	in_buf.length = xdr_getpos(xdrs);
533*0Sstevel@tonic-gate 	in_buf.value = buf;
534*0Sstevel@tonic-gate 	if ((major = gss_sign(&minor, ap->context, ap->qop, &in_buf,
535*0Sstevel@tonic-gate 					&out_buf)) != GSS_S_COMPLETE) {
536*0Sstevel@tonic-gate 		if (major == GSS_S_CONTEXT_EXPIRED) {
537*0Sstevel@tonic-gate 			ap->invalid = TRUE;
538*0Sstevel@tonic-gate 		}
539*0Sstevel@tonic-gate 		return (FALSE);
540*0Sstevel@tonic-gate 	}
541*0Sstevel@tonic-gate 	verf.oa_base = out_buf.value;
542*0Sstevel@tonic-gate 	verf.oa_length = out_buf.length;
543*0Sstevel@tonic-gate 	ret = xdr_opaque_auth(xdrs, &verf);
544*0Sstevel@tonic-gate 	(void) gss_release_buffer(&minor, &out_buf);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	return (ret);
547*0Sstevel@tonic-gate }
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate /*
550*0Sstevel@tonic-gate  * Function: rpc_gss_nextverf.  Not used.
551*0Sstevel@tonic-gate  */
552*0Sstevel@tonic-gate static void
553*0Sstevel@tonic-gate rpc_gss_nextverf()
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate /*
558*0Sstevel@tonic-gate  * Function: rpc_gss_marshall - not used.
559*0Sstevel@tonic-gate  */
560*0Sstevel@tonic-gate static bool_t
561*0Sstevel@tonic-gate rpc_gss_marshall(auth, xdrs)
562*0Sstevel@tonic-gate 	AUTH		*auth;
563*0Sstevel@tonic-gate 	XDR		*xdrs;
564*0Sstevel@tonic-gate {
565*0Sstevel@tonic-gate 	if (!xdr_opaque_auth(xdrs, &auth->ah_cred) ||
566*0Sstevel@tonic-gate 				!xdr_opaque_auth(xdrs, &auth->ah_verf))
567*0Sstevel@tonic-gate 		return (FALSE);
568*0Sstevel@tonic-gate 	return (TRUE);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate /*
572*0Sstevel@tonic-gate  * Validate sequence window upon a successful RPCSEC_GSS INIT session.
573*0Sstevel@tonic-gate  * The sequence window sent back by the server should be verifiable by
574*0Sstevel@tonic-gate  * the verifier which is a checksum of the sequence window.
575*0Sstevel@tonic-gate  */
576*0Sstevel@tonic-gate static bool_t
577*0Sstevel@tonic-gate validate_seqwin(rpc_gss_data *ap)
578*0Sstevel@tonic-gate {
579*0Sstevel@tonic-gate 	uint_t			seq_win_net;
580*0Sstevel@tonic-gate 	OM_uint32		major = 0, minor = 0;
581*0Sstevel@tonic-gate 	gss_buffer_desc		msg_buf, tok_buf;
582*0Sstevel@tonic-gate 	int			qop_state = 0;
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	seq_win_net = (uint_t)htonl(ap->seq_window);
585*0Sstevel@tonic-gate 	msg_buf.length = sizeof (seq_win_net);
586*0Sstevel@tonic-gate 	msg_buf.value = (char *)&seq_win_net;
587*0Sstevel@tonic-gate 	tok_buf.length = ap->verifier->oa_length;
588*0Sstevel@tonic-gate 	tok_buf.value = ap->verifier->oa_base;
589*0Sstevel@tonic-gate 	major = gss_verify(&minor, ap->context, &msg_buf, &tok_buf, &qop_state);
590*0Sstevel@tonic-gate 	if (major != GSS_S_COMPLETE)
591*0Sstevel@tonic-gate 	    return (FALSE);
592*0Sstevel@tonic-gate 	return (TRUE);
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate /*
596*0Sstevel@tonic-gate  * Validate RPC response verifier from server.  The response verifier
597*0Sstevel@tonic-gate  * is the checksum of the request sequence number.
598*0Sstevel@tonic-gate  */
599*0Sstevel@tonic-gate static bool_t
600*0Sstevel@tonic-gate rpc_gss_validate(auth, verf)
601*0Sstevel@tonic-gate 	AUTH			*auth;
602*0Sstevel@tonic-gate 	struct opaque_auth	*verf;
603*0Sstevel@tonic-gate {
604*0Sstevel@tonic-gate 	/*LINTED*/
605*0Sstevel@tonic-gate 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
606*0Sstevel@tonic-gate 	uint_t			seq_num_net;
607*0Sstevel@tonic-gate 	OM_uint32		major, minor;
608*0Sstevel@tonic-gate 	gss_buffer_desc		msg_buf, tok_buf;
609*0Sstevel@tonic-gate 	int			qop_state;
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	/*
612*0Sstevel@tonic-gate 	 * If context is not established yet, save the verifier for
613*0Sstevel@tonic-gate 	 * validating the sequence window later at the end of context
614*0Sstevel@tonic-gate 	 * creation session.
615*0Sstevel@tonic-gate 	 */
616*0Sstevel@tonic-gate 	if (!ap->established) {
617*0Sstevel@tonic-gate 	    if (ap->verifier == NULL) {
618*0Sstevel@tonic-gate 		ap->verifier = malloc(sizeof (struct opaque_auth));
619*0Sstevel@tonic-gate 		memset(ap->verifier, 0, sizeof (struct opaque_auth));
620*0Sstevel@tonic-gate 		if (verf->oa_length > 0)
621*0Sstevel@tonic-gate 		    ap->verifier->oa_base = malloc(verf->oa_length);
622*0Sstevel@tonic-gate 	    } else {
623*0Sstevel@tonic-gate 		if (ap->verifier->oa_length > 0)
624*0Sstevel@tonic-gate 		    free(ap->verifier->oa_base);
625*0Sstevel@tonic-gate 		if (verf->oa_length > 0)
626*0Sstevel@tonic-gate 		    ap->verifier->oa_base = malloc(verf->oa_length);
627*0Sstevel@tonic-gate 	    }
628*0Sstevel@tonic-gate 	    ap->verifier->oa_length = verf->oa_length;
629*0Sstevel@tonic-gate 	    bcopy(verf->oa_base, ap->verifier->oa_base, verf->oa_length);
630*0Sstevel@tonic-gate 	    return (TRUE);
631*0Sstevel@tonic-gate 	}
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	seq_num_net = (uint_t)htonl(ap->seq_num);
634*0Sstevel@tonic-gate 	msg_buf.length = sizeof (seq_num_net);
635*0Sstevel@tonic-gate 	msg_buf.value = (char *)&seq_num_net;
636*0Sstevel@tonic-gate 	tok_buf.length = verf->oa_length;
637*0Sstevel@tonic-gate 	tok_buf.value = verf->oa_base;
638*0Sstevel@tonic-gate 	major = gss_verify(&minor, ap->context, &msg_buf, &tok_buf, &qop_state);
639*0Sstevel@tonic-gate 	if (major != GSS_S_COMPLETE)
640*0Sstevel@tonic-gate 		return (FALSE);
641*0Sstevel@tonic-gate 	return (TRUE);
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate /*
645*0Sstevel@tonic-gate  * Refresh client context.  This is necessary sometimes because the
646*0Sstevel@tonic-gate  * server will ocassionally destroy contexts based on LRU method, or
647*0Sstevel@tonic-gate  * because of expired credentials.
648*0Sstevel@tonic-gate  */
649*0Sstevel@tonic-gate static bool_t
650*0Sstevel@tonic-gate rpc_gss_refresh(auth, msg)
651*0Sstevel@tonic-gate 	AUTH		*auth;
652*0Sstevel@tonic-gate 	struct rpc_msg	*msg;
653*0Sstevel@tonic-gate {
654*0Sstevel@tonic-gate 	/*LINTED*/
655*0Sstevel@tonic-gate 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
656*0Sstevel@tonic-gate 	OM_uint32	gssstat, minor_stat;
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	/*
659*0Sstevel@tonic-gate 	 * The context needs to be recreated only when the error status
660*0Sstevel@tonic-gate 	 * returned from the server is one of the following:
661*0Sstevel@tonic-gate 	 *	RPCSEC_GSS_NOCRED and RPCSEC_GSS_FAILED
662*0Sstevel@tonic-gate 	 * The existing context should not be destroyed unless the above
663*0Sstevel@tonic-gate 	 * error status codes are received or if the context has not
664*0Sstevel@tonic-gate 	 * been set up.
665*0Sstevel@tonic-gate 	 */
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	if (msg->rjcted_rply.rj_why == RPCSEC_GSS_NOCRED ||
668*0Sstevel@tonic-gate 			msg->rjcted_rply.rj_why == RPCSEC_GSS_FAILED ||
669*0Sstevel@tonic-gate 							!ap->established) {
670*0Sstevel@tonic-gate 		/*
671*0Sstevel@tonic-gate 		 * Destroy the context if necessary.  Use the same memory
672*0Sstevel@tonic-gate 		 * for the new context since we've already passed a pointer
673*0Sstevel@tonic-gate 		 * to it to the user.
674*0Sstevel@tonic-gate 		 */
675*0Sstevel@tonic-gate 		if (ap->context != GSS_C_NO_CONTEXT) {
676*0Sstevel@tonic-gate 			(void) gss_delete_sec_context(&minor_stat, &ap->context,
677*0Sstevel@tonic-gate 								NULL);
678*0Sstevel@tonic-gate 			ap->context = GSS_C_NO_CONTEXT;
679*0Sstevel@tonic-gate 		}
680*0Sstevel@tonic-gate 		if (ap->ctx_handle.length != 0) {
681*0Sstevel@tonic-gate 			(void) gss_release_buffer(&minor_stat,
682*0Sstevel@tonic-gate 							&ap->ctx_handle);
683*0Sstevel@tonic-gate 			ap->ctx_handle.length = 0;
684*0Sstevel@tonic-gate 			ap->ctx_handle.value = NULL;
685*0Sstevel@tonic-gate 		}
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 		/*
688*0Sstevel@tonic-gate 		 * If the context was not already established, don't try to
689*0Sstevel@tonic-gate 		 * recreate it.
690*0Sstevel@tonic-gate 		 */
691*0Sstevel@tonic-gate 		if (!ap->established) {
692*0Sstevel@tonic-gate 			ap->invalid = TRUE;
693*0Sstevel@tonic-gate 			return (FALSE);
694*0Sstevel@tonic-gate 		}
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 		/*
697*0Sstevel@tonic-gate 		 * Recreate context.
698*0Sstevel@tonic-gate 		 */
699*0Sstevel@tonic-gate 		if (rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
700*0Sstevel@tonic-gate 		    (gss_OID *)0, (OM_uint32 *)0, (OM_uint32 *)0))
701*0Sstevel@tonic-gate 			return (TRUE);
702*0Sstevel@tonic-gate 		else {
703*0Sstevel@tonic-gate 			ap->invalid = TRUE;
704*0Sstevel@tonic-gate 			return (FALSE);
705*0Sstevel@tonic-gate 		}
706*0Sstevel@tonic-gate 	}
707*0Sstevel@tonic-gate 	return (FALSE);
708*0Sstevel@tonic-gate }
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate /*
711*0Sstevel@tonic-gate  * Destroy a context.
712*0Sstevel@tonic-gate  */
713*0Sstevel@tonic-gate static void
714*0Sstevel@tonic-gate rpc_gss_destroy(auth)
715*0Sstevel@tonic-gate 	AUTH		*auth;
716*0Sstevel@tonic-gate {
717*0Sstevel@tonic-gate 	/*LINTED*/
718*0Sstevel@tonic-gate 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	rpc_gss_destroy_pvt(auth);
721*0Sstevel@tonic-gate 	free((char *)ap);
722*0Sstevel@tonic-gate 	free(auth);
723*0Sstevel@tonic-gate }
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate /*
726*0Sstevel@tonic-gate  * Private interface to destroy a context without freeing up
727*0Sstevel@tonic-gate  * the memory used by it.  We need to do this when a refresh
728*0Sstevel@tonic-gate  * fails, for example, so the user will still have a handle.
729*0Sstevel@tonic-gate  */
730*0Sstevel@tonic-gate static void
731*0Sstevel@tonic-gate rpc_gss_destroy_pvt(auth)
732*0Sstevel@tonic-gate 	AUTH		*auth;
733*0Sstevel@tonic-gate {
734*0Sstevel@tonic-gate 	struct timeval	timeout;
735*0Sstevel@tonic-gate 	OM_uint32	minor_stat;
736*0Sstevel@tonic-gate 	/*LINTED*/
737*0Sstevel@tonic-gate 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	/*
740*0Sstevel@tonic-gate 	 * If we have a server context id, inform server that we are
741*0Sstevel@tonic-gate 	 * destroying the context.
742*0Sstevel@tonic-gate 	 */
743*0Sstevel@tonic-gate 	if (ap->ctx_handle.length != 0) {
744*0Sstevel@tonic-gate 		ap->gss_proc = RPCSEC_GSS_DESTROY;
745*0Sstevel@tonic-gate 		timeout.tv_sec = 1;
746*0Sstevel@tonic-gate 		timeout.tv_usec = 0;
747*0Sstevel@tonic-gate 		(void) clnt_call(ap->clnt, NULLPROC, xdr_void, NULL,
748*0Sstevel@tonic-gate 						xdr_void, NULL, timeout);
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 		(void) gss_release_buffer(&minor_stat, &ap->ctx_handle);
751*0Sstevel@tonic-gate 		ap->ctx_handle.length = 0;
752*0Sstevel@tonic-gate 		ap->ctx_handle.value = NULL;
753*0Sstevel@tonic-gate 	}
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	/*
756*0Sstevel@tonic-gate 	 * Destroy local GSS context.
757*0Sstevel@tonic-gate 	 */
758*0Sstevel@tonic-gate 	if (ap->context != GSS_C_NO_CONTEXT) {
759*0Sstevel@tonic-gate 		(void) gss_delete_sec_context(&minor_stat, &ap->context, NULL);
760*0Sstevel@tonic-gate 		ap->context = GSS_C_NO_CONTEXT;
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	/*
764*0Sstevel@tonic-gate 	 * Looks like we need to release default credentials if we use it.
765*0Sstevel@tonic-gate 	 * Non-default creds need to be released by user.
766*0Sstevel@tonic-gate 	 */
767*0Sstevel@tonic-gate 	if (ap->my_cred == GSS_C_NO_CREDENTIAL)
768*0Sstevel@tonic-gate 		(void) gss_release_cred(&minor_stat, &ap->my_cred);
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	/*
771*0Sstevel@tonic-gate 	 * Release any internal name structures.
772*0Sstevel@tonic-gate 	 */
773*0Sstevel@tonic-gate 	if (ap->target_name != NULL) {
774*0Sstevel@tonic-gate 		(void) gss_release_name(&minor_stat, &ap->target_name);
775*0Sstevel@tonic-gate 		ap->target_name = NULL;
776*0Sstevel@tonic-gate 	}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	/*
779*0Sstevel@tonic-gate 	 * Free the verifier saved for sequence window checking.
780*0Sstevel@tonic-gate 	 */
781*0Sstevel@tonic-gate 	if (ap->verifier != NULL) {
782*0Sstevel@tonic-gate 	    if (ap->verifier->oa_length > 0)
783*0Sstevel@tonic-gate 		free(ap->verifier->oa_base);
784*0Sstevel@tonic-gate 	    free(ap->verifier);
785*0Sstevel@tonic-gate 	    ap->verifier = NULL;
786*0Sstevel@tonic-gate 	}
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate  * Wrap client side data.  The encoded header is passed in through
791*0Sstevel@tonic-gate  * buf and buflen.  The header is up to but not including the
792*0Sstevel@tonic-gate  * credential field.
793*0Sstevel@tonic-gate  */
794*0Sstevel@tonic-gate bool_t
795*0Sstevel@tonic-gate __rpc_gss_wrap(auth, buf, buflen, out_xdrs, xdr_func, xdr_ptr)
796*0Sstevel@tonic-gate 	AUTH			*auth;
797*0Sstevel@tonic-gate 	char			*buf;		/* encoded header */
798*0Sstevel@tonic-gate 	uint_t			buflen;		/* encoded header length */
799*0Sstevel@tonic-gate 	XDR			*out_xdrs;
800*0Sstevel@tonic-gate 	bool_t			(*xdr_func)();
801*0Sstevel@tonic-gate 	caddr_t			xdr_ptr;
802*0Sstevel@tonic-gate {
803*0Sstevel@tonic-gate 	/*LINTED*/
804*0Sstevel@tonic-gate 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
805*0Sstevel@tonic-gate 	XDR			xdrs;
806*0Sstevel@tonic-gate 	char			tmp_buf[512];
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	/*
810*0Sstevel@tonic-gate 	 * Reject an invalid context.
811*0Sstevel@tonic-gate 	 */
812*0Sstevel@tonic-gate 	if (ap->invalid)
813*0Sstevel@tonic-gate 		return (FALSE);
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	/*
816*0Sstevel@tonic-gate 	 * If context is established, bump up sequence number.
817*0Sstevel@tonic-gate 	 */
818*0Sstevel@tonic-gate 	if (ap->established)
819*0Sstevel@tonic-gate 		ap->seq_num++;
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	/*
822*0Sstevel@tonic-gate 	 * Create the header in a temporary XDR context and buffer
823*0Sstevel@tonic-gate 	 * before putting it out.
824*0Sstevel@tonic-gate 	 */
825*0Sstevel@tonic-gate 	xdrmem_create(&xdrs, tmp_buf, sizeof (tmp_buf), XDR_ENCODE);
826*0Sstevel@tonic-gate 	if (!XDR_PUTBYTES(&xdrs, buf, buflen))
827*0Sstevel@tonic-gate 		return (FALSE);
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	/*
830*0Sstevel@tonic-gate 	 * create cred field
831*0Sstevel@tonic-gate 	 */
832*0Sstevel@tonic-gate 	if (!marshall_creds(ap, &xdrs))
833*0Sstevel@tonic-gate 		return (FALSE);
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	/*
836*0Sstevel@tonic-gate 	 * create verifier
837*0Sstevel@tonic-gate 	 */
838*0Sstevel@tonic-gate 	if (!marshall_verf(ap, &xdrs, tmp_buf))
839*0Sstevel@tonic-gate 		return (FALSE);
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 	/*
842*0Sstevel@tonic-gate 	 * write out header and destroy temp structures
843*0Sstevel@tonic-gate 	 */
844*0Sstevel@tonic-gate 	if (!XDR_PUTBYTES(out_xdrs, tmp_buf, XDR_GETPOS(&xdrs)))
845*0Sstevel@tonic-gate 		return (FALSE);
846*0Sstevel@tonic-gate 	XDR_DESTROY(&xdrs);
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 	/*
849*0Sstevel@tonic-gate 	 * If context is not established, or if neither integrity
850*0Sstevel@tonic-gate 	 * nor privacy is used, just XDR encode data.
851*0Sstevel@tonic-gate 	 */
852*0Sstevel@tonic-gate 	if (!ap->established || ap->service == rpc_gss_svc_none)
853*0Sstevel@tonic-gate 		return ((*xdr_func)(out_xdrs, xdr_ptr));
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	return (__rpc_gss_wrap_data(ap->service, ap->qop, ap->context,
856*0Sstevel@tonic-gate 				ap->seq_num, out_xdrs, xdr_func, xdr_ptr));
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate /*
860*0Sstevel@tonic-gate  * Unwrap received data.
861*0Sstevel@tonic-gate  */
862*0Sstevel@tonic-gate bool_t
863*0Sstevel@tonic-gate __rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
864*0Sstevel@tonic-gate 	AUTH			*auth;
865*0Sstevel@tonic-gate 	XDR			*in_xdrs;
866*0Sstevel@tonic-gate 	bool_t			(*xdr_func)();
867*0Sstevel@tonic-gate 	caddr_t			xdr_ptr;
868*0Sstevel@tonic-gate {
869*0Sstevel@tonic-gate 	/*LINTED*/
870*0Sstevel@tonic-gate 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	/*
873*0Sstevel@tonic-gate 	 * If context is not established, of if neither integrity
874*0Sstevel@tonic-gate 	 * nor privacy is used, just XDR encode data.
875*0Sstevel@tonic-gate 	 */
876*0Sstevel@tonic-gate 	if (!ap->established || ap->service == rpc_gss_svc_none)
877*0Sstevel@tonic-gate 		return ((*xdr_func)(in_xdrs, xdr_ptr));
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	return (__rpc_gss_unwrap_data(ap->service,
880*0Sstevel@tonic-gate 				ap->context,
881*0Sstevel@tonic-gate 				ap->seq_num,
882*0Sstevel@tonic-gate 				ap->qop,
883*0Sstevel@tonic-gate 				in_xdrs, xdr_func, xdr_ptr));
884*0Sstevel@tonic-gate }
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate int
887*0Sstevel@tonic-gate __rpc_gss_max_data_length(auth, max_tp_unit_len)
888*0Sstevel@tonic-gate 	AUTH		*auth;
889*0Sstevel@tonic-gate 	int		max_tp_unit_len;
890*0Sstevel@tonic-gate {
891*0Sstevel@tonic-gate 	/*LINTED*/
892*0Sstevel@tonic-gate 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	if (!ap->established || max_tp_unit_len <= 0)
895*0Sstevel@tonic-gate 		return (0);
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	return (__find_max_data_length(ap->service,
898*0Sstevel@tonic-gate 			ap->context,
899*0Sstevel@tonic-gate 			ap->qop,
900*0Sstevel@tonic-gate 			max_tp_unit_len));
901*0Sstevel@tonic-gate }
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate #undef  rpc_gss_err
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate rpc_gss_error_t	rpc_gss_err;
906*0Sstevel@tonic-gate static mutex_t	rge_lock;		/* protects TSD key creation */
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate rpc_gss_error_t *
909*0Sstevel@tonic-gate __rpc_gss_err()
910*0Sstevel@tonic-gate {
911*0Sstevel@tonic-gate 	static thread_key_t rpc_gss_err_key = 0;
912*0Sstevel@tonic-gate 	rpc_gss_error_t *tsd = 0;
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 	if (_thr_main())
915*0Sstevel@tonic-gate 		return (&rpc_gss_err);
916*0Sstevel@tonic-gate 	if (_thr_getspecific(rpc_gss_err_key, (void **) &tsd) != 0) {
917*0Sstevel@tonic-gate 		mutex_lock(&rge_lock);
918*0Sstevel@tonic-gate 		if (_thr_keycreate(&rpc_gss_err_key, free) != 0) {
919*0Sstevel@tonic-gate 			mutex_unlock(&rge_lock);
920*0Sstevel@tonic-gate 			return (&rpc_gss_err);
921*0Sstevel@tonic-gate 		}
922*0Sstevel@tonic-gate 		mutex_unlock(&rge_lock);
923*0Sstevel@tonic-gate 	}
924*0Sstevel@tonic-gate 	if (!tsd) {
925*0Sstevel@tonic-gate 		tsd = (rpc_gss_error_t *)
926*0Sstevel@tonic-gate 			calloc(1, sizeof (rpc_gss_error_t));
927*0Sstevel@tonic-gate 		if (_thr_setspecific(rpc_gss_err_key, (void *) tsd) != 0) {
928*0Sstevel@tonic-gate 			if (tsd)
929*0Sstevel@tonic-gate 				free(tsd);
930*0Sstevel@tonic-gate 			return (&rpc_gss_err);
931*0Sstevel@tonic-gate 		}
932*0Sstevel@tonic-gate 		memset(tsd, 0, sizeof (rpc_gss_error_t));
933*0Sstevel@tonic-gate 		return (tsd);
934*0Sstevel@tonic-gate 	}
935*0Sstevel@tonic-gate 	return (tsd);
936*0Sstevel@tonic-gate }
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate void
939*0Sstevel@tonic-gate __rpc_gss_get_error(error)
940*0Sstevel@tonic-gate 	rpc_gss_error_t	*error;
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	error->rpc_gss_error = rpc_gss_err.rpc_gss_error;
944*0Sstevel@tonic-gate 	error->system_error = rpc_gss_err.system_error;
945*0Sstevel@tonic-gate }
946