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