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