xref: /illumos-gate/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c (revision 48bbca816818409505a6e214d0911fda44e622e3)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 /*
29  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
30  *
31  * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
32  */
33 
34 /*
35  * Server side handling of RPCSEC_GSS flavor.
36  */
37 
38 #include <sys/systm.h>
39 #include <sys/kstat.h>
40 #include <sys/cmn_err.h>
41 #include <sys/debug.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_ext.h>
46 #include <rpc/rpc.h>
47 #include <rpc/rpcsec_defs.h>
48 #include <sys/sunddi.h>
49 #include <sys/atomic.h>
50 
51 extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
52 
53 #ifdef	DEBUG
54 extern void prom_printf(const char *, ...);
55 #endif
56 
57 #ifdef  _KERNEL
58 #define	memcmp(a, b, l) bcmp((a), (b), (l))
59 #endif
60 
61 
62 /*
63  * Sequence window definitions.
64  */
65 #define	SEQ_ARR_SIZE	4
66 #define	SEQ_WIN		(SEQ_ARR_SIZE*32)
67 #define	SEQ_HI_BIT	0x80000000
68 #define	SEQ_LO_BIT	1
69 #define	DIV_BY_32	5
70 #define	SEQ_MASK	0x1f
71 #define	SEQ_MAX		((unsigned int)0x80000000)
72 
73 
74 /* cache retransmit data */
75 typedef struct _retrans_entry {
76 	uint32_t	xid;
77 	rpc_gss_init_res result;
78 } retrans_entry;
79 
80 /*
81  * Server side RPCSEC_GSS context information.
82  */
83 typedef struct _svc_rpc_gss_data {
84 	struct _svc_rpc_gss_data	*next, *prev;
85 	struct _svc_rpc_gss_data	*lru_next, *lru_prev;
86 	bool_t				established;
87 	gss_ctx_id_t			context;
88 	gss_buffer_desc			client_name;
89 	time_t				expiration;
90 	uint_t				seq_num;
91 	uint_t				seq_bits[SEQ_ARR_SIZE];
92 	uint_t				key;
93 	OM_uint32			qop;
94 	bool_t				done_docallback;
95 	bool_t				locked;
96 	rpc_gss_rawcred_t		raw_cred;
97 	rpc_gss_ucred_t			u_cred;
98 	time_t				u_cred_set;
99 	void				*cookie;
100 	gss_cred_id_t			deleg;
101 	kmutex_t			clm;
102 	int				ref_cnt;
103 	time_t				last_ref_time;
104 	bool_t				stale;
105 	retrans_entry			*retrans_data;
106 } svc_rpc_gss_data;
107 
108 /*
109  * Data structures used for LRU based context management.
110  */
111 
112 
113 #define	HASH(key) ((key) % svc_rpc_gss_hashmod)
114 /* Size of hash table for svc_rpc_gss_data structures */
115 #define	GSS_DATA_HASH_SIZE	1024
116 
117 /*
118  * The following two defines specify a time delta that is used in
119  * sweep_clients. When the last_ref_time of a context is older than
120  * than the current time minus the delta, i.e, the context has not
121  * been referenced in the last delta seconds, we will return the
122  * context back to the cache if the ref_cnt is zero. The first delta
123  * value will be used when sweep_clients is called from
124  * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
125  * all entries except those that are currently "active". By active we
126  * mean those that have been referenced in the last ACTIVE_DELTA
127  * seconds. If sweep_client is not being called from reclaim, then we
128  * will reclaim all entries that are "inactive". By inactive we mean
129  * those entries that have not been accessed in INACTIVE_DELTA
130  * seconds.  Note we always assume that ACTIVE_DELTA is less than
131  * INACTIVE_DELTA, so that reaping entries from a reclaim operation
132  * will necessarily imply reaping all "inactive" entries and then
133  * some.
134  */
135 
136 /*
137  * If low on memory reap cache entries that have not been active for
138  * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
139  */
140 #define	ACTIVE_DELTA		30*60		/* 30 minutes */
141 
142 /*
143  * If in sweeping contexts we find contexts with a ref_cnt equal to zero
144  * and the context has not been referenced in INACTIVE_DELTA seconds, return
145  * the entry to the cache.
146  */
147 #define	INACTIVE_DELTA		8*60*60		/* 8 hours */
148 
149 int				svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
150 static svc_rpc_gss_data		**clients;
151 static svc_rpc_gss_data		*lru_first, *lru_last;
152 static time_t			sweep_interval = 60*60;
153 static time_t			last_swept = 0;
154 static int			num_gss_contexts = 0;
155 static time_t			svc_rpcgss_gid_timeout = 60*60*12;
156 static kmem_cache_t		*svc_data_handle;
157 static time_t			svc_rpc_gss_active_delta = ACTIVE_DELTA;
158 static time_t			svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
159 
160 /*
161  * lock used with context/lru variables
162  */
163 static kmutex_t			ctx_mutex;
164 
165 /*
166  * Data structure to contain cache statistics
167  */
168 
169 static struct {
170 	int64_t total_entries_allocated;
171 	int64_t no_reclaims;
172 	int64_t no_returned_by_reclaim;
173 } svc_rpc_gss_cache_stats;
174 
175 
176 /*
177  * lock used with server credential variables list
178  *
179  * server cred list locking guidelines:
180  * - Writer's lock holder has exclusive access to the list
181  */
182 static krwlock_t		cred_lock;
183 
184 /*
185  * server callback list
186  */
187 typedef struct rpc_gss_cblist_s {
188 	struct rpc_gss_cblist_s		*next;
189 	rpc_gss_callback_t	cb;
190 } rpc_gss_cblist_t;
191 
192 static rpc_gss_cblist_t			*rpc_gss_cblist = NULL;
193 
194 /*
195  * lock used with callback variables
196  */
197 static kmutex_t			cb_mutex;
198 
199 /*
200  * forward declarations
201  */
202 static bool_t			svc_rpc_gss_wrap();
203 static bool_t			svc_rpc_gss_unwrap();
204 static svc_rpc_gss_data		*create_client();
205 static svc_rpc_gss_data		*get_client();
206 static svc_rpc_gss_data		*find_client();
207 static void			destroy_client();
208 static void			sweep_clients(bool_t);
209 static void			insert_client();
210 static bool_t			check_verf(struct rpc_msg *, gss_ctx_id_t,
211 					int *, uid_t);
212 static bool_t			set_response_verf();
213 static void			retrans_add(svc_rpc_gss_data *, uint32_t,
214 					rpc_gss_init_res *);
215 static void			retrans_del(svc_rpc_gss_data *);
216 static bool_t			transfer_sec_context(svc_rpc_gss_data *);
217 static void			common_client_data_free(svc_rpc_gss_data *);
218 
219 /*
220  * server side wrap/unwrap routines
221  */
222 struct svc_auth_ops svc_rpc_gss_ops = {
223 	svc_rpc_gss_wrap,
224 	svc_rpc_gss_unwrap,
225 };
226 
227 /* taskq(9F) */
228 typedef struct svcrpcsec_gss_taskq_arg {
229 	SVCXPRT			*rq_xprt;
230 	rpc_gss_init_arg	*rpc_call_arg;
231 	struct rpc_msg		*msg;
232 	svc_rpc_gss_data	*client_data;
233 	uint_t			cr_version;
234 	rpc_gss_service_t	cr_service;
235 } svcrpcsec_gss_taskq_arg_t;
236 
237 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
238 int rpcsec_gss_init_taskq_nthreads = 1;
239 static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL;
240 
241 extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
242 extern void rpc_msg_free(struct rpc_msg **, int);
243 
244 /*
245  * from svc_clts.c:
246  * Transport private data.
247  * Kept in xprt->xp_p2buf.
248  */
249 struct udp_data {
250 	mblk_t	*ud_resp;			/* buffer for response */
251 	mblk_t	*ud_inmp;			/* mblk chain of request */
252 };
253 
254 /*ARGSUSED*/
255 static int
256 svc_gss_data_create(void *buf, void *pdata, int kmflag)
257 {
258 	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
259 
260 	mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
261 
262 	return (0);
263 }
264 
265 /*ARGSUSED*/
266 static void
267 svc_gss_data_destroy(void *buf, void *pdata)
268 {
269 	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
270 
271 	mutex_destroy(&client_data->clm);
272 }
273 
274 
275 /*ARGSUSED*/
276 static void
277 svc_gss_data_reclaim(void *pdata)
278 {
279 	mutex_enter(&ctx_mutex);
280 
281 	svc_rpc_gss_cache_stats.no_reclaims++;
282 	sweep_clients(TRUE);
283 
284 	mutex_exit(&ctx_mutex);
285 }
286 
287 /*
288  *  Init stuff on the server side.
289  */
290 void
291 svc_gss_init()
292 {
293 	mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
294 	mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
295 	rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
296 	clients = (svc_rpc_gss_data **)
297 	    kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
298 	    KM_SLEEP);
299 	svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
300 	    sizeof (svc_rpc_gss_data), 0,
301 	    svc_gss_data_create,
302 	    svc_gss_data_destroy,
303 	    svc_gss_data_reclaim,
304 	    NULL, NULL, 0);
305 
306 	if (svcrpcsec_gss_init_taskq == NULL) {
307 		svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL,
308 		    "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads,
309 		    TASKQ_DEFAULTPRI, 0);
310 		if (svcrpcsec_gss_init_taskq == NULL)
311 			cmn_err(CE_NOTE,
312 			    "svc_gss_init: ddi_taskq_create failed");
313 	}
314 }
315 
316 /*
317  * Destroy structures allocated in svc_gss_init().
318  * This routine is called by _init() if mod_install() failed.
319  */
320 void
321 svc_gss_fini()
322 {
323 	mutex_destroy(&cb_mutex);
324 	mutex_destroy(&ctx_mutex);
325 	rw_destroy(&cred_lock);
326 	kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
327 	kmem_cache_destroy(svc_data_handle);
328 }
329 
330 /*
331  * Cleanup routine for destroying context, called after service
332  * procedure is executed. Actually we just decrement the reference count
333  * associated with this context. If the reference count is zero and the
334  * context is marked as stale, we would then destroy the context. Additionally,
335  * we check if its been longer than sweep_interval since the last sweep_clients
336  * was run, and if so run sweep_clients to free all stale contexts with zero
337  * reference counts or contexts that are old. (Haven't been access in
338  * svc_rpc_inactive_delta seconds).
339  */
340 void
341 rpc_gss_cleanup(SVCXPRT *clone_xprt)
342 {
343 	svc_rpc_gss_data	*cl;
344 	SVCAUTH			*svcauth;
345 
346 	/*
347 	 * First check if current context needs to be cleaned up.
348 	 * There might be other threads stale this client data
349 	 * in between.
350 	 */
351 	svcauth = &clone_xprt->xp_auth;
352 	mutex_enter(&ctx_mutex);
353 	if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
354 		mutex_enter(&cl->clm);
355 		ASSERT(cl->ref_cnt > 0);
356 		if (--cl->ref_cnt == 0 && cl->stale) {
357 			mutex_exit(&cl->clm);
358 			destroy_client(cl);
359 			svcauth->svc_ah_private = NULL;
360 		} else
361 			mutex_exit(&cl->clm);
362 	}
363 
364 	/*
365 	 * Check for other expired contexts.
366 	 */
367 	if ((gethrestime_sec() - last_swept) > sweep_interval)
368 		sweep_clients(FALSE);
369 
370 	mutex_exit(&ctx_mutex);
371 }
372 
373 /*
374  * Shift the array arr of length arrlen right by nbits bits.
375  */
376 static void
377 shift_bits(arr, arrlen, nbits)
378 	uint_t	*arr;
379 	int	arrlen;
380 	int	nbits;
381 {
382 	int	i, j;
383 	uint_t	lo, hi;
384 
385 	/*
386 	 * If the number of bits to be shifted exceeds SEQ_WIN, just
387 	 * zero out the array.
388 	 */
389 	if (nbits < SEQ_WIN) {
390 		for (i = 0; i < nbits; i++) {
391 			hi = 0;
392 			for (j = 0; j < arrlen; j++) {
393 				lo = arr[j] & SEQ_LO_BIT;
394 				arr[j] >>= 1;
395 				if (hi)
396 					arr[j] |= SEQ_HI_BIT;
397 				hi = lo;
398 			}
399 		}
400 	} else {
401 		for (j = 0; j < arrlen; j++)
402 			arr[j] = 0;
403 	}
404 }
405 
406 /*
407  * Check that the received sequence number seq_num is valid.
408  */
409 static bool_t
410 check_seq(cl, seq_num, kill_context)
411 	svc_rpc_gss_data	*cl;
412 	uint_t			seq_num;
413 	bool_t			*kill_context;
414 {
415 	int			i, j;
416 	uint_t			bit;
417 
418 	/*
419 	 * If it exceeds the maximum, kill context.
420 	 */
421 	if (seq_num >= SEQ_MAX) {
422 		*kill_context = TRUE;
423 		RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
424 		return (FALSE);
425 	}
426 
427 	/*
428 	 * If greater than the last seen sequence number, just shift
429 	 * the sequence window so that it starts at the new sequence
430 	 * number and extends downwards by SEQ_WIN.
431 	 */
432 	if (seq_num > cl->seq_num) {
433 		(void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
434 				(int)(seq_num - cl->seq_num));
435 		cl->seq_bits[0] |= SEQ_HI_BIT;
436 		cl->seq_num = seq_num;
437 		return (TRUE);
438 	}
439 
440 	/*
441 	 * If it is outside the sequence window, return failure.
442 	 */
443 	i = cl->seq_num - seq_num;
444 	if (i >= SEQ_WIN) {
445 		RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
446 		return (FALSE);
447 	}
448 
449 	/*
450 	 * If within sequence window, set the bit corresponding to it
451 	 * if not already seen;  if already seen, return failure.
452 	 */
453 	j = SEQ_MASK - (i & SEQ_MASK);
454 	bit = j > 0 ? (1 << j) : 1;
455 	i >>= DIV_BY_32;
456 	if (cl->seq_bits[i] & bit) {
457 		RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
458 		return (FALSE);
459 	}
460 	cl->seq_bits[i] |= bit;
461 	return (TRUE);
462 }
463 
464 /*
465  * Set server callback.
466  */
467 bool_t
468 rpc_gss_set_callback(cb)
469 	rpc_gss_callback_t	*cb;
470 {
471 	rpc_gss_cblist_t		*cbl, *tmp;
472 
473 	if (cb->callback == NULL) {
474 		RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
475 		return (FALSE);
476 	}
477 
478 	/* check if there is already an entry in the rpc_gss_cblist. */
479 	mutex_enter(&cb_mutex);
480 	if (rpc_gss_cblist) {
481 		for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
482 			if ((tmp->cb.callback == cb->callback) &&
483 			    (tmp->cb.version == cb->version) &&
484 			    (tmp->cb.program == cb->program)) {
485 				mutex_exit(&cb_mutex);
486 				return (TRUE);
487 			}
488 		}
489 	}
490 
491 	/* Not in rpc_gss_cblist.  Create a new entry. */
492 	if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
493 	    == NULL) {
494 		mutex_exit(&cb_mutex);
495 		return (FALSE);
496 	}
497 	cbl->cb = *cb;
498 	cbl->next = rpc_gss_cblist;
499 	rpc_gss_cblist = cbl;
500 	mutex_exit(&cb_mutex);
501 	return (TRUE);
502 }
503 
504 /*
505  * Locate callback (if specified) and call server.  Release any
506  * delegated credentials unless passed to server and the server
507  * accepts the context.  If a callback is not specified, accept
508  * the incoming context.
509  */
510 static bool_t
511 do_callback(req, client_data)
512 	struct svc_req		*req;
513 	svc_rpc_gss_data	*client_data;
514 {
515 	rpc_gss_cblist_t		*cbl;
516 	bool_t			ret = TRUE, found = FALSE;
517 	rpc_gss_lock_t		lock;
518 	OM_uint32		minor;
519 	mutex_enter(&cb_mutex);
520 	for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
521 		if (req->rq_prog != cbl->cb.program ||
522 					req->rq_vers != cbl->cb.version)
523 			continue;
524 		found = TRUE;
525 		lock.locked = FALSE;
526 		lock.raw_cred = &client_data->raw_cred;
527 		ret = (*cbl->cb.callback)(req, client_data->deleg,
528 			client_data->context, &lock, &client_data->cookie);
529 		req->rq_xprt->xp_cookie = client_data->cookie;
530 
531 		if (ret) {
532 			client_data->locked = lock.locked;
533 			client_data->deleg = GSS_C_NO_CREDENTIAL;
534 		}
535 		break;
536 	}
537 	if (!found) {
538 		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
539 			(void) kgss_release_cred(&minor, &client_data->deleg,
540 					crgetuid(CRED()));
541 			client_data->deleg = GSS_C_NO_CREDENTIAL;
542 		}
543 	}
544 	mutex_exit(&cb_mutex);
545 	return (ret);
546 }
547 
548 /*
549  * Get caller credentials.
550  */
551 bool_t
552 rpc_gss_getcred(req, rcred, ucred, cookie)
553 	struct svc_req		*req;
554 	rpc_gss_rawcred_t	**rcred;
555 	rpc_gss_ucred_t		**ucred;
556 	void			**cookie;
557 {
558 	SVCAUTH			*svcauth;
559 	svc_rpc_gss_data	*client_data;
560 	int			gssstat, gidlen;
561 
562 	svcauth = &req->rq_xprt->xp_auth;
563 	client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
564 
565 	mutex_enter(&client_data->clm);
566 
567 	if (rcred != NULL) {
568 		svcauth->raw_cred = client_data->raw_cred;
569 		*rcred = &svcauth->raw_cred;
570 	}
571 	if (ucred != NULL) {
572 		*ucred = &client_data->u_cred;
573 
574 		if (client_data->u_cred_set == 0 ||
575 		    client_data->u_cred_set < gethrestime_sec()) {
576 		    if (client_data->u_cred_set == 0) {
577 			if ((gssstat = kgsscred_expname_to_unix_cred(
578 			    &client_data->client_name,
579 			    &client_data->u_cred.uid,
580 			    &client_data->u_cred.gid,
581 			    &client_data->u_cred.gidlist,
582 			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
583 				RPCGSS_LOG(1, "rpc_gss_getcred: "
584 				    "kgsscred_expname_to_unix_cred failed %x\n",
585 				    gssstat);
586 				*ucred = NULL;
587 			} else {
588 				client_data->u_cred.gidlen = (short)gidlen;
589 				client_data->u_cred_set =
590 				    gethrestime_sec() + svc_rpcgss_gid_timeout;
591 			}
592 		    } else if (client_data->u_cred_set < gethrestime_sec()) {
593 			if ((gssstat = kgss_get_group_info(
594 			    client_data->u_cred.uid,
595 			    &client_data->u_cred.gid,
596 			    &client_data->u_cred.gidlist,
597 			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
598 				RPCGSS_LOG(1, "rpc_gss_getcred: "
599 				    "kgss_get_group_info failed %x\n",
600 				    gssstat);
601 				*ucred = NULL;
602 			} else {
603 				client_data->u_cred.gidlen = (short)gidlen;
604 				client_data->u_cred_set =
605 				    gethrestime_sec() + svc_rpcgss_gid_timeout;
606 			}
607 		    }
608 		}
609 	}
610 
611 	if (cookie != NULL)
612 		*cookie = client_data->cookie;
613 	req->rq_xprt->xp_cookie = client_data->cookie;
614 
615 	mutex_exit(&client_data->clm);
616 
617 	return (TRUE);
618 }
619 
620 /*
621  * Transfer the context data from the user land to the kernel.
622  */
623 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
624 
625 	gss_buffer_desc process_token;
626 	OM_uint32 gssstat, minor;
627 
628 	/*
629 	 * Call kgss_export_sec_context
630 	 * if an error is returned log a message
631 	 * go to error handling
632 	 * Otherwise call kgss_import_sec_context to
633 	 * convert the token into a context
634 	 */
635 	gssstat  = kgss_export_sec_context(&minor, client_data->context,
636 				&process_token);
637 	/*
638 	 * if export_sec_context returns an error we delete the
639 	 * context just to be safe.
640 	 */
641 	if (gssstat == GSS_S_NAME_NOT_MN) {
642 		RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
643 				"Kernel mod unavailable\n");
644 
645 	} else if (gssstat != GSS_S_COMPLETE) {
646 		RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed  "
647 				" gssstat = 0x%x\n", gssstat);
648 		(void) gss_release_buffer(&minor, &process_token);
649 		(void) kgss_delete_sec_context(&minor, &client_data->context,
650 				NULL);
651 		return (FALSE);
652 
653 	} else if (process_token.length == 0) {
654 		RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
655 				"for export_sec_context, but "
656 				"gsstat == GSS_S_COMPLETE\n");
657 		(void) kgss_delete_sec_context(&minor, &client_data->context,
658 				NULL);
659 		return (FALSE);
660 
661 	} else {
662 		gssstat = kgss_import_sec_context(&minor, &process_token,
663 					client_data->context);
664 		if (gssstat != GSS_S_COMPLETE) {
665 			RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
666 				" failed gssstat = 0x%x\n", gssstat);
667 			(void) kgss_delete_sec_context(&minor,
668 				&client_data->context, NULL);
669 			(void) gss_release_buffer(&minor, &process_token);
670 			return (FALSE);
671 		}
672 
673 		RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
674 		(void) gss_release_buffer(&minor, &process_token);
675 	}
676 
677 	return (TRUE);
678 }
679 
680 /*
681  * do_gss_accept is called from a taskq and does all the work for a
682  * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
683  */
684 static enum auth_stat
685 do_gss_accept(
686 	SVCXPRT *xprt,
687 	rpc_gss_init_arg *call_arg,
688 	struct rpc_msg *msg,
689 	svc_rpc_gss_data *client_data,
690 	uint_t cr_version,
691 	rpc_gss_service_t cr_service)
692 {
693 	rpc_gss_init_res	call_res;
694 	gss_buffer_desc		output_token;
695 	OM_uint32		gssstat, minor, minor_stat, time_rec;
696 	int			ret_flags, ret;
697 	gss_OID 		mech_type = GSS_C_NULL_OID;
698 	int			free_mech_type = 1;
699 	struct svc_req		r, *rqst;
700 
701 	rqst = &r;
702 	rqst->rq_xprt = xprt;
703 
704 	/*
705 	 * Initialize output_token.
706 	 */
707 	output_token.length = 0;
708 	output_token.value = NULL;
709 
710 	bzero((char *)&call_res, sizeof (call_res));
711 
712 	mutex_enter(&client_data->clm);
713 	if (client_data->stale) {
714 		ret = RPCSEC_GSS_NOCRED;
715 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
716 		goto error2;
717 	}
718 
719 	/*
720 	 * Any response we send will use ctx_handle, so set it now;
721 	 * also set seq_window since this won't change.
722 	 */
723 	call_res.ctx_handle.length = sizeof (client_data->key);
724 	call_res.ctx_handle.value = (char *)&client_data->key;
725 	call_res.seq_window = SEQ_WIN;
726 
727 	gssstat = GSS_S_FAILURE;
728 	minor = 0;
729 	minor_stat = 0;
730 	rw_enter(&cred_lock, RW_READER);
731 
732 	if (client_data->client_name.length) {
733 		(void) gss_release_buffer(&minor,
734 		    &client_data->client_name);
735 	}
736 	gssstat = kgss_accept_sec_context(&minor_stat,
737 	    &client_data->context,
738 	    GSS_C_NO_CREDENTIAL,
739 	    call_arg,
740 	    GSS_C_NO_CHANNEL_BINDINGS,
741 	    &client_data->client_name,
742 	    &mech_type,
743 	    &output_token,
744 	    &ret_flags,
745 	    &time_rec,
746 	    NULL,		/* don't need a delegated cred back */
747 	    crgetuid(CRED()));
748 
749 	RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
750 
751 	if (gssstat == GSS_S_COMPLETE) {
752 		/*
753 		 * Set the raw and unix credentials at this
754 		 * point.  This saves a lot of computation
755 		 * later when credentials are retrieved.
756 		 */
757 		client_data->raw_cred.version = cr_version;
758 		client_data->raw_cred.service = cr_service;
759 
760 		if (client_data->raw_cred.mechanism) {
761 			kgss_free_oid(client_data->raw_cred.mechanism);
762 			client_data->raw_cred.mechanism = NULL;
763 		}
764 		client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
765 		/*
766 		 * client_data is now responsible for freeing
767 		 * the data of 'mech_type'.
768 		 */
769 		free_mech_type = 0;
770 
771 		if (client_data->raw_cred.client_principal) {
772 			kmem_free((caddr_t)client_data->\
773 			    raw_cred.client_principal,
774 			    client_data->raw_cred.\
775 			    client_principal->len + sizeof (int));
776 			client_data->raw_cred.client_principal = NULL;
777 		}
778 
779 		/*
780 		 *  The client_name returned from
781 		 *  kgss_accept_sec_context() is in an
782 		 *  exported flat format.
783 		 */
784 		if (! __rpc_gss_make_principal(
785 		    &client_data->raw_cred.client_principal,
786 		    &client_data->client_name)) {
787 			RPCGSS_LOG0(1, "_svcrpcsec_gss: "
788 			    "make principal failed\n");
789 			gssstat = GSS_S_FAILURE;
790 			(void) gss_release_buffer(&minor_stat, &output_token);
791 		}
792 	}
793 
794 	rw_exit(&cred_lock);
795 
796 	call_res.gss_major = gssstat;
797 	call_res.gss_minor = minor_stat;
798 
799 	if (gssstat != GSS_S_COMPLETE &&
800 	    gssstat != GSS_S_CONTINUE_NEEDED) {
801 		call_res.ctx_handle.length = 0;
802 		call_res.ctx_handle.value = NULL;
803 		call_res.seq_window = 0;
804 		rpc_gss_display_status(gssstat, minor_stat, mech_type,
805 		    crgetuid(CRED()),
806 		    "_svc_rpcsec_gss gss_accept_sec_context");
807 		(void) svc_sendreply(rqst->rq_xprt,
808 		    __xdr_rpc_gss_init_res, (caddr_t)&call_res);
809 		client_data->stale = TRUE;
810 		ret = AUTH_OK;
811 		goto error2;
812 	}
813 
814 	/*
815 	 * If appropriate, set established to TRUE *after* sending
816 	 * response (otherwise, the client will receive the final
817 	 * token encrypted)
818 	 */
819 	if (gssstat == GSS_S_COMPLETE) {
820 		/*
821 		 * Context is established.  Set expiration time
822 		 * for the context.
823 		 */
824 		client_data->seq_num = 1;
825 		if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
826 			client_data->expiration = GSS_C_INDEFINITE;
827 		} else {
828 			client_data->expiration =
829 			    time_rec + gethrestime_sec();
830 		}
831 
832 		if (!transfer_sec_context(client_data)) {
833 			ret = RPCSEC_GSS_FAILED;
834 			client_data->stale = TRUE;
835 			RPCGSS_LOG0(1,
836 			    "_svc_rpcsec_gss: transfer sec context failed\n");
837 			goto error2;
838 		}
839 
840 		client_data->established = TRUE;
841 	}
842 
843 	/*
844 	 * This step succeeded.  Send a response, along with
845 	 * a token if there's one.  Don't dispatch.
846 	 */
847 
848 	if (output_token.length != 0)
849 		GSS_COPY_BUFFER(call_res.token, output_token);
850 
851 	/*
852 	 * If GSS_S_COMPLETE: set response verifier to
853 	 * checksum of SEQ_WIN
854 	 */
855 	if (gssstat == GSS_S_COMPLETE) {
856 		if (!set_response_verf(rqst, msg, client_data,
857 		    (uint_t)SEQ_WIN)) {
858 			ret = RPCSEC_GSS_FAILED;
859 			client_data->stale = TRUE;
860 			RPCGSS_LOG0(1,
861 			    "_svc_rpcsec_gss:set response verifier failed\n");
862 			goto error2;
863 		}
864 	}
865 
866 	if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
867 	    (caddr_t)&call_res)) {
868 		ret = RPCSEC_GSS_FAILED;
869 		client_data->stale = TRUE;
870 		RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
871 		goto error2;
872 	}
873 
874 	/*
875 	 * Cache last response in case it is lost and the client
876 	 * retries on an established context.
877 	 */
878 	(void) retrans_add(client_data, msg->rm_xid, &call_res);
879 	ASSERT(client_data->ref_cnt > 0);
880 	client_data->ref_cnt--;
881 	mutex_exit(&client_data->clm);
882 
883 	(void) gss_release_buffer(&minor_stat, &output_token);
884 
885 	return (AUTH_OK);
886 
887 error2:
888 	ASSERT(client_data->ref_cnt > 0);
889 	client_data->ref_cnt--;
890 	mutex_exit(&client_data->clm);
891 	(void) gss_release_buffer(&minor_stat, &output_token);
892 	if (free_mech_type && mech_type)
893 		kgss_free_oid(mech_type);
894 
895 	return (ret);
896 }
897 
898 static void
899 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
900 {
901 	enum auth_stat retval;
902 	svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
903 
904 	retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
905 	    arg->client_data, arg->cr_version, arg->cr_service);
906 	if (retval != AUTH_OK) {
907 		cmn_err(CE_NOTE,
908 		    "svcrpcsec_gss_taskq_func:  do_gss_accept fail 0x%x",
909 		    retval);
910 	}
911 	rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
912 	svc_clone_unlink(arg->rq_xprt);
913 	svc_clone_free(arg->rq_xprt);
914 	xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
915 	kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
916 
917 	kmem_free(arg, sizeof (*arg));
918 }
919 
920 static enum auth_stat
921 rpcsec_gss_init(
922 	struct svc_req		*rqst,
923 	struct rpc_msg		*msg,
924 	rpc_gss_creds		creds,
925 	bool_t			*no_dispatch,
926 	svc_rpc_gss_data	*c_d) /* client data, can be NULL */
927 {
928 	svc_rpc_gss_data	*client_data;
929 	int ret;
930 	svcrpcsec_gss_taskq_arg_t *arg;
931 
932 	if (creds.ctx_handle.length != 0) {
933 		RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
934 		ret = AUTH_BADCRED;
935 		return (ret);
936 	}
937 
938 	client_data = c_d ? c_d : create_client();
939 	if (client_data == NULL) {
940 		RPCGSS_LOG0(1,
941 		    "_svcrpcsec_gss: can't create a new cache entry\n");
942 		ret = AUTH_FAILED;
943 		return (ret);
944 	}
945 
946 	mutex_enter(&client_data->clm);
947 	if (client_data->stale) {
948 		ret = RPCSEC_GSS_NOCRED;
949 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
950 		goto error2;
951 	}
952 
953 	/*
954 	 * kgss_accept_sec_context()/gssd(1M) can be overly time
955 	 * consuming so let's queue it and return asap.
956 	 *
957 	 * taskq func must free arg.
958 	 */
959 	arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
960 
961 	/* taskq func must free rpc_call_arg & deserialized arguments */
962 	arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
963 
964 	/* deserialize arguments */
965 	if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
966 	    (caddr_t)arg->rpc_call_arg)) {
967 		ret = RPCSEC_GSS_FAILED;
968 		client_data->stale = TRUE;
969 		goto error2;
970 	}
971 
972 	/* get a xprt clone for taskq thread, taskq func must free it */
973 	arg->rq_xprt = svc_clone_init();
974 	svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
975 	arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
976 
977 
978 	/* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
979 	arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
980 	arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
981 
982 	/* get a dup of rpc msg for taskq thread */
983 	arg->msg = rpc_msg_dup(msg);  /* taskq func must free msg dup */
984 
985 	arg->client_data = client_data;
986 	arg->cr_version = creds.version;
987 	arg->cr_service = creds.service;
988 
989 	/* should be ok to hold clm lock as taskq will have new thread(s) */
990 	ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
991 	    svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
992 	if (ret == DDI_FAILURE) {
993 		cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
994 		ret = RPCSEC_GSS_FAILED;
995 		rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
996 		svc_clone_unlink(arg->rq_xprt);
997 		svc_clone_free(arg->rq_xprt);
998 		kmem_free(arg, sizeof (*arg));
999 		goto error2;
1000 	}
1001 
1002 	mutex_exit(&client_data->clm);
1003 	*no_dispatch = TRUE;
1004 	return (AUTH_OK);
1005 
1006 error2:
1007 	ASSERT(client_data->ref_cnt > 0);
1008 	client_data->ref_cnt--;
1009 	mutex_exit(&client_data->clm);
1010 	cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1011 	return (ret);
1012 }
1013 
1014 static enum auth_stat
1015 rpcsec_gss_continue_init(
1016 	struct svc_req		*rqst,
1017 	struct rpc_msg		*msg,
1018 	rpc_gss_creds		creds,
1019 	bool_t			*no_dispatch)
1020 {
1021 	int ret;
1022 	svc_rpc_gss_data	*client_data;
1023 	svc_rpc_gss_parms_t	*gss_parms;
1024 	rpc_gss_init_res	*retrans_result;
1025 
1026 	if (creds.ctx_handle.length == 0) {
1027 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1028 		ret = AUTH_BADCRED;
1029 		return (ret);
1030 	}
1031 	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1032 		ret = RPCSEC_GSS_NOCRED;
1033 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1034 		return (ret);
1035 	}
1036 
1037 	mutex_enter(&client_data->clm);
1038 	if (client_data->stale) {
1039 		ret = RPCSEC_GSS_NOCRED;
1040 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1041 		goto error2;
1042 	}
1043 
1044 	/*
1045 	 * If context not established, go thru INIT code but with
1046 	 * this client handle.
1047 	 */
1048 	if (!client_data->established) {
1049 		mutex_exit(&client_data->clm);
1050 		return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1051 		    client_data));
1052 	}
1053 
1054 	/*
1055 	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1056 	 */
1057 	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1058 	rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1059 
1060 	/*
1061 	 * Keep copy of parameters we'll need for response, for the
1062 	 * sake of reentrancy (we don't want to look in the context
1063 	 * data because when we are sending a response, another
1064 	 * request may have come in).
1065 	 */
1066 	gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1067 	gss_parms->established = client_data->established;
1068 	gss_parms->service = creds.service;
1069 	gss_parms->qop_rcvd = (uint_t)client_data->qop;
1070 	gss_parms->context = (void *)client_data->context;
1071 	gss_parms->seq_num = creds.seq_num;
1072 
1073 	/*
1074 	 * This is an established context. Continue to
1075 	 * satisfy retried continue init requests out of
1076 	 * the retransmit cache.  Throw away any that don't
1077 	 * have a matching xid or the cach is empty.
1078 	 * Delete the retransmit cache once the client sends
1079 	 * a data request.
1080 	 */
1081 	if (client_data->retrans_data &&
1082 	    (client_data->retrans_data->xid == msg->rm_xid)) {
1083 		retrans_result = &client_data->retrans_data->result;
1084 		if (set_response_verf(rqst, msg, client_data,
1085 		    (uint_t)retrans_result->seq_window)) {
1086 			gss_parms->established = FALSE;
1087 			(void) svc_sendreply(rqst->rq_xprt,
1088 			    __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
1089 			*no_dispatch = TRUE;
1090 			ASSERT(client_data->ref_cnt > 0);
1091 			client_data->ref_cnt--;
1092 		}
1093 	}
1094 	mutex_exit(&client_data->clm);
1095 
1096 	return (AUTH_OK);
1097 
1098 error2:
1099 	ASSERT(client_data->ref_cnt > 0);
1100 	client_data->ref_cnt--;
1101 	mutex_exit(&client_data->clm);
1102 	return (ret);
1103 }
1104 
1105 static enum auth_stat
1106 rpcsec_gss_data(
1107 	struct svc_req		*rqst,
1108 	struct rpc_msg		*msg,
1109 	rpc_gss_creds		creds,
1110 	bool_t			*no_dispatch)
1111 {
1112 	int ret;
1113 	svc_rpc_gss_parms_t	*gss_parms;
1114 	svc_rpc_gss_data	*client_data;
1115 
1116 	switch (creds.service) {
1117 	case rpc_gss_svc_none:
1118 	case rpc_gss_svc_integrity:
1119 	case rpc_gss_svc_privacy:
1120 		break;
1121 	default:
1122 		cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1123 		    creds.service);
1124 		RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1125 		    creds.service);
1126 		ret = AUTH_BADCRED;
1127 		return (ret);
1128 	}
1129 
1130 	if (creds.ctx_handle.length == 0) {
1131 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1132 		ret = AUTH_BADCRED;
1133 		return (ret);
1134 	}
1135 	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1136 		ret = RPCSEC_GSS_NOCRED;
1137 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1138 		return (ret);
1139 	}
1140 
1141 
1142 	mutex_enter(&client_data->clm);
1143 	if (!client_data->established) {
1144 		ret = AUTH_FAILED;
1145 		goto error2;
1146 	}
1147 	if (client_data->stale) {
1148 		ret = RPCSEC_GSS_NOCRED;
1149 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1150 		goto error2;
1151 	}
1152 
1153 	/*
1154 	 * Once the context is established and there is no more
1155 	 * retransmission of last continue init request, it is safe
1156 	 * to delete the retransmit cache entry.
1157 	 */
1158 	if (client_data->retrans_data)
1159 		retrans_del(client_data);
1160 
1161 	/*
1162 	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1163 	 */
1164 	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1165 	rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1166 
1167 	/*
1168 	 * Keep copy of parameters we'll need for response, for the
1169 	 * sake of reentrancy (we don't want to look in the context
1170 	 * data because when we are sending a response, another
1171 	 * request may have come in).
1172 	 */
1173 	gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1174 	gss_parms->established = client_data->established;
1175 	gss_parms->service = creds.service;
1176 	gss_parms->qop_rcvd = (uint_t)client_data->qop;
1177 	gss_parms->context = (void *)client_data->context;
1178 	gss_parms->seq_num = creds.seq_num;
1179 
1180 	/*
1181 	 * Context is already established.  Check verifier, and
1182 	 * note parameters we will need for response in gss_parms.
1183 	 */
1184 	if (!check_verf(msg, client_data->context,
1185 	    (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1186 		ret = RPCSEC_GSS_NOCRED;
1187 		RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1188 		goto error2;
1189 	}
1190 
1191 	/*
1192 	 *  Check and invoke callback if necessary.
1193 	 */
1194 	if (!client_data->done_docallback) {
1195 		client_data->done_docallback = TRUE;
1196 		client_data->qop = gss_parms->qop_rcvd;
1197 		client_data->raw_cred.qop = gss_parms->qop_rcvd;
1198 		client_data->raw_cred.service = creds.service;
1199 		if (!do_callback(rqst, client_data)) {
1200 			ret = AUTH_FAILED;
1201 			RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1202 			goto error2;
1203 		}
1204 	}
1205 
1206 	/*
1207 	 * If the context was locked, make sure that the client
1208 	 * has not changed QOP.
1209 	 */
1210 	if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1211 		ret = AUTH_BADVERF;
1212 		RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1213 		goto error2;
1214 	}
1215 
1216 	/*
1217 	 * Validate sequence number.
1218 	 */
1219 	if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1220 		if (client_data->stale) {
1221 			ret = RPCSEC_GSS_FAILED;
1222 			RPCGSS_LOG0(1,
1223 			    "_svc_rpcsec_gss:check seq failed\n");
1224 		} else {
1225 			RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1226 			    "failed on good context. Ignoring "
1227 			    "request\n");
1228 			/*
1229 			 * Operational error, drop packet silently.
1230 			 * The client will recover after timing out,
1231 			 * assuming this is a client error and not
1232 			 * a relpay attack.  Don't dispatch.
1233 			 */
1234 			ret = AUTH_OK;
1235 			*no_dispatch = TRUE;
1236 		}
1237 		goto error2;
1238 	}
1239 
1240 	/*
1241 	 * set response verifier
1242 	 */
1243 	if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1244 		ret = RPCSEC_GSS_FAILED;
1245 		client_data->stale = TRUE;
1246 		RPCGSS_LOG0(1,
1247 		    "_svc_rpcsec_gss:set response verifier failed\n");
1248 		goto error2;
1249 	}
1250 
1251 	/*
1252 	 * If context is locked, make sure that the client
1253 	 * has not changed the security service.
1254 	 */
1255 	if (client_data->locked &&
1256 	    client_data->raw_cred.service != creds.service) {
1257 		RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1258 		    "security service changed.\n");
1259 		ret = AUTH_FAILED;
1260 		goto error2;
1261 	}
1262 
1263 	/*
1264 	 * Set client credentials to raw credential
1265 	 * structure in context.  This is okay, since
1266 	 * this will not change during the lifetime of
1267 	 * the context (so it's MT safe).
1268 	 */
1269 	rqst->rq_clntcred = (char *)&client_data->raw_cred;
1270 
1271 	mutex_exit(&client_data->clm);
1272 	return (AUTH_OK);
1273 
1274 error2:
1275 	ASSERT(client_data->ref_cnt > 0);
1276 	client_data->ref_cnt--;
1277 	mutex_exit(&client_data->clm);
1278 	return (ret);
1279 }
1280 
1281 /*
1282  * Note we don't have a client yet to use this routine and test it.
1283  */
1284 static enum auth_stat
1285 rpcsec_gss_destroy(
1286 	struct svc_req		*rqst,
1287 	rpc_gss_creds		creds,
1288 	bool_t			*no_dispatch)
1289 {
1290 	svc_rpc_gss_data	*client_data;
1291 	int ret;
1292 
1293 	if (creds.ctx_handle.length == 0) {
1294 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1295 		ret = AUTH_BADCRED;
1296 		return (ret);
1297 	}
1298 	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1299 		ret = RPCSEC_GSS_NOCRED;
1300 		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1301 		return (ret);
1302 	}
1303 
1304 	mutex_enter(&client_data->clm);
1305 	if (!client_data->established) {
1306 		ret = AUTH_FAILED;
1307 		goto error2;
1308 	}
1309 	if (client_data->stale) {
1310 		ret = RPCSEC_GSS_NOCRED;
1311 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1312 		goto error2;
1313 	}
1314 
1315 	(void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1316 	*no_dispatch = TRUE;
1317 	ASSERT(client_data->ref_cnt > 0);
1318 	client_data->ref_cnt--;
1319 	client_data->stale = TRUE;
1320 	mutex_exit(&client_data->clm);
1321 	return (AUTH_OK);
1322 
1323 error2:
1324 	ASSERT(client_data->ref_cnt > 0);
1325 	client_data->ref_cnt--;
1326 	client_data->stale = TRUE;
1327 	mutex_exit(&client_data->clm);
1328 	return (ret);
1329 }
1330 
1331 /*
1332  * Server side authentication for RPCSEC_GSS.
1333  */
1334 enum auth_stat
1335 __svcrpcsec_gss(
1336 	struct svc_req		*rqst,
1337 	struct rpc_msg		*msg,
1338 	bool_t			*no_dispatch)
1339 {
1340 	XDR			xdrs;
1341 	rpc_gss_creds		creds;
1342 	struct opaque_auth	*cred;
1343 	int			ret;
1344 
1345 	*no_dispatch = FALSE;
1346 
1347 	/*
1348 	 * Initialize response verifier to NULL verifier.  If
1349 	 * necessary, this will be changed later.
1350 	 */
1351 	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1352 	rqst->rq_xprt->xp_verf.oa_base = NULL;
1353 	rqst->rq_xprt->xp_verf.oa_length = 0;
1354 
1355 	/*
1356 	 * Pull out and check credential and verifier.
1357 	 */
1358 	cred = &msg->rm_call.cb_cred;
1359 
1360 	if (cred->oa_length == 0) {
1361 		RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1362 		return (AUTH_BADCRED);
1363 	}
1364 
1365 	xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1366 	bzero((char *)&creds, sizeof (creds));
1367 	if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1368 		XDR_DESTROY(&xdrs);
1369 		RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1370 		ret = AUTH_BADCRED;
1371 		return (AUTH_BADCRED);
1372 	}
1373 	XDR_DESTROY(&xdrs);
1374 
1375 	switch (creds.gss_proc) {
1376 	case RPCSEC_GSS_INIT:
1377 		ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1378 		break;
1379 	case RPCSEC_GSS_CONTINUE_INIT:
1380 		ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1381 		break;
1382 	case RPCSEC_GSS_DATA:
1383 		ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1384 		break;
1385 	case RPCSEC_GSS_DESTROY:
1386 		ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1387 		break;
1388 	default:
1389 		cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1390 		    creds.gss_proc);
1391 		ret = AUTH_BADCRED;
1392 	}
1393 
1394 	if (creds.ctx_handle.length != 0)
1395 		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1396 	return (ret);
1397 }
1398 
1399 /*
1400  * Check verifier.  The verifier is the checksum of the RPC header
1401  * upto and including the credentials field.
1402  */
1403 
1404 /* ARGSUSED */
1405 static bool_t
1406 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1407 {
1408 	int			*buf, *tmp;
1409 	char			hdr[128];
1410 	struct opaque_auth	*oa;
1411 	int			len;
1412 	gss_buffer_desc		msg_buf;
1413 	gss_buffer_desc		tok_buf;
1414 	OM_uint32		gssstat, minor_stat;
1415 
1416 	/*
1417 	 * We have to reconstruct the RPC header from the previously
1418 	 * parsed information, since we haven't kept the header intact.
1419 	 */
1420 
1421 	oa = &msg->rm_call.cb_cred;
1422 	if (oa->oa_length > MAX_AUTH_BYTES)
1423 		return (FALSE);
1424 
1425 	/* 8 XDR units from the IXDR macro calls. */
1426 	if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1427 	    RNDUP(oa->oa_length)))
1428 		return (FALSE);
1429 	buf = (int *)hdr;
1430 	IXDR_PUT_U_INT32(buf, msg->rm_xid);
1431 	IXDR_PUT_ENUM(buf, msg->rm_direction);
1432 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1433 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1434 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1435 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1436 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
1437 	IXDR_PUT_U_INT32(buf, oa->oa_length);
1438 	if (oa->oa_length) {
1439 		len = RNDUP(oa->oa_length);
1440 		tmp = buf;
1441 		buf += len / sizeof (int);
1442 		*(buf - 1) = 0;
1443 		(void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1444 	}
1445 	len = ((char *)buf) - hdr;
1446 	msg_buf.length = len;
1447 	msg_buf.value = hdr;
1448 	oa = &msg->rm_call.cb_verf;
1449 	tok_buf.length = oa->oa_length;
1450 	tok_buf.value = oa->oa_base;
1451 
1452 	gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1453 	    qop_state);
1454 	if (gssstat != GSS_S_COMPLETE) {
1455 		RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1456 
1457 		RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1458 		RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1459 		RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1460 		    tok_buf.length);
1461 		RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1462 		    (void *)oa->oa_base);
1463 		RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1464 
1465 		return (FALSE);
1466 	}
1467 	return (TRUE);
1468 }
1469 
1470 
1471 /*
1472  * Set response verifier.  This is the checksum of the given number.
1473  * (e.g. sequence number or sequence window)
1474  */
1475 static bool_t
1476 set_response_verf(rqst, msg, cl, num)
1477 	struct svc_req		*rqst;
1478 	struct rpc_msg		*msg;
1479 	svc_rpc_gss_data	*cl;
1480 	uint_t			num;
1481 {
1482 	OM_uint32		minor;
1483 	gss_buffer_desc		in_buf, out_buf;
1484 	uint_t			num_net;
1485 
1486 	num_net = (uint_t)htonl(num);
1487 	in_buf.length = sizeof (num);
1488 	in_buf.value = (char *)&num_net;
1489 /* XXX uid ? */
1490 
1491 	if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf,
1492 				&out_buf)) != GSS_S_COMPLETE)
1493 		return (FALSE);
1494 
1495 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1496 	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1497 	rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1498 	bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1499 	(void) gss_release_buffer(&minor, &out_buf);
1500 	return (TRUE);
1501 }
1502 
1503 /*
1504  * Create client context.
1505  */
1506 static svc_rpc_gss_data *
1507 create_client()
1508 {
1509 	svc_rpc_gss_data	*client_data;
1510 	static uint_t		key = 1;
1511 
1512 	client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1513 	    KM_SLEEP);
1514 	if (client_data == NULL)
1515 		return (NULL);
1516 
1517 	/*
1518 	 * set up client data structure
1519 	 */
1520 	client_data->next = NULL;
1521 	client_data->prev = NULL;
1522 	client_data->lru_next = NULL;
1523 	client_data->lru_prev = NULL;
1524 	client_data->client_name.length = 0;
1525 	client_data->client_name.value = NULL;
1526 	client_data->seq_num = 0;
1527 	bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1528 	client_data->key = 0;
1529 	client_data->cookie = NULL;
1530 	bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1531 	client_data->established = FALSE;
1532 	client_data->locked = FALSE;
1533 	client_data->u_cred_set = 0;
1534 	client_data->context = GSS_C_NO_CONTEXT;
1535 	client_data->expiration = GSS_C_INDEFINITE;
1536 	client_data->deleg = GSS_C_NO_CREDENTIAL;
1537 	client_data->ref_cnt = 1;
1538 	client_data->last_ref_time = gethrestime_sec();
1539 	client_data->qop = GSS_C_QOP_DEFAULT;
1540 	client_data->done_docallback = FALSE;
1541 	client_data->stale = FALSE;
1542 	client_data->retrans_data = NULL;
1543 	bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1544 
1545 	/*
1546 	 * The client context handle is a 32-bit key (unsigned int).
1547 	 * The key is incremented until there is no duplicate for it.
1548 	 */
1549 
1550 	svc_rpc_gss_cache_stats.total_entries_allocated++;
1551 	mutex_enter(&ctx_mutex);
1552 	for (;;) {
1553 		client_data->key = key++;
1554 		if (find_client(client_data->key) == NULL) {
1555 			insert_client(client_data);
1556 			mutex_exit(&ctx_mutex);
1557 			return (client_data);
1558 		}
1559 	}
1560 	/*NOTREACHED*/
1561 }
1562 
1563 /*
1564  * Insert client context into hash list and LRU list.
1565  */
1566 static void
1567 insert_client(client_data)
1568 	svc_rpc_gss_data	*client_data;
1569 {
1570 	svc_rpc_gss_data	*cl;
1571 	int			index = HASH(client_data->key);
1572 
1573 	ASSERT(mutex_owned(&ctx_mutex));
1574 
1575 	client_data->prev = NULL;
1576 	cl = clients[index];
1577 	if ((client_data->next = cl) != NULL)
1578 		cl->prev = client_data;
1579 	clients[index] = client_data;
1580 
1581 	client_data->lru_prev = NULL;
1582 	if ((client_data->lru_next = lru_first) != NULL)
1583 		lru_first->lru_prev = client_data;
1584 	else
1585 		lru_last = client_data;
1586 	lru_first = client_data;
1587 
1588 	num_gss_contexts++;
1589 }
1590 
1591 /*
1592  * Fetch a client, given the client context handle.  Move it to the
1593  * top of the LRU list since this is the most recently used context.
1594  */
1595 static svc_rpc_gss_data *
1596 get_client(ctx_handle)
1597 	gss_buffer_t		ctx_handle;
1598 {
1599 	uint_t			key = *(uint_t *)ctx_handle->value;
1600 	svc_rpc_gss_data	*cl;
1601 
1602 	mutex_enter(&ctx_mutex);
1603 	if ((cl = find_client(key)) != NULL) {
1604 		mutex_enter(&cl->clm);
1605 		if (cl->stale) {
1606 			if (cl->ref_cnt == 0) {
1607 				mutex_exit(&cl->clm);
1608 				destroy_client(cl);
1609 			} else {
1610 				mutex_exit(&cl->clm);
1611 			}
1612 			mutex_exit(&ctx_mutex);
1613 			return (NULL);
1614 		}
1615 		cl->ref_cnt++;
1616 		cl->last_ref_time = gethrestime_sec();
1617 		mutex_exit(&cl->clm);
1618 		if (cl != lru_first) {
1619 			cl->lru_prev->lru_next = cl->lru_next;
1620 			if (cl->lru_next != NULL)
1621 				cl->lru_next->lru_prev = cl->lru_prev;
1622 			else
1623 				lru_last = cl->lru_prev;
1624 			cl->lru_prev = NULL;
1625 			cl->lru_next = lru_first;
1626 			lru_first->lru_prev = cl;
1627 			lru_first = cl;
1628 		}
1629 	}
1630 	mutex_exit(&ctx_mutex);
1631 	return (cl);
1632 }
1633 
1634 /*
1635  * Given the client context handle, find the context corresponding to it.
1636  * Don't change its LRU state since it may not be used.
1637  */
1638 static svc_rpc_gss_data *
1639 find_client(key)
1640 	uint_t			key;
1641 {
1642 	int			index = HASH(key);
1643 	svc_rpc_gss_data	*cl = NULL;
1644 
1645 	ASSERT(mutex_owned(&ctx_mutex));
1646 
1647 	for (cl = clients[index]; cl != NULL; cl = cl->next) {
1648 		if (cl->key == key)
1649 			break;
1650 	}
1651 	return (cl);
1652 }
1653 
1654 /*
1655  * Destroy a client context.
1656  */
1657 static void
1658 destroy_client(client_data)
1659 	svc_rpc_gss_data	*client_data;
1660 {
1661 	OM_uint32		minor;
1662 	int			index = HASH(client_data->key);
1663 
1664 	ASSERT(mutex_owned(&ctx_mutex));
1665 
1666 	/*
1667 	 * remove from hash list
1668 	 */
1669 	if (client_data->prev == NULL)
1670 		clients[index] = client_data->next;
1671 	else
1672 		client_data->prev->next = client_data->next;
1673 	if (client_data->next != NULL)
1674 		client_data->next->prev = client_data->prev;
1675 
1676 	/*
1677 	 * remove from LRU list
1678 	 */
1679 	if (client_data->lru_prev == NULL)
1680 		lru_first = client_data->lru_next;
1681 	else
1682 		client_data->lru_prev->lru_next = client_data->lru_next;
1683 	if (client_data->lru_next != NULL)
1684 		client_data->lru_next->lru_prev = client_data->lru_prev;
1685 	else
1686 		lru_last = client_data->lru_prev;
1687 
1688 	/*
1689 	 * If there is a GSS context, clean up GSS state.
1690 	 */
1691 	if (client_data->context != GSS_C_NO_CONTEXT) {
1692 		(void) kgss_delete_sec_context(&minor, &client_data->context,
1693 					NULL);
1694 
1695 		common_client_data_free(client_data);
1696 
1697 		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1698 		    (void) kgss_release_cred(&minor, &client_data->deleg,
1699 				crgetuid(CRED()));
1700 		}
1701 	}
1702 
1703 	if (client_data->u_cred.gidlist != NULL) {
1704 	    kmem_free((char *)client_data->u_cred.gidlist,
1705 			client_data->u_cred.gidlen * sizeof (gid_t));
1706 	    client_data->u_cred.gidlist = NULL;
1707 	}
1708 	if (client_data->retrans_data != NULL)
1709 		retrans_del(client_data);
1710 
1711 	kmem_cache_free(svc_data_handle, client_data);
1712 	num_gss_contexts--;
1713 }
1714 
1715 /*
1716  * Check for expired and stale client contexts.
1717  */
1718 static void
1719 sweep_clients(bool_t from_reclaim)
1720 {
1721 	svc_rpc_gss_data	*cl, *next;
1722 	time_t			last_reference_needed;
1723 	time_t			now = gethrestime_sec();
1724 
1725 	ASSERT(mutex_owned(&ctx_mutex));
1726 
1727 	last_reference_needed = now - (from_reclaim ?
1728 	    svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
1729 
1730 	cl = lru_last;
1731 	while (cl) {
1732 		/*
1733 		 * We assume here that any manipulation of the LRU pointers
1734 		 * and hash bucket pointers are only done when holding the
1735 		 * ctx_mutex.
1736 		 */
1737 		next = cl->lru_prev;
1738 
1739 		mutex_enter(&cl->clm);
1740 
1741 		if ((cl->expiration != GSS_C_INDEFINITE &&
1742 		    cl->expiration <= now) || cl->stale ||
1743 		    cl->last_ref_time <= last_reference_needed) {
1744 
1745 			if ((cl->expiration != GSS_C_INDEFINITE &&
1746 			    cl->expiration <= now) || cl->stale ||
1747 			    (cl->last_ref_time <= last_reference_needed &&
1748 			    cl->ref_cnt == 0)) {
1749 
1750 				cl->stale = TRUE;
1751 
1752 				if (cl->ref_cnt == 0) {
1753 					mutex_exit(&cl->clm);
1754 					if (from_reclaim)
1755 						svc_rpc_gss_cache_stats.
1756 						    no_returned_by_reclaim++;
1757 					destroy_client(cl);
1758 				} else
1759 					mutex_exit(&cl->clm);
1760 			} else
1761 				mutex_exit(&cl->clm);
1762 		} else
1763 			mutex_exit(&cl->clm);
1764 
1765 		cl = next;
1766 	}
1767 
1768 	last_swept = gethrestime_sec();
1769 }
1770 
1771 /*
1772  * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1773  * and write the result to xdrs.
1774  */
1775 static bool_t
1776 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1777 	SVCAUTH			*auth;
1778 	XDR			*out_xdrs;
1779 	bool_t			(*xdr_func)();
1780 	caddr_t			xdr_ptr;
1781 {
1782 	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1783 	bool_t ret;
1784 
1785 	/*
1786 	 * If context is not established, or if neither integrity nor
1787 	 * privacy service is used, don't wrap - just XDR encode.
1788 	 * Otherwise, wrap data using service and QOP parameters.
1789 	 */
1790 	if (!gss_parms->established ||
1791 				gss_parms->service == rpc_gss_svc_none)
1792 		return ((*xdr_func)(out_xdrs, xdr_ptr));
1793 
1794 	ret = __rpc_gss_wrap_data(gss_parms->service,
1795 				(OM_uint32)gss_parms->qop_rcvd,
1796 				(gss_ctx_id_t)gss_parms->context,
1797 				gss_parms->seq_num,
1798 				out_xdrs, xdr_func, xdr_ptr);
1799 	return (ret);
1800 }
1801 
1802 /*
1803  * Decrypt the serialized arguments and XDR decode them.
1804  */
1805 static bool_t
1806 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1807 	SVCAUTH			*auth;
1808 	XDR			*in_xdrs;
1809 	bool_t			(*xdr_func)();
1810 	caddr_t			xdr_ptr;
1811 {
1812 	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1813 
1814 	/*
1815 	 * If context is not established, or if neither integrity nor
1816 	 * privacy service is used, don't unwrap - just XDR decode.
1817 	 * Otherwise, unwrap data.
1818 	 */
1819 	if (!gss_parms->established ||
1820 				gss_parms->service == rpc_gss_svc_none)
1821 		return ((*xdr_func)(in_xdrs, xdr_ptr));
1822 
1823 	return (__rpc_gss_unwrap_data(gss_parms->service,
1824 				(gss_ctx_id_t)gss_parms->context,
1825 				gss_parms->seq_num,
1826 				gss_parms->qop_rcvd,
1827 				in_xdrs, xdr_func, xdr_ptr));
1828 }
1829 
1830 
1831 /* ARGSUSED */
1832 int
1833 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1834 {
1835 	return (0);
1836 }
1837 
1838 /*
1839  * Add retransmit entry to the context cache entry for a new xid.
1840  * If there is already an entry, delete it before adding the new one.
1841  */
1842 static void retrans_add(client, xid, result)
1843 	svc_rpc_gss_data *client;
1844 	uint32_t	xid;
1845 	rpc_gss_init_res *result;
1846 {
1847 	retrans_entry	*rdata;
1848 
1849 	if (client->retrans_data && client->retrans_data->xid == xid)
1850 		return;
1851 
1852 	rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1853 
1854 	if (rdata == NULL)
1855 		return;
1856 
1857 	rdata->xid = xid;
1858 	rdata->result = *result;
1859 
1860 	if (result->token.length != 0) {
1861 		GSS_DUP_BUFFER(rdata->result.token, result->token);
1862 	}
1863 
1864 	if (client->retrans_data)
1865 		retrans_del(client);
1866 
1867 	client->retrans_data = rdata;
1868 }
1869 
1870 /*
1871  * Delete the retransmit data from the context cache entry.
1872  */
1873 static void retrans_del(client)
1874 	svc_rpc_gss_data *client;
1875 {
1876 	retrans_entry *rdata;
1877 	OM_uint32 minor_stat;
1878 
1879 	if (client->retrans_data == NULL)
1880 		return;
1881 
1882 	rdata = client->retrans_data;
1883 	if (rdata->result.token.length != 0) {
1884 	    (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1885 	}
1886 
1887 	kmem_free((caddr_t)rdata, sizeof (*rdata));
1888 	client->retrans_data = NULL;
1889 }
1890 
1891 /*
1892  * This function frees the following fields of svc_rpc_gss_data:
1893  *	client_name, raw_cred.client_principal, raw_cred.mechanism.
1894  */
1895 static void
1896 common_client_data_free(svc_rpc_gss_data *client_data)
1897 {
1898 	if (client_data->client_name.length > 0) {
1899 		(void) gss_release_buffer(NULL, &client_data->client_name);
1900 	}
1901 
1902 	if (client_data->raw_cred.client_principal) {
1903 		kmem_free((caddr_t)client_data->raw_cred.client_principal,
1904 		    client_data->raw_cred.client_principal->len +
1905 		    sizeof (int));
1906 		client_data->raw_cred.client_principal = NULL;
1907 	}
1908 
1909 	/*
1910 	 * In the user GSS-API library, mechanism (mech_type returned
1911 	 * by gss_accept_sec_context) is static storage, however
1912 	 * since all the work is done for gss_accept_sec_context under
1913 	 * gssd, what is returned in the kernel, is a copy from the oid
1914 	 * obtained under from gssd, so need to free it when destroying
1915 	 * the client data.
1916 	 */
1917 
1918 	if (client_data->raw_cred.mechanism) {
1919 		kgss_free_oid(client_data->raw_cred.mechanism);
1920 		client_data->raw_cred.mechanism = NULL;
1921 	}
1922 }
1923