xref: /titanic_51/usr/src/lib/rpcsec_gss/svc_rpcsec_gss.c (revision b3697b90e692e3e5d859fb77d285d4c056d99eda)
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 2008 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 = 0;
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 
1101 	oa = &msg->rm_call.cb_cred;
1102 	if (oa->oa_length > MAX_AUTH_BYTES)
1103 		return (FALSE);
1104 
1105 	/* 8 XDR units from the IXDR macro calls. */
1106 	if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1107 			    RNDUP(oa->oa_length)))
1108 		return (FALSE);
1109 	buf = hdr;
1110 
1111 	IXDR_PUT_U_INT32(buf, msg->rm_xid);
1112 	IXDR_PUT_ENUM(buf, msg->rm_direction);
1113 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1114 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1115 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1116 	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1117 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
1118 	IXDR_PUT_U_INT32(buf, oa->oa_length);
1119 	if (oa->oa_length) {
1120 		len = RNDUP(oa->oa_length);
1121 		tmp = buf;
1122 		buf += len / sizeof (int);
1123 		*(buf - 1) = 0;
1124 		(void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length);
1125 	}
1126 	len = ((char *)buf) - (char *)hdr;
1127 	msg_buf.length = len;
1128 	msg_buf.value = (char *)hdr;
1129 	oa = &msg->rm_call.cb_verf;
1130 	tok_buf.length = oa->oa_length;
1131 	tok_buf.value = oa->oa_base;
1132 
1133 	gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1134 				qop_state);
1135 	if (gssstat != GSS_S_COMPLETE)
1136 		return (FALSE);
1137 	return (TRUE);
1138 }
1139 
1140 /*
1141  * Set response verifier.  This is the checksum of the given number.
1142  * (e.g. sequence number or sequence window)
1143  */
1144 static bool_t
1145 set_response_verf(rqst, msg, cl, num)
1146 	struct svc_req		*rqst;
1147 	struct rpc_msg		*msg;
1148 	svc_rpc_gss_data	*cl;
1149 	uint_t			num;
1150 {
1151 	OM_uint32		minor;
1152 	gss_buffer_desc		in_buf, out_buf;
1153 	uint_t			num_net;
1154 
1155 	num_net = (uint_t)htonl(num);
1156 	in_buf.length = sizeof (num);
1157 	in_buf.value = (char *)&num_net;
1158 	if (gss_sign(&minor, cl->context, cl->qop, &in_buf,
1159 					&out_buf) != GSS_S_COMPLETE)
1160 		return (FALSE);
1161 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1162 	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1163 	rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1164 	memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value,
1165 		out_buf.length);
1166 	(void) gss_release_buffer(&minor, &out_buf);
1167 	return (TRUE);
1168 }
1169 
1170 /*
1171  * Create client context.
1172  */
1173 static svc_rpc_gss_data *
1174 create_client()
1175 {
1176 	svc_rpc_gss_data	*client_data;
1177 	static uint_t		key = 1;
1178 
1179 	client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data));
1180 	if (client_data == NULL)
1181 		return (NULL);
1182 	memset((char *)client_data, 0, sizeof (*client_data));
1183 
1184 	/*
1185 	 * set up client data structure
1186 	 */
1187 	client_data->established = FALSE;
1188 	client_data->locked = FALSE;
1189 	client_data->u_cred_set = FALSE;
1190 	client_data->context = GSS_C_NO_CONTEXT;
1191 	client_data->expiration = init_lifetime + time(0);
1192 	client_data->ref_cnt = 1;
1193 	client_data->qop = GSS_C_QOP_DEFAULT;
1194 	client_data->done_docallback = FALSE;
1195 	client_data->stale = FALSE;
1196 	client_data->time_secs_set = 0;
1197 	client_data->retrans_data = NULL;
1198 	mutex_init(&client_data->clm, USYNC_THREAD, NULL);
1199 	/*
1200 	 * Check totals.  If we've hit the limit, we destroy a context
1201 	 * based on LRU method.
1202 	 */
1203 	mutex_lock(&ctx_mutex);
1204 	if (num_gss_contexts >= max_gss_contexts) {
1205 		/*
1206 		 * now try on LRU basis
1207 		 */
1208 		drop_lru_client();
1209 		if (num_gss_contexts >= max_gss_contexts) {
1210 			mutex_unlock(&ctx_mutex);
1211 			free((char *)client_data);
1212 			return (NULL);
1213 		}
1214 	}
1215 
1216 	/*
1217 	 * The client context handle is a 32-bit key (unsigned int).
1218 	 * The key is incremented until there is no duplicate for it.
1219 	 */
1220 	for (;;) {
1221 		client_data->key = key++;
1222 		if (find_client(client_data->key) == NULL) {
1223 			insert_client(client_data);
1224 			/*
1225 			 * Set cleanup callback if we haven't.
1226 			 */
1227 			if (!cleanup_cb_set) {
1228 				old_cleanup_cb =
1229 				    (void (*)()) __svc_set_proc_cleanup_cb(
1230 				    (void *)ctx_cleanup);
1231 				cleanup_cb_set = TRUE;
1232 			}
1233 			mutex_unlock(&ctx_mutex);
1234 			return (client_data);
1235 		}
1236 	}
1237 	/*NOTREACHED*/
1238 }
1239 
1240 /*
1241  * Insert client context into hash list and LRU list.
1242  */
1243 static void
1244 insert_client(client_data)
1245 	svc_rpc_gss_data	*client_data;
1246 {
1247 	svc_rpc_gss_data	*cl;
1248 	int			index = (client_data->key & HASHMASK);
1249 
1250 	client_data->prev = NULL;
1251 	cl = clients[index];
1252 	if ((client_data->next = cl) != NULL)
1253 		cl->prev = client_data;
1254 	clients[index] = client_data;
1255 
1256 	client_data->lru_prev = NULL;
1257 	if ((client_data->lru_next = lru_first) != NULL)
1258 		lru_first->lru_prev = client_data;
1259 	else
1260 		lru_last = client_data;
1261 	lru_first = client_data;
1262 
1263 	num_gss_contexts++;
1264 }
1265 
1266 /*
1267  * Fetch a client, given the client context handle.  Move it to the
1268  * top of the LRU list since this is the most recently used context.
1269  */
1270 static svc_rpc_gss_data *
1271 get_client(ctx_handle)
1272 	gss_buffer_t		ctx_handle;
1273 {
1274 	uint_t			key = *(uint_t *)ctx_handle->value;
1275 	svc_rpc_gss_data	*cl;
1276 
1277 	mutex_lock(&ctx_mutex);
1278 	if ((cl = find_client(key)) != NULL) {
1279 		mutex_lock(&cl->clm);
1280 		if (cl->stale) {
1281 			mutex_unlock(&cl->clm);
1282 			mutex_unlock(&ctx_mutex);
1283 			return (NULL);
1284 		}
1285 		cl->ref_cnt++;
1286 		mutex_unlock(&cl->clm);
1287 		if (cl != lru_first) {
1288 			cl->lru_prev->lru_next = cl->lru_next;
1289 			if (cl->lru_next != NULL)
1290 				cl->lru_next->lru_prev = cl->lru_prev;
1291 			else
1292 				lru_last = cl->lru_prev;
1293 			cl->lru_prev = NULL;
1294 			cl->lru_next = lru_first;
1295 			lru_first->lru_prev = cl;
1296 			lru_first = cl;
1297 		}
1298 	}
1299 	mutex_unlock(&ctx_mutex);
1300 	return (cl);
1301 }
1302 
1303 /*
1304  * Given the client context handle, find the context corresponding to it.
1305  * Don't change its LRU state since it may not be used.
1306  */
1307 static svc_rpc_gss_data *
1308 find_client(key)
1309 	uint_t			key;
1310 {
1311 	int			index = (key & HASHMASK);
1312 	svc_rpc_gss_data	*cl;
1313 
1314 	for (cl = clients[index]; cl != NULL; cl = cl->next) {
1315 		if (cl->key == key)
1316 			break;
1317 	}
1318 	return (cl);
1319 }
1320 
1321 /*
1322  * Destroy a client context.
1323  */
1324 static void
1325 destroy_client(client_data)
1326 	svc_rpc_gss_data	*client_data;
1327 {
1328 	OM_uint32		minor;
1329 	int			index = (client_data->key & HASHMASK);
1330 
1331 	/*
1332 	 * remove from hash list
1333 	 */
1334 	if (client_data->prev == NULL)
1335 		clients[index] = client_data->next;
1336 	else
1337 		client_data->prev->next = client_data->next;
1338 	if (client_data->next != NULL)
1339 		client_data->next->prev = client_data->prev;
1340 
1341 	/*
1342 	 * remove from LRU list
1343 	 */
1344 	if (client_data->lru_prev == NULL)
1345 		lru_first = client_data->lru_next;
1346 	else
1347 		client_data->lru_prev->lru_next = client_data->lru_next;
1348 	if (client_data->lru_next != NULL)
1349 		client_data->lru_next->lru_prev = client_data->lru_prev;
1350 	else
1351 		lru_last = client_data->lru_prev;
1352 
1353 	/*
1354 	 * If there is a GSS context, clean up GSS state.
1355 	 */
1356 	if (client_data->context != GSS_C_NO_CONTEXT) {
1357 		(void) gss_delete_sec_context(&minor, &client_data->context,
1358 								NULL);
1359 		if (client_data->client_name)
1360 		    (void) gss_release_name(&minor, &client_data->client_name);
1361 		if (client_data->raw_cred.client_principal)
1362 		    free((char *)client_data->raw_cred.client_principal);
1363 		if (client_data->u_cred.gidlist != NULL)
1364 		    free((char *)client_data->u_cred.gidlist);
1365 		if (client_data->deleg != GSS_C_NO_CREDENTIAL)
1366 		    (void) gss_release_cred(&minor, &client_data->deleg);
1367 	}
1368 
1369 	if (client_data->retrans_data != NULL)
1370 		retrans_del(client_data);
1371 
1372 	free(client_data);
1373 	num_gss_contexts--;
1374 }
1375 
1376 /*
1377  * Check for expired client contexts.
1378  */
1379 static void
1380 sweep_clients()
1381 {
1382 	svc_rpc_gss_data	*cl, *next;
1383 	int			index;
1384 
1385 	for (index = 0; index < HASHMOD; index++) {
1386 		cl = clients[index];
1387 		while (cl) {
1388 			next = cl->next;
1389 			mutex_lock(&cl->clm);
1390 			if ((cl->expiration != GSS_C_INDEFINITE &&
1391 			    cl->expiration <= time(0)) || cl->stale) {
1392 				cl->stale = TRUE;
1393 				if (cl->ref_cnt == 0) {
1394 					mutex_unlock(&cl->clm);
1395 					destroy_client(cl);
1396 				} else
1397 					mutex_unlock(&cl->clm);
1398 			} else
1399 				mutex_unlock(&cl->clm);
1400 			cl = next;
1401 		}
1402 	}
1403 	last_swept = time(0);
1404 }
1405 
1406 /*
1407  * Drop the least recently used client context, if possible.
1408  */
1409 static void
1410 drop_lru_client()
1411 {
1412 	mutex_lock(&lru_last->clm);
1413 	lru_last->stale = TRUE;
1414 	mutex_unlock(&lru_last->clm);
1415 	if (lru_last->ref_cnt == 0)
1416 		destroy_client(lru_last);
1417 	else
1418 		sweep_clients();
1419 }
1420 
1421 /*
1422  * find service credentials
1423  * return cred if found,
1424  * other wise, NULL
1425  */
1426 
1427 svc_creds_list_t *
1428 find_svc_cred(char *service_name, uint_t program, uint_t version) {
1429 
1430 	svc_creds_list_t	*sc;
1431 
1432 	if (!svc_creds_list)
1433 		return (NULL);
1434 
1435 	for (sc = svc_creds_list; sc != NULL; sc = sc->next) {
1436 		if (program != sc->program || version != sc->version)
1437 			continue;
1438 
1439 		if (strcmp(service_name, sc->server_name) != 0)
1440 			continue;
1441 		return (sc);
1442 	}
1443 	return (NULL);
1444 }
1445 
1446 /*
1447  * Set the server principal name.
1448  */
1449 bool_t
1450 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version)
1451 	char			*server_name;
1452 	char			*mech;
1453 	OM_uint32		req_time;
1454 	uint_t			program;
1455 	uint_t			version;
1456 {
1457 	gss_name_t		name;
1458 	svc_creds_list_t	*svc_cred;
1459 	gss_OID			mechanism;
1460 	gss_OID_set_desc	oid_set_desc;
1461 	gss_OID_set		oid_set;
1462 	OM_uint32		ret_time;
1463 	OM_uint32		major, minor;
1464 	gss_buffer_desc		name_buf;
1465 
1466 	if (!__rpc_gss_mech_to_oid(mech, &mechanism)) {
1467 		return (FALSE);
1468 	}
1469 
1470 	name_buf.value = server_name;
1471 	name_buf.length = strlen(server_name);
1472 	major = gss_import_name(&minor, &name_buf,
1473 				(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name);
1474 	if (major != GSS_S_COMPLETE) {
1475 		return (FALSE);
1476 	}
1477 
1478 	/* Check if there is already an entry in the svc_creds_list. */
1479 	rw_wrlock(&cred_lock);
1480 	if (svc_cred = find_svc_cred(server_name, program, version)) {
1481 
1482 		major = gss_add_cred(&minor, svc_cred->cred, name,
1483 					mechanism, GSS_C_ACCEPT,
1484 					0, req_time, NULL,
1485 					&oid_set, NULL,
1486 					&ret_time);
1487 		(void) gss_release_name(&minor, &name);
1488 		if (major == GSS_S_COMPLETE) {
1489 			/*
1490 			 * Successfully added the mech to the cred handle
1491 			 * free the existing oid_set in svc_cred
1492 			 */
1493 			gss_release_oid_set(&minor, &svc_cred->oid_set);
1494 			svc_cred->oid_set = oid_set;
1495 			rw_unlock(&cred_lock);
1496 			return (TRUE);
1497 		} else if (major == GSS_S_DUPLICATE_ELEMENT) {
1498 			rw_unlock(&cred_lock);
1499 			return (TRUE);
1500 		} else if (major == GSS_S_CREDENTIALS_EXPIRED) {
1501 			if (rpc_gss_refresh_svc_cred(svc_cred)) {
1502 				rw_unlock(&cred_lock);
1503 				return (TRUE);
1504 			} else {
1505 				rw_unlock(&cred_lock);
1506 				return (FALSE);
1507 			}
1508 		} else {
1509 			rw_unlock(&cred_lock);
1510 			return (FALSE);
1511 		}
1512 	} else {
1513 		svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred));
1514 		if (svc_cred == NULL) {
1515 			(void) gss_release_name(&minor, &name);
1516 			rw_unlock(&cred_lock);
1517 			return (FALSE);
1518 		}
1519 		oid_set_desc.count = 1;
1520 		oid_set_desc.elements = mechanism;
1521 		major = gss_acquire_cred(&minor, name, req_time,
1522 						&oid_set_desc,
1523 						GSS_C_ACCEPT,
1524 						&svc_cred->cred,
1525 						&oid_set, &ret_time);
1526 
1527 		if (major != GSS_S_COMPLETE) {
1528 			(void) gss_release_name(&minor, &name);
1529 			free(svc_cred);
1530 			rw_unlock(&cred_lock);
1531 			return (FALSE);
1532 		}
1533 
1534 		svc_cred->name = name;
1535 		svc_cred->program = program;
1536 		svc_cred->version = version;
1537 		svc_cred->req_time = req_time;
1538 		svc_cred->oid_set = oid_set;
1539 		svc_cred->server_name = strdup(server_name);
1540 		if (svc_cred->server_name == NULL) {
1541 			(void) gss_release_name(&minor, &name);
1542 			free((char *)svc_cred);
1543 			rw_unlock(&cred_lock);
1544 			return (FALSE);
1545 		}
1546 		mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL);
1547 
1548 		svc_cred->next = svc_creds_list;
1549 		svc_creds_list = svc_cred;
1550 		svc_creds_count++;
1551 		rw_unlock(&cred_lock);
1552 
1553 		return (TRUE);
1554 	}
1555 }
1556 /*
1557  * Refresh server credentials.
1558  */
1559 static bool_t
1560 rpc_gss_refresh_svc_cred(svc_cred)
1561 	svc_creds_list_t	*svc_cred;
1562 {
1563 	OM_uint32		major, minor;
1564 	gss_OID_set		oid_set;
1565 	OM_uint32		ret_time;
1566 
1567 	(void) gss_release_cred(&minor, &svc_cred->cred);
1568 	svc_cred->cred = GSS_C_NO_CREDENTIAL;
1569 	major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time,
1570 		svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set,
1571 		&ret_time);
1572 	if (major != GSS_S_COMPLETE) {
1573 		return (FALSE);
1574 	}
1575 	gss_release_oid_set(&minor, &svc_cred->oid_set);
1576 	svc_cred->oid_set = oid_set;
1577 	return (TRUE);
1578 }
1579 
1580 /*
1581  * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1582  * and write the result to xdrs.
1583  */
1584 static bool_t
1585 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1586 	SVCAUTH			*auth;
1587 	XDR			*out_xdrs;
1588 	bool_t			(*xdr_func)();
1589 	caddr_t			xdr_ptr;
1590 {
1591 	svc_rpc_gss_parms_t	*gss_parms = &auth->svc_gss_parms;
1592 
1593 	/*
1594 	 * If context is not established, or if neither integrity nor
1595 	 * privacy service is used, don't wrap - just XDR encode.
1596 	 * Otherwise, wrap data using service and QOP parameters.
1597 	 */
1598 	if (!gss_parms->established ||
1599 				gss_parms->service == rpc_gss_svc_none)
1600 		return ((*xdr_func)(out_xdrs, xdr_ptr));
1601 
1602 	return (__rpc_gss_wrap_data(gss_parms->service,
1603 				(OM_uint32)gss_parms->qop_rcvd,
1604 				(gss_ctx_id_t)gss_parms->context,
1605 				gss_parms->seq_num,
1606 				out_xdrs, xdr_func, xdr_ptr));
1607 }
1608 
1609 /*
1610  * Decrypt the serialized arguments and XDR decode them.
1611  */
1612 static bool_t
1613 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1614 	SVCAUTH			*auth;
1615 	XDR			*in_xdrs;
1616 	bool_t			(*xdr_func)();
1617 	caddr_t			xdr_ptr;
1618 {
1619 	svc_rpc_gss_parms_t	*gss_parms = &auth->svc_gss_parms;
1620 
1621 	/*
1622 	 * If context is not established, or if neither integrity nor
1623 	 * privacy service is used, don't unwrap - just XDR decode.
1624 	 * Otherwise, unwrap data.
1625 	 */
1626 	if (!gss_parms->established ||
1627 				gss_parms->service == rpc_gss_svc_none)
1628 		return ((*xdr_func)(in_xdrs, xdr_ptr));
1629 
1630 	return (__rpc_gss_unwrap_data(gss_parms->service,
1631 				(gss_ctx_id_t)gss_parms->context,
1632 				gss_parms->seq_num,
1633 				gss_parms->qop_rcvd,
1634 				in_xdrs, xdr_func, xdr_ptr));
1635 }
1636 
1637 int
1638 __rpc_gss_svc_max_data_length(req, max_tp_unit_len)
1639 	struct svc_req	*req;
1640 	int		max_tp_unit_len;
1641 {
1642 	SVCAUTH			*svcauth;
1643 	svc_rpc_gss_parms_t	*gss_parms;
1644 
1645 	svcauth = __svc_get_svcauth(req->rq_xprt);
1646 	gss_parms = &svcauth->svc_gss_parms;
1647 
1648 	if (!gss_parms->established || max_tp_unit_len <= 0)
1649 		return (0);
1650 
1651 	return (__find_max_data_length(gss_parms->service,
1652 			(gss_ctx_id_t)gss_parms->context,
1653 			gss_parms->qop_rcvd, max_tp_unit_len));
1654 }
1655 
1656 /*
1657  * Add retransmit entry to the context cache entry for a new xid.
1658  * If there is already an entry, delete it before adding the new one.
1659  */
1660 static void retrans_add(client, xid, result)
1661 	svc_rpc_gss_data *client;
1662 	uint32_t	xid;
1663 	rpc_gss_init_res *result;
1664 {
1665 	retrans_entry	*rdata;
1666 
1667 	if (client->retrans_data && client->retrans_data->xid == xid)
1668 		return;
1669 
1670 	rdata = (retrans_entry *) malloc(sizeof (*rdata));
1671 	if (rdata == NULL)
1672 		return;
1673 
1674 	rdata->xid = xid;
1675 	rdata->result = *result;
1676 
1677 	if (result->token.length != 0) {
1678 		GSS_DUP_BUFFER(rdata->result.token, result->token);
1679 	}
1680 
1681 	if (client->retrans_data)
1682 		retrans_del(client);
1683 
1684 	client->retrans_data = rdata;
1685 }
1686 
1687 /*
1688  * Delete the retransmit data from the context cache entry.
1689  */
1690 static void retrans_del(client)
1691 	svc_rpc_gss_data *client;
1692 {
1693 	retrans_entry *rdata;
1694 	OM_uint32 minor_stat;
1695 
1696 	if (client->retrans_data == NULL)
1697 		return;
1698 
1699 	rdata = client->retrans_data;
1700 	if (rdata->result.token.length != 0) {
1701 		(void) gss_release_buffer(&minor_stat, &rdata->result.token);
1702 	}
1703 
1704 	free((caddr_t)rdata);
1705 	client->retrans_data = NULL;
1706 }
1707