Home | History | Annotate | Download | only in rpcsec_gss
      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