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