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