xref: /illumos-gate/usr/src/lib/rpcsec_gss/svc_rpcsec_gss.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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 1995-2003 Sun Microsystems, Inc.
24  * All rights reserved.  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 		ret = AUTH_BADCRED;
604 		goto error;
605 	}
606 
607 	xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
608 
609 	memset((char *)&creds, 0, sizeof (creds));
610 	if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
611 		XDR_DESTROY(&xdrs);
612 		ret = AUTH_BADCRED;
613 		goto error;
614 	}
615 	XDR_DESTROY(&xdrs);
616 
617 	/*
618 	 * If this is a control message and proc is GSSAPI_INIT, then
619 	 * create a client handle for this client.  Otherwise, look up
620 	 * the existing handle.
621 	 */
622 	if (creds.gss_proc == RPCSEC_GSS_INIT) {
623 		if (creds.ctx_handle.length != 0) {
624 			ret = AUTH_BADCRED;
625 			goto error;
626 		}
627 		if ((client_data = create_client()) == NULL) {
628 			ret = AUTH_FAILED;
629 			goto error;
630 		}
631 	} else {
632 		/*
633 		 * Only verify values for service parameter when proc
634 		 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT.
635 		 * RFC2203 says contents for sequence and service args
636 		 * are undefined for creation procs.
637 		 *
638 		 * Note: only need to check for *CONTINUE_INIT here because
639 		 *	if() clause already checked for RPCSEC_GSS_INIT
640 		 */
641 		if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) {
642 			switch (creds.service) {
643 			case rpc_gss_svc_none:
644 			case rpc_gss_svc_integrity:
645 			case rpc_gss_svc_privacy:
646 				break;
647 			default:
648 				ret = AUTH_BADCRED;
649 				goto error;
650 			}
651 		}
652 		if (creds.ctx_handle.length == 0) {
653 			ret = AUTH_BADCRED;
654 			goto error;
655 		}
656 		if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
657 			ret = RPCSEC_GSS_NOCRED;
658 			goto error;
659 		}
660 	}
661 
662 	/*
663 	 * lock the client data until it's safe; if it's already stale,
664 	 * no more processing is possible
665 	 */
666 	mutex_lock(&client_data->clm);
667 	if (client_data->stale) {
668 		ret = RPCSEC_GSS_NOCRED;
669 		goto error2;
670 	}
671 
672 	/*
673 	 * Any response we send will use ctx_handle, so set it now;
674 	 * also set seq_window since this won't change.
675 	 */
676 	call_res.ctx_handle.length = sizeof (client_data->key);
677 	call_res.ctx_handle.value = (char *)&client_data->key;
678 	call_res.seq_window = SEQ_WIN;
679 
680 	/*
681 	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
682 	 */
683 	svcauth = __svc_get_svcauth(rqst->rq_xprt);
684 	svcauth->svc_ah_ops = svc_rpc_gss_ops;
685 	svcauth->svc_ah_private = (caddr_t)client_data;
686 
687 	/*
688 	 * Keep copy of parameters we'll need for response, for the
689 	 * sake of reentrancy (we don't want to look in the context
690 	 * data because when we are sending a response, another
691 	 * request may have come in.
692 	 */
693 	gss_parms = &svcauth->svc_gss_parms;
694 	gss_parms->established = client_data->established;
695 	gss_parms->service = creds.service;
696 	gss_parms->qop_rcvd = (uint_t)client_data->qop;
697 	gss_parms->context = (void *)client_data->context;
698 	gss_parms->seq_num = creds.seq_num;
699 
700 	if (!client_data->established) {
701 		if (creds.gss_proc == RPCSEC_GSS_DATA) {
702 			ret = RPCSEC_GSS_FAILED;
703 			client_data->stale = TRUE;
704 			goto error2;
705 		}
706 
707 		/*
708 		 * If the context is not established, then only GSSAPI_INIT
709 		 * and _CONTINUE requests are valid.
710 		 */
711 		if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc !=
712 						RPCSEC_GSS_CONTINUE_INIT) {
713 			ret = RPCSEC_GSS_FAILED;
714 			client_data->stale = TRUE;
715 			goto error2;
716 		}
717 
718 		/*
719 		 * call is for us, deserialize arguments
720 		 */
721 		memset(&call_arg, 0, sizeof (call_arg));
722 		if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
723 							(caddr_t)&call_arg)) {
724 			ret = RPCSEC_GSS_FAILED;
725 			client_data->stale = TRUE;
726 			goto error2;
727 		}
728 
729 		gssstat = GSS_S_FAILURE;
730 		minor_stat = 0;
731 		rw_rdlock(&cred_lock);
732 		/*
733 		 * set next sc to point to the server cred
734 		 * if the  client_data contains server_creds
735 		 */
736 		for (sc = svc_creds_list; sc != NULL; sc = sc->next) {
737 			if (rqst->rq_prog != sc->program ||
738 					rqst->rq_vers != sc->version)
739 				continue;
740 
741 			mutex_lock(&sc->refresh_mutex);
742 			gssstat = gss_accept_sec_context(&minor_stat,
743 				&client_data->context,
744 				sc->cred,
745 				&call_arg,
746 				GSS_C_NO_CHANNEL_BINDINGS,
747 				&client_data->client_name,
748 				&mech_type,
749 				&output_token,
750 				&ret_flags,
751 				&time_rec,
752 				NULL);
753 
754 			if (gssstat == GSS_S_CREDENTIALS_EXPIRED) {
755 				if (rpc_gss_refresh_svc_cred(sc)) {
756 					gssstat = gss_accept_sec_context(
757 						&minor_stat,
758 						&client_data->context,
759 						sc->cred,
760 						&call_arg,
761 						GSS_C_NO_CHANNEL_BINDINGS,
762 						&client_data->client_name,
763 						&mech_type,
764 						&output_token,
765 						&ret_flags,
766 						&time_rec,
767 						NULL);
768 					mutex_unlock(&sc->refresh_mutex);
769 
770 				} else {
771 					mutex_unlock(&sc->refresh_mutex);
772 					gssstat = GSS_S_NO_CRED;
773 					break;
774 				}
775 
776 			} else
777 				mutex_unlock(&sc->refresh_mutex);
778 
779 			if (gssstat == GSS_S_COMPLETE) {
780 				/*
781 				 * Server_creds was right - set it.  Also
782 				 * set the raw and unix credentials at this
783 				 * point.  This saves a lot of computation
784 				 * later when credentials are retrieved.
785 				 */
786 				/*
787 				 * XXX server_creds will prob be stale
788 				 * after rpc_gss_refresh_svc_cred(), but
789 				 * it appears not to ever be referenced
790 				 * anyways.
791 				 */
792 				mutex_lock(&sc->refresh_mutex);
793 				client_data->server_creds = sc->cred;
794 				client_data->raw_cred.version = creds.version;
795 				client_data->raw_cred.service = creds.service;
796 				client_data->raw_cred.svc_principal =
797 						sc->server_name;
798 				mutex_unlock(&sc->refresh_mutex);
799 
800 				if ((client_data->raw_cred.mechanism
801 					= __rpc_gss_oid_to_mech(mech_type))
802 					== NULL) {
803 					gssstat = GSS_S_FAILURE;
804 					(void) gss_release_buffer(&minor_stat,
805 								&output_token);
806 				} else if (!set_client_principal(client_data->
807 					client_name, &client_data->
808 					raw_cred.client_principal)) {
809 					gssstat = GSS_S_FAILURE;
810 					(void) gss_release_buffer(&minor_stat,
811 								&output_token);
812 				}
813 				break;
814 			}
815 
816 			if (gssstat == GSS_S_CONTINUE_NEEDED) {
817 				/*
818 				 * XXX server_creds will prob be stale
819 				 * after rpc_gss_refresh_svc_cred(), but
820 				 * it appears not to ever be referenced
821 				 * anyways.
822 				 */
823 				mutex_lock(&sc->refresh_mutex);
824 				client_data->server_creds = sc->cred;
825 				mutex_unlock(&sc->refresh_mutex);
826 				break;
827 			}
828 
829 		}
830 		rw_unlock(&cred_lock);
831 
832 		call_res.gss_major = gssstat;
833 		call_res.gss_minor = minor_stat;
834 
835 		xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg);
836 
837 		if (gssstat != GSS_S_COMPLETE &&
838 					gssstat != GSS_S_CONTINUE_NEEDED) {
839 			/*
840 			 * We have a failure - send response and delete
841 			 * the context.  Don't dispatch. Set ctx_handle
842 			 * to NULL and seq_window to 0.
843 			 */
844 			call_res.ctx_handle.length = 0;
845 			call_res.ctx_handle.value = NULL;
846 			call_res.seq_window = 0;
847 
848 			svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
849 						(caddr_t)&call_res);
850 			*no_dispatch = TRUE;
851 			ret = AUTH_OK;
852 			client_data->stale = TRUE;
853 			goto error2;
854 		}
855 
856 		/*
857 		 * This step succeeded.  Send a response, along with
858 		 * a token if there's one.  Don't dispatch.
859 		 */
860 		if (output_token.length != 0) {
861 			GSS_COPY_BUFFER(call_res.token, output_token);
862 		}
863 
864 		/*
865 		 * set response verifier: checksum of SEQ_WIN
866 		 */
867 		if (gssstat == GSS_S_COMPLETE) {
868 			if (!set_response_verf(rqst, msg, client_data,
869 				(uint_t)SEQ_WIN)) {
870 				ret = RPCSEC_GSS_FAILED;
871 				client_data->stale = TRUE;
872 				(void) gss_release_buffer(&minor_stat,
873 							&output_token);
874 				goto error2;
875 			}
876 		}
877 
878 		svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
879 							(caddr_t)&call_res);
880 		/*
881 		 * Cache last response in case it is lost and the client
882 		 * retries on an established context.
883 		 */
884 		(void) retrans_add(client_data, msg->rm_xid, &call_res);
885 		*no_dispatch = TRUE;
886 		(void) gss_release_buffer(&minor_stat, &output_token);
887 
888 		/*
889 		 * If appropriate, set established to TRUE *after* sending
890 		 * response (otherwise, the client will receive the final
891 		 * token encrypted)
892 		 */
893 		if (gssstat == GSS_S_COMPLETE) {
894 			/*
895 			 * Context is established.  Set expiry time for
896 			 * context (the minimum of time_rec and max_lifetime).
897 			 */
898 			client_data->seq_num = 1;
899 			if (time_rec == GSS_C_INDEFINITE) {
900 				if (max_lifetime != GSS_C_INDEFINITE)
901 					client_data->expiration =
902 							max_lifetime + time(0);
903 				else
904 					client_data->expiration =
905 							GSS_C_INDEFINITE;
906 			} else if (max_lifetime == GSS_C_INDEFINITE ||
907 							max_lifetime > time_rec)
908 				client_data->expiration = time_rec + time(0);
909 			else
910 				client_data->expiration = max_lifetime +
911 								time(0);
912 			client_data->established = TRUE;
913 		}
914 
915 	} else {
916 		if ((creds.gss_proc != RPCSEC_GSS_DATA) &&
917 			(creds.gss_proc != RPCSEC_GSS_DESTROY)) {
918 
919 		    switch (creds.gss_proc) {
920 
921 		    case RPCSEC_GSS_CONTINUE_INIT:
922 			/*
923 			 * This is an established context. Continue to
924 			 * satisfy retried continue init requests out of
925 			 * the retransmit cache.  Throw away any that don't
926 			 * have a matching xid or the cach is empty.
927 			 * Delete the retransmit cache once the client sends
928 			 * a data request.
929 			 */
930 			if (client_data->retrans_data &&
931 			    (client_data->retrans_data->xid == msg->rm_xid)) {
932 
933 			    retrans_result = &client_data->retrans_data->result;
934 			    if (set_response_verf(rqst, msg, client_data,
935 				(uint_t)retrans_result->seq_window)) {
936 
937 				gss_parms->established = FALSE;
938 				svc_sendreply(rqst->rq_xprt,
939 					__xdr_rpc_gss_init_res,
940 					(caddr_t)retrans_result);
941 				*no_dispatch = TRUE;
942 				goto success;
943 			    }
944 			}
945 			/* fall thru to default */
946 
947 		    default:
948 			syslog(LOG_ERR, "_svcrpcsec_gss: non-data request "
949 				"on an established context");
950 			ret = AUTH_FAILED;
951 			goto error2;
952 		    }
953 		}
954 
955 		/*
956 		 * Once the context is established and there is no more
957 		 * retransmission of last continue init request, it is safe
958 		 * to delete the retransmit cache entry.
959 		 */
960 		if (client_data->retrans_data)
961 			retrans_del(client_data);
962 
963 		/*
964 		 * Context is already established.  Check verifier, and
965 		 * note parameters we will need for response in gss_parms.
966 		 */
967 		if (!check_verf(msg, client_data->context,
968 						&gss_parms->qop_rcvd)) {
969 			ret = RPCSEC_GSS_NOCRED;
970 			goto error2;
971 		}
972 		/*
973 		 *  Check and invoke callback if necessary.
974 		 */
975 		if (!client_data->done_docallback) {
976 			client_data->done_docallback = TRUE;
977 			client_data->qop = gss_parms->qop_rcvd;
978 			client_data->raw_cred.qop = __rpc_gss_num_to_qop(
979 						client_data->raw_cred.mechanism,
980 							gss_parms->qop_rcvd);
981 			client_data->raw_cred.service = creds.service;
982 			if (!do_callback(rqst, client_data)) {
983 				ret = AUTH_FAILED;
984 				client_data->stale = TRUE;
985 				goto error2;
986 			}
987 		}
988 
989 		/*
990 		 * If the context was locked, make sure that the client
991 		 * has not changed QOP.
992 		 */
993 		if (client_data->locked &&
994 				gss_parms->qop_rcvd != client_data->qop) {
995 			ret = AUTH_BADVERF;
996 			goto error2;
997 		}
998 
999 		/*
1000 		 * Validate sequence number.
1001 		 */
1002 		if (!check_seq(client_data, creds.seq_num,
1003 						&client_data->stale)) {
1004 			if (client_data->stale)
1005 				ret = RPCSEC_GSS_FAILED;
1006 			else {
1007 				/*
1008 				 * Operational error, drop packet silently.
1009 				 * The client will recover after timing out,
1010 				 * assuming this is a client error and not
1011 				 * a relpay attack.  Don't dispatch.
1012 				 */
1013 				ret = AUTH_OK;
1014 				*no_dispatch = TRUE;
1015 			}
1016 			goto error2;
1017 		}
1018 
1019 		/*
1020 		 * set response verifier
1021 		 */
1022 		if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1023 			ret = RPCSEC_GSS_FAILED;
1024 			client_data->stale = TRUE;
1025 			goto error2;
1026 		}
1027 
1028 		/*
1029 		 * If this is a control message RPCSEC_GSS_DESTROY, process
1030 		 * the call; otherwise, return AUTH_OK so it will be
1031 		 * dispatched to the application server.
1032 		 */
1033 		if (creds.gss_proc == RPCSEC_GSS_DESTROY) {
1034 			svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1035 			*no_dispatch = TRUE;
1036 			client_data->stale = TRUE;
1037 
1038 		} else {
1039 			/*
1040 			 * This should be an RPCSEC_GSS_DATA request.
1041 			 * If context is locked, make sure that the client
1042 			 * has not changed the security service.
1043 			 */
1044 			if (client_data->locked &&
1045 			    client_data->raw_cred.service != creds.service) {
1046 				ret = AUTH_FAILED;
1047 				goto error2;
1048 			}
1049 
1050 			/*
1051 			 * Set client credentials to raw credential
1052 			 * structure in context.  This is okay, since
1053 			 * this will not change during the lifetime of
1054 			 * the context (so it's MT safe).
1055 			 */
1056 			rqst->rq_clntcred = (char *)&client_data->raw_cred;
1057 		}
1058 	}
1059 
1060 success:
1061 	/*
1062 	 * Success.
1063 	 */
1064 	if (creds.ctx_handle.length != 0)
1065 		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1066 	mutex_unlock(&client_data->clm);
1067 	return (AUTH_OK);
1068 error2:
1069 	mutex_unlock(&client_data->clm);
1070 error:
1071 	/*
1072 	 * Failure.
1073 	 */
1074 	if (creds.ctx_handle.length != 0)
1075 		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1076 	return (ret);
1077 }
1078 
1079 /*
1080  * Check verifier.  The verifier is the checksum of the RPC header
1081  * upto and including the credentials field.
1082  */
1083 static bool_t
1084 check_verf(msg, context, qop_state)
1085 	struct rpc_msg		*msg;
1086 	gss_ctx_id_t		context;
1087 	int			*qop_state;
1088 {
1089 	int			*buf, *tmp;
1090 	int			hdr[32];
1091 	struct opaque_auth	*oa;
1092 	int			len;
1093 	gss_buffer_desc		msg_buf;
1094 	gss_buffer_desc		tok_buf;
1095 	OM_uint32		gssstat, minor_stat;
1096 
1097 	/*
1098 	 * We have to reconstruct the RPC header from the previously
1099 	 * parsed information, since we haven't kept the header intact.
1100 	 */
1101 	buf = hdr;
1102 	IXDR_PUT_U_INT32(buf, msg->rm_xid);
1103 	IXDR_PUT_ENUM(buf, msg->rm_direction);
1104 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1105 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1106 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1107 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1108 	oa = &msg->rm_call.cb_cred;
1109 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
1110 	IXDR_PUT_U_INT32(buf, oa->oa_length);
1111 	if (oa->oa_length) {
1112 		len = RNDUP(oa->oa_length);
1113 		tmp = buf;
1114 		buf += len / sizeof (int);
1115 		*(buf - 1) = 0;
1116 		(void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length);
1117 	}
1118 	len = ((char *)buf) - (char *)hdr;
1119 	msg_buf.length = len;
1120 	msg_buf.value = (char *)hdr;
1121 	oa = &msg->rm_call.cb_verf;
1122 	tok_buf.length = oa->oa_length;
1123 	tok_buf.value = oa->oa_base;
1124 
1125 	gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1126 				qop_state);
1127 	if (gssstat != GSS_S_COMPLETE)
1128 		return (FALSE);
1129 	return (TRUE);
1130 }
1131 
1132 /*
1133  * Set response verifier.  This is the checksum of the given number.
1134  * (e.g. sequence number or sequence window)
1135  */
1136 static bool_t
1137 set_response_verf(rqst, msg, cl, num)
1138 	struct svc_req		*rqst;
1139 	struct rpc_msg		*msg;
1140 	svc_rpc_gss_data	*cl;
1141 	uint_t			num;
1142 {
1143 	OM_uint32		minor;
1144 	gss_buffer_desc		in_buf, out_buf;
1145 	uint_t			num_net;
1146 
1147 	num_net = (uint_t)htonl(num);
1148 	in_buf.length = sizeof (num);
1149 	in_buf.value = (char *)&num_net;
1150 	if (gss_sign(&minor, cl->context, cl->qop, &in_buf,
1151 					&out_buf) != GSS_S_COMPLETE)
1152 		return (FALSE);
1153 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1154 	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1155 	rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1156 	memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value,
1157 		out_buf.length);
1158 	(void) gss_release_buffer(&minor, &out_buf);
1159 	return (TRUE);
1160 }
1161 
1162 /*
1163  * Create client context.
1164  */
1165 static svc_rpc_gss_data *
1166 create_client()
1167 {
1168 	svc_rpc_gss_data	*client_data;
1169 	static uint_t		key = 1;
1170 
1171 	client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data));
1172 	if (client_data == NULL)
1173 		return (NULL);
1174 	memset((char *)client_data, 0, sizeof (*client_data));
1175 
1176 	/*
1177 	 * set up client data structure
1178 	 */
1179 	client_data->established = FALSE;
1180 	client_data->locked = FALSE;
1181 	client_data->u_cred_set = FALSE;
1182 	client_data->context = GSS_C_NO_CONTEXT;
1183 	client_data->expiration = init_lifetime + time(0);
1184 	client_data->ref_cnt = 1;
1185 	client_data->qop = GSS_C_QOP_DEFAULT;
1186 	client_data->done_docallback = FALSE;
1187 	client_data->stale = FALSE;
1188 	client_data->time_secs_set = 0;
1189 	client_data->retrans_data = NULL;
1190 	mutex_init(&client_data->clm, USYNC_THREAD, NULL);
1191 	/*
1192 	 * Check totals.  If we've hit the limit, we destroy a context
1193 	 * based on LRU method.
1194 	 */
1195 	mutex_lock(&ctx_mutex);
1196 	if (num_gss_contexts >= max_gss_contexts) {
1197 		/*
1198 		 * now try on LRU basis
1199 		 */
1200 		drop_lru_client();
1201 		if (num_gss_contexts >= max_gss_contexts) {
1202 			mutex_unlock(&ctx_mutex);
1203 			free((char *)client_data);
1204 			return (NULL);
1205 		}
1206 	}
1207 
1208 	/*
1209 	 * The client context handle is a 32-bit key (unsigned int).
1210 	 * The key is incremented until there is no duplicate for it.
1211 	 */
1212 	for (;;) {
1213 		client_data->key = key++;
1214 		if (find_client(client_data->key) == NULL) {
1215 			insert_client(client_data);
1216 			/*
1217 			 * Set cleanup callback if we haven't.
1218 			 */
1219 			if (!cleanup_cb_set) {
1220 				old_cleanup_cb =
1221 					(void (*)()) __svc_set_proc_cleanup_cb(
1222 							(void *)ctx_cleanup);
1223 				cleanup_cb_set = TRUE;
1224 			}
1225 			mutex_unlock(&ctx_mutex);
1226 			return (client_data);
1227 		}
1228 	}
1229 	/*NOTREACHED*/
1230 }
1231 
1232 /*
1233  * Insert client context into hash list and LRU list.
1234  */
1235 static void
1236 insert_client(client_data)
1237 	svc_rpc_gss_data	*client_data;
1238 {
1239 	svc_rpc_gss_data	*cl;
1240 	int			index = (client_data->key & HASHMASK);
1241 
1242 	client_data->prev = NULL;
1243 	cl = clients[index];
1244 	if ((client_data->next = cl) != NULL)
1245 		cl->prev = client_data;
1246 	clients[index] = client_data;
1247 
1248 	client_data->lru_prev = NULL;
1249 	if ((client_data->lru_next = lru_first) != NULL)
1250 		lru_first->lru_prev = client_data;
1251 	else
1252 		lru_last = client_data;
1253 	lru_first = client_data;
1254 
1255 	num_gss_contexts++;
1256 }
1257 
1258 /*
1259  * Fetch a client, given the client context handle.  Move it to the
1260  * top of the LRU list since this is the most recently used context.
1261  */
1262 static svc_rpc_gss_data *
1263 get_client(ctx_handle)
1264 	gss_buffer_t		ctx_handle;
1265 {
1266 	uint_t			key = *(uint_t *)ctx_handle->value;
1267 	svc_rpc_gss_data	*cl;
1268 
1269 	mutex_lock(&ctx_mutex);
1270 	if ((cl = find_client(key)) != NULL) {
1271 		mutex_lock(&cl->clm);
1272 		if (cl->stale) {
1273 			mutex_unlock(&cl->clm);
1274 			mutex_unlock(&ctx_mutex);
1275 			return (NULL);
1276 		}
1277 		cl->ref_cnt++;
1278 		mutex_unlock(&cl->clm);
1279 		if (cl != lru_first) {
1280 			cl->lru_prev->lru_next = cl->lru_next;
1281 			if (cl->lru_next != NULL)
1282 				cl->lru_next->lru_prev = cl->lru_prev;
1283 			else
1284 				lru_last = cl->lru_prev;
1285 			cl->lru_prev = NULL;
1286 			cl->lru_next = lru_first;
1287 			lru_first->lru_prev = cl;
1288 			lru_first = cl;
1289 		}
1290 	}
1291 	mutex_unlock(&ctx_mutex);
1292 	return (cl);
1293 }
1294 
1295 /*
1296  * Given the client context handle, find the context corresponding to it.
1297  * Don't change its LRU state since it may not be used.
1298  */
1299 static svc_rpc_gss_data *
1300 find_client(key)
1301 	uint_t			key;
1302 {
1303 	int			index = (key & HASHMASK);
1304 	svc_rpc_gss_data	*cl;
1305 
1306 	for (cl = clients[index]; cl != NULL; cl = cl->next) {
1307 		if (cl->key == key)
1308 			break;
1309 	}
1310 	return (cl);
1311 }
1312 
1313 /*
1314  * Destroy a client context.
1315  */
1316 static void
1317 destroy_client(client_data)
1318 	svc_rpc_gss_data	*client_data;
1319 {
1320 	OM_uint32		minor;
1321 	int			index = (client_data->key & HASHMASK);
1322 
1323 	/*
1324 	 * remove from hash list
1325 	 */
1326 	if (client_data->prev == NULL)
1327 		clients[index] = client_data->next;
1328 	else
1329 		client_data->prev->next = client_data->next;
1330 	if (client_data->next != NULL)
1331 		client_data->next->prev = client_data->prev;
1332 
1333 	/*
1334 	 * remove from LRU list
1335 	 */
1336 	if (client_data->lru_prev == NULL)
1337 		lru_first = client_data->lru_next;
1338 	else
1339 		client_data->lru_prev->lru_next = client_data->lru_next;
1340 	if (client_data->lru_next != NULL)
1341 		client_data->lru_next->lru_prev = client_data->lru_prev;
1342 	else
1343 		lru_last = client_data->lru_prev;
1344 
1345 	/*
1346 	 * If there is a GSS context, clean up GSS state.
1347 	 */
1348 	if (client_data->context != GSS_C_NO_CONTEXT) {
1349 		(void) gss_delete_sec_context(&minor, &client_data->context,
1350 								NULL);
1351 		if (client_data->client_name)
1352 		    (void) gss_release_name(&minor, &client_data->client_name);
1353 		if (client_data->raw_cred.client_principal)
1354 		    free((char *)client_data->raw_cred.client_principal);
1355 		if (client_data->u_cred.gidlist != NULL)
1356 		    free((char *)client_data->u_cred.gidlist);
1357 		if (client_data->deleg != GSS_C_NO_CREDENTIAL)
1358 		    (void) gss_release_cred(&minor, &client_data->deleg);
1359 	}
1360 
1361 	if (client_data->retrans_data != NULL)
1362 		retrans_del(client_data);
1363 
1364 	free(client_data);
1365 	num_gss_contexts--;
1366 }
1367 
1368 /*
1369  * Check for expired client contexts.
1370  */
1371 static void
1372 sweep_clients()
1373 {
1374 	svc_rpc_gss_data	*cl, *next;
1375 	int			index;
1376 
1377 	for (index = 0; index < HASHMOD; index++) {
1378 		cl = clients[index];
1379 		while (cl) {
1380 			next = cl->next;
1381 			mutex_lock(&cl->clm);
1382 			if ((cl->expiration != GSS_C_INDEFINITE &&
1383 			    cl->expiration <= time(0)) || cl->stale) {
1384 				cl->stale = TRUE;
1385 				if (cl->ref_cnt == 0) {
1386 					mutex_unlock(&cl->clm);
1387 					destroy_client(cl);
1388 				} else
1389 					mutex_unlock(&cl->clm);
1390 			} else
1391 				mutex_unlock(&cl->clm);
1392 			cl = next;
1393 		}
1394 	}
1395 	last_swept = time(0);
1396 }
1397 
1398 /*
1399  * Drop the least recently used client context, if possible.
1400  */
1401 static void
1402 drop_lru_client()
1403 {
1404 	mutex_lock(&lru_last->clm);
1405 	lru_last->stale = TRUE;
1406 	mutex_unlock(&lru_last->clm);
1407 	if (lru_last->ref_cnt == 0)
1408 		destroy_client(lru_last);
1409 	else
1410 		sweep_clients();
1411 }
1412 
1413 /*
1414  * find service credentials
1415  * return cred if found,
1416  * other wise, NULL
1417  */
1418 
1419 svc_creds_list_t *
1420 find_svc_cred(char *service_name, uint_t program, uint_t version) {
1421 
1422 	svc_creds_list_t	*sc;
1423 
1424 	if (!svc_creds_list)
1425 		return (NULL);
1426 
1427 	for (sc = svc_creds_list; sc != NULL; sc = sc->next) {
1428 		if (program != sc->program || version != sc->version)
1429 			continue;
1430 
1431 		if (strcmp(service_name, sc->server_name) != 0)
1432 			continue;
1433 		return (sc);
1434 	}
1435 	return (NULL);
1436 }
1437 
1438 /*
1439  * Set the server principal name.
1440  */
1441 bool_t
1442 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version)
1443 	char			*server_name;
1444 	char			*mech;
1445 	OM_uint32		req_time;
1446 	uint_t			program;
1447 	uint_t			version;
1448 {
1449 	gss_name_t		name;
1450 	svc_creds_list_t	*svc_cred;
1451 	gss_OID			mechanism;
1452 	gss_OID_set_desc	oid_set_desc;
1453 	gss_OID_set		oid_set;
1454 	OM_uint32		ret_time;
1455 	OM_uint32		major, minor;
1456 	gss_buffer_desc		name_buf;
1457 
1458 	if (!__rpc_gss_mech_to_oid(mech, &mechanism)) {
1459 		return (FALSE);
1460 	}
1461 
1462 	name_buf.value = server_name;
1463 	name_buf.length = strlen(server_name);
1464 	major = gss_import_name(&minor, &name_buf,
1465 				(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name);
1466 	if (major != GSS_S_COMPLETE) {
1467 		return (FALSE);
1468 	}
1469 
1470 	/* Check if there is already an entry in the svc_creds_list. */
1471 	rw_wrlock(&cred_lock);
1472 	if (svc_cred = find_svc_cred(server_name, program, version)) {
1473 
1474 		major = gss_add_cred(&minor, svc_cred->cred, name,
1475 					mechanism, GSS_C_ACCEPT,
1476 					0, req_time, NULL,
1477 					&oid_set, NULL,
1478 					&ret_time);
1479 		(void) gss_release_name(&minor, &name);
1480 		if (major == GSS_S_COMPLETE) {
1481 			/*
1482 			 * Successfully added the mech to the cred handle
1483 			 * free the existing oid_set in svc_cred
1484 			 */
1485 			gss_release_oid_set(&minor, &svc_cred->oid_set);
1486 			svc_cred->oid_set = oid_set;
1487 			rw_unlock(&cred_lock);
1488 			return (TRUE);
1489 		} else if (major == GSS_S_DUPLICATE_ELEMENT) {
1490 			rw_unlock(&cred_lock);
1491 			return (TRUE);
1492 		} else if (major == GSS_S_CREDENTIALS_EXPIRED) {
1493 			if (rpc_gss_refresh_svc_cred(svc_cred)) {
1494 				rw_unlock(&cred_lock);
1495 				return (TRUE);
1496 			} else {
1497 				rw_unlock(&cred_lock);
1498 				return (FALSE);
1499 			}
1500 		} else {
1501 			rw_unlock(&cred_lock);
1502 			return (FALSE);
1503 		}
1504 	} else {
1505 		svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred));
1506 		if (svc_cred == NULL) {
1507 			(void) gss_release_name(&minor, &name);
1508 			rw_unlock(&cred_lock);
1509 			return (FALSE);
1510 		}
1511 		oid_set_desc.count = 1;
1512 		oid_set_desc.elements = mechanism;
1513 		major = gss_acquire_cred(&minor, name, req_time,
1514 						&oid_set_desc,
1515 						GSS_C_ACCEPT,
1516 						&svc_cred->cred,
1517 						&oid_set, &ret_time);
1518 
1519 		if (major != GSS_S_COMPLETE) {
1520 			(void) gss_release_name(&minor, &name);
1521 			free(svc_cred);
1522 			rw_unlock(&cred_lock);
1523 			return (FALSE);
1524 		}
1525 
1526 		svc_cred->name = name;
1527 		svc_cred->program = program;
1528 		svc_cred->version = version;
1529 		svc_cred->req_time = req_time;
1530 		svc_cred->oid_set = oid_set;
1531 		svc_cred->server_name = strdup(server_name);
1532 		if (svc_cred->server_name == NULL) {
1533 			(void) gss_release_name(&minor, &name);
1534 			free((char *)svc_cred);
1535 			rw_unlock(&cred_lock);
1536 			return (FALSE);
1537 		}
1538 		mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL);
1539 
1540 		svc_cred->next = svc_creds_list;
1541 		svc_creds_list = svc_cred;
1542 		svc_creds_count++;
1543 		rw_unlock(&cred_lock);
1544 
1545 		return (TRUE);
1546 	}
1547 }
1548 /*
1549  * Refresh server credentials.
1550  */
1551 static bool_t
1552 rpc_gss_refresh_svc_cred(svc_cred)
1553 	svc_creds_list_t	*svc_cred;
1554 {
1555 	OM_uint32		major, minor;
1556 	gss_OID_set		oid_set;
1557 	OM_uint32		ret_time;
1558 
1559 	(void) gss_release_cred(&minor, &svc_cred->cred);
1560 	svc_cred->cred = GSS_C_NO_CREDENTIAL;
1561 	major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time,
1562 		svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set,
1563 		&ret_time);
1564 	if (major != GSS_S_COMPLETE) {
1565 		return (FALSE);
1566 	}
1567 	gss_release_oid_set(&minor, &svc_cred->oid_set);
1568 	svc_cred->oid_set = oid_set;
1569 	return (TRUE);
1570 }
1571 
1572 /*
1573  * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1574  * and write the result to xdrs.
1575  */
1576 static bool_t
1577 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1578 	SVCAUTH			*auth;
1579 	XDR			*out_xdrs;
1580 	bool_t			(*xdr_func)();
1581 	caddr_t			xdr_ptr;
1582 {
1583 	svc_rpc_gss_parms_t	*gss_parms = &auth->svc_gss_parms;
1584 
1585 	/*
1586 	 * If context is not established, or if neither integrity nor
1587 	 * privacy service is used, don't wrap - just XDR encode.
1588 	 * Otherwise, wrap data using service and QOP parameters.
1589 	 */
1590 	if (!gss_parms->established ||
1591 				gss_parms->service == rpc_gss_svc_none)
1592 		return ((*xdr_func)(out_xdrs, xdr_ptr));
1593 
1594 	return (__rpc_gss_wrap_data(gss_parms->service,
1595 				(OM_uint32)gss_parms->qop_rcvd,
1596 				(gss_ctx_id_t)gss_parms->context,
1597 				gss_parms->seq_num,
1598 				out_xdrs, xdr_func, xdr_ptr));
1599 }
1600 
1601 /*
1602  * Decrypt the serialized arguments and XDR decode them.
1603  */
1604 static bool_t
1605 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1606 	SVCAUTH			*auth;
1607 	XDR			*in_xdrs;
1608 	bool_t			(*xdr_func)();
1609 	caddr_t			xdr_ptr;
1610 {
1611 	svc_rpc_gss_parms_t	*gss_parms = &auth->svc_gss_parms;
1612 
1613 	/*
1614 	 * If context is not established, or if neither integrity nor
1615 	 * privacy service is used, don't unwrap - just XDR decode.
1616 	 * Otherwise, unwrap data.
1617 	 */
1618 	if (!gss_parms->established ||
1619 				gss_parms->service == rpc_gss_svc_none)
1620 		return ((*xdr_func)(in_xdrs, xdr_ptr));
1621 
1622 	return (__rpc_gss_unwrap_data(gss_parms->service,
1623 				(gss_ctx_id_t)gss_parms->context,
1624 				gss_parms->seq_num,
1625 				gss_parms->qop_rcvd,
1626 				in_xdrs, xdr_func, xdr_ptr));
1627 }
1628 
1629 int
1630 __rpc_gss_svc_max_data_length(req, max_tp_unit_len)
1631 	struct svc_req	*req;
1632 	int		max_tp_unit_len;
1633 {
1634 	SVCAUTH			*svcauth;
1635 	svc_rpc_gss_parms_t	*gss_parms;
1636 
1637 	svcauth = __svc_get_svcauth(req->rq_xprt);
1638 	gss_parms = &svcauth->svc_gss_parms;
1639 
1640 	if (!gss_parms->established || max_tp_unit_len <= 0)
1641 		return (0);
1642 
1643 	return (__find_max_data_length(gss_parms->service,
1644 			(gss_ctx_id_t)gss_parms->context,
1645 			gss_parms->qop_rcvd, max_tp_unit_len));
1646 }
1647 
1648 /*
1649  * Add retransmit entry to the context cache entry for a new xid.
1650  * If there is already an entry, delete it before adding the new one.
1651  */
1652 static void retrans_add(client, xid, result)
1653 	svc_rpc_gss_data *client;
1654 	uint32_t	xid;
1655 	rpc_gss_init_res *result;
1656 {
1657 	retrans_entry	*rdata;
1658 
1659 	if (client->retrans_data && client->retrans_data->xid == xid)
1660 		return;
1661 
1662 	rdata = (retrans_entry *) malloc(sizeof (*rdata));
1663 	if (rdata == NULL)
1664 		return;
1665 
1666 	rdata->xid = xid;
1667 	rdata->result = *result;
1668 
1669 	if (result->token.length != 0) {
1670 		GSS_DUP_BUFFER(rdata->result.token, result->token);
1671 	}
1672 
1673 	if (client->retrans_data)
1674 		retrans_del(client);
1675 
1676 	client->retrans_data = rdata;
1677 }
1678 
1679 /*
1680  * Delete the retransmit data from the context cache entry.
1681  */
1682 static void retrans_del(client)
1683 	svc_rpc_gss_data *client;
1684 {
1685 	retrans_entry *rdata;
1686 	OM_uint32 minor_stat;
1687 
1688 	if (client->retrans_data == NULL)
1689 		return;
1690 
1691 	rdata = client->retrans_data;
1692 	if (rdata->result.token.length != 0) {
1693 		(void) gss_release_buffer(&minor_stat, &rdata->result.token);
1694 	}
1695 
1696 	free((caddr_t)rdata);
1697 	client->retrans_data = NULL;
1698 }
1699