xref: /illumos-gate/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c (revision bfed486ad8de8b8ebc6345a8e10accae08bf2f45)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 
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 
226 /*ARGSUSED*/
227 static int
228 svc_gss_data_create(void *buf, void *pdata, int kmflag)
229 {
230 	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
231 
232 	mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
233 
234 	return (0);
235 }
236 
237 /*ARGSUSED*/
238 static void
239 svc_gss_data_destroy(void *buf, void *pdata)
240 {
241 	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
242 
243 	mutex_destroy(&client_data->clm);
244 }
245 
246 
247 /*ARGSUSED*/
248 static void
249 svc_gss_data_reclaim(void *pdata)
250 {
251 	mutex_enter(&ctx_mutex);
252 
253 	svc_rpc_gss_cache_stats.no_reclaims++;
254 	sweep_clients(TRUE);
255 
256 	mutex_exit(&ctx_mutex);
257 }
258 
259 /*
260  *  Init stuff on the server side.
261  */
262 void
263 svc_gss_init()
264 {
265 	mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
266 	mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
267 	rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
268 	clients = (svc_rpc_gss_data **)
269 		kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
270 			KM_SLEEP);
271 	svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
272 					    sizeof (svc_rpc_gss_data), 0,
273 					    svc_gss_data_create,
274 					    svc_gss_data_destroy,
275 					    svc_gss_data_reclaim,
276 					    NULL, NULL, 0);
277 
278 }
279 
280 /*
281  * Destroy structures allocated in svc_gss_init().
282  * This routine is called by _init() if mod_install() failed.
283  */
284 void
285 svc_gss_fini()
286 {
287 	mutex_destroy(&cb_mutex);
288 	mutex_destroy(&ctx_mutex);
289 	rw_destroy(&cred_lock);
290 	kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
291 	kmem_cache_destroy(svc_data_handle);
292 }
293 
294 /*
295  * Cleanup routine for destroying context, called after service
296  * procedure is executed. Actually we just decrement the reference count
297  * associated with this context. If the reference count is zero and the
298  * context is marked as stale, we would then destroy the context. Additionally,
299  * we check if its been longer than sweep_interval since the last sweep_clients
300  * was run, and if so run sweep_clients to free all stale contexts with zero
301  * reference counts or contexts that are old. (Haven't been access in
302  * svc_rpc_inactive_delta seconds).
303  */
304 void
305 rpc_gss_cleanup(SVCXPRT *clone_xprt)
306 {
307 	svc_rpc_gss_data	*cl;
308 	SVCAUTH			*svcauth;
309 
310 	/*
311 	 * First check if current context needs to be cleaned up.
312 	 * There might be other threads stale this client data
313 	 * in between.
314 	 */
315 	svcauth = &clone_xprt->xp_auth;
316 	mutex_enter(&ctx_mutex);
317 	if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
318 		mutex_enter(&cl->clm);
319 		ASSERT(cl->ref_cnt > 0);
320 		if (--cl->ref_cnt == 0 && cl->stale) {
321 			mutex_exit(&cl->clm);
322 			destroy_client(cl);
323 			svcauth->svc_ah_private = NULL;
324 		} else
325 			mutex_exit(&cl->clm);
326 	}
327 
328 	/*
329 	 * Check for other expired contexts.
330 	 */
331 	if ((gethrestime_sec() - last_swept) > sweep_interval)
332 		sweep_clients(FALSE);
333 
334 	mutex_exit(&ctx_mutex);
335 }
336 
337 /*
338  * Shift the array arr of length arrlen right by nbits bits.
339  */
340 static void
341 shift_bits(arr, arrlen, nbits)
342 	uint_t	*arr;
343 	int	arrlen;
344 	int	nbits;
345 {
346 	int	i, j;
347 	uint_t	lo, hi;
348 
349 	/*
350 	 * If the number of bits to be shifted exceeds SEQ_WIN, just
351 	 * zero out the array.
352 	 */
353 	if (nbits < SEQ_WIN) {
354 		for (i = 0; i < nbits; i++) {
355 			hi = 0;
356 			for (j = 0; j < arrlen; j++) {
357 				lo = arr[j] & SEQ_LO_BIT;
358 				arr[j] >>= 1;
359 				if (hi)
360 					arr[j] |= SEQ_HI_BIT;
361 				hi = lo;
362 			}
363 		}
364 	} else {
365 		for (j = 0; j < arrlen; j++)
366 			arr[j] = 0;
367 	}
368 }
369 
370 /*
371  * Check that the received sequence number seq_num is valid.
372  */
373 static bool_t
374 check_seq(cl, seq_num, kill_context)
375 	svc_rpc_gss_data	*cl;
376 	uint_t			seq_num;
377 	bool_t			*kill_context;
378 {
379 	int			i, j;
380 	uint_t			bit;
381 
382 	/*
383 	 * If it exceeds the maximum, kill context.
384 	 */
385 	if (seq_num >= SEQ_MAX) {
386 		*kill_context = TRUE;
387 		RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
388 		return (FALSE);
389 	}
390 
391 	/*
392 	 * If greater than the last seen sequence number, just shift
393 	 * the sequence window so that it starts at the new sequence
394 	 * number and extends downwards by SEQ_WIN.
395 	 */
396 	if (seq_num > cl->seq_num) {
397 		(void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
398 				(int)(seq_num - cl->seq_num));
399 		cl->seq_bits[0] |= SEQ_HI_BIT;
400 		cl->seq_num = seq_num;
401 		return (TRUE);
402 	}
403 
404 	/*
405 	 * If it is outside the sequence window, return failure.
406 	 */
407 	i = cl->seq_num - seq_num;
408 	if (i >= SEQ_WIN) {
409 		RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
410 		return (FALSE);
411 	}
412 
413 	/*
414 	 * If within sequence window, set the bit corresponding to it
415 	 * if not already seen;  if already seen, return failure.
416 	 */
417 	j = SEQ_MASK - (i & SEQ_MASK);
418 	bit = j > 0 ? (1 << j) : 1;
419 	i >>= DIV_BY_32;
420 	if (cl->seq_bits[i] & bit) {
421 		RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
422 		return (FALSE);
423 	}
424 	cl->seq_bits[i] |= bit;
425 	return (TRUE);
426 }
427 
428 /*
429  * Set server callback.
430  */
431 bool_t
432 rpc_gss_set_callback(cb)
433 	rpc_gss_callback_t	*cb;
434 {
435 	rpc_gss_cblist_t		*cbl, *tmp;
436 
437 	if (cb->callback == NULL) {
438 		RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
439 		return (FALSE);
440 	}
441 
442 	/* check if there is already an entry in the rpc_gss_cblist. */
443 	mutex_enter(&cb_mutex);
444 	if (rpc_gss_cblist) {
445 		for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
446 			if ((tmp->cb.callback == cb->callback) &&
447 			    (tmp->cb.version == cb->version) &&
448 			    (tmp->cb.program == cb->program)) {
449 				mutex_exit(&cb_mutex);
450 				return (TRUE);
451 			}
452 		}
453 	}
454 
455 	/* Not in rpc_gss_cblist.  Create a new entry. */
456 	if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
457 	    == NULL) {
458 		mutex_exit(&cb_mutex);
459 		return (FALSE);
460 	}
461 	cbl->cb = *cb;
462 	cbl->next = rpc_gss_cblist;
463 	rpc_gss_cblist = cbl;
464 	mutex_exit(&cb_mutex);
465 	return (TRUE);
466 }
467 
468 /*
469  * Locate callback (if specified) and call server.  Release any
470  * delegated credentials unless passed to server and the server
471  * accepts the context.  If a callback is not specified, accept
472  * the incoming context.
473  */
474 static bool_t
475 do_callback(req, client_data)
476 	struct svc_req		*req;
477 	svc_rpc_gss_data	*client_data;
478 {
479 	rpc_gss_cblist_t		*cbl;
480 	bool_t			ret = TRUE, found = FALSE;
481 	rpc_gss_lock_t		lock;
482 	OM_uint32		minor;
483 	mutex_enter(&cb_mutex);
484 	for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
485 		if (req->rq_prog != cbl->cb.program ||
486 					req->rq_vers != cbl->cb.version)
487 			continue;
488 		found = TRUE;
489 		lock.locked = FALSE;
490 		lock.raw_cred = &client_data->raw_cred;
491 		ret = (*cbl->cb.callback)(req, client_data->deleg,
492 			client_data->context, &lock, &client_data->cookie);
493 		req->rq_xprt->xp_cookie = client_data->cookie;
494 
495 		if (ret) {
496 			client_data->locked = lock.locked;
497 			client_data->deleg = GSS_C_NO_CREDENTIAL;
498 		}
499 		break;
500 	}
501 	if (!found) {
502 		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
503 			(void) kgss_release_cred(&minor, &client_data->deleg,
504 					crgetuid(CRED()));
505 			client_data->deleg = GSS_C_NO_CREDENTIAL;
506 		}
507 	}
508 	mutex_exit(&cb_mutex);
509 	return (ret);
510 }
511 
512 /*
513  * Get caller credentials.
514  */
515 bool_t
516 rpc_gss_getcred(req, rcred, ucred, cookie)
517 	struct svc_req		*req;
518 	rpc_gss_rawcred_t	**rcred;
519 	rpc_gss_ucred_t		**ucred;
520 	void			**cookie;
521 {
522 	SVCAUTH			*svcauth;
523 	svc_rpc_gss_data	*client_data;
524 	int			gssstat, gidlen;
525 
526 	svcauth = &req->rq_xprt->xp_auth;
527 	client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
528 
529 	mutex_enter(&client_data->clm);
530 
531 	if (rcred != NULL) {
532 		svcauth->raw_cred = client_data->raw_cred;
533 		*rcred = &svcauth->raw_cred;
534 	}
535 	if (ucred != NULL) {
536 		*ucred = &client_data->u_cred;
537 
538 		if (client_data->u_cred_set == 0 ||
539 		    client_data->u_cred_set < gethrestime_sec()) {
540 		    if (client_data->u_cred_set == 0) {
541 			if ((gssstat = kgsscred_expname_to_unix_cred(
542 			    &client_data->client_name,
543 			    &client_data->u_cred.uid,
544 			    &client_data->u_cred.gid,
545 			    &client_data->u_cred.gidlist,
546 			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
547 				RPCGSS_LOG(1, "rpc_gss_getcred: "
548 				    "kgsscred_expname_to_unix_cred failed %x\n",
549 				    gssstat);
550 				*ucred = NULL;
551 			} else {
552 				client_data->u_cred.gidlen = (short)gidlen;
553 				client_data->u_cred_set =
554 				    gethrestime_sec() + svc_rpcgss_gid_timeout;
555 			}
556 		    } else if (client_data->u_cred_set < gethrestime_sec()) {
557 			if ((gssstat = kgss_get_group_info(
558 			    client_data->u_cred.uid,
559 			    &client_data->u_cred.gid,
560 			    &client_data->u_cred.gidlist,
561 			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
562 				RPCGSS_LOG(1, "rpc_gss_getcred: "
563 				    "kgss_get_group_info failed %x\n",
564 				    gssstat);
565 				*ucred = NULL;
566 			} else {
567 				client_data->u_cred.gidlen = (short)gidlen;
568 				client_data->u_cred_set =
569 				    gethrestime_sec() + svc_rpcgss_gid_timeout;
570 			}
571 		    }
572 		}
573 	}
574 
575 	if (cookie != NULL)
576 		*cookie = client_data->cookie;
577 	req->rq_xprt->xp_cookie = client_data->cookie;
578 
579 	mutex_exit(&client_data->clm);
580 
581 	return (TRUE);
582 }
583 
584 /*
585  * Transfer the context data from the user land to the kernel.
586  */
587 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
588 
589 	gss_buffer_desc process_token;
590 	OM_uint32 gssstat, minor;
591 
592 	/*
593 	 * Call kgss_export_sec_context
594 	 * if an error is returned log a message
595 	 * go to error handling
596 	 * Otherwise call kgss_import_sec_context to
597 	 * convert the token into a context
598 	 */
599 	gssstat  = kgss_export_sec_context(&minor, client_data->context,
600 				&process_token);
601 	/*
602 	 * if export_sec_context returns an error we delete the
603 	 * context just to be safe.
604 	 */
605 	if (gssstat == GSS_S_NAME_NOT_MN) {
606 		RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
607 				"Kernel mod unavailable\n");
608 
609 	} else if (gssstat != GSS_S_COMPLETE) {
610 		RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed  "
611 				" gssstat = 0x%x\n", gssstat);
612 		(void) gss_release_buffer(&minor, &process_token);
613 		(void) kgss_delete_sec_context(&minor, &client_data->context,
614 				NULL);
615 		return (FALSE);
616 
617 	} else if (process_token.length == 0) {
618 		RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
619 				"for export_sec_context, but "
620 				"gsstat == GSS_S_COMPLETE\n");
621 		(void) kgss_delete_sec_context(&minor, &client_data->context,
622 				NULL);
623 		return (FALSE);
624 
625 	} else {
626 		gssstat = kgss_import_sec_context(&minor, &process_token,
627 					client_data->context);
628 		if (gssstat != GSS_S_COMPLETE) {
629 			RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
630 				" failed gssstat = 0x%x\n", gssstat);
631 			(void) kgss_delete_sec_context(&minor,
632 				&client_data->context, NULL);
633 			(void) gss_release_buffer(&minor, &process_token);
634 			return (FALSE);
635 		}
636 
637 		RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
638 		(void) gss_release_buffer(&minor, &process_token);
639 	}
640 
641 	return (TRUE);
642 }
643 
644 
645 /*
646  * Server side authentication for RPCSEC_GSS.
647  */
648 enum auth_stat
649 __svcrpcsec_gss(rqst, msg, no_dispatch)
650 	struct svc_req		*rqst;
651 	struct rpc_msg		*msg;
652 	bool_t			*no_dispatch;
653 {
654 	XDR			xdrs;
655 	rpc_gss_creds		creds;
656 	rpc_gss_init_arg	call_arg;
657 	rpc_gss_init_res	call_res, *retrans_result;
658 	gss_buffer_desc		output_token;
659 	OM_uint32		gssstat, minor, minor_stat, time_rec;
660 	struct opaque_auth	*cred;
661 	svc_rpc_gss_data	*client_data;
662 	int			ret_flags, ret;
663 	svc_rpc_gss_parms_t	*gss_parms;
664 	gss_OID 		mech_type = GSS_C_NULL_OID;
665 	int			free_mech_type = 1;
666 
667 	*no_dispatch = FALSE;
668 
669 	/*
670 	 * Initialize response verifier to NULL verifier.  If
671 	 * necessary, this will be changed later.
672 	 */
673 	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
674 	rqst->rq_xprt->xp_verf.oa_base = NULL;
675 	rqst->rq_xprt->xp_verf.oa_length = 0;
676 
677 	/*
678 	 * Need to null out results to start with.
679 	 */
680 	bzero((char *)&call_res, sizeof (call_res));
681 
682 	/*
683 	 * Pull out and check credential and verifier.
684 	 */
685 	cred = &msg->rm_call.cb_cred;
686 
687 	/*
688 	 * Initialize output_token.
689 	 */
690 	output_token.length = 0;
691 	output_token.value = NULL;
692 
693 	if (cred->oa_length == 0) {
694 		RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
695 		return (AUTH_BADCRED);
696 	}
697 
698 	xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
699 	bzero((char *)&creds, sizeof (creds));
700 	if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
701 		XDR_DESTROY(&xdrs);
702 		RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
703 		ret = AUTH_BADCRED;
704 		goto error;
705 	}
706 	XDR_DESTROY(&xdrs);
707 
708 	/*
709 	 * If this is a control message and proc is GSSAPI_INIT, then
710 	 * create a client handle for this client.  Otherwise, look up
711 	 * the existing handle.
712 	 */
713 	if (creds.gss_proc == RPCSEC_GSS_INIT) {
714 		if (creds.ctx_handle.length != 0) {
715 			RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
716 			ret = AUTH_BADCRED;
717 			goto error;
718 		}
719 		if ((client_data = create_client()) == NULL) {
720 			RPCGSS_LOG0(1,
721 			"_svcrpcsec_gss: can't create a new cache entry\n");
722 			ret = AUTH_FAILED;
723 			goto error;
724 		}
725 	} else {
726 		/*
727 		 * Only verify values for service parameter when proc
728 		 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT.
729 		 * RFC2203 says contents for sequence and service args
730 		 * are undefined for creation procs.
731 		 *
732 		 * Note: only need to check for *CONTINUE_INIT here because
733 		 *	 if() clause already checked for RPCSEC_GSS_INIT
734 		 */
735 		if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) {
736 			switch (creds.service) {
737 			case rpc_gss_svc_none:
738 			case rpc_gss_svc_integrity:
739 			case rpc_gss_svc_privacy:
740 				break;
741 			default:
742 				RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service "
743 					"type: 0x%x\n", creds.service);
744 				ret = AUTH_BADCRED;
745 				goto error;
746 			}
747 		}
748 		if (creds.ctx_handle.length == 0) {
749 			RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
750 			ret = AUTH_BADCRED;
751 			goto error;
752 		}
753 		if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
754 			ret = RPCSEC_GSS_NOCRED;
755 			RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
756 			goto error;
757 		}
758 	}
759 
760 	/*
761 	 * lock the client data until it's safe; if it's already stale,
762 	 * no more processing is possible
763 	 */
764 	mutex_enter(&client_data->clm);
765 	if (client_data->stale) {
766 		ret = RPCSEC_GSS_NOCRED;
767 		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
768 		goto error2;
769 	}
770 
771 	/*
772 	 * Any response we send will use ctx_handle, so set it now;
773 	 * also set seq_window since this won't change.
774 	 */
775 	call_res.ctx_handle.length = sizeof (client_data->key);
776 	call_res.ctx_handle.value = (char *)&client_data->key;
777 	call_res.seq_window = SEQ_WIN;
778 
779 	/*
780 	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
781 	 */
782 	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
783 	rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
784 
785 	/*
786 	 * Keep copy of parameters we'll need for response, for the
787 	 * sake of reentrancy (we don't want to look in the context
788 	 * data because when we are sending a response, another
789 	 * request may have come in).
790 	 */
791 	gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
792 	gss_parms->established = client_data->established;
793 	gss_parms->service = creds.service;
794 	gss_parms->qop_rcvd = (uint_t)client_data->qop;
795 	gss_parms->context = (void *)client_data->context;
796 	gss_parms->seq_num = creds.seq_num;
797 
798 	if (!client_data->established) {
799 		if (creds.gss_proc == RPCSEC_GSS_DATA) {
800 			RPCGSS_LOG0(1, "_svcrpcsec_gss: data exchange "
801 				"message but context not established\n");
802 
803 			ret = RPCSEC_GSS_FAILED;
804 			client_data->stale = TRUE;
805 			goto error2;
806 		}
807 
808 		/*
809 		 * If the context is not established, then only
810 		 * RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT
811 		 * requests are valid.
812 		 */
813 		if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc !=
814 						RPCSEC_GSS_CONTINUE_INIT) {
815 			RPCGSS_LOG(1, "_svcrpcsec_gss: not an INIT or "
816 				"CONTINUE_INIT message (0x%x) and context not "
817 				"established\n", creds.gss_proc);
818 
819 			ret = RPCSEC_GSS_FAILED;
820 			client_data->stale = TRUE;
821 			goto error2;
822 		}
823 
824 		/*
825 		 * call is for us, deserialize arguments
826 		 */
827 		bzero(&call_arg, sizeof (call_arg));
828 		if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
829 							(caddr_t)&call_arg)) {
830 			RPCGSS_LOG0(1, "_svcrpcsec_gss: SVC_GETARGS failed\n");
831 			ret = RPCSEC_GSS_FAILED;
832 			client_data->stale = TRUE;
833 			goto error2;
834 		}
835 
836 		gssstat = GSS_S_FAILURE;
837 		minor = 0;
838 		minor_stat = 0;
839 		rw_enter(&cred_lock, RW_READER);
840 
841 		if (client_data->client_name.length) {
842 			(void) gss_release_buffer(&minor,
843 				&client_data->client_name);
844 		}
845 		gssstat = kgss_accept_sec_context(&minor_stat,
846 				&client_data->context,
847 				GSS_C_NO_CREDENTIAL,
848 				&call_arg,
849 				GSS_C_NO_CHANNEL_BINDINGS,
850 				&client_data->client_name,
851 				&mech_type,
852 				&output_token,
853 				&ret_flags,
854 				&time_rec,
855 				/*
856 				 * Don't need a delegated cred back.
857 				 * No memory will be allocated if
858 				 * passing NULL.
859 				 */
860 				NULL,
861 				crgetuid(CRED()));
862 
863 		RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
864 
865 		if (gssstat == GSS_S_COMPLETE) {
866 			/*
867 			 * Server_creds was right - set it.  Also
868 			 * set the raw and unix credentials at this
869 			 * point.  This saves a lot of computation
870 			 * later when credentials are retrieved.
871 			 */
872 			client_data->raw_cred.version = creds.version;
873 			client_data->raw_cred.service = creds.service;
874 
875 			if (client_data->raw_cred.mechanism) {
876 			    kgss_free_oid(client_data->\
877 				raw_cred.mechanism);
878 			    client_data->raw_cred.mechanism = NULL;
879 			}
880 			client_data->raw_cred.mechanism =
881 				(rpc_gss_OID) mech_type;
882 			/*
883 			 * client_data is now responsible for freeing
884 			 * the data of 'mech_type'.
885 			 */
886 			free_mech_type = 0;
887 
888 			if (client_data->raw_cred.client_principal) {
889 			    kmem_free((caddr_t)client_data->\
890 				raw_cred.client_principal,
891 				client_data->raw_cred.\
892 				client_principal->len + sizeof (int));
893 			    client_data->raw_cred.client_principal =
894 				NULL;
895 			}
896 			/*
897 			 *  The client_name returned from
898 			 *  kgss_accept_sec_context() is in an
899 			 *  exported flat format.
900 			 */
901 			if (! __rpc_gss_make_principal(
902 			    &client_data->raw_cred.client_principal,
903 			    &client_data->client_name)) {
904 				RPCGSS_LOG0(1, "_svcrpcsec_gss: "
905 				    "make principal failed\n");
906 				gssstat = GSS_S_FAILURE;
907 				(void) gss_release_buffer(&minor_stat,
908 							&output_token);
909 			}
910 		}
911 
912 		rw_exit(&cred_lock);
913 
914 		call_res.gss_major = gssstat;
915 		call_res.gss_minor = minor_stat;
916 
917 		xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg);
918 
919 		if (gssstat != GSS_S_COMPLETE &&
920 		    gssstat != GSS_S_CONTINUE_NEEDED) {
921 			/*
922 			 * We have a failure - send response and delete
923 			 * the context.  Don't dispatch.  Set ctx_handle
924 			 * to NULL and seq_window to 0.
925 			 */
926 			call_res.ctx_handle.length = 0;
927 			call_res.ctx_handle.value = NULL;
928 			call_res.seq_window = 0;
929 			rpc_gss_display_status(gssstat,
930 				minor_stat,
931 				mech_type,
932 				crgetuid(CRED()),
933 				"_svc_rpcsec_gss gss_accept_sec_context");
934 			(void) svc_sendreply(rqst->rq_xprt,
935 				__xdr_rpc_gss_init_res, (caddr_t)&call_res);
936 			*no_dispatch = TRUE;
937 			client_data->stale = TRUE;
938 			ret = AUTH_OK;
939 			goto error2;
940 		}
941 
942 		/*
943 		 * If appropriate, set established to TRUE *after* sending
944 		 * response (otherwise, the client will receive the final
945 		 * token encrypted)
946 		 */
947 
948 		if (gssstat == GSS_S_COMPLETE) {
949 			/*
950 			 * Context is established.  Set expiration time
951 			 * for the context.
952 			 */
953 			client_data->seq_num = 1;
954 			if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
955 				client_data->expiration = GSS_C_INDEFINITE;
956 			} else {
957 				client_data->expiration =
958 				    time_rec + gethrestime_sec();
959 			}
960 
961 			if (!transfer_sec_context(client_data)) {
962 				ret = RPCSEC_GSS_FAILED;
963 				client_data->stale = TRUE;
964 				RPCGSS_LOG0(1,
965 			    "_svc_rpcsec_gss: transfer sec context failed\n");
966 				goto error2;
967 			}
968 
969 			client_data->established = TRUE;
970 		}
971 
972 		/*
973 		 * This step succeeded.  Send a response, along with
974 		 * a token if there's one.  Don't dispatch.
975 		 */
976 
977 		if (output_token.length != 0) {
978 			GSS_COPY_BUFFER(call_res.token, output_token);
979 		}
980 		/*
981 		 * If GSS_S_COMPLETE: set response verifier to
982 		 * checksum of SEQ_WIN
983 		 */
984 
985 		if (gssstat == GSS_S_COMPLETE) {
986 		    if (!set_response_verf(rqst, msg, client_data,
987 				(uint_t)SEQ_WIN)) {
988 			ret = RPCSEC_GSS_FAILED;
989 			client_data->stale = TRUE;
990 			RPCGSS_LOG0(1,
991 			"_svc_rpcsec_gss:set response verifier failed\n");
992 			goto error2;
993 		    }
994 		}
995 
996 		(void) svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
997 							(caddr_t)&call_res);
998 		/*
999 		 * Cache last response in case it is lost and the client
1000 		 * retries on an established context.
1001 		 */
1002 		(void) retrans_add(client_data, msg->rm_xid, &call_res);
1003 		*no_dispatch = TRUE;
1004 		ASSERT(client_data->ref_cnt > 0);
1005 		client_data->ref_cnt--;
1006 		(void) gss_release_buffer(&minor_stat, &output_token);
1007 
1008 	} else {
1009 		if ((creds.gss_proc != RPCSEC_GSS_DATA) &&
1010 		    (creds.gss_proc != RPCSEC_GSS_DESTROY)) {
1011 
1012 		    switch (creds.gss_proc) {
1013 
1014 		    case RPCSEC_GSS_CONTINUE_INIT:
1015 			/*
1016 			 * This is an established context. Continue to
1017 			 * satisfy retried continue init requests out of
1018 			 * the retransmit cache.  Throw away any that don't
1019 			 * have a matching xid or the cach is empty.
1020 			 * Delete the retransmit cache once the client sends
1021 			 * a data request.
1022 			 */
1023 			if (client_data->retrans_data &&
1024 			    (client_data->retrans_data->xid == msg->rm_xid)) {
1025 
1026 			    retrans_result = &client_data->retrans_data->result;
1027 			    if (set_response_verf(rqst, msg, client_data,
1028 				(uint_t)retrans_result->seq_window)) {
1029 
1030 				gss_parms->established = FALSE;
1031 				(void) svc_sendreply(rqst->rq_xprt,
1032 					__xdr_rpc_gss_init_res,
1033 					(caddr_t)retrans_result);
1034 				*no_dispatch = TRUE;
1035 				ASSERT(client_data->ref_cnt > 0);
1036 				client_data->ref_cnt--;
1037 				goto success;
1038 			    }
1039 			}
1040 			/* fall thru to default */
1041 
1042 		    default:
1043 			RPCGSS_LOG0(1, "_svcrpcsec_gss: non-data request "
1044 				"on an established context\n");
1045 			ret = AUTH_FAILED;
1046 			goto error2;
1047 		    }
1048 		}
1049 
1050 		/*
1051 		 * Once the context is established and there is no more
1052 		 * retransmission of last continue init request, it is safe
1053 		 * to delete the retransmit cache entry.
1054 		 */
1055 		if (client_data->retrans_data)
1056 			retrans_del(client_data);
1057 
1058 		/*
1059 		 * Context is already established.  Check verifier, and
1060 		 * note parameters we will need for response in gss_parms.
1061 		 */
1062 		if (!check_verf(msg, client_data->context,
1063 			(int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1064 			ret = RPCSEC_GSS_NOCRED;
1065 			RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1066 			goto error2;
1067 		}
1068 
1069 		/*
1070 		 *  Check and invoke callback if necessary.
1071 		 */
1072 		if (!client_data->done_docallback) {
1073 			client_data->done_docallback = TRUE;
1074 			client_data->qop = gss_parms->qop_rcvd;
1075 			client_data->raw_cred.qop = gss_parms->qop_rcvd;
1076 			client_data->raw_cred.service = creds.service;
1077 			if (!do_callback(rqst, client_data)) {
1078 				ret = AUTH_FAILED;
1079 				RPCGSS_LOG0(1,
1080 					"_svc_rpcsec_gss:callback failed\n");
1081 				goto error2;
1082 			}
1083 		}
1084 
1085 		/*
1086 		 * If the context was locked, make sure that the client
1087 		 * has not changed QOP.
1088 		 */
1089 		if (client_data->locked &&
1090 				gss_parms->qop_rcvd != client_data->qop) {
1091 			ret = AUTH_BADVERF;
1092 			RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1093 			goto error2;
1094 		}
1095 
1096 		/*
1097 		 * Validate sequence number.
1098 		 */
1099 		if (!check_seq(client_data, creds.seq_num,
1100 						&client_data->stale)) {
1101 			if (client_data->stale) {
1102 				ret = RPCSEC_GSS_FAILED;
1103 				RPCGSS_LOG0(1,
1104 					"_svc_rpcsec_gss:check seq failed\n");
1105 			} else {
1106 				RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1107 					"failed on good context. Ignoring "
1108 					"request\n");
1109 				/*
1110 				 * Operational error, drop packet silently.
1111 				 * The client will recover after timing out,
1112 				 * assuming this is a client error and not
1113 				 * a relpay attack.  Don't dispatch.
1114 				 */
1115 				ret = AUTH_OK;
1116 				*no_dispatch = TRUE;
1117 			}
1118 			goto error2;
1119 		}
1120 
1121 		/*
1122 		 * set response verifier
1123 		 */
1124 		if (!set_response_verf(rqst, msg, client_data,
1125 				creds.seq_num)) {
1126 			ret = RPCSEC_GSS_FAILED;
1127 			client_data->stale = TRUE;
1128 			RPCGSS_LOG0(1,
1129 			"_svc_rpcsec_gss:set response verifier failed\n");
1130 			goto error2;
1131 		}
1132 
1133 		/*
1134 		 * If this is a control message RPCSEC_GSS_DESTROY, process
1135 		 * the call; otherwise, return AUTH_OK so it will be
1136 		 * dispatched to the application server.
1137 		 */
1138 		if (creds.gss_proc == RPCSEC_GSS_DESTROY) {
1139 			/*
1140 			 * XXX Kernel client is not issuing this procudure
1141 			 * right now. Need to revisit.
1142 			 */
1143 			(void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1144 			*no_dispatch = TRUE;
1145 			ASSERT(client_data->ref_cnt > 0);
1146 			client_data->ref_cnt--;
1147 			client_data->stale = TRUE;
1148 		} else {
1149 			/* This should be an RPCSEC_GSS_DATA request. */
1150 			ASSERT(creds.gss_proc == RPCSEC_GSS_DATA);
1151 
1152 			/*
1153 			 * If context is locked, make sure that the client
1154 			 * has not changed the security service.
1155 			 */
1156 			if (client_data->locked &&
1157 			    client_data->raw_cred.service != creds.service) {
1158 				RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1159 					"security service changed.\n");
1160 				ret = AUTH_FAILED;
1161 				goto error2;
1162 			}
1163 
1164 			/*
1165 			 * Set client credentials to raw credential
1166 			 * structure in context.  This is okay, since
1167 			 * this will not change during the lifetime of
1168 			 * the context (so it's MT safe).
1169 			 */
1170 			rqst->rq_clntcred = (char *)&client_data->raw_cred;
1171 		}
1172 	}
1173 
1174 success:
1175 	/*
1176 	 * Success.
1177 	 */
1178 	if (creds.ctx_handle.length != 0)
1179 		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1180 	mutex_exit(&client_data->clm);
1181 
1182 	return (AUTH_OK);
1183 error2:
1184 	ASSERT(client_data->ref_cnt > 0);
1185 	client_data->ref_cnt--;
1186 	(void) gss_release_buffer(&minor_stat, &output_token);
1187 	if (free_mech_type && mech_type)
1188 		kgss_free_oid(mech_type);
1189 	mutex_exit(&client_data->clm);
1190 error:
1191 	/*
1192 	 * Failure.
1193 	 */
1194 	if (creds.ctx_handle.length != 0)
1195 		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1196 
1197 	return (ret);
1198 }
1199 
1200 /*
1201  * Check verifier.  The verifier is the checksum of the RPC header
1202  * upto and including the credentials field.
1203  */
1204 
1205 /* ARGSUSED */
1206 static bool_t
1207 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1208 {
1209 	int			*buf, *tmp;
1210 	char			hdr[128];
1211 	struct opaque_auth	*oa;
1212 	int			len;
1213 	gss_buffer_desc		msg_buf;
1214 	gss_buffer_desc		tok_buf;
1215 	OM_uint32		gssstat, minor_stat;
1216 
1217 	/*
1218 	 * We have to reconstruct the RPC header from the previously
1219 	 * parsed information, since we haven't kept the header intact.
1220 	 */
1221 
1222 	oa = &msg->rm_call.cb_cred;
1223 	if (oa->oa_length > MAX_AUTH_BYTES)
1224 		return (FALSE);
1225 
1226 	/* 8 XDR units from the IXDR macro calls. */
1227 	if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1228 	    RNDUP(oa->oa_length)))
1229 		return (FALSE);
1230 	buf = (int *)hdr;
1231 	IXDR_PUT_U_INT32(buf, msg->rm_xid);
1232 	IXDR_PUT_ENUM(buf, msg->rm_direction);
1233 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1234 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1235 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1236 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1237 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
1238 	IXDR_PUT_U_INT32(buf, oa->oa_length);
1239 	if (oa->oa_length) {
1240 		len = RNDUP(oa->oa_length);
1241 		tmp = buf;
1242 		buf += len / sizeof (int);
1243 		*(buf - 1) = 0;
1244 		(void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1245 	}
1246 	len = ((char *)buf) - hdr;
1247 	msg_buf.length = len;
1248 	msg_buf.value = hdr;
1249 	oa = &msg->rm_call.cb_verf;
1250 	tok_buf.length = oa->oa_length;
1251 	tok_buf.value = oa->oa_base;
1252 
1253 	gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1254 				qop_state);
1255 	if (gssstat != GSS_S_COMPLETE) {
1256 		RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1257 
1258 		RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1259 		RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1260 		RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1261 				tok_buf.length);
1262 		RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1263 			(void *)oa->oa_base);
1264 		RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1265 
1266 		return (FALSE);
1267 	}
1268 	return (TRUE);
1269 }
1270 
1271 /*
1272  * Set response verifier.  This is the checksum of the given number.
1273  * (e.g. sequence number or sequence window)
1274  */
1275 static bool_t
1276 set_response_verf(rqst, msg, cl, num)
1277 	struct svc_req		*rqst;
1278 	struct rpc_msg		*msg;
1279 	svc_rpc_gss_data	*cl;
1280 	uint_t			num;
1281 {
1282 	OM_uint32		minor;
1283 	gss_buffer_desc		in_buf, out_buf;
1284 	uint_t			num_net;
1285 
1286 	num_net = (uint_t)htonl(num);
1287 	in_buf.length = sizeof (num);
1288 	in_buf.value = (char *)&num_net;
1289 /* XXX uid ? */
1290 	if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf,
1291 				&out_buf)) != GSS_S_COMPLETE)
1292 		return (FALSE);
1293 
1294 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1295 	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1296 	rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1297 	bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1298 	(void) gss_release_buffer(&minor, &out_buf);
1299 	return (TRUE);
1300 }
1301 
1302 /*
1303  * Create client context.
1304  */
1305 static svc_rpc_gss_data *
1306 create_client()
1307 {
1308 	svc_rpc_gss_data	*client_data;
1309 	static uint_t		key = 1;
1310 
1311 	client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1312 							    KM_SLEEP);
1313 	if (client_data == NULL)
1314 		return (NULL);
1315 
1316 	/*
1317 	 * set up client data structure
1318 	 */
1319 	client_data->next = NULL;
1320 	client_data->prev = NULL;
1321 	client_data->lru_next = NULL;
1322 	client_data->lru_prev = NULL;
1323 	client_data->client_name.length = 0;
1324 	client_data->client_name.value = NULL;
1325 	client_data->seq_num = 0;
1326 	bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1327 	client_data->key = 0;
1328 	client_data->cookie = NULL;
1329 	bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1330 	client_data->established = FALSE;
1331 	client_data->locked = FALSE;
1332 	client_data->u_cred_set = 0;
1333 	client_data->context = GSS_C_NO_CONTEXT;
1334 	client_data->expiration = GSS_C_INDEFINITE;
1335 	client_data->deleg = GSS_C_NO_CREDENTIAL;
1336 	client_data->ref_cnt = 1;
1337 	client_data->last_ref_time = gethrestime_sec();
1338 	client_data->qop = GSS_C_QOP_DEFAULT;
1339 	client_data->done_docallback = FALSE;
1340 	client_data->stale = FALSE;
1341 	client_data->retrans_data = NULL;
1342 	bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1343 
1344 	/*
1345 	 * The client context handle is a 32-bit key (unsigned int).
1346 	 * The key is incremented until there is no duplicate for it.
1347 	 */
1348 
1349 	svc_rpc_gss_cache_stats.total_entries_allocated++;
1350 	mutex_enter(&ctx_mutex);
1351 	for (;;) {
1352 		client_data->key = key++;
1353 		if (find_client(client_data->key) == NULL) {
1354 			insert_client(client_data);
1355 			mutex_exit(&ctx_mutex);
1356 			return (client_data);
1357 		}
1358 	}
1359 	/*NOTREACHED*/
1360 }
1361 
1362 /*
1363  * Insert client context into hash list and LRU list.
1364  */
1365 static void
1366 insert_client(client_data)
1367 	svc_rpc_gss_data	*client_data;
1368 {
1369 	svc_rpc_gss_data	*cl;
1370 	int			index = HASH(client_data->key);
1371 
1372 	ASSERT(mutex_owned(&ctx_mutex));
1373 
1374 	client_data->prev = NULL;
1375 	cl = clients[index];
1376 	if ((client_data->next = cl) != NULL)
1377 		cl->prev = client_data;
1378 	clients[index] = client_data;
1379 
1380 	client_data->lru_prev = NULL;
1381 	if ((client_data->lru_next = lru_first) != NULL)
1382 		lru_first->lru_prev = client_data;
1383 	else
1384 		lru_last = client_data;
1385 	lru_first = client_data;
1386 
1387 	num_gss_contexts++;
1388 }
1389 
1390 /*
1391  * Fetch a client, given the client context handle.  Move it to the
1392  * top of the LRU list since this is the most recently used context.
1393  */
1394 static svc_rpc_gss_data *
1395 get_client(ctx_handle)
1396 	gss_buffer_t		ctx_handle;
1397 {
1398 	uint_t			key = *(uint_t *)ctx_handle->value;
1399 	svc_rpc_gss_data	*cl;
1400 
1401 	mutex_enter(&ctx_mutex);
1402 	if ((cl = find_client(key)) != NULL) {
1403 		mutex_enter(&cl->clm);
1404 		if (cl->stale) {
1405 			if (cl->ref_cnt == 0) {
1406 				mutex_exit(&cl->clm);
1407 				destroy_client(cl);
1408 			} else {
1409 				mutex_exit(&cl->clm);
1410 			}
1411 			mutex_exit(&ctx_mutex);
1412 			return (NULL);
1413 		}
1414 		cl->ref_cnt++;
1415 		cl->last_ref_time = gethrestime_sec();
1416 		mutex_exit(&cl->clm);
1417 		if (cl != lru_first) {
1418 			cl->lru_prev->lru_next = cl->lru_next;
1419 			if (cl->lru_next != NULL)
1420 				cl->lru_next->lru_prev = cl->lru_prev;
1421 			else
1422 				lru_last = cl->lru_prev;
1423 			cl->lru_prev = NULL;
1424 			cl->lru_next = lru_first;
1425 			lru_first->lru_prev = cl;
1426 			lru_first = cl;
1427 		}
1428 	}
1429 	mutex_exit(&ctx_mutex);
1430 	return (cl);
1431 }
1432 
1433 /*
1434  * Given the client context handle, find the context corresponding to it.
1435  * Don't change its LRU state since it may not be used.
1436  */
1437 static svc_rpc_gss_data *
1438 find_client(key)
1439 	uint_t			key;
1440 {
1441 	int			index = HASH(key);
1442 	svc_rpc_gss_data	*cl = NULL;
1443 
1444 	ASSERT(mutex_owned(&ctx_mutex));
1445 
1446 	for (cl = clients[index]; cl != NULL; cl = cl->next) {
1447 		if (cl->key == key)
1448 			break;
1449 	}
1450 	return (cl);
1451 }
1452 
1453 /*
1454  * Destroy a client context.
1455  */
1456 static void
1457 destroy_client(client_data)
1458 	svc_rpc_gss_data	*client_data;
1459 {
1460 	OM_uint32		minor;
1461 	int			index = HASH(client_data->key);
1462 
1463 	ASSERT(mutex_owned(&ctx_mutex));
1464 
1465 	/*
1466 	 * remove from hash list
1467 	 */
1468 	if (client_data->prev == NULL)
1469 		clients[index] = client_data->next;
1470 	else
1471 		client_data->prev->next = client_data->next;
1472 	if (client_data->next != NULL)
1473 		client_data->next->prev = client_data->prev;
1474 
1475 	/*
1476 	 * remove from LRU list
1477 	 */
1478 	if (client_data->lru_prev == NULL)
1479 		lru_first = client_data->lru_next;
1480 	else
1481 		client_data->lru_prev->lru_next = client_data->lru_next;
1482 	if (client_data->lru_next != NULL)
1483 		client_data->lru_next->lru_prev = client_data->lru_prev;
1484 	else
1485 		lru_last = client_data->lru_prev;
1486 
1487 	/*
1488 	 * If there is a GSS context, clean up GSS state.
1489 	 */
1490 	if (client_data->context != GSS_C_NO_CONTEXT) {
1491 		(void) kgss_delete_sec_context(&minor, &client_data->context,
1492 					NULL);
1493 
1494 		common_client_data_free(client_data);
1495 
1496 		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1497 		    (void) kgss_release_cred(&minor, &client_data->deleg,
1498 				crgetuid(CRED()));
1499 		}
1500 	}
1501 
1502 	if (client_data->u_cred.gidlist != NULL) {
1503 	    kmem_free((char *)client_data->u_cred.gidlist,
1504 			client_data->u_cred.gidlen * sizeof (gid_t));
1505 	    client_data->u_cred.gidlist = NULL;
1506 	}
1507 	if (client_data->retrans_data != NULL)
1508 		retrans_del(client_data);
1509 
1510 	kmem_cache_free(svc_data_handle, client_data);
1511 	num_gss_contexts--;
1512 }
1513 
1514 /*
1515  * Check for expired and stale client contexts.
1516  */
1517 static void
1518 sweep_clients(bool_t from_reclaim)
1519 {
1520 	svc_rpc_gss_data	*cl, *next;
1521 	time_t			last_reference_needed;
1522 	time_t			now = gethrestime_sec();
1523 
1524 	ASSERT(mutex_owned(&ctx_mutex));
1525 
1526 	last_reference_needed = now - (from_reclaim ?
1527 				    svc_rpc_gss_active_delta :
1528 				    svc_rpc_gss_inactive_delta);
1529 
1530 	cl = lru_last;
1531 	while (cl) {
1532 		/*
1533 		 * We assume here that any manipulation of the LRU pointers
1534 		 * and hash bucket pointers are only done when holding the
1535 		 * ctx_mutex.
1536 		 */
1537 		next = cl->lru_prev;
1538 
1539 		mutex_enter(&cl->clm);
1540 
1541 		if ((cl->expiration != GSS_C_INDEFINITE &&
1542 		    cl->expiration <= now) || cl->stale ||
1543 		    cl->last_ref_time <= last_reference_needed) {
1544 
1545 			if ((cl->expiration != GSS_C_INDEFINITE &&
1546 			    cl->expiration <= now) || cl->stale ||
1547 			    (cl->last_ref_time <= last_reference_needed &&
1548 			    cl->ref_cnt == 0)) {
1549 
1550 				cl->stale = TRUE;
1551 
1552 				if (cl->ref_cnt == 0) {
1553 					mutex_exit(&cl->clm);
1554 					if (from_reclaim)
1555 						svc_rpc_gss_cache_stats.
1556 						    no_returned_by_reclaim++;
1557 					destroy_client(cl);
1558 				} else
1559 					mutex_exit(&cl->clm);
1560 			} else
1561 				mutex_exit(&cl->clm);
1562 		} else
1563 			mutex_exit(&cl->clm);
1564 
1565 		cl = next;
1566 	}
1567 
1568 	last_swept = gethrestime_sec();
1569 }
1570 
1571 /*
1572  * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1573  * and write the result to xdrs.
1574  */
1575 static bool_t
1576 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1577 	SVCAUTH			*auth;
1578 	XDR			*out_xdrs;
1579 	bool_t			(*xdr_func)();
1580 	caddr_t			xdr_ptr;
1581 {
1582 	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1583 
1584 	/*
1585 	 * If context is not established, or if neither integrity nor
1586 	 * privacy service is used, don't wrap - just XDR encode.
1587 	 * Otherwise, wrap data using service and QOP parameters.
1588 	 */
1589 	if (!gss_parms->established ||
1590 				gss_parms->service == rpc_gss_svc_none)
1591 		return ((*xdr_func)(out_xdrs, xdr_ptr));
1592 
1593 	return (__rpc_gss_wrap_data(gss_parms->service,
1594 				(OM_uint32)gss_parms->qop_rcvd,
1595 				(gss_ctx_id_t)gss_parms->context,
1596 				gss_parms->seq_num,
1597 				out_xdrs, xdr_func, xdr_ptr));
1598 }
1599 
1600 /*
1601  * Decrypt the serialized arguments and XDR decode them.
1602  */
1603 static bool_t
1604 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1605 	SVCAUTH			*auth;
1606 	XDR			*in_xdrs;
1607 	bool_t			(*xdr_func)();
1608 	caddr_t			xdr_ptr;
1609 {
1610 	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1611 
1612 	/*
1613 	 * If context is not established, or if neither integrity nor
1614 	 * privacy service is used, don't unwrap - just XDR decode.
1615 	 * Otherwise, unwrap data.
1616 	 */
1617 	if (!gss_parms->established ||
1618 				gss_parms->service == rpc_gss_svc_none)
1619 		return ((*xdr_func)(in_xdrs, xdr_ptr));
1620 
1621 	return (__rpc_gss_unwrap_data(gss_parms->service,
1622 				(gss_ctx_id_t)gss_parms->context,
1623 				gss_parms->seq_num,
1624 				gss_parms->qop_rcvd,
1625 				in_xdrs, xdr_func, xdr_ptr));
1626 }
1627 
1628 
1629 /* ARGSUSED */
1630 int
1631 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1632 {
1633 	return (0);
1634 }
1635 
1636 /*
1637  * Add retransmit entry to the context cache entry for a new xid.
1638  * If there is already an entry, delete it before adding the new one.
1639  */
1640 static void retrans_add(client, xid, result)
1641 	svc_rpc_gss_data *client;
1642 	uint32_t	xid;
1643 	rpc_gss_init_res *result;
1644 {
1645 	retrans_entry	*rdata;
1646 
1647 	if (client->retrans_data && client->retrans_data->xid == xid)
1648 		return;
1649 
1650 	rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1651 
1652 	if (rdata == NULL)
1653 		return;
1654 
1655 	rdata->xid = xid;
1656 	rdata->result = *result;
1657 
1658 	if (result->token.length != 0) {
1659 		GSS_DUP_BUFFER(rdata->result.token, result->token);
1660 	}
1661 
1662 	if (client->retrans_data)
1663 		retrans_del(client);
1664 
1665 	client->retrans_data = rdata;
1666 }
1667 
1668 /*
1669  * Delete the retransmit data from the context cache entry.
1670  */
1671 static void retrans_del(client)
1672 	svc_rpc_gss_data *client;
1673 {
1674 	retrans_entry *rdata;
1675 	OM_uint32 minor_stat;
1676 
1677 	if (client->retrans_data == NULL)
1678 		return;
1679 
1680 	rdata = client->retrans_data;
1681 	if (rdata->result.token.length != 0) {
1682 	    (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1683 	}
1684 
1685 	kmem_free((caddr_t)rdata, sizeof (*rdata));
1686 	client->retrans_data = NULL;
1687 }
1688 
1689 /*
1690  * This function frees the following fields of svc_rpc_gss_data:
1691  *	client_name, raw_cred.client_principal, raw_cred.mechanism.
1692  */
1693 static void
1694 common_client_data_free(svc_rpc_gss_data *client_data)
1695 {
1696 	if (client_data->client_name.length > 0) {
1697 		(void) gss_release_buffer(NULL, &client_data->client_name);
1698 	}
1699 
1700 	if (client_data->raw_cred.client_principal) {
1701 		kmem_free((caddr_t)client_data->raw_cred.client_principal,
1702 			client_data->raw_cred.client_principal->len +
1703 			sizeof (int));
1704 		client_data->raw_cred.client_principal = NULL;
1705 	}
1706 
1707 	/*
1708 	 * In the user GSS-API library, mechanism (mech_type returned
1709 	 * by gss_accept_sec_context) is static storage, however
1710 	 * since all the work is done for gss_accept_sec_context under
1711 	 * gssd, what is returned in the kernel, is a copy from the oid
1712 	 * obtained under from gssd, so need to free it when destroying
1713 	 * the client data.
1714 	 */
1715 
1716 	if (client_data->raw_cred.mechanism) {
1717 		kgss_free_oid(client_data->raw_cred.mechanism);
1718 		client_data->raw_cred.mechanism = NULL;
1719 	}
1720 }
1721