Home | History | Annotate | Download | only in sec_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  4321    casper  * Common Development and Distribution License (the "License").
      6  4321    casper  * 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     0    stevel /*
     22  6403   gt29601  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel /*
     27     0    stevel  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
     28     0    stevel  *
     29     0    stevel  * $Header:
     30     0    stevel  * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi.c,v
     31     0    stevel  * 1.14 1995/03/22 22:07:55 jik Exp $
     32     0    stevel  */
     33     0    stevel 
     34     0    stevel #include  <sys/systm.h>
     35     0    stevel #include  <sys/types.h>
     36     0    stevel #include  <gssapi/gssapi.h>
     37     0    stevel #include  <rpc/rpc.h>
     38     0    stevel #include  <rpc/rpcsec_defs.h>
     39     0    stevel #include  <sys/debug.h>
     40     0    stevel #include  <sys/cmn_err.h>
     41     0    stevel #include  <sys/ddi.h>
     42     0    stevel 
     43     0    stevel static	void	rpc_gss_nextverf();
     44     0    stevel static	bool_t	rpc_gss_marshall();
     45     0    stevel static	bool_t	rpc_gss_validate();
     46     0    stevel static	bool_t	rpc_gss_refresh();
     47     0    stevel static	void	rpc_gss_destroy();
     48     0    stevel #if 0
     49     0    stevel static	void	rpc_gss_destroy_pvt();
     50     0    stevel #endif
     51     0    stevel static	void	rpc_gss_free_pvt();
     52     0    stevel static	int	rpc_gss_seccreate_pvt();
     53     0    stevel static  bool_t	rpc_gss_wrap();
     54     0    stevel static  bool_t	rpc_gss_unwrap();
     55     0    stevel static	bool_t	validate_seqwin();
     56     0    stevel 
     57     0    stevel 
     58     0    stevel #ifdef	DEBUG
     59     0    stevel #include <sys/promif.h>
     60     0    stevel #endif
     61     0    stevel 
     62     0    stevel static struct auth_ops rpc_gss_ops = {
     63     0    stevel 	rpc_gss_nextverf,
     64     0    stevel 	rpc_gss_marshall,
     65     0    stevel 	rpc_gss_validate,
     66     0    stevel 	rpc_gss_refresh,
     67     0    stevel 	rpc_gss_destroy,
     68     0    stevel 	rpc_gss_wrap,
     69     0    stevel 	rpc_gss_unwrap,
     70     0    stevel };
     71     0    stevel 
     72     0    stevel /*
     73     0    stevel  * Private data for RPCSEC_GSS.
     74     0    stevel  */
     75     0    stevel typedef struct _rpc_gss_data {
     76     0    stevel 	bool_t		established;	/* TRUE when established */
     77     0    stevel 	CLIENT		*clnt;		/* associated client handle */
     78     0    stevel 	int		version;	/* RPCSEC version */
     79     0    stevel 	gss_ctx_id_t	context;	/* GSS context id */
     80     0    stevel 	gss_buffer_desc	ctx_handle;	/* RPCSEC GSS context handle */
     81     0    stevel 	uint_t		seq_num;	/* last sequence number rcvd */
     82     0    stevel 	gss_cred_id_t	my_cred;	/* caller's GSS credentials */
     83     0    stevel 	OM_uint32	qop;		/* requested QOP */
     84     0    stevel 	rpc_gss_service_t	service;	/* requested service */
     85     0    stevel 	uint_t		gss_proc;	/* GSS control procedure */
     86     0    stevel 	gss_name_t	target_name;	/* target server */
     87     0    stevel 	int		req_flags;	/* GSS request bits */
     88     0    stevel 	gss_OID		mech_type;	/* GSS mechanism */
     89     0    stevel 	OM_uint32	time_req;	/* requested cred lifetime */
     90     0    stevel 	bool_t		invalid;	/* can't use this any more */
     91     0    stevel 	OM_uint32	seq_window;	/* server sequence window */
     92     0    stevel 	struct opaque_auth *verifier;	/* rpc reply verifier saved for */
     93     0    stevel 					/* validating the sequence window */
     94     0    stevel 	gss_channel_bindings_t	icb;
     95     0    stevel } rpc_gss_data;
     96     0    stevel #define	AUTH_PRIVATE(auth)	((rpc_gss_data *)auth->ah_private)
     97     0    stevel 
     98     0    stevel #define	INTERRUPT_OK	1	/* allow interrupt */
     99     0    stevel 
    100     0    stevel /*
    101     0    stevel  *  RPCSEC_GSS auth cache definitions.
    102     0    stevel  */
    103     0    stevel 
    104     0    stevel /* The table size must be a power of two. */
    105     0    stevel #define	GSSAUTH_TABLESIZE 16
    106     0    stevel #define	HASH(keynum, uid_num) \
    107  4321    casper 	((((intptr_t)(keynum)) ^ ((int)uid_num)) & (GSSAUTH_TABLESIZE - 1))
    108     0    stevel 
    109     0    stevel /*
    110     0    stevel  * gss auth cache entry.
    111     0    stevel  */
    112     0    stevel typedef struct ga_cache_entry {
    113     0    stevel 	void	*cache_key;
    114     0    stevel 	uid_t	uid;
    115     0    stevel 	zoneid_t zoneid;
    116     0    stevel 	bool_t	in_use;
    117     0    stevel 	time_t	ref_time; /* the time referenced previously */
    118     0    stevel 	time_t	ctx_expired_time; /* when the context will be expired */
    119     0    stevel 	AUTH	*auth;
    120     0    stevel 	struct ga_cache_entry *next;
    121     0    stevel } *ga_cache_list;
    122     0    stevel 
    123     0    stevel struct ga_cache_entry	*ga_cache_table[GSSAUTH_TABLESIZE];
    124     0    stevel static krwlock_t	ga_cache_table_lock;
    125     0    stevel static struct kmem_cache *ga_cache_handle;
    126     0    stevel static void gssauth_cache_reclaim(void *);
    127     0    stevel 
    128     0    stevel static void gssauth_zone_fini(zoneid_t, void *);
    129     0    stevel static zone_key_t	gssauth_zone_key;
    130     0    stevel 
    131     0    stevel int ga_cache_hit;
    132     0    stevel int ga_cache_miss;
    133     0    stevel int ga_cache_reclaim;
    134     0    stevel 
    135     0    stevel #define	NOT_DEAD(ptr)	ASSERT((((intptr_t)(ptr)) != 0xdeadbeef))
    136     0    stevel 
    137     0    stevel void
    138     0    stevel gssauth_init(void)
    139     0    stevel {
    140     0    stevel 	/*
    141     0    stevel 	 * Initialize gss auth cache table lock
    142     0    stevel 	 */
    143     0    stevel 	rw_init(&ga_cache_table_lock, NULL, RW_DEFAULT, NULL);
    144     0    stevel 
    145     0    stevel 	/*
    146     0    stevel 	 * Allocate gss auth cache handle
    147     0    stevel 	 */
    148     0    stevel 	ga_cache_handle = kmem_cache_create("ga_cache_handle",
    149  6403   gt29601 	    sizeof (struct ga_cache_entry), 0, NULL, NULL,
    150  6403   gt29601 	    gssauth_cache_reclaim, NULL, NULL, 0);
    151     0    stevel 	zone_key_create(&gssauth_zone_key, NULL, NULL, gssauth_zone_fini);
    152     0    stevel }
    153     0    stevel 
    154     0    stevel /*
    155     0    stevel  * Destroy the structures previously initialized in gssauth_init()
    156     0    stevel  * This routine is called by _init() if mod_install() failed.
    157     0    stevel  */
    158     0    stevel void
    159     0    stevel gssauth_fini(void)
    160     0    stevel {
    161     0    stevel 	(void) zone_key_delete(gssauth_zone_key);
    162     0    stevel 	kmem_cache_destroy(ga_cache_handle);
    163     0    stevel 	rw_destroy(&ga_cache_table_lock);
    164     0    stevel }
    165     0    stevel 
    166     0    stevel /*
    167     0    stevel  * This is a cleanup routine to release cached entries when a zone is being
    168     0    stevel  * destroyed.  The code is also used when kmem calls us to free up memory, at
    169     0    stevel  * which point ``zoneid'' will be ALL_ZONES.  We don't honor the cache timeout
    170     0    stevel  * when the zone is going away, since the zoneid (and all associated cached
    171     0    stevel  * entries) are invalid.
    172     0    stevel  */
    173     0    stevel time_t rpc_gss_cache_time = 60 * 60;
    174     0    stevel 
    175     0    stevel /* ARGSUSED */
    176     0    stevel static void
    177     0    stevel gssauth_zone_fini(zoneid_t zoneid, void *unused)
    178     0    stevel {
    179     0    stevel 	struct ga_cache_entry *p, *prev, *next;
    180     0    stevel 	int i;
    181     0    stevel 	time_t now;
    182     0    stevel 
    183     0    stevel 	rw_enter(&ga_cache_table_lock, RW_WRITER);
    184     0    stevel 
    185     0    stevel 	for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
    186     0    stevel 		prev = NULL;
    187     0    stevel 		for (p = ga_cache_table[i]; p; p = next) {
    188     0    stevel 			NOT_DEAD(p->next);
    189     0    stevel 			next = p->next;
    190     0    stevel 			NOT_DEAD(next);
    191     0    stevel 			if (zoneid == ALL_ZONES) {	/* kmem callback */
    192     0    stevel 				/*
    193     0    stevel 				 * Free entries that have not been
    194     0    stevel 				 * used for rpc_gss_cache_time seconds.
    195     0    stevel 				 */
    196     0    stevel 				now = gethrestime_sec();
    197     0    stevel 				if ((p->ref_time + rpc_gss_cache_time >
    198  6403   gt29601 				    now) || p->in_use) {
    199     0    stevel 					if ((p->ref_time + rpc_gss_cache_time <=
    200  6403   gt29601 					    now) && p->in_use) {
    201     0    stevel 						RPCGSS_LOG0(2, "gssauth_cache_"
    202     0    stevel 						    "reclaim: in_use\n");
    203     0    stevel 					}
    204     0    stevel 					prev = p;
    205     0    stevel 					continue;
    206     0    stevel 				}
    207     0    stevel 			} else {
    208     0    stevel 				if (p->zoneid != zoneid) {
    209     0    stevel 					prev = p;
    210     0    stevel 					continue;
    211     0    stevel 				}
    212     0    stevel 				ASSERT(!p->in_use);
    213     0    stevel 			}
    214     0    stevel 
    215     0    stevel 			RPCGSS_LOG(2, "gssauth_cache_reclaim: destroy auth "
    216  6403   gt29601 			    "%p\n", (void *)p->auth);
    217     0    stevel 			rpc_gss_destroy(p->auth);
    218     0    stevel 			kmem_cache_free(ga_cache_handle, (void *)p);
    219     0    stevel 			if (prev == NULL) {
    220     0    stevel 				ga_cache_table[i] = next;
    221     0    stevel 			} else {
    222     0    stevel 				NOT_DEAD(prev->next);
    223     0    stevel 				prev->next = next;
    224     0    stevel 			}
    225     0    stevel 		}
    226     0    stevel 	}
    227     0    stevel 
    228     0    stevel 	rw_exit(&ga_cache_table_lock);
    229     0    stevel 
    230     0    stevel }
    231     0    stevel 
    232     0    stevel /*
    233     0    stevel  * Called by the kernel memory allocator when
    234     0    stevel  * memory is low. Free unused cache entries.
    235     0    stevel  * If that's not enough, the VM system will
    236     0    stevel  * call again for some more.
    237     0    stevel  */
    238     0    stevel /*ARGSUSED*/
    239     0    stevel static void
    240     0    stevel gssauth_cache_reclaim(void *cdrarg)
    241     0    stevel {
    242     0    stevel 	gssauth_zone_fini(ALL_ZONES, NULL);
    243     0    stevel }
    244     0    stevel 
    245     0    stevel #define	NOT_NULL(ptr)	ASSERT(ptr)
    246     0    stevel #define	IS_ALIGNED(ptr)	ASSERT((((intptr_t)(ptr)) & 3) == 0)
    247     0    stevel 
    248     0    stevel /*
    249     0    stevel  *  Get the client gss security service handle.
    250     0    stevel  *  If it is in the cache table, get it, otherwise, create
    251     0    stevel  *  a new one by calling rpc_gss_seccreate().
    252     0    stevel  */
    253     0    stevel int
    254     0    stevel rpc_gss_secget(CLIENT *clnt,
    255     0    stevel 	char	*principal,
    256     0    stevel 	rpc_gss_OID	mechanism,
    257     0    stevel 	rpc_gss_service_t service_type,
    258     0    stevel 	uint_t	qop,
    259     0    stevel 	rpc_gss_options_req_t *options_req,
    260     0    stevel 	rpc_gss_options_ret_t *options_ret,
    261     0    stevel 	void *cache_key,
    262     0    stevel 	cred_t *cr,
    263     0    stevel 	AUTH **retauth)
    264     0    stevel {
    265     0    stevel 	struct ga_cache_entry **head, *current, *new, *prev;
    266     0    stevel 	AUTH *auth = NULL;
    267     0    stevel 	rpc_gss_data	*ap;
    268     0    stevel 	rpc_gss_options_ret_t opt_ret;
    269     0    stevel 	int status = 0;
    270     0    stevel 	uid_t uid = crgetuid(cr);
    271     0    stevel 	zoneid_t zoneid = getzoneid();
    272     0    stevel 
    273     0    stevel 	if (retauth == NULL)
    274     0    stevel 		return (EINVAL);
    275     0    stevel 	*retauth = NULL;
    276     0    stevel 
    277     0    stevel 	NOT_NULL(cr);
    278     0    stevel 	IS_ALIGNED(cr);
    279     0    stevel #ifdef DEBUG
    280     0    stevel if (HASH(cache_key, uid) < 0) {
    281     0    stevel 	prom_printf("cache_key %p, cr %p\n", cache_key, (void *)cr);
    282     0    stevel }
    283     0    stevel #endif
    284     0    stevel 
    285     0    stevel 	/*
    286     0    stevel 	 *  Get a valid gss auth handle from the cache table.
    287     0    stevel 	 *  If auth in cache is invalid and not in use, destroy it.
    288     0    stevel 	 */
    289     0    stevel 	prev = NULL;
    290     0    stevel 	rw_enter(&ga_cache_table_lock, RW_WRITER);
    291     0    stevel 
    292     0    stevel 	ASSERT(HASH(cache_key, uid) >= 0);
    293     0    stevel 	head = &ga_cache_table[HASH(cache_key, uid)];
    294     0    stevel 	NOT_NULL(head);
    295     0    stevel 	IS_ALIGNED(head);
    296     0    stevel 
    297     0    stevel 	for (current = *head; current; current = current->next) {
    298     0    stevel 		NOT_NULL(current);
    299     0    stevel 		IS_ALIGNED(current);
    300     0    stevel 		if ((cache_key == current->cache_key) &&
    301     0    stevel 			(uid == current->uid) && (zoneid == current->zoneid) &&
    302     0    stevel 			!current->in_use) {
    303     0    stevel 			current->in_use = TRUE;
    304     0    stevel 			current->ref_time = gethrestime_sec();
    305     0    stevel 			ap = AUTH_PRIVATE(current->auth);
    306     0    stevel 			ap->clnt = clnt;
    307     0    stevel 			ga_cache_hit++;
    308     0    stevel 			if (ap->invalid ||
    309     0    stevel 			    ((current->ctx_expired_time != GSS_C_INDEFINITE) &&
    310  6636       gtb 			    (gethrestime_sec() >=
    311     0    stevel 			    current->ctx_expired_time))) {
    312     0    stevel 			    RPCGSS_LOG0(1, "NOTICE: rpc_gss_secget: time to "
    313     0    stevel 					"refresh the auth\n");
    314     0    stevel 			    if (prev == NULL) {
    315     0    stevel 				*head = current->next;
    316     0    stevel 			    } else {
    317     0    stevel 				prev->next = current->next;
    318     0    stevel 			    }
    319     0    stevel 			    rpc_gss_destroy(current->auth);
    320     0    stevel 			    kmem_cache_free(ga_cache_handle, (void *) current);
    321     0    stevel 			    auth = NULL;
    322     0    stevel 			} else {
    323     0    stevel 			    auth = current->auth;
    324     0    stevel 			}
    325     0    stevel 			break;
    326     0    stevel 		} else {
    327     0    stevel 			prev = current;
    328     0    stevel 		}
    329     0    stevel 	}
    330     0    stevel 	rw_exit(&ga_cache_table_lock);
    331     0    stevel 
    332     0    stevel 	/*
    333     0    stevel 	 *  If no valid gss auth handle can be found in the cache, create
    334     0    stevel 	 *  a new one.
    335     0    stevel 	 */
    336     0    stevel 	if (!auth) {
    337     0    stevel 		ga_cache_miss++;
    338     0    stevel 		if (options_ret == NULL)
    339     0    stevel 			options_ret = &opt_ret;
    340     0    stevel 
    341     0    stevel 		status = rpc_gss_seccreate(clnt, principal, mechanism,
    342     0    stevel 			service_type, qop, options_req, options_ret, cr, &auth);
    343     0    stevel 		if (status == 0) {
    344     0    stevel 			RPCGSS_LOG(2, "rpc_gss_secget: new auth %p\n",
    345     0    stevel 					(void *)auth);
    346     0    stevel 			new = kmem_cache_alloc(ga_cache_handle, KM_NOSLEEP);
    347     0    stevel 			IS_ALIGNED(new);
    348     0    stevel 			NOT_DEAD(new);
    349     0    stevel 			if (new) {
    350     0    stevel 				new->cache_key = cache_key;
    351     0    stevel 				new->uid = uid;
    352     0    stevel 				new->zoneid = zoneid;
    353     0    stevel 				new->in_use = TRUE;
    354     0    stevel 				new->ref_time = gethrestime_sec();
    355     0    stevel 				if (options_ret->time_ret != GSS_C_INDEFINITE) {
    356     0    stevel 				    new->ctx_expired_time = new->ref_time +
    357     0    stevel 					options_ret->time_ret;
    358     0    stevel 				} else {
    359     0    stevel 				    new->ctx_expired_time = GSS_C_INDEFINITE;
    360     0    stevel 				}
    361     0    stevel 				new->auth = auth;
    362     0    stevel 				rw_enter(&ga_cache_table_lock, RW_WRITER);
    363     0    stevel 				NOT_DEAD(*head);
    364     0    stevel 				NOT_DEAD(new->next);
    365     0    stevel 				new->next = *head;
    366     0    stevel 				*head = new;
    367     0    stevel 				rw_exit(&ga_cache_table_lock);
    368     0    stevel 			}
    369     0    stevel 			/* done with opt_ret */
    370     0    stevel 			if (options_ret == &opt_ret) {
    371     0    stevel 			    kgss_free_oid((gss_OID) opt_ret.actual_mechanism);
    372     0    stevel 			}
    373     0    stevel 		}
    374     0    stevel 	}
    375     0    stevel 
    376     0    stevel 	*retauth = auth;
    377     0    stevel 	return (status);
    378     0    stevel }
    379     0    stevel 
    380     0    stevel 
    381     0    stevel 
    382     0    stevel /*
    383     0    stevel  *  rpc_gss_secfree will destroy a rpcsec_gss context only if
    384     0    stevel  *  the auth handle is not in the cache table.
    385     0    stevel  */
    386     0    stevel void
    387     0    stevel rpc_gss_secfree(AUTH *auth)
    388     0    stevel {
    389     0    stevel 	struct ga_cache_entry *next, *cur;
    390     0    stevel 	int i;
    391     0    stevel 
    392     0    stevel 	/*
    393     0    stevel 	 *  Check the cache table to find the auth.
    394     0    stevel 	 *  Marked it unused.
    395     0    stevel 	 */
    396     0    stevel 	rw_enter(&ga_cache_table_lock, RW_WRITER);
    397     0    stevel 	for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
    398     0    stevel 		for (cur = ga_cache_table[i]; cur; cur = next) {
    399     0    stevel 			NOT_DEAD(cur);
    400     0    stevel 			next = cur->next;
    401     0    stevel 			NOT_DEAD(next);
    402     0    stevel 			if (cur->auth == auth) {
    403  6403   gt29601 				ASSERT(cur->in_use == TRUE);
    404  6403   gt29601 				cur->in_use = FALSE;
    405  6403   gt29601 				rw_exit(&ga_cache_table_lock);
    406  6403   gt29601 				return;
    407     0    stevel 			}
    408     0    stevel 		}
    409     0    stevel 	}
    410     0    stevel 	rw_exit(&ga_cache_table_lock);
    411     0    stevel 	RPCGSS_LOG(2, "rpc_gss_secfree: destroy auth %p\n", (void *)auth);
    412     0    stevel 	rpc_gss_destroy(auth);
    413     0    stevel }
    414     0    stevel 
    415     0    stevel 
    416     0    stevel /*
    417     0    stevel  *  Create a gss security service context.
    418     0    stevel  */
    419     0    stevel int
    420     0    stevel rpc_gss_seccreate(CLIENT *clnt,
    421     0    stevel 	char			*principal,	/* target service@server */
    422     0    stevel 	rpc_gss_OID		mechanism,	/* security mechanism */
    423     0    stevel 	rpc_gss_service_t	service_type,	/* security service */
    424     0    stevel 	uint_t			qop,		/* requested QOP */
    425     0    stevel 	rpc_gss_options_req_t	*options_req,	/* requested options */
    426     0    stevel 	rpc_gss_options_ret_t	*options_ret,	/* returned options */
    427     0    stevel 	cred_t			*cr,		/* client's unix cred */
    428     0    stevel 	AUTH			**retauth)	/* auth handle */
    429     0    stevel {
    430     0    stevel 	OM_uint32		gssstat;
    431     0    stevel 	OM_uint32		minor_stat;
    432     0    stevel 	gss_name_t		target_name;
    433     0    stevel 	int			ret_flags;
    434     0    stevel 	OM_uint32		time_rec;
    435     0    stevel 	gss_buffer_desc		input_name;
    436     0    stevel 	AUTH			*auth = NULL;
    437     0    stevel 	rpc_gss_data		*ap = NULL;
    438     0    stevel 	int			error;
    439     0    stevel 
    440     0    stevel 	/*
    441     0    stevel 	 * convert name to GSS internal type
    442     0    stevel 	 */
    443     0    stevel 	input_name.value = principal;
    444     0    stevel 	input_name.length = strlen(principal);
    445     0    stevel 
    446     0    stevel 	gssstat = gss_import_name(&minor_stat, &input_name,
    447  6403   gt29601 	    (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target_name);
    448     0    stevel 
    449     0    stevel 	if (gssstat != GSS_S_COMPLETE) {
    450     0    stevel 		RPCGSS_LOG0(1,
    451  6403   gt29601 		    "rpc_gss_seccreate: unable to import gss name\n");
    452     0    stevel 		return (ENOMEM);
    453     0    stevel 	}
    454     0    stevel 
    455     0    stevel 	/*
    456     0    stevel 	 * Create AUTH handle.  Save the necessary interface information
    457     0    stevel 	 * so that the client can refresh the handle later if needed.
    458     0    stevel 	 */
    459     0    stevel 	if ((auth = (AUTH *) kmem_alloc(sizeof (*auth), KM_SLEEP)) != NULL)
    460     0    stevel 		ap = (rpc_gss_data *) kmem_alloc(sizeof (*ap), KM_SLEEP);
    461     0    stevel 	if (auth == NULL || ap == NULL) {
    462     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_seccreate: out of memory\n");
    463     0    stevel 		if (auth != NULL)
    464     0    stevel 			kmem_free((char *)auth, sizeof (*auth));
    465     0    stevel 		(void) gss_release_name(&minor_stat, &target_name);
    466     0    stevel 		return (ENOMEM);
    467     0    stevel 	}
    468     0    stevel 
    469     0    stevel 	bzero((char *)ap, sizeof (*ap));
    470     0    stevel 	ap->clnt = clnt;
    471     0    stevel 	ap->version = RPCSEC_GSS_VERSION;
    472     0    stevel 	if (options_req != NULL) {
    473     0    stevel 		ap->my_cred = options_req->my_cred;
    474     0    stevel 		ap->req_flags = options_req->req_flags;
    475     0    stevel 		ap->time_req = options_req->time_req;
    476     0    stevel 		ap->icb = options_req->input_channel_bindings;
    477     0    stevel 	} else {
    478     0    stevel 		ap->my_cred = GSS_C_NO_CREDENTIAL;
    479     0    stevel 		ap->req_flags = GSS_C_MUTUAL_FLAG;
    480     0    stevel 		ap->time_req = 0;
    481     0    stevel 		ap->icb = GSS_C_NO_CHANNEL_BINDINGS;
    482     0    stevel 	}
    483     0    stevel 	if ((ap->service = service_type) == rpc_gss_svc_default)
    484     0    stevel 		ap->service = rpc_gss_svc_integrity;
    485     0    stevel 	ap->qop = qop;
    486     0    stevel 	ap->target_name = target_name;
    487     0    stevel 
    488     0    stevel 	/*
    489     0    stevel 	 * Now invoke the real interface that sets up the context from
    490     0    stevel 	 * the information stashed away in the private data.
    491     0    stevel 	 */
    492     0    stevel 	if (error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
    493  6403   gt29601 	    mechanism, &ap->mech_type, &ret_flags, &time_rec, cr, 0)) {
    494     0    stevel 		if (ap->target_name) {
    495     0    stevel 			(void) gss_release_name(&minor_stat, &ap->target_name);
    496     0    stevel 		}
    497     0    stevel 		kmem_free((char *)ap, sizeof (*ap));
    498     0    stevel 		kmem_free((char *)auth, sizeof (*auth));
    499     0    stevel 		RPCGSS_LOG(1, "rpc_gss_seccreate: init context failed"
    500  6403   gt29601 		    " errno=%d\n", error);
    501     0    stevel 		return (error);
    502     0    stevel 	}
    503     0    stevel 
    504     0    stevel 	/*
    505     0    stevel 	 * Make sure that the requested service is supported.  In all
    506     0    stevel 	 * cases, integrity service must be available.
    507     0    stevel 	 */
    508     0    stevel 	if ((ap->service == rpc_gss_svc_privacy &&
    509  6403   gt29601 	    !(ret_flags & GSS_C_CONF_FLAG)) ||
    510  6403   gt29601 	    !(ret_flags & GSS_C_INTEG_FLAG)) {
    511     0    stevel 		rpc_gss_destroy(auth);
    512     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_seccreate: service not supported\n");
    513     0    stevel 		return (EPROTONOSUPPORT);
    514     0    stevel 	}
    515     0    stevel 
    516     0    stevel 	/*
    517     0    stevel 	 * return option values if requested
    518     0    stevel 	 */
    519     0    stevel 	if (options_ret != NULL) {
    520     0    stevel 		options_ret->major_status = gssstat;
    521     0    stevel 		options_ret->minor_status = minor_stat;
    522     0    stevel 		options_ret->rpcsec_version = ap->version;
    523     0    stevel 		options_ret->ret_flags = ret_flags;
    524     0    stevel 		options_ret->time_ret = time_rec;
    525     0    stevel 		options_ret->gss_context = ap->context;
    526     0    stevel 		/*
    527     0    stevel 		 *  Caller's responsibility to free this.
    528     0    stevel 		 */
    529     0    stevel 		NOT_NULL(ap->mech_type);
    530     0    stevel 		__rpc_gss_dup_oid(ap->mech_type,
    531  6403   gt29601 		    (gss_OID *)&options_ret->actual_mechanism);
    532     0    stevel 	}
    533     0    stevel 
    534     0    stevel 	*retauth = auth;
    535     0    stevel 	return (0);
    536     0    stevel }
    537     0    stevel 
    538     0    stevel /*
    539     0    stevel  * Private interface to create a context.  This is the interface
    540     0    stevel  * that's invoked when the context has to be refreshed.
    541     0    stevel  */
    542     0    stevel static int
    543     0    stevel rpc_gss_seccreate_pvt(gssstat, minor_stat, auth, ap, desired_mech_type,
    544     0    stevel 			actual_mech_type, ret_flags, time_rec, cr, isrefresh)
    545     0    stevel 	OM_uint32		*gssstat;
    546     0    stevel 	OM_uint32		*minor_stat;
    547     0    stevel 	AUTH			*auth;
    548     0    stevel 	rpc_gss_data		*ap;
    549     0    stevel 	gss_OID			desired_mech_type;
    550     0    stevel 	gss_OID			*actual_mech_type;
    551     0    stevel 	int			*ret_flags;
    552     0    stevel 	OM_uint32		*time_rec;
    553     0    stevel 	cred_t			*cr;
    554     0    stevel 	int			isrefresh;
    555     0    stevel {
    556     0    stevel 	CLIENT			*clnt = ap->clnt;
    557     0    stevel 	AUTH			*save_auth;
    558     0    stevel 	enum clnt_stat		callstat;
    559     0    stevel 	rpc_gss_init_arg	call_arg;
    560     0    stevel 	rpc_gss_init_res	call_res;
    561     0    stevel 	gss_buffer_desc		*input_token_p, input_token, process_token;
    562     0    stevel 	int 			free_results = 0;
    563     0    stevel 	k_sigset_t		smask;
    564     0    stevel 	int			error = 0;
    565     0    stevel 
    566     0    stevel 	/*
    567     0    stevel 	 * (re)initialize AUTH handle and private data.
    568     0    stevel 	 */
    569     0    stevel 	bzero((char *)auth, sizeof (*auth));
    570     0    stevel 	auth->ah_ops = &rpc_gss_ops;
    571     0    stevel 	auth->ah_private = (caddr_t)ap;
    572     0    stevel 	auth->ah_cred.oa_flavor = RPCSEC_GSS;
    573     0    stevel 
    574     0    stevel 	ap->established = FALSE;
    575     0    stevel 	ap->ctx_handle.length = 0;
    576     0    stevel 	ap->ctx_handle.value = NULL;
    577     0    stevel 	ap->context = NULL;
    578     0    stevel 	ap->seq_num = 0;
    579     0    stevel 	ap->gss_proc = RPCSEC_GSS_INIT;
    580     0    stevel 
    581     0    stevel 	/*
    582     0    stevel 	 * should not change clnt->cl_auth at this time, so save
    583     0    stevel 	 * old handle
    584     0    stevel 	 */
    585     0    stevel 	save_auth = clnt->cl_auth;
    586     0    stevel 	clnt->cl_auth = auth;
    587     0    stevel 
    588     0    stevel 	/*
    589     0    stevel 	 * set state for starting context setup
    590     0    stevel 	 */
    591     0    stevel 	bzero((char *)&call_arg, sizeof (call_arg));
    592     0    stevel 	input_token_p = GSS_C_NO_BUFFER;
    593     0    stevel 
    594     0    stevel next_token:
    595     0    stevel 	*gssstat = kgss_init_sec_context(minor_stat,
    596     0    stevel 					ap->my_cred,
    597     0    stevel 					&ap->context,
    598     0    stevel 					ap->target_name,
    599     0    stevel 					desired_mech_type,
    600     0    stevel 					ap->req_flags,
    601     0    stevel 					ap->time_req,
    602     0    stevel 					NULL,
    603     0    stevel 					input_token_p,
    604     0    stevel 					actual_mech_type,
    605     0    stevel 					&call_arg,
    606     0    stevel 					ret_flags,
    607     0    stevel 					time_rec,
    608     0    stevel 					crgetuid(cr));
    609     0    stevel 
    610     0    stevel 	if (input_token_p != GSS_C_NO_BUFFER) {
    611     0    stevel 		OM_uint32 minor_stat2;
    612     0    stevel 
    613     0    stevel 		(void) gss_release_buffer(&minor_stat2, input_token_p);
    614     0    stevel 		input_token_p = GSS_C_NO_BUFFER;
    615     0    stevel 	}
    616     0    stevel 
    617     0    stevel 	if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
    618     0    stevel 		rpc_gss_display_status(*gssstat, *minor_stat,
    619     0    stevel 			desired_mech_type, crgetuid(cr),
    620     0    stevel 			"rpcsec_gss_secreate_pvt:gss_init_sec_context");
    621     0    stevel 		error = EACCES;
    622     0    stevel 		goto cleanup;
    623     0    stevel 	}
    624     0    stevel 
    625     0    stevel 	/*
    626     0    stevel 	 * if we got a token, pass it on
    627     0    stevel 	 */
    628     0    stevel 	if (call_arg.length != 0) {
    629     0    stevel 		struct timeval timeout = {30, 0};
    630     0    stevel 		int	 rpcsec_retry = isrefresh ?
    631     0    stevel 			RPCSEC_GSS_REFRESH_ATTEMPTS : 1;
    632     0    stevel 		uint32_t oldxid;
    633     0    stevel 		uint32_t zeroxid = 0;
    634     0    stevel 
    635     0    stevel 		bzero((char *)&call_res, sizeof (call_res));
    636     0    stevel 
    637     0    stevel 		(void) CLNT_CONTROL(clnt, CLGET_XID, (char *)&oldxid);
    638     0    stevel 		(void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&zeroxid);
    639     0    stevel 
    640     0    stevel 
    641     0    stevel 		while (rpcsec_retry > 0) {
    642     0    stevel 			struct rpc_err rpcerr;
    643     0    stevel 
    644     0    stevel 			sigintr(&smask, INTERRUPT_OK);
    645     0    stevel 
    646     0    stevel 			callstat = clnt_call(clnt, NULLPROC,
    647     0    stevel 				__xdr_rpc_gss_init_arg, (caddr_t)&call_arg,
    648     0    stevel 				__xdr_rpc_gss_init_res, (caddr_t)&call_res,
    649     0    stevel 				timeout);
    650     0    stevel 
    651     0    stevel 			sigunintr(&smask);
    652     0    stevel 
    653     0    stevel 			if (callstat == RPC_SUCCESS) {
    654     0    stevel 				error = 0;
    655     0    stevel 				if (isrefresh &&
    656     0    stevel 				    call_res.gss_major == GSS_S_FAILURE) {
    657     0    stevel 
    658     0    stevel 					clock_t one_sec = drv_usectohz(1000000);
    659     0    stevel 
    660     0    stevel 					rpcsec_retry--;
    661     0    stevel 
    662     0    stevel 					/*
    663     0    stevel 					 * Pause a little and try again.
    664     0    stevel 					 */
    665     0    stevel 
    666     0    stevel 					if (clnt->cl_nosignal == TRUE) {
    667     0    stevel 						delay(one_sec);
    668     0    stevel 					} else {
    669     0    stevel 						if (delay_sig(one_sec)) {
    670     0    stevel 							error = EINTR;
    671     0    stevel 							break;
    672     0    stevel 						}
    673     0    stevel 					}
    674     0    stevel 					continue;
    675     0    stevel 				}
    676     0    stevel 				break;
    677     0    stevel 			}
    678     0    stevel 
    679     0    stevel 			if (callstat == RPC_TIMEDOUT) {
    680     0    stevel 				error = ETIMEDOUT;
    681     0    stevel 				break;
    682     0    stevel 			}
    683     0    stevel 
    684     0    stevel 			if (callstat == RPC_XPRTFAILED) {
    685     0    stevel 				error = ECONNRESET;
    686     0    stevel 				break;
    687     0    stevel 			}
    688     0    stevel 
    689     0    stevel 			if (callstat == RPC_INTR) {
    690     0    stevel 				error = EINTR;
    691     0    stevel 				break;
    692     0    stevel 			}
    693     0    stevel 
    694     0    stevel 			if (callstat == RPC_INPROGRESS) {
    695     0    stevel 				continue;
    696     0    stevel 			}
    697     0    stevel 
    698     0    stevel 			clnt_geterr(clnt, &rpcerr);
    699     0    stevel 			error = rpcerr.re_errno;
    700     0    stevel 			break;
    701     0    stevel 		}
    702     0    stevel 
    703     0    stevel 		(void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&oldxid);
    704     0    stevel 
    705     0    stevel 		(void) gss_release_buffer(minor_stat, &call_arg);
    706     0    stevel 
    707     0    stevel 		if (callstat != RPC_SUCCESS) {
    708     0    stevel 			RPCGSS_LOG(1,
    709     0    stevel 			    "rpc_gss_seccreate_pvt: clnt_call failed %d\n",
    710     0    stevel 			    callstat);
    711     0    stevel 			goto cleanup;
    712     0    stevel 		}
    713     0    stevel 
    714     0    stevel 		/*
    715     0    stevel 		 * we have results - note that these need to be freed
    716     0    stevel 		 */
    717     0    stevel 		free_results = 1;
    718     0    stevel 
    719     0    stevel 		if ((call_res.gss_major != GSS_S_COMPLETE) &&
    720     0    stevel 		    (call_res.gss_major != GSS_S_CONTINUE_NEEDED)) {
    721     0    stevel 			RPCGSS_LOG1(1, "rpc_gss_seccreate_pvt: "
    722     0    stevel 				"call_res gss_major %x, gss_minor %x\n",
    723     0    stevel 				call_res.gss_major, call_res.gss_minor);
    724     0    stevel 			error = EACCES;
    725     0    stevel 			goto cleanup;
    726     0    stevel 		}
    727     0    stevel 
    728     0    stevel 		ap->gss_proc = RPCSEC_GSS_CONTINUE_INIT;
    729     0    stevel 
    730     0    stevel 		/*
    731     0    stevel 		 * check for ctx_handle
    732     0    stevel 		 */
    733     0    stevel 		if (ap->ctx_handle.length == 0) {
    734     0    stevel 			if (call_res.ctx_handle.length == 0) {
    735     0    stevel 				RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: zero "
    736     0    stevel 					"length handle in response\n");
    737     0    stevel 				error = EACCES;
    738     0    stevel 				goto cleanup;
    739     0    stevel 			}
    740     0    stevel 			GSS_DUP_BUFFER(ap->ctx_handle,
    741     0    stevel 					call_res.ctx_handle);
    742     0    stevel 		} else if (!GSS_BUFFERS_EQUAL(ap->ctx_handle,
    743     0    stevel 						call_res.ctx_handle)) {
    744     0    stevel 			RPCGSS_LOG0(1,
    745     0    stevel 			"rpc_gss_seccreate_pvt: ctx_handle not the same\n");
    746     0    stevel 			error = EACCES;
    747     0    stevel 			goto cleanup;
    748     0    stevel 		}
    749     0    stevel 
    750     0    stevel 		/*
    751     0    stevel 		 * check for token
    752     0    stevel 		 */
    753     0    stevel 		if (call_res.token.length != 0) {
    754     0    stevel 			if (*gssstat == GSS_S_COMPLETE) {
    755     0    stevel 				RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: non "
    756     0    stevel 					"zero length token in response, but "
    757     0    stevel 					"gsstat == GSS_S_COMPLETE\n");
    758     0    stevel 				error = EACCES;
    759     0    stevel 				goto cleanup;
    760     0    stevel 			}
    761     0    stevel 			GSS_DUP_BUFFER(input_token, call_res.token);
    762     0    stevel 			input_token_p = &input_token;
    763     0    stevel 
    764     0    stevel 		} else if (*gssstat != GSS_S_COMPLETE) {
    765     0    stevel 			RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length "
    766     0    stevel 				"token in response, but "
    767     0    stevel 				"gsstat != GSS_S_COMPLETE\n");
    768     0    stevel 			error = EACCES;
    769     0    stevel 			goto cleanup;
    770     0    stevel 		}
    771     0    stevel 
    772     0    stevel 		/* save the sequence window value; validate later */
    773     0    stevel 		ap->seq_window = call_res.seq_window;
    774     0    stevel 		xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
    775     0    stevel 		free_results = 0;
    776     0    stevel 	}
    777     0    stevel 
    778     0    stevel 	/*
    779     0    stevel 	 * results were okay.. continue if necessary
    780     0    stevel 	 */
    781     0    stevel 	if (*gssstat == GSS_S_CONTINUE_NEEDED) {
    782     0    stevel 		goto next_token;
    783     0    stevel 	}
    784     0    stevel 
    785     0    stevel 	/*
    786     0    stevel 	 * Context is established. Now use kgss_export_sec_context and
    787     0    stevel 	 * kgss_import_sec_context to transfer the context from the user
    788     0    stevel 	 * land to kernel if the mechanism specific kernel module is
    789     0    stevel 	 * available.
    790     0    stevel 	 */
    791     0    stevel 	*gssstat  = kgss_export_sec_context(minor_stat, ap->context,
    792     0    stevel 						&process_token);
    793     0    stevel 	if (*gssstat == GSS_S_NAME_NOT_MN) {
    794     0    stevel 		RPCGSS_LOG(2, "rpc_gss_seccreate_pvt: export_sec_context "
    795     0    stevel 			"Kernel Module unavailable  gssstat = 0x%x\n",
    796     0    stevel 			*gssstat);
    797     0    stevel 		goto done;
    798     0    stevel 	} else if (*gssstat != GSS_S_COMPLETE) {
    799     0    stevel 		(void) rpc_gss_display_status(*gssstat, *minor_stat,
    800    75  rg137905 			isrefresh ? GSS_C_NULL_OID : *actual_mech_type,
    801    75  rg137905 					crgetuid(cr),
    802     0    stevel 			"rpcsec_gss_secreate_pvt:gss_export_sec_context");
    803     0    stevel 		(void) kgss_delete_sec_context(minor_stat,
    804     0    stevel 					&ap->context, NULL);
    805     0    stevel 		error = EACCES;
    806     0    stevel 		goto cleanup;
    807     0    stevel 	} else if (process_token.length == 0) {
    808     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length "
    809     0    stevel 				"token in response for export_sec_context, but "
    810     0    stevel 				"gsstat == GSS_S_COMPLETE\n");
    811     0    stevel 		(void) kgss_delete_sec_context(minor_stat,
    812     0    stevel 					&ap->context, NULL);
    813     0    stevel 		error = EACCES;
    814     0    stevel 		goto cleanup;
    815     0    stevel 	} else
    816     0    stevel 		*gssstat = kgss_import_sec_context(minor_stat, &process_token,
    817     0    stevel 							ap->context);
    818     0    stevel 
    819     0    stevel 	if (*gssstat == GSS_S_COMPLETE) {
    820     0    stevel 		(void) gss_release_buffer(minor_stat, &process_token);
    821     0    stevel 	} else {
    822     0    stevel 		rpc_gss_display_status(*gssstat, *minor_stat,
    823     0    stevel 			desired_mech_type, crgetuid(cr),
    824     0    stevel 			"rpcsec_gss_secreate_pvt:gss_import_sec_context");
    825     0    stevel 		(void) kgss_delete_sec_context(minor_stat,
    826     0    stevel 					&ap->context, NULL);
    827     0    stevel 		(void) gss_release_buffer(minor_stat, &process_token);
    828     0    stevel 		error = EACCES;
    829     0    stevel 		goto cleanup;
    830     0    stevel 	}
    831     0    stevel 
    832     0    stevel done:
    833     0    stevel 	/*
    834     0    stevel 	 * Validate the sequence window - RFC 2203 section 5.2.3.1
    835     0    stevel 	 */
    836     0    stevel 	if (!validate_seqwin(ap)) {
    837     0    stevel 		error = EACCES;
    838     0    stevel 		goto cleanup;
    839     0    stevel 	}
    840     0    stevel 
    841     0    stevel 	/*
    842     0    stevel 	 * Done!  Security context creation is successful.
    843     0    stevel 	 * Ready for exchanging data.
    844     0    stevel 	 */
    845     0    stevel 	ap->established = TRUE;
    846     0    stevel 	ap->seq_num = 1;
    847     0    stevel 	ap->gss_proc = RPCSEC_GSS_DATA;
    848     0    stevel 	ap->invalid = FALSE;
    849     0    stevel 
    850     0    stevel 	clnt->cl_auth = save_auth;	/* restore cl_auth */
    851     0    stevel 
    852     0    stevel 	return (0);
    853     0    stevel 
    854     0    stevel cleanup:
    855     0    stevel 	if (free_results)
    856     0    stevel 		xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
    857     0    stevel 	clnt->cl_auth = save_auth;	/* restore cl_auth */
    858     0    stevel 
    859     0    stevel 	/*
    860     0    stevel 	 * If need to retry for AUTH_REFRESH, do not cleanup the
    861     0    stevel 	 * auth private data.
    862     0    stevel 	 */
    863     0    stevel 	if (isrefresh && (error == ETIMEDOUT || error == ECONNRESET)) {
    864     0    stevel 		return (error);
    865     0    stevel 	}
    866     0    stevel 
    867     0    stevel 	if (ap->context != NULL) {
    868     0    stevel 		rpc_gss_free_pvt(auth);
    869     0    stevel 	}
    870     0    stevel 
    871     0    stevel 	return (error? error : EACCES);
    872     0    stevel }
    873     0    stevel 
    874     0    stevel /*
    875     0    stevel  * Marshall credentials.
    876     0    stevel  */
    877     0    stevel static bool_t
    878     0    stevel marshall_creds(ap, xdrs, cred_buf_len)
    879     0    stevel 	rpc_gss_data		*ap;
    880     0    stevel 	XDR			*xdrs;
    881     0    stevel 	uint_t			cred_buf_len;
    882     0    stevel {
    883     0    stevel 	rpc_gss_creds		ag_creds;
    884     0    stevel 	char			*cred_buf;
    885     0    stevel 	struct opaque_auth	creds;
    886     0    stevel 	XDR			cred_xdrs;
    887     0    stevel 
    888     0    stevel 	ag_creds.version = ap->version;
    889     0    stevel 	ag_creds.gss_proc = ap->gss_proc;
    890     0    stevel 	ag_creds.seq_num = ap->seq_num;
    891     0    stevel 	ag_creds.service = ap->service;
    892     0    stevel 
    893     0    stevel 	/*
    894     0    stevel 	 * If context has not been set up yet, use NULL handle.
    895     0    stevel 	 */
    896     0    stevel 	if (ap->ctx_handle.length > 0)
    897     0    stevel 		ag_creds.ctx_handle = ap->ctx_handle;
    898     0    stevel 	else {
    899     0    stevel 		ag_creds.ctx_handle.length = 0;
    900     0    stevel 		ag_creds.ctx_handle.value = NULL;
    901     0    stevel 	}
    902     0    stevel 
    903     0    stevel 	cred_buf = kmem_alloc(cred_buf_len, KM_SLEEP);
    904     0    stevel 	xdrmem_create(&cred_xdrs, (caddr_t)cred_buf, cred_buf_len,
    905     0    stevel 								XDR_ENCODE);
    906     0    stevel 	if (!__xdr_rpc_gss_creds(&cred_xdrs, &ag_creds)) {
    907     0    stevel 		kmem_free(cred_buf, MAX_AUTH_BYTES);
    908     0    stevel 		XDR_DESTROY(&cred_xdrs);
    909     0    stevel 		return (FALSE);
    910     0    stevel 	}
    911     0    stevel 
    912     0    stevel 	creds.oa_flavor = RPCSEC_GSS;
    913     0    stevel 	creds.oa_base = cred_buf;
    914     0    stevel 	creds.oa_length = xdr_getpos(&cred_xdrs);
    915     0    stevel 	XDR_DESTROY(&cred_xdrs);
    916     0    stevel 
    917     0    stevel 	if (!xdr_opaque_auth(xdrs, &creds)) {
    918     0    stevel 		kmem_free(cred_buf, cred_buf_len);
    919     0    stevel 		return (FALSE);
    920     0    stevel 	}
    921     0    stevel 
    922     0    stevel 	kmem_free(cred_buf, cred_buf_len);
    923     0    stevel 	return (TRUE);
    924     0    stevel }
    925     0    stevel 
    926     0    stevel /*
    927     0    stevel  * Marshall verifier.  The verifier is the checksum of the RPC header
    928     0    stevel  * up to and including the credential field.  The XDR handle that's
    929     0    stevel  * passed in has the header up to and including the credential field
    930     0    stevel  * encoded.  A pointer to the transmit buffer is also passed in.
    931     0    stevel  */
    932     0    stevel static bool_t
    933     0    stevel marshall_verf(ap, xdrs, buf)
    934     0    stevel 	rpc_gss_data		*ap;
    935     0    stevel 	XDR			*xdrs;	/* send XDR */
    936     0    stevel 	char			*buf;	/* pointer of send buffer */
    937     0    stevel {
    938     0    stevel 	struct opaque_auth	verf;
    939     0    stevel 	OM_uint32		major, minor;
    940     0    stevel 	gss_buffer_desc		in_buf, out_buf;
    941     0    stevel 	bool_t			ret = FALSE;
    942     0    stevel 
    943     0    stevel 	/*
    944     0    stevel 	 * If context is not established yet, use NULL verifier.
    945     0    stevel 	 */
    946     0    stevel 	if (!ap->established) {
    947     0    stevel 		verf.oa_flavor = AUTH_NONE;
    948     0    stevel 		verf.oa_base = NULL;
    949     0    stevel 		verf.oa_length = 0;
    950     0    stevel 		return (xdr_opaque_auth(xdrs, &verf));
    951     0    stevel 	}
    952     0    stevel 
    953     0    stevel 	verf.oa_flavor = RPCSEC_GSS;
    954     0    stevel 	in_buf.length = xdr_getpos(xdrs);
    955     0    stevel 	in_buf.value = buf;
    956     0    stevel 	if ((major = kgss_sign(&minor, ap->context, ap->qop, &in_buf,
    957     0    stevel 				&out_buf)) != GSS_S_COMPLETE) {
    958     0    stevel 		if (major == GSS_S_CONTEXT_EXPIRED) {
    959     0    stevel 			ap->invalid = TRUE;
    960     0    stevel 		}
    961     0    stevel 		RPCGSS_LOG1(1,
    962     0    stevel 		    "marshall_verf: kgss_sign failed GSS Major %x Minor %x\n",
    963     0    stevel 		    major, minor);
    964     0    stevel 		return (FALSE);
    965     0    stevel 	}
    966     0    stevel 	verf.oa_base = out_buf.value;
    967     0    stevel 	verf.oa_length = out_buf.length;
    968     0    stevel 	ret = xdr_opaque_auth(xdrs, &verf);
    969     0    stevel 	(void) gss_release_buffer(&minor, &out_buf);
    970     0    stevel 
    971     0    stevel 	return (ret);
    972     0    stevel }
    973     0    stevel 
    974     0    stevel /*
    975     0    stevel  * Validate sequence window upon a successful RPCSEC_GSS INIT session.
    976     0    stevel  * The sequence window sent back by the server should be verifiable by
    977     0    stevel  * the verifier which is a checksum of the sequence window.
    978     0    stevel  */
    979     0    stevel static bool_t
    980     0    stevel validate_seqwin(rpc_gss_data *ap)
    981     0    stevel {
    982     0    stevel 	uint_t			seq_win_net;
    983     0    stevel 	OM_uint32		major = 0, minor = 0;
    984     0    stevel 	gss_buffer_desc		msg_buf, tok_buf;
    985     0    stevel 	int			qop_state = 0;
    986     0    stevel 
    987     0    stevel 	ASSERT(ap->verifier);
    988     0    stevel 	ASSERT(ap->context);
    989     0    stevel 	seq_win_net = (uint_t)htonl(ap->seq_window);
    990     0    stevel 	msg_buf.length = sizeof (seq_win_net);
    991     0    stevel 	msg_buf.value = (char *)&seq_win_net;
    992     0    stevel 	tok_buf.length = ap->verifier->oa_length;
    993     0    stevel 	tok_buf.value = ap->verifier->oa_base;
    994     0    stevel 	major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf,
    995  6403   gt29601 	    &qop_state);
    996     0    stevel 
    997     0    stevel 	if (major != GSS_S_COMPLETE) {
    998  6403   gt29601 		RPCGSS_LOG1(1,
    999  6403   gt29601 		    "validate_seqwin: kgss_verify failed GSS Major "
   1000  6403   gt29601 		    "%x Minor %x\n", major, minor);
   1001  6403   gt29601 		RPCGSS_LOG1(1, "seq_window %d, verf len %d ", ap->seq_window,
   1002  6403   gt29601 		    ap->verifier->oa_length);
   1003  6403   gt29601 		return (FALSE);
   1004     0    stevel 	}
   1005     0    stevel 	return (TRUE);
   1006     0    stevel }
   1007     0    stevel 
   1008     0    stevel /*
   1009     0    stevel  * Validate RPC response verifier from server.  The response verifier
   1010     0    stevel  * is the checksum of the request sequence number.
   1011     0    stevel  */
   1012     0    stevel static bool_t
   1013     0    stevel rpc_gss_validate(auth, verf)
   1014     0    stevel 	AUTH			*auth;
   1015     0    stevel 	struct opaque_auth	*verf;
   1016     0    stevel {
   1017     0    stevel 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
   1018     0    stevel 	uint_t			seq_num_net;
   1019     0    stevel 	OM_uint32		major, minor;
   1020     0    stevel 	gss_buffer_desc		msg_buf, tok_buf;
   1021     0    stevel 	int			qop_state;
   1022     0    stevel 
   1023     0    stevel 	/*
   1024     0    stevel 	 * If context is not established yet, save the verifier for
   1025     0    stevel 	 * validating the sequence window later at the end of context
   1026     0    stevel 	 * creation session.
   1027     0    stevel 	 */
   1028     0    stevel 	if (!ap->established) {
   1029     0    stevel 	    if (ap->verifier == NULL) {
   1030     0    stevel 		ap->verifier = kmem_zalloc(sizeof (struct opaque_auth),
   1031     0    stevel 						KM_SLEEP);
   1032     0    stevel 		if (verf->oa_length > 0)
   1033     0    stevel 		    ap->verifier->oa_base = kmem_zalloc(verf->oa_length,
   1034     0    stevel 						KM_SLEEP);
   1035     0    stevel 	    } else {
   1036     0    stevel 		if (ap->verifier->oa_length > 0)
   1037     0    stevel 		    kmem_free(ap->verifier->oa_base, ap->verifier->oa_length);
   1038     0    stevel 		if (verf->oa_length > 0)
   1039     0    stevel 		    ap->verifier->oa_base = kmem_zalloc(verf->oa_length,
   1040     0    stevel 						KM_SLEEP);
   1041     0    stevel 	    }
   1042     0    stevel 	    ap->verifier->oa_length = verf->oa_length;
   1043     0    stevel 	    bcopy(verf->oa_base, ap->verifier->oa_base, verf->oa_length);
   1044     0    stevel 	    return (TRUE);
   1045     0    stevel 	}
   1046     0    stevel 
   1047     0    stevel 	seq_num_net = (uint_t)htonl(ap->seq_num);
   1048     0    stevel 	msg_buf.length = sizeof (seq_num_net);
   1049     0    stevel 	msg_buf.value = (char *)&seq_num_net;
   1050     0    stevel 	tok_buf.length = verf->oa_length;
   1051     0    stevel 	tok_buf.value = verf->oa_base;
   1052     0    stevel 	major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf,
   1053     0    stevel 				&qop_state);
   1054     0    stevel 	if (major != GSS_S_COMPLETE) {
   1055     0    stevel 		RPCGSS_LOG1(1,
   1056     0    stevel 		"rpc_gss_validate: kgss_verify failed GSS Major %x Minor %x\n",
   1057     0    stevel 		major, minor);
   1058     0    stevel 		return (FALSE);
   1059     0    stevel 	}
   1060     0    stevel 	return (TRUE);
   1061     0    stevel }
   1062     0    stevel 
   1063     0    stevel /*
   1064     0    stevel  * Refresh client context.  This is necessary sometimes because the
   1065     0    stevel  * server will ocassionally destroy contexts based on LRU method, or
   1066     0    stevel  * because of expired credentials.
   1067     0    stevel  */
   1068     0    stevel static bool_t
   1069     0    stevel rpc_gss_refresh(auth, msg, cr)
   1070     0    stevel 	AUTH		*auth;
   1071     0    stevel 	struct rpc_msg	*msg;
   1072     0    stevel 	cred_t		*cr;
   1073     0    stevel {
   1074     0    stevel 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
   1075     0    stevel 	gss_ctx_id_t	ctx_sav = NULL;
   1076     0    stevel 	gss_buffer_desc	ctx_hdle_sav = {0, NULL};
   1077     0    stevel 	uint_t		sn_sav, proc_sav;
   1078     0    stevel 	bool_t		est_sav;
   1079     0    stevel 	OM_uint32	gssstat, minor_stat;
   1080     0    stevel 	int error;
   1081     0    stevel 
   1082     0    stevel 	/*
   1083     0    stevel 	 * The context needs to be recreated only when the error status
   1084     0    stevel 	 * returned from the server is one of the following:
   1085     0    stevel 	 *	RPCSEC_GSS_NOCRED and RPCSEC_GSS_FAILED
   1086     0    stevel 	 * The existing context should not be destroyed unless the above
   1087     0    stevel 	 * error status codes are received or if the context has not
   1088     0    stevel 	 * been set up.
   1089     0    stevel 	 */
   1090     0    stevel 
   1091     0    stevel 	if (msg->rjcted_rply.rj_why == RPCSEC_GSS_NOCRED ||
   1092     0    stevel 			msg->rjcted_rply.rj_why == RPCSEC_GSS_FAILED ||
   1093     0    stevel 							!ap->established) {
   1094     0    stevel 		/*
   1095     0    stevel 		 * Destroy the context if necessary.  Use the same memory
   1096     0    stevel 		 * for the new context since we've already passed a pointer
   1097     0    stevel 		 * to it to the user.
   1098     0    stevel 		 */
   1099     0    stevel 		if (ap->context != NULL) {
   1100     0    stevel 			ctx_sav = ap->context;
   1101     0    stevel 			ap->context = NULL;
   1102     0    stevel 		}
   1103     0    stevel 		if (ap->ctx_handle.length != 0) {
   1104     0    stevel 			ctx_hdle_sav.length = ap->ctx_handle.length;
   1105     0    stevel 			ctx_hdle_sav.value = ap->ctx_handle.value;
   1106     0    stevel 			ap->ctx_handle.length = 0;
   1107     0    stevel 			ap->ctx_handle.value = NULL;
   1108     0    stevel 		}
   1109     0    stevel 
   1110     0    stevel 		/*
   1111     0    stevel 		 * If the context was not already established, don't try to
   1112     0    stevel 		 * recreate it.
   1113     0    stevel 		 */
   1114     0    stevel 		if (!ap->established) {
   1115     0    stevel 			ap->invalid = TRUE;
   1116     0    stevel 			RPCGSS_LOG0(1,
   1117     0    stevel 			"rpc_gss_refresh: context was not established\n");
   1118     0    stevel 			error = EINVAL;
   1119     0    stevel 			goto out;
   1120     0    stevel 		}
   1121     0    stevel 
   1122     0    stevel 		est_sav = ap->established;
   1123     0    stevel 		sn_sav = ap->seq_num;
   1124     0    stevel 		proc_sav = ap->gss_proc;
   1125     0    stevel 
   1126     0    stevel 		/*
   1127     0    stevel 		 * Recreate context.
   1128     0    stevel 		 */
   1129     0    stevel 		error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth,
   1130     0    stevel 				ap, ap->mech_type, (gss_OID *)NULL, (int *)NULL,
   1131     0    stevel 				(OM_uint32 *)NULL, cr, 1);
   1132     0    stevel 
   1133     0    stevel 		switch (error) {
   1134     0    stevel 		case 0:
   1135     0    stevel 			RPCGSS_LOG(1,
   1136     0    stevel 			"rpc_gss_refresh: auth %p refreshed\n", (void *)auth);
   1137     0    stevel 			goto out;
   1138     0    stevel 
   1139     0    stevel 		case ETIMEDOUT:
   1140     0    stevel 		case ECONNRESET:
   1141     0    stevel 			RPCGSS_LOG0(1, "rpc_gss_refresh: try again\n");
   1142     0    stevel 
   1143     0    stevel 			if (ap->context != NULL) {
   1144     0    stevel 			    (void) kgss_delete_sec_context(&minor_stat,
   1145     0    stevel 					&ap->context, NULL);
   1146     0    stevel 			}
   1147     0    stevel 			if (ap->ctx_handle.length != 0) {
   1148     0    stevel 			    (void) gss_release_buffer(&minor_stat,
   1149     0    stevel 					&ap->ctx_handle);
   1150     0    stevel 			}
   1151     0    stevel 
   1152     0    stevel 			/*
   1153     0    stevel 			 * Restore the original value for the caller to
   1154     0    stevel 			 * try again later.
   1155     0    stevel 			 */
   1156     0    stevel 			ap->context = ctx_sav;
   1157     0    stevel 			ap->ctx_handle.length = ctx_hdle_sav.length;
   1158     0    stevel 			ap->ctx_handle.value = ctx_hdle_sav.value;
   1159     0    stevel 			ap->established = est_sav;
   1160     0    stevel 			ap->seq_num = sn_sav;
   1161     0    stevel 			ap->gss_proc = proc_sav;
   1162     0    stevel 
   1163     0    stevel 			return (FALSE);
   1164     0    stevel 
   1165     0    stevel 		default:
   1166     0    stevel 			ap->invalid = TRUE;
   1167     0    stevel 			RPCGSS_LOG(1, "rpc_gss_refresh: can't refresh this "
   1168     0    stevel 				"auth, error=%d\n", error);
   1169     0    stevel 			goto out;
   1170     0    stevel 		}
   1171     0    stevel 	}
   1172     0    stevel 	RPCGSS_LOG0(1, "rpc_gss_refresh: don't refresh");
   1173     0    stevel 	return (FALSE);
   1174     0    stevel 
   1175     0    stevel out:
   1176     0    stevel 	if (ctx_sav != NULL) {
   1177     0    stevel 		(void) kgss_delete_sec_context(&minor_stat,
   1178     0    stevel 				&ctx_sav, NULL);
   1179     0    stevel 	}
   1180     0    stevel 	if (ctx_hdle_sav.length != 0) {
   1181     0    stevel 		(void) gss_release_buffer(&minor_stat, &ctx_hdle_sav);
   1182     0    stevel 	}
   1183     0    stevel 
   1184     0    stevel 	return (error == 0);
   1185     0    stevel }
   1186     0    stevel 
   1187     0    stevel /*
   1188     0    stevel  * Destroy a context.
   1189     0    stevel  */
   1190     0    stevel static void
   1191     0    stevel rpc_gss_destroy(auth)
   1192     0    stevel 	AUTH		*auth;
   1193     0    stevel {
   1194     0    stevel 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
   1195     0    stevel 
   1196     0    stevel 	/*
   1197     0    stevel 	 *  XXX Currently, we do not ping the server (rpc_gss_destroy_pvt)
   1198     0    stevel 	 *  to destroy the context in the server cache.
   1199     0    stevel 	 *  We assume there is a good LRU/aging mechanism for the
   1200     0    stevel 	 *  context cache on the server side.
   1201     0    stevel 	 */
   1202     0    stevel 	rpc_gss_free_pvt(auth);
   1203     0    stevel 	kmem_free((char *)ap, sizeof (*ap));
   1204     0    stevel 	kmem_free(auth, sizeof (*auth));
   1205     0    stevel }
   1206     0    stevel 
   1207     0    stevel /*
   1208     0    stevel  * Private interface to free memory allocated in the rpcsec_gss private
   1209     0    stevel  * data structure (rpc_gss_data).
   1210     0    stevel  */
   1211     0    stevel static void
   1212     0    stevel rpc_gss_free_pvt(auth)
   1213     0    stevel 	AUTH		*auth;
   1214     0    stevel {
   1215     0    stevel 	OM_uint32	minor_stat;
   1216     0    stevel 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
   1217     0    stevel 
   1218     0    stevel 	if (ap->ctx_handle.length != 0) {
   1219     0    stevel 		(void) gss_release_buffer(&minor_stat, &ap->ctx_handle);
   1220     0    stevel 		ap->ctx_handle.length = 0;
   1221     0    stevel 		ap->ctx_handle.value = NULL;
   1222     0    stevel 	}
   1223     0    stevel 
   1224     0    stevel 	/*
   1225     0    stevel 	 * Destroy local GSS context.
   1226     0    stevel 	 */
   1227     0    stevel 	if (ap->context != NULL) {
   1228     0    stevel 		(void) kgss_delete_sec_context(&minor_stat, &ap->context, NULL);
   1229     0    stevel 		ap->context = NULL;
   1230     0    stevel 	}
   1231     0    stevel 
   1232     0    stevel 	/*
   1233     0    stevel 	 * Looks like we need to release default credentials if we use it.
   1234     0    stevel 	 * Non-default creds need to be released by user.
   1235     0    stevel 	 */
   1236     0    stevel 	if (ap->my_cred == GSS_C_NO_CREDENTIAL)
   1237     0    stevel 		(void) kgss_release_cred(&minor_stat, &ap->my_cred,
   1238     0    stevel 					crgetuid(CRED()));
   1239     0    stevel 
   1240     0    stevel 	/*
   1241     0    stevel 	 * Release any internal name structures.
   1242     0    stevel 	 */
   1243     0    stevel 	if (ap->target_name != NULL) {
   1244     0    stevel 		(void) gss_release_name(&minor_stat, &ap->target_name);
   1245     0    stevel 		ap->target_name = NULL;
   1246     0    stevel 	}
   1247     0    stevel 
   1248     0    stevel 	/*
   1249     0    stevel 	 * Free mech_type oid structure.
   1250     0    stevel 	 */
   1251     0    stevel 	if (ap->mech_type != NULL) {
   1252     0    stevel 		kgss_free_oid(ap->mech_type);
   1253     0    stevel 		ap->mech_type = NULL;
   1254     0    stevel 	}
   1255     0    stevel 
   1256     0    stevel 	/*
   1257     0    stevel 	 * Free the verifier saved for sequence window checking.
   1258     0    stevel 	 */
   1259     0    stevel 	if (ap->verifier != NULL) {
   1260     0    stevel 	    if (ap->verifier->oa_length > 0) {
   1261     0    stevel 		kmem_free(ap->verifier->oa_base, ap->verifier->oa_length);
   1262     0    stevel 	    }
   1263     0    stevel 	    kmem_free(ap->verifier, sizeof (struct opaque_auth));
   1264     0    stevel 	    ap->verifier = NULL;
   1265     0    stevel 	}
   1266     0    stevel }
   1267     0    stevel 
   1268     0    stevel #if 0
   1269     0    stevel /*
   1270     0    stevel  * XXX this function is not used right now.
   1271     0    stevel  * There is a client handle issue needs to be resolved.
   1272     0    stevel  *
   1273     0    stevel  * This is a private interface which will destroy a context
   1274     0    stevel  * without freeing up the memory used by it.  We need to do this when
   1275     0    stevel  * a refresh fails, for example, so the user will still have a handle.
   1276     0    stevel  */
   1277     0    stevel static void
   1278     0    stevel rpc_gss_destroy_pvt(auth)
   1279     0    stevel 	AUTH		*auth;
   1280     0    stevel {
   1281     0    stevel 	struct timeval	timeout;
   1282     0    stevel 	rpc_gss_data	*ap = AUTH_PRIVATE(auth);
   1283     0    stevel 
   1284     0    stevel 	/*
   1285     0    stevel 	 * If we have a server context id, inform server that we are
   1286     0    stevel 	 * destroying the context.
   1287     0    stevel 	 */
   1288     0    stevel 	if (ap->ctx_handle.length != 0) {
   1289     0    stevel 		uint32_t oldxid;
   1290     0    stevel 		uint32_t zeroxid = 0;
   1291     0    stevel 
   1292     0    stevel 		ap->gss_proc = RPCSEC_GSS_DESTROY;
   1293     0    stevel 		timeout.tv_sec = 10;
   1294     0    stevel 		timeout.tv_usec = 0;
   1295     0    stevel 		(void) CLNT_CONTROL(ap->clnt, CLGET_XID, (char *)&oldxid);
   1296     0    stevel 		(void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&zeroxid);
   1297     0    stevel 		(void) clnt_call(ap->clnt, NULLPROC, xdr_void, NULL,
   1298     0    stevel 						xdr_void, NULL, timeout);
   1299     0    stevel 		(void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&oldxid);
   1300     0    stevel 	}
   1301     0    stevel 
   1302     0    stevel 	rpc_gss_free_pvt(auth);
   1303     0    stevel }
   1304     0    stevel #endif
   1305     0    stevel 
   1306     0    stevel /*
   1307     0    stevel  * Wrap client side data.  The encoded header is passed in through
   1308     0    stevel  * buf and buflen.  The header is up to but not including the
   1309     0    stevel  * credential field.
   1310     0    stevel  */
   1311     0    stevel bool_t
   1312     0    stevel rpc_gss_wrap(auth, buf, buflen, out_xdrs, xdr_func, xdr_ptr)
   1313     0    stevel 	AUTH			*auth;
   1314     0    stevel 	char			*buf;		/* encoded header */
   1315     0    stevel /* has been changed to u_int in the user land */
   1316     0    stevel 	uint_t			buflen;		/* encoded header length */
   1317     0    stevel 	XDR			*out_xdrs;
   1318     0    stevel 	xdrproc_t		xdr_func;
   1319     0    stevel 	caddr_t			xdr_ptr;
   1320     0    stevel {
   1321     0    stevel 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
   1322     0    stevel 	XDR			xdrs;
   1323     0    stevel 	char			*tmp_buf;
   1324     0    stevel 	uint_t			xdr_buf_len, cred_buf_len;
   1325     0    stevel 
   1326     0    stevel /*
   1327     0    stevel  *  Here is how MAX_SIGNED_LEN is estimated.
   1328     0    stevel  *  Signing a 48 bytes buffer using des_cbc_md5 would end up with
   1329     0    stevel  *  a buffer length 33 (padded data + 16 bytes of seq_num/checksum).
   1330     0    stevel  *  Current known max seq_num/checksum size is 24 bytes.
   1331     0    stevel  *  88 is derived from RNDUP(33+(24-16)) * 2.
   1332     0    stevel  */
   1333     0    stevel #define	MAX_SIGNED_LEN	88
   1334     0    stevel 
   1335     0    stevel 	/*
   1336     0    stevel 	 * Reject an invalid context.
   1337     0    stevel 	 */
   1338     0    stevel 	if (ap->invalid) {
   1339     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_wrap: reject an invalid context\n");
   1340     0    stevel 		return (FALSE);
   1341     0    stevel 	}
   1342     0    stevel 
   1343     0    stevel 	/*
   1344     0    stevel 	 * If context is established, bump up sequence number.
   1345     0    stevel 	 */
   1346     0    stevel 	if (ap->established)
   1347     0    stevel 		ap->seq_num++;
   1348     0    stevel 
   1349     0    stevel 	/*
   1350     0    stevel 	 * Create the header in a temporary XDR context and buffer
   1351     0    stevel 	 * before putting it out.
   1352     0    stevel 	 */
   1353     0    stevel 	cred_buf_len = RNDUP(sizeof (ap->version) + sizeof (ap->gss_proc) +
   1354     0    stevel 			sizeof (ap->seq_num) + sizeof (ap->service) +
   1355     0    stevel 			sizeof (ap->ctx_handle) + ap->ctx_handle.length);
   1356     0    stevel 
   1357     0    stevel 	xdr_buf_len = buflen + cred_buf_len + sizeof (struct opaque_auth) +
   1358     0    stevel 			MAX_SIGNED_LEN;
   1359     0    stevel 	tmp_buf = kmem_alloc(xdr_buf_len, KM_SLEEP);
   1360     0    stevel 	xdrmem_create(&xdrs, tmp_buf, xdr_buf_len, XDR_ENCODE);
   1361     0    stevel 	if (!XDR_PUTBYTES(&xdrs, buf, buflen)) {
   1362     0    stevel 		kmem_free(tmp_buf, xdr_buf_len);
   1363     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_wrap: xdr putbytes failed\n");
   1364     0    stevel 		return (FALSE);
   1365     0    stevel 	}
   1366     0    stevel 
   1367     0    stevel 	/*
   1368     0    stevel 	 * create cred field
   1369     0    stevel 	 */
   1370     0    stevel 	if (!marshall_creds(ap, &xdrs, cred_buf_len)) {
   1371     0    stevel 		kmem_free(tmp_buf, xdr_buf_len);
   1372     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_creds failed\n");
   1373     0    stevel 		return (FALSE);
   1374     0    stevel 	}
   1375     0    stevel 
   1376     0    stevel 	/*
   1377     0    stevel 	 * create verifier
   1378     0    stevel 	 */
   1379     0    stevel 	if (!marshall_verf(ap, &xdrs, tmp_buf)) {
   1380     0    stevel 		kmem_free(tmp_buf, xdr_buf_len);
   1381     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_verf failed\n");
   1382     0    stevel 		return (FALSE);
   1383     0    stevel 	}
   1384     0    stevel 
   1385     0    stevel 	/*
   1386     0    stevel 	 * write out header and destroy temp structures
   1387     0    stevel 	 */
   1388     0    stevel 	if (!XDR_PUTBYTES(out_xdrs, tmp_buf, XDR_GETPOS(&xdrs))) {
   1389     0    stevel 		kmem_free(tmp_buf, xdr_buf_len);
   1390     0    stevel 		RPCGSS_LOG0(1, "rpc_gss_wrap: write out header failed\n");
   1391     0    stevel 		return (FALSE);
   1392     0    stevel 	}
   1393     0    stevel 	XDR_DESTROY(&xdrs);
   1394     0    stevel 	kmem_free(tmp_buf, xdr_buf_len);
   1395     0    stevel 
   1396     0    stevel 	/*
   1397     0    stevel 	 * If context is not established, or if neither integrity
   1398     0    stevel 	 * nor privacy is used, just XDR encode data.
   1399     0    stevel 	 */
   1400     0    stevel 	if (!ap->established || ap->service == rpc_gss_svc_none) {
   1401     0    stevel 		return ((*xdr_func)(out_xdrs, xdr_ptr));
   1402     0    stevel 	}
   1403     0    stevel 
   1404     0    stevel 	return (__rpc_gss_wrap_data(ap->service, ap->qop, ap->context,
   1405     0    stevel 				ap->seq_num, out_xdrs, xdr_func, xdr_ptr));
   1406     0    stevel }
   1407     0    stevel 
   1408     0    stevel /*
   1409     0    stevel  * Unwrap received data.
   1410     0    stevel  */
   1411     0    stevel bool_t
   1412     0    stevel rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
   1413     0    stevel 	AUTH			*auth;
   1414     0    stevel 	XDR			*in_xdrs;
   1415     0    stevel 	bool_t			(*xdr_func)();
   1416     0    stevel 	caddr_t			xdr_ptr;
   1417     0    stevel {
   1418     0    stevel 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
   1419     0    stevel 
   1420     0    stevel 	/*
   1421     0    stevel 	 * If context is not established, of if neither integrity
   1422     0    stevel 	 * nor privacy is used, just XDR encode data.
   1423     0    stevel 	 */
   1424     0    stevel 	if (!ap->established || ap->service == rpc_gss_svc_none)
   1425     0    stevel 		return ((*xdr_func)(in_xdrs, xdr_ptr));
   1426     0    stevel 
   1427     0    stevel 	return (__rpc_gss_unwrap_data(ap->service,
   1428     0    stevel 				ap->context,
   1429     0    stevel 				ap->seq_num,
   1430     0    stevel 				ap->qop,
   1431     0    stevel 				in_xdrs, xdr_func, xdr_ptr));
   1432     0    stevel }
   1433     0    stevel 
   1434     0    stevel /*
   1435     0    stevel  *  Revoke an GSSAPI based security credentials
   1436     0    stevel  *  from the cache table.
   1437     0    stevel  */
   1438     0    stevel int
   1439     0    stevel rpc_gss_revauth(uid_t uid, rpc_gss_OID mech)
   1440     0    stevel {
   1441     0    stevel 	struct ga_cache_entry *next, *prev, *cur;
   1442     0    stevel 	rpc_gss_data *ap;
   1443     0    stevel 	zoneid_t zoneid = getzoneid();
   1444     0    stevel 	int i;
   1445     0    stevel 
   1446     0    stevel 	/*
   1447     0    stevel 	 *  Check the cache table against the uid and the
   1448     0    stevel 	 *  mechanism type.
   1449     0    stevel 	 */
   1450     0    stevel 	rw_enter(&ga_cache_table_lock, RW_WRITER);
   1451     0    stevel 	for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
   1452     0    stevel 		prev = NULL;
   1453     0    stevel 		for (cur = ga_cache_table[i]; cur; cur = next) {
   1454     0    stevel 			NOT_DEAD(cur);
   1455     0    stevel 			next = cur->next;
   1456     0    stevel 			NOT_DEAD(next);
   1457     0    stevel 			ap = AUTH_PRIVATE(cur->auth);
   1458     0    stevel 			if (__rpc_gss_oids_equal(ap->mech_type,
   1459     0    stevel 			    (gss_OID) mech) && (cur->uid == uid) &&
   1460     0    stevel 			    (cur->zoneid == zoneid)) {
   1461     0    stevel 				if (cur->in_use) {
   1462     0    stevel 					RPCGSS_LOG(2, "rpc_gss_revauth:invalid "
   1463  6403   gt29601 					    "auth %p\n", (void *)cur->auth);
   1464     0    stevel 					ap->invalid = TRUE;
   1465     0    stevel 				} else {
   1466     0    stevel 					RPCGSS_LOG(2, "rpc_gss_revauth:destroy "
   1467  6403   gt29601 					    "auth %p\n", (void *)cur->auth);
   1468     0    stevel 					rpc_gss_destroy(cur->auth);
   1469     0    stevel 					kmem_cache_free(ga_cache_handle,
   1470  6403   gt29601 					    (void *)cur);
   1471     0    stevel 				}
   1472     0    stevel 				if (prev == NULL) {
   1473     0    stevel 					ga_cache_table[i] = next;
   1474     0    stevel 				} else {
   1475     0    stevel 					prev->next = next;
   1476     0    stevel 					NOT_DEAD(prev->next);
   1477     0    stevel 				}
   1478     0    stevel 			} else {
   1479     0    stevel 				prev = cur;
   1480     0    stevel 			}
   1481     0    stevel 		}
   1482     0    stevel 	}
   1483     0    stevel 	rw_exit(&ga_cache_table_lock);
   1484     0    stevel 
   1485     0    stevel 	return (0);
   1486     0    stevel }
   1487     0    stevel 
   1488     0    stevel 
   1489     0    stevel /*
   1490     0    stevel  *  Delete all the entries indexed by the cache_key.
   1491     0    stevel  *
   1492     0    stevel  *  For example, the cache_key used for NFS is the address of the
   1493     0    stevel  *  security entry for each mount point.  When the file system is unmounted,
   1494     0    stevel  *  all the cache entries indexed by this key should be deleted.
   1495     0    stevel  */
   1496     0    stevel void
   1497     0    stevel rpc_gss_secpurge(void *cache_key)
   1498     0    stevel {
   1499     0    stevel 	struct ga_cache_entry *next, *prev, *cur;
   1500     0    stevel 	int i;
   1501     0    stevel 
   1502     0    stevel 	/*
   1503     0    stevel 	 *  Check the cache table against the cache_key.
   1504     0    stevel 	 */
   1505     0    stevel 	rw_enter(&ga_cache_table_lock, RW_WRITER);
   1506     0    stevel 	for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
   1507     0    stevel 		prev = NULL;
   1508     0    stevel 		for (cur = ga_cache_table[i]; cur; cur = next) {
   1509     0    stevel 			NOT_DEAD(cur);
   1510     0    stevel 			next = cur->next;
   1511     0    stevel 			NOT_DEAD(next);
   1512     0    stevel 			if (cache_key == cur->cache_key) {
   1513     0    stevel 				RPCGSS_LOG(2, "rpc_gss_secpurge: destroy auth "
   1514  6403   gt29601 				    "%p\n", (void *)cur->auth);
   1515  6403   gt29601 				if (cur->in_use == FALSE)
   1516  6403   gt29601 					rpc_gss_destroy(cur->auth);
   1517     0    stevel 				kmem_cache_free(ga_cache_handle, (void *)cur);
   1518     0    stevel 				if (prev == NULL) {
   1519     0    stevel 					ga_cache_table[i] = next;
   1520     0    stevel 				} else {
   1521     0    stevel 					NOT_DEAD(prev->next);
   1522     0    stevel 					prev->next = next;
   1523     0    stevel 				}
   1524     0    stevel 			} else {
   1525     0    stevel 				prev = cur;
   1526     0    stevel 			}
   1527     0    stevel 		}
   1528     0    stevel 	}
   1529     0    stevel 	rw_exit(&ga_cache_table_lock);
   1530     0    stevel }
   1531     0    stevel 
   1532     0    stevel /*
   1533     0    stevel  * Function: rpc_gss_nextverf.  Not used.
   1534     0    stevel  */
   1535     0    stevel static void
   1536     0    stevel rpc_gss_nextverf()
   1537     0    stevel {
   1538     0    stevel }
   1539     0    stevel 
   1540     0    stevel /*
   1541     0    stevel  * Function: rpc_gss_marshall - no op routine.
   1542     0    stevel  *		rpc_gss_wrap() is doing the marshalling.
   1543     0    stevel  */
   1544     0    stevel /*ARGSUSED*/
   1545     0    stevel static bool_t
   1546     0    stevel rpc_gss_marshall(auth, xdrs)
   1547     0    stevel 	AUTH		*auth;
   1548     0    stevel 	XDR		*xdrs;
   1549     0    stevel {
   1550     0    stevel 	return (TRUE);
   1551     0    stevel }
   1552     0    stevel 
   1553     0    stevel /*
   1554     0    stevel  * Set service defaults.
   1555     0    stevel  * Not supported yet.
   1556     0    stevel  */
   1557     0    stevel /* ARGSUSED */
   1558     0    stevel bool_t
   1559     0    stevel rpc_gss_set_defaults(auth, service, qop)
   1560     0    stevel 	AUTH			*auth;
   1561     0    stevel 	rpc_gss_service_t	service;
   1562     0    stevel 	uint_t			qop;
   1563     0    stevel {
   1564     0    stevel 	return (FALSE);
   1565     0    stevel }
   1566     0    stevel 
   1567     0    stevel /* ARGSUSED */
   1568     0    stevel int
   1569     0    stevel rpc_gss_max_data_length(AUTH *rpcgss_handle, int max_tp_unit_len)
   1570     0    stevel {
   1571     0    stevel 	return (0);
   1572     0    stevel }
   1573  7387    Robert 
   1574  7387    Robert rpc_gss_service_t
   1575  7387    Robert rpc_gss_get_service_type(AUTH *auth)
   1576  7387    Robert {
   1577  7387    Robert 	rpc_gss_data		*ap = AUTH_PRIVATE(auth);
   1578  7387    Robert 
   1579  7387    Robert 	return (ap->service);
   1580  7387    Robert }
   1581