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