xref: /freebsd-src/lib/librpcsec_gss/rpcsec_gss.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
18f55a568SDoug Rabson /*-
28f55a568SDoug Rabson  * Copyright (c) 2008 Doug Rabson
38f55a568SDoug Rabson  * All rights reserved.
48f55a568SDoug Rabson  *
58f55a568SDoug Rabson  * Redistribution and use in source and binary forms, with or without
68f55a568SDoug Rabson  * modification, are permitted provided that the following conditions
78f55a568SDoug Rabson  * are met:
88f55a568SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
98f55a568SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
108f55a568SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
118f55a568SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
128f55a568SDoug Rabson  *    documentation and/or other materials provided with the distribution.
138f55a568SDoug Rabson  *
148f55a568SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158f55a568SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168f55a568SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178f55a568SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188f55a568SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198f55a568SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208f55a568SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218f55a568SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228f55a568SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238f55a568SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248f55a568SDoug Rabson  * SUCH DAMAGE.
258f55a568SDoug Rabson  */
268f55a568SDoug Rabson /*
27*8a16b7a1SPedro F. Giffuni   SPDX-License-Identifier: BSD-3-Clause
28*8a16b7a1SPedro F. Giffuni 
298f55a568SDoug Rabson   auth_gss.c
308f55a568SDoug Rabson 
318f55a568SDoug Rabson   RPCSEC_GSS client routines.
328f55a568SDoug Rabson 
338f55a568SDoug Rabson   Copyright (c) 2000 The Regents of the University of Michigan.
348f55a568SDoug Rabson   All rights reserved.
358f55a568SDoug Rabson 
368f55a568SDoug Rabson   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
378f55a568SDoug Rabson   All rights reserved, all wrongs reversed.
388f55a568SDoug Rabson 
398f55a568SDoug Rabson   Redistribution and use in source and binary forms, with or without
408f55a568SDoug Rabson   modification, are permitted provided that the following conditions
418f55a568SDoug Rabson   are met:
428f55a568SDoug Rabson 
438f55a568SDoug Rabson   1. Redistributions of source code must retain the above copyright
448f55a568SDoug Rabson      notice, this list of conditions and the following disclaimer.
458f55a568SDoug Rabson   2. Redistributions in binary form must reproduce the above copyright
468f55a568SDoug Rabson      notice, this list of conditions and the following disclaimer in the
478f55a568SDoug Rabson      documentation and/or other materials provided with the distribution.
488f55a568SDoug Rabson   3. Neither the name of the University nor the names of its
498f55a568SDoug Rabson      contributors may be used to endorse or promote products derived
508f55a568SDoug Rabson      from this software without specific prior written permission.
518f55a568SDoug Rabson 
528f55a568SDoug Rabson   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
538f55a568SDoug Rabson   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
548f55a568SDoug Rabson   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
558f55a568SDoug Rabson   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
568f55a568SDoug Rabson   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
578f55a568SDoug Rabson   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
588f55a568SDoug Rabson   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
598f55a568SDoug Rabson   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
608f55a568SDoug Rabson   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
618f55a568SDoug Rabson   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
628f55a568SDoug Rabson   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
638f55a568SDoug Rabson 
648f55a568SDoug Rabson   $Id: auth_gss.c,v 1.32 2002/01/15 15:43:00 andros Exp $
658f55a568SDoug Rabson */
668f55a568SDoug Rabson 
678f55a568SDoug Rabson #include <stdio.h>
688f55a568SDoug Rabson #include <stdlib.h>
698f55a568SDoug Rabson #include <unistd.h>
708f55a568SDoug Rabson #include <string.h>
718f55a568SDoug Rabson #include <errno.h>
728f55a568SDoug Rabson #include <netinet/in.h>
738f55a568SDoug Rabson #include <rpc/rpc.h>
748f55a568SDoug Rabson #include <rpc/rpcsec_gss.h>
758f55a568SDoug Rabson #include "rpcsec_gss_int.h"
768f55a568SDoug Rabson 
778f55a568SDoug Rabson static void	rpc_gss_nextverf(AUTH*);
788f55a568SDoug Rabson static bool_t	rpc_gss_marshal(AUTH *, XDR *);
798f55a568SDoug Rabson static bool_t	rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret);
808f55a568SDoug Rabson static bool_t	rpc_gss_refresh(AUTH *, void *);
818f55a568SDoug Rabson static bool_t	rpc_gss_validate(AUTH *, struct opaque_auth *);
828f55a568SDoug Rabson static void	rpc_gss_destroy(AUTH *);
838f55a568SDoug Rabson static void	rpc_gss_destroy_context(AUTH *, bool_t);
848f55a568SDoug Rabson 
858f55a568SDoug Rabson static struct auth_ops rpc_gss_ops = {
868f55a568SDoug Rabson 	rpc_gss_nextverf,
878f55a568SDoug Rabson 	rpc_gss_marshal,
888f55a568SDoug Rabson 	rpc_gss_validate,
898f55a568SDoug Rabson 	rpc_gss_refresh,
908f55a568SDoug Rabson 	rpc_gss_destroy
918f55a568SDoug Rabson };
928f55a568SDoug Rabson 
938f55a568SDoug Rabson enum rpcsec_gss_state {
948f55a568SDoug Rabson 	RPCSEC_GSS_START,
958f55a568SDoug Rabson 	RPCSEC_GSS_CONTEXT,
968f55a568SDoug Rabson 	RPCSEC_GSS_ESTABLISHED
978f55a568SDoug Rabson };
988f55a568SDoug Rabson 
998f55a568SDoug Rabson struct rpc_gss_data {
1008f55a568SDoug Rabson 	rpc_gss_options_req_t	gd_options;	/* GSS context options */
1018f55a568SDoug Rabson 	enum rpcsec_gss_state	gd_state;	/* connection state */
1028f55a568SDoug Rabson 	gss_buffer_desc		gd_verf;	/* save GSS_S_COMPLETE
1038f55a568SDoug Rabson 						 * NULL RPC verfier to
1048f55a568SDoug Rabson 						 * process at end of
1058f55a568SDoug Rabson 						 * context negotiation */
1068f55a568SDoug Rabson 	CLIENT			*gd_clnt;	/* client handle */
1078f55a568SDoug Rabson 	gss_name_t		gd_name;	/* service name */
1088f55a568SDoug Rabson 	gss_OID			gd_mech;	/* mechanism to use */
1098f55a568SDoug Rabson 	gss_qop_t		gd_qop;		/* quality of protection */
1108f55a568SDoug Rabson 	gss_ctx_id_t		gd_ctx;		/* context id */
1118f55a568SDoug Rabson 	struct rpc_gss_cred	gd_cred;	/* client credentials */
1128f55a568SDoug Rabson 	u_int			gd_win;		/* sequence window */
1138f55a568SDoug Rabson };
1148f55a568SDoug Rabson 
1158f55a568SDoug Rabson #define	AUTH_PRIVATE(auth)	((struct rpc_gss_data *)auth->ah_private)
1168f55a568SDoug Rabson 
1178f55a568SDoug Rabson static struct timeval AUTH_TIMEOUT = { 25, 0 };
1188f55a568SDoug Rabson 
1198f55a568SDoug Rabson AUTH *
rpc_gss_seccreate(CLIENT * clnt,const char * principal,const char * mechanism,rpc_gss_service_t service,const char * qop,rpc_gss_options_req_t * options_req,rpc_gss_options_ret_t * options_ret)1208f55a568SDoug Rabson rpc_gss_seccreate(CLIENT *clnt, const char *principal,
1218f55a568SDoug Rabson     const char *mechanism, rpc_gss_service_t service, const char *qop,
1228f55a568SDoug Rabson     rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
1238f55a568SDoug Rabson {
1248f55a568SDoug Rabson 	AUTH			*auth, *save_auth;
1258f55a568SDoug Rabson 	rpc_gss_options_ret_t	options;
1268f55a568SDoug Rabson 	gss_OID			oid;
1278f55a568SDoug Rabson 	u_int			qop_num;
1288f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
1298f55a568SDoug Rabson 	OM_uint32		maj_stat = 0, min_stat = 0;
1308f55a568SDoug Rabson 	gss_buffer_desc		principal_desc;
1318f55a568SDoug Rabson 
1328f55a568SDoug Rabson 	/*
1338f55a568SDoug Rabson 	 * Bail out now if we don't know this mechanism.
1348f55a568SDoug Rabson 	 */
1358f55a568SDoug Rabson 	if (!rpc_gss_mech_to_oid(mechanism, &oid))
1368f55a568SDoug Rabson 		return (NULL);
1378f55a568SDoug Rabson 
1388f55a568SDoug Rabson 	if (qop) {
1398f55a568SDoug Rabson 		if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num))
1408f55a568SDoug Rabson 			return (NULL);
1418f55a568SDoug Rabson 	} else {
1428f55a568SDoug Rabson 		qop_num = GSS_C_QOP_DEFAULT;
1438f55a568SDoug Rabson 	}
1448f55a568SDoug Rabson 
1458f55a568SDoug Rabson 	/*
1468f55a568SDoug Rabson 	 * If the caller doesn't want the options, point at local
1478f55a568SDoug Rabson 	 * storage to simplify the code below.
1488f55a568SDoug Rabson 	 */
1498f55a568SDoug Rabson 	if (!options_ret)
1508f55a568SDoug Rabson 		options_ret = &options;
1518f55a568SDoug Rabson 
1528f55a568SDoug Rabson 	/*
1538f55a568SDoug Rabson 	 * Default service is integrity.
1548f55a568SDoug Rabson 	 */
1558f55a568SDoug Rabson 	if (service == rpc_gss_svc_default)
1568f55a568SDoug Rabson 		service = rpc_gss_svc_integrity;
1578f55a568SDoug Rabson 
1588f55a568SDoug Rabson 	memset(options_ret, 0, sizeof(*options_ret));
1598f55a568SDoug Rabson 
1608f55a568SDoug Rabson 	log_debug("in rpc_gss_seccreate()");
1618f55a568SDoug Rabson 
1628f55a568SDoug Rabson 	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
1638f55a568SDoug Rabson 
1648f55a568SDoug Rabson 	auth = mem_alloc(sizeof(*auth));
1658f55a568SDoug Rabson 	if (auth == NULL) {
1668f55a568SDoug Rabson 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1678f55a568SDoug Rabson 		rpc_createerr.cf_error.re_errno = ENOMEM;
1688f55a568SDoug Rabson 		return (NULL);
1698f55a568SDoug Rabson 	}
1708f55a568SDoug Rabson 	gd = mem_alloc(sizeof(*gd));
1718f55a568SDoug Rabson 	if (gd == NULL) {
1728f55a568SDoug Rabson 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1738f55a568SDoug Rabson 		rpc_createerr.cf_error.re_errno = ENOMEM;
1748f55a568SDoug Rabson 		free(auth);
1758f55a568SDoug Rabson 		return (NULL);
1768f55a568SDoug Rabson 	}
1778f55a568SDoug Rabson 
1788f55a568SDoug Rabson 	auth->ah_ops = &rpc_gss_ops;
1798f55a568SDoug Rabson 	auth->ah_private = (caddr_t) gd;
1808f55a568SDoug Rabson 	auth->ah_cred.oa_flavor = RPCSEC_GSS;
1818f55a568SDoug Rabson 
1828f55a568SDoug Rabson 	principal_desc.value = (void *)(intptr_t) principal;
1838f55a568SDoug Rabson 	principal_desc.length = strlen(principal);
1848f55a568SDoug Rabson 	maj_stat = gss_import_name(&min_stat, &principal_desc,
1858f55a568SDoug Rabson 	    GSS_C_NT_HOSTBASED_SERVICE, &gd->gd_name);
1868f55a568SDoug Rabson 	if (maj_stat != GSS_S_COMPLETE) {
1878f55a568SDoug Rabson 		options_ret->major_status = maj_stat;
1888f55a568SDoug Rabson 		options_ret->minor_status = min_stat;
1898f55a568SDoug Rabson 		goto bad;
1908f55a568SDoug Rabson 	}
1918f55a568SDoug Rabson 
1928f55a568SDoug Rabson 	if (options_req) {
1938f55a568SDoug Rabson 		gd->gd_options = *options_req;
1948f55a568SDoug Rabson 	} else {
1958f55a568SDoug Rabson 		gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG;
1968f55a568SDoug Rabson 		gd->gd_options.time_req = 0;
1978f55a568SDoug Rabson 		gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL;
1988f55a568SDoug Rabson 		gd->gd_options.input_channel_bindings = NULL;
1998f55a568SDoug Rabson 	}
2008f55a568SDoug Rabson 	gd->gd_clnt = clnt;
2018f55a568SDoug Rabson 	gd->gd_ctx = GSS_C_NO_CONTEXT;
2028f55a568SDoug Rabson 	gd->gd_mech = oid;
2038f55a568SDoug Rabson 	gd->gd_qop = qop_num;
2048f55a568SDoug Rabson 
2058f55a568SDoug Rabson 	gd->gd_cred.gc_version = RPCSEC_GSS_VERSION;
2068f55a568SDoug Rabson 	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
2078f55a568SDoug Rabson 	gd->gd_cred.gc_seq = 0;
2088f55a568SDoug Rabson 	gd->gd_cred.gc_svc = service;
2098f55a568SDoug Rabson 
2108f55a568SDoug Rabson 	save_auth = clnt->cl_auth;
2118f55a568SDoug Rabson 
2128f55a568SDoug Rabson 	clnt->cl_auth = auth;
2138f55a568SDoug Rabson 	if (!rpc_gss_init(auth, options_ret)) {
2148f55a568SDoug Rabson 		clnt->cl_auth = save_auth;
2158f55a568SDoug Rabson 		goto bad;
2168f55a568SDoug Rabson 	}
2178f55a568SDoug Rabson 
2188f55a568SDoug Rabson 	clnt->cl_auth = save_auth;
2198f55a568SDoug Rabson 
2208f55a568SDoug Rabson 	return (auth);
2218f55a568SDoug Rabson 
2228f55a568SDoug Rabson  bad:
2238f55a568SDoug Rabson 	AUTH_DESTROY(auth);
2248f55a568SDoug Rabson 	return (NULL);
2258f55a568SDoug Rabson }
2268f55a568SDoug Rabson 
2278f55a568SDoug Rabson bool_t
rpc_gss_set_defaults(AUTH * auth,rpc_gss_service_t service,const char * qop)2288f55a568SDoug Rabson rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop)
2298f55a568SDoug Rabson {
2308f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
2318f55a568SDoug Rabson 	u_int			qop_num;
2328f55a568SDoug Rabson 	const char		*mechanism;
2338f55a568SDoug Rabson 
2348f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
2358f55a568SDoug Rabson 	if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) {
2368f55a568SDoug Rabson 		return (FALSE);
2378f55a568SDoug Rabson 	}
2388f55a568SDoug Rabson 
2398f55a568SDoug Rabson 	if (qop) {
2408f55a568SDoug Rabson 		if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) {
2418f55a568SDoug Rabson 			return (FALSE);
2428f55a568SDoug Rabson 		}
2438f55a568SDoug Rabson 	} else {
2448f55a568SDoug Rabson 		qop_num = GSS_C_QOP_DEFAULT;
2458f55a568SDoug Rabson 	}
2468f55a568SDoug Rabson 
2478f55a568SDoug Rabson 	gd->gd_cred.gc_svc = service;
2488f55a568SDoug Rabson 	gd->gd_qop = qop_num;
2498f55a568SDoug Rabson 	return (TRUE);
2508f55a568SDoug Rabson }
2518f55a568SDoug Rabson 
2528f55a568SDoug Rabson static void
rpc_gss_nextverf(__unused AUTH * auth)2538f55a568SDoug Rabson rpc_gss_nextverf(__unused AUTH *auth)
2548f55a568SDoug Rabson {
2558f55a568SDoug Rabson 
2568f55a568SDoug Rabson 	/* not used */
2578f55a568SDoug Rabson }
2588f55a568SDoug Rabson 
2598f55a568SDoug Rabson static bool_t
rpc_gss_marshal(__unused AUTH * auth,__unused XDR * xdrs)2608f55a568SDoug Rabson rpc_gss_marshal(__unused AUTH *auth, __unused XDR *xdrs)
2618f55a568SDoug Rabson {
2628f55a568SDoug Rabson 
2638f55a568SDoug Rabson 	/* not used */
2648f55a568SDoug Rabson 	return (FALSE);
2658f55a568SDoug Rabson }
2668f55a568SDoug Rabson 
2678f55a568SDoug Rabson static bool_t
rpc_gss_validate(AUTH * auth,struct opaque_auth * verf)2688f55a568SDoug Rabson rpc_gss_validate(AUTH *auth, struct opaque_auth *verf)
2698f55a568SDoug Rabson {
2708f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
2718f55a568SDoug Rabson 	gss_qop_t		qop_state;
2728f55a568SDoug Rabson 	uint32_t		num;
2738f55a568SDoug Rabson 	gss_buffer_desc		signbuf, checksum;
2748f55a568SDoug Rabson 	OM_uint32		maj_stat, min_stat;
2758f55a568SDoug Rabson 
2768f55a568SDoug Rabson 	log_debug("in rpc_gss_validate()");
2778f55a568SDoug Rabson 
2788f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
2798f55a568SDoug Rabson 
2808f55a568SDoug Rabson 	if (gd->gd_state == RPCSEC_GSS_CONTEXT) {
2818f55a568SDoug Rabson 		/*
2828f55a568SDoug Rabson 		 * Save the on the wire verifier to validate last INIT
2838f55a568SDoug Rabson 		 * phase packet after decode if the major status is
2848f55a568SDoug Rabson 		 * GSS_S_COMPLETE.
2858f55a568SDoug Rabson 		 */
2868f55a568SDoug Rabson 		if (gd->gd_verf.value)
2878f55a568SDoug Rabson 			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
2888f55a568SDoug Rabson 			    (char *) &gd->gd_verf);
2898f55a568SDoug Rabson 		gd->gd_verf.value = mem_alloc(verf->oa_length);
2908f55a568SDoug Rabson 		if (gd->gd_verf.value == NULL) {
2918f55a568SDoug Rabson 			fprintf(stderr, "gss_validate: out of memory\n");
2928f55a568SDoug Rabson 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
2938f55a568SDoug Rabson 			return (FALSE);
2948f55a568SDoug Rabson 		}
2958f55a568SDoug Rabson 		memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length);
2968f55a568SDoug Rabson 		gd->gd_verf.length = verf->oa_length;
2978f55a568SDoug Rabson 		return (TRUE);
2988f55a568SDoug Rabson 	}
2998f55a568SDoug Rabson 
3008f55a568SDoug Rabson 	num = htonl(gd->gd_cred.gc_seq);
3018f55a568SDoug Rabson 	signbuf.value = &num;
3028f55a568SDoug Rabson 	signbuf.length = sizeof(num);
3038f55a568SDoug Rabson 
3048f55a568SDoug Rabson 	checksum.value = verf->oa_base;
3058f55a568SDoug Rabson 	checksum.length = verf->oa_length;
3068f55a568SDoug Rabson 
3078f55a568SDoug Rabson 	maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, &signbuf,
3088f55a568SDoug Rabson 	    &checksum, &qop_state);
3098f55a568SDoug Rabson 	if (maj_stat != GSS_S_COMPLETE || qop_state != gd->gd_qop) {
3108f55a568SDoug Rabson 		log_status("gss_verify_mic", gd->gd_mech, maj_stat, min_stat);
3118f55a568SDoug Rabson 		if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
3128f55a568SDoug Rabson 			rpc_gss_destroy_context(auth, TRUE);
3138f55a568SDoug Rabson 		}
3148f55a568SDoug Rabson 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
3158f55a568SDoug Rabson 		return (FALSE);
3168f55a568SDoug Rabson 	}
3178f55a568SDoug Rabson 	return (TRUE);
3188f55a568SDoug Rabson }
3198f55a568SDoug Rabson 
3208f55a568SDoug Rabson static bool_t
rpc_gss_init(AUTH * auth,rpc_gss_options_ret_t * options_ret)3218f55a568SDoug Rabson rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
3228f55a568SDoug Rabson {
3238f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
3248f55a568SDoug Rabson 	struct rpc_gss_init_res	 gr;
3258f55a568SDoug Rabson 	gss_buffer_desc		*recv_tokenp, recv_token, send_token;
3268f55a568SDoug Rabson 	OM_uint32		 maj_stat, min_stat, call_stat;
3278f55a568SDoug Rabson 	const char		*mech;
3288f55a568SDoug Rabson 
3298f55a568SDoug Rabson 	log_debug("in rpc_gss_refresh()");
3308f55a568SDoug Rabson 
3318f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
3328f55a568SDoug Rabson 
3338f55a568SDoug Rabson 	if (gd->gd_state != RPCSEC_GSS_START)
3348f55a568SDoug Rabson 		return (TRUE);
3358f55a568SDoug Rabson 
3368f55a568SDoug Rabson 	/* GSS context establishment loop. */
3378f55a568SDoug Rabson 	gd->gd_state = RPCSEC_GSS_CONTEXT;
3388f55a568SDoug Rabson 	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
3398f55a568SDoug Rabson 	gd->gd_cred.gc_seq = 0;
3408f55a568SDoug Rabson 
3418f55a568SDoug Rabson 	memset(&recv_token, 0, sizeof(recv_token));
3428f55a568SDoug Rabson 	memset(&gr, 0, sizeof(gr));
3438f55a568SDoug Rabson 	recv_tokenp = GSS_C_NO_BUFFER;
3448f55a568SDoug Rabson 
3458f55a568SDoug Rabson 	for (;;) {
3468f55a568SDoug Rabson 		maj_stat = gss_init_sec_context(&min_stat,
3478f55a568SDoug Rabson 		    gd->gd_options.my_cred,
3488f55a568SDoug Rabson 		    &gd->gd_ctx,
3498f55a568SDoug Rabson 		    gd->gd_name,
3508f55a568SDoug Rabson 		    gd->gd_mech,
3518f55a568SDoug Rabson 		    gd->gd_options.req_flags,
3528f55a568SDoug Rabson 		    gd->gd_options.time_req,
3538f55a568SDoug Rabson 		    gd->gd_options.input_channel_bindings,
3548f55a568SDoug Rabson 		    recv_tokenp,
3558f55a568SDoug Rabson 		    &gd->gd_mech,	/* used mech */
3568f55a568SDoug Rabson 		    &send_token,
3578f55a568SDoug Rabson 		    &options_ret->ret_flags,
3588f55a568SDoug Rabson 		    &options_ret->time_req);
3598f55a568SDoug Rabson 
3608f55a568SDoug Rabson 		/*
3618f55a568SDoug Rabson 		 * Free the token which we got from the server (if
3628f55a568SDoug Rabson 		 * any).  Remember that this was allocated by XDR, not
3638f55a568SDoug Rabson 		 * GSS-API.
3648f55a568SDoug Rabson 		 */
3658f55a568SDoug Rabson 		if (recv_tokenp != GSS_C_NO_BUFFER) {
3668f55a568SDoug Rabson 			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
3678f55a568SDoug Rabson 			    (char *) &recv_token);
3688f55a568SDoug Rabson 			recv_tokenp = GSS_C_NO_BUFFER;
3698f55a568SDoug Rabson 		}
3708f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE &&
3718f55a568SDoug Rabson 		    maj_stat != GSS_S_CONTINUE_NEEDED) {
3728f55a568SDoug Rabson 			log_status("gss_init_sec_context", gd->gd_mech,
3738f55a568SDoug Rabson 			    maj_stat, min_stat);
3748f55a568SDoug Rabson 			options_ret->major_status = maj_stat;
3758f55a568SDoug Rabson 			options_ret->minor_status = min_stat;
3768f55a568SDoug Rabson 			break;
3778f55a568SDoug Rabson 		}
3788f55a568SDoug Rabson 		if (send_token.length != 0) {
3798f55a568SDoug Rabson 			memset(&gr, 0, sizeof(gr));
3808f55a568SDoug Rabson 
3818f55a568SDoug Rabson 			call_stat = clnt_call(gd->gd_clnt, NULLPROC,
3828f55a568SDoug Rabson 			    (xdrproc_t)xdr_gss_buffer_desc,
3838f55a568SDoug Rabson 			    &send_token,
3848f55a568SDoug Rabson 			    (xdrproc_t)xdr_rpc_gss_init_res,
3858f55a568SDoug Rabson 			    (caddr_t)&gr, AUTH_TIMEOUT);
3868f55a568SDoug Rabson 
3878f55a568SDoug Rabson 			gss_release_buffer(&min_stat, &send_token);
3888f55a568SDoug Rabson 
3898f55a568SDoug Rabson 			if (call_stat != RPC_SUCCESS)
3908f55a568SDoug Rabson 				break;
3918f55a568SDoug Rabson 
3928f55a568SDoug Rabson 			if (gr.gr_major != GSS_S_COMPLETE &&
3938f55a568SDoug Rabson 			    gr.gr_major != GSS_S_CONTINUE_NEEDED) {
3948f55a568SDoug Rabson 				log_status("server reply", gd->gd_mech,
3958f55a568SDoug Rabson 				    gr.gr_major, gr.gr_minor);
3968f55a568SDoug Rabson 				options_ret->major_status = gr.gr_major;
3978f55a568SDoug Rabson 				options_ret->minor_status = gr.gr_minor;
3988f55a568SDoug Rabson 				break;
3998f55a568SDoug Rabson 			}
4008f55a568SDoug Rabson 
4018f55a568SDoug Rabson 			/*
4028f55a568SDoug Rabson 			 * Save the server's gr_handle value, freeing
4038f55a568SDoug Rabson 			 * what we have already (remember that this
4048f55a568SDoug Rabson 			 * was allocated by XDR, not GSS-API).
4058f55a568SDoug Rabson 			 */
4068f55a568SDoug Rabson 			if (gr.gr_handle.length != 0) {
4078f55a568SDoug Rabson 				xdr_free((xdrproc_t) xdr_gss_buffer_desc,
4088f55a568SDoug Rabson 				    (char *) &gd->gd_cred.gc_handle);
4098f55a568SDoug Rabson 				gd->gd_cred.gc_handle = gr.gr_handle;
4108f55a568SDoug Rabson 			}
4118f55a568SDoug Rabson 
4128f55a568SDoug Rabson 			/*
4138f55a568SDoug Rabson 			 * Save the server's token as well.
4148f55a568SDoug Rabson 			 */
4158f55a568SDoug Rabson 			if (gr.gr_token.length != 0) {
4168f55a568SDoug Rabson 				recv_token = gr.gr_token;
4178f55a568SDoug Rabson 				recv_tokenp = &recv_token;
4188f55a568SDoug Rabson 			}
4198f55a568SDoug Rabson 
4208f55a568SDoug Rabson 			/*
4218f55a568SDoug Rabson 			 * Since we have copied out all the bits of gr
4228f55a568SDoug Rabson 			 * which XDR allocated for us, we don't need
4238f55a568SDoug Rabson 			 * to free it.
4248f55a568SDoug Rabson 			 */
4258f55a568SDoug Rabson 			gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
4268f55a568SDoug Rabson 		}
4278f55a568SDoug Rabson 
4288f55a568SDoug Rabson 		if (maj_stat == GSS_S_COMPLETE) {
4298f55a568SDoug Rabson 			gss_buffer_desc   bufin;
4308f55a568SDoug Rabson 			u_int seq, qop_state = 0;
4318f55a568SDoug Rabson 
4328f55a568SDoug Rabson 			/*
4338f55a568SDoug Rabson 			 * gss header verifier,
4348f55a568SDoug Rabson 			 * usually checked in gss_validate
4358f55a568SDoug Rabson 			 */
4368f55a568SDoug Rabson 			seq = htonl(gr.gr_win);
4378f55a568SDoug Rabson 			bufin.value = (unsigned char *)&seq;
4388f55a568SDoug Rabson 			bufin.length = sizeof(seq);
4398f55a568SDoug Rabson 
4408f55a568SDoug Rabson 			maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
4418f55a568SDoug Rabson 			    &bufin, &gd->gd_verf, &qop_state);
4428f55a568SDoug Rabson 
4438f55a568SDoug Rabson 			if (maj_stat != GSS_S_COMPLETE ||
4448f55a568SDoug Rabson 			    qop_state != gd->gd_qop) {
4458f55a568SDoug Rabson 				log_status("gss_verify_mic", gd->gd_mech,
4468f55a568SDoug Rabson 				    maj_stat, min_stat);
4478f55a568SDoug Rabson 				if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
4488f55a568SDoug Rabson 					rpc_gss_destroy_context(auth, TRUE);
4498f55a568SDoug Rabson 				}
4508f55a568SDoug Rabson 				_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR,
4518f55a568SDoug Rabson 				    EPERM);
4528f55a568SDoug Rabson 				options_ret->major_status = maj_stat;
4538f55a568SDoug Rabson 				options_ret->minor_status = min_stat;
4548f55a568SDoug Rabson 				return (FALSE);
4558f55a568SDoug Rabson 			}
4568f55a568SDoug Rabson 
4578f55a568SDoug Rabson 			options_ret->major_status = GSS_S_COMPLETE;
4588f55a568SDoug Rabson 			options_ret->minor_status = 0;
4598f55a568SDoug Rabson 			options_ret->rpcsec_version = gd->gd_cred.gc_version;
4608f55a568SDoug Rabson 			options_ret->gss_context = gd->gd_ctx;
4618f55a568SDoug Rabson 			if (rpc_gss_oid_to_mech(gd->gd_mech, &mech)) {
4628f55a568SDoug Rabson 				strlcpy(options_ret->actual_mechanism,
4638f55a568SDoug Rabson 				    mech,
4648f55a568SDoug Rabson 				    sizeof(options_ret->actual_mechanism));
4658f55a568SDoug Rabson 			}
4668f55a568SDoug Rabson 
4678f55a568SDoug Rabson 			gd->gd_state = RPCSEC_GSS_ESTABLISHED;
4688f55a568SDoug Rabson 			gd->gd_cred.gc_proc = RPCSEC_GSS_DATA;
4698f55a568SDoug Rabson 			gd->gd_cred.gc_seq = 0;
4708f55a568SDoug Rabson 			gd->gd_win = gr.gr_win;
4718f55a568SDoug Rabson 			break;
4728f55a568SDoug Rabson 		}
4738f55a568SDoug Rabson 	}
4748f55a568SDoug Rabson 	xdr_free((xdrproc_t) xdr_gss_buffer_desc,
4758f55a568SDoug Rabson 	    (char *) &gd->gd_verf);
4768f55a568SDoug Rabson 
4778f55a568SDoug Rabson 	/* End context negotiation loop. */
4788f55a568SDoug Rabson 	if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) {
4798f55a568SDoug Rabson 		rpc_createerr.cf_stat = RPC_AUTHERROR;
4808f55a568SDoug Rabson 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
4818f55a568SDoug Rabson 		return (FALSE);
4828f55a568SDoug Rabson 	}
4838f55a568SDoug Rabson 
4848f55a568SDoug Rabson 	return (TRUE);
4858f55a568SDoug Rabson }
4868f55a568SDoug Rabson 
4878f55a568SDoug Rabson static bool_t
rpc_gss_refresh(AUTH * auth,void * msg)4888f55a568SDoug Rabson rpc_gss_refresh(AUTH *auth, void *msg)
4898f55a568SDoug Rabson {
4908f55a568SDoug Rabson 	struct rpc_msg *reply = (struct rpc_msg *) msg;
4918f55a568SDoug Rabson 	rpc_gss_options_ret_t options;
4928f55a568SDoug Rabson 
4938f55a568SDoug Rabson 	/*
4948f55a568SDoug Rabson 	 * If the error was RPCSEC_GSS_CREDPROBLEM of
4958f55a568SDoug Rabson 	 * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All
4968f55a568SDoug Rabson 	 * other errors are fatal.
4978f55a568SDoug Rabson 	 */
4988f55a568SDoug Rabson 	if (reply->rm_reply.rp_stat == MSG_DENIED
4998f55a568SDoug Rabson 	    && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR
5008f55a568SDoug Rabson 	    && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM
5018f55a568SDoug Rabson 		|| reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) {
5028f55a568SDoug Rabson 		rpc_gss_destroy_context(auth, FALSE);
5038f55a568SDoug Rabson 		memset(&options, 0, sizeof(options));
5048f55a568SDoug Rabson 		return (rpc_gss_init(auth, &options));
5058f55a568SDoug Rabson 	}
5068f55a568SDoug Rabson 
5078f55a568SDoug Rabson 	return (FALSE);
5088f55a568SDoug Rabson }
5098f55a568SDoug Rabson 
5108f55a568SDoug Rabson static void
rpc_gss_destroy_context(AUTH * auth,bool_t send_destroy)5118f55a568SDoug Rabson rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy)
5128f55a568SDoug Rabson {
5138f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
5148f55a568SDoug Rabson 	OM_uint32		 min_stat;
5158f55a568SDoug Rabson 
5168f55a568SDoug Rabson 	log_debug("in rpc_gss_destroy_context()");
5178f55a568SDoug Rabson 
5188f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
5198f55a568SDoug Rabson 
5208f55a568SDoug Rabson 	if (gd->gd_state == RPCSEC_GSS_ESTABLISHED && send_destroy) {
5218f55a568SDoug Rabson 		gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY;
5228f55a568SDoug Rabson 		clnt_call(gd->gd_clnt, NULLPROC,
5238f55a568SDoug Rabson 		    (xdrproc_t)xdr_void, NULL,
5248f55a568SDoug Rabson 		    (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
5258f55a568SDoug Rabson 	}
5268f55a568SDoug Rabson 
5278f55a568SDoug Rabson 	/*
5288f55a568SDoug Rabson 	 * Free the context token. Remember that this was
5298f55a568SDoug Rabson 	 * allocated by XDR, not GSS-API.
5308f55a568SDoug Rabson 	 */
5318f55a568SDoug Rabson 	xdr_free((xdrproc_t) xdr_gss_buffer_desc,
5328f55a568SDoug Rabson 	    (char *) &gd->gd_cred.gc_handle);
5338f55a568SDoug Rabson 	gd->gd_cred.gc_handle.length = 0;
5348f55a568SDoug Rabson 
5358f55a568SDoug Rabson 	if (gd->gd_ctx != GSS_C_NO_CONTEXT)
5368f55a568SDoug Rabson 		gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL);
5378f55a568SDoug Rabson 
5388f55a568SDoug Rabson 	gd->gd_state = RPCSEC_GSS_START;
5398f55a568SDoug Rabson }
5408f55a568SDoug Rabson 
5418f55a568SDoug Rabson static void
rpc_gss_destroy(AUTH * auth)5428f55a568SDoug Rabson rpc_gss_destroy(AUTH *auth)
5438f55a568SDoug Rabson {
5448f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
5458f55a568SDoug Rabson 	OM_uint32		 min_stat;
5468f55a568SDoug Rabson 
5478f55a568SDoug Rabson 	log_debug("in rpc_gss_destroy()");
5488f55a568SDoug Rabson 
5498f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
5508f55a568SDoug Rabson 
5518f55a568SDoug Rabson 	rpc_gss_destroy_context(auth, TRUE);
5528f55a568SDoug Rabson 
5538f55a568SDoug Rabson 	if (gd->gd_name != GSS_C_NO_NAME)
5548f55a568SDoug Rabson 		gss_release_name(&min_stat, &gd->gd_name);
5558f55a568SDoug Rabson 	if (gd->gd_verf.value)
5568f55a568SDoug Rabson 		xdr_free((xdrproc_t) xdr_gss_buffer_desc,
5578f55a568SDoug Rabson 		    (char *) &gd->gd_verf);
5588f55a568SDoug Rabson 
5598f55a568SDoug Rabson 	mem_free(gd, sizeof(*gd));
5608f55a568SDoug Rabson 	mem_free(auth, sizeof(*auth));
5618f55a568SDoug Rabson }
5628f55a568SDoug Rabson 
5638f55a568SDoug Rabson bool_t
__rpc_gss_wrap(AUTH * auth,void * header,size_t headerlen,XDR * xdrs,xdrproc_t xdr_args,void * args_ptr)5648f55a568SDoug Rabson __rpc_gss_wrap(AUTH *auth, void *header, size_t headerlen,
5658f55a568SDoug Rabson     XDR* xdrs, xdrproc_t xdr_args, void *args_ptr)
5668f55a568SDoug Rabson {
5678f55a568SDoug Rabson 	XDR			 tmpxdrs;
5688f55a568SDoug Rabson 	char			 credbuf[MAX_AUTH_BYTES];
5698f55a568SDoug Rabson 	char			 tmpheader[MAX_AUTH_BYTES];
5708f55a568SDoug Rabson 	struct opaque_auth	 creds, verf;
5718f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
5728f55a568SDoug Rabson 	gss_buffer_desc		 rpcbuf, checksum;
5738f55a568SDoug Rabson 	OM_uint32		 maj_stat, min_stat;
5748f55a568SDoug Rabson 	bool_t			 xdr_stat;
5758f55a568SDoug Rabson 
5768f55a568SDoug Rabson 	log_debug("in rpc_gss_wrap()");
5778f55a568SDoug Rabson 
5788f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
5798f55a568SDoug Rabson 
5808f55a568SDoug Rabson 	if (gd->gd_state == RPCSEC_GSS_ESTABLISHED)
5818f55a568SDoug Rabson 		gd->gd_cred.gc_seq++;
5828f55a568SDoug Rabson 
5838f55a568SDoug Rabson 	/*
5848f55a568SDoug Rabson 	 * We need to encode our creds and then put the header and
5858f55a568SDoug Rabson 	 * creds together in a buffer so that we can create a checksum
5868f55a568SDoug Rabson 	 * for the verf.
5878f55a568SDoug Rabson 	 */
5888f55a568SDoug Rabson 	xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE);
5898f55a568SDoug Rabson 	if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gd_cred)) {
5908f55a568SDoug Rabson 		XDR_DESTROY(&tmpxdrs);
5918f55a568SDoug Rabson 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
5928f55a568SDoug Rabson 		return (FALSE);
5938f55a568SDoug Rabson 	}
5948f55a568SDoug Rabson 	creds.oa_flavor = RPCSEC_GSS;
5958f55a568SDoug Rabson 	creds.oa_base = credbuf;
5968f55a568SDoug Rabson 	creds.oa_length = XDR_GETPOS(&tmpxdrs);
5978f55a568SDoug Rabson 	XDR_DESTROY(&tmpxdrs);
5988f55a568SDoug Rabson 
5998f55a568SDoug Rabson 	xdrmem_create(&tmpxdrs, tmpheader, sizeof(tmpheader), XDR_ENCODE);
6008f55a568SDoug Rabson 	if (!XDR_PUTBYTES(&tmpxdrs, header, headerlen) ||
6018f55a568SDoug Rabson 	    !xdr_opaque_auth(&tmpxdrs, &creds)) {
6028f55a568SDoug Rabson 		XDR_DESTROY(&tmpxdrs);
6038f55a568SDoug Rabson 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
6048f55a568SDoug Rabson 		return (FALSE);
6058f55a568SDoug Rabson 	}
6068f55a568SDoug Rabson 	headerlen = XDR_GETPOS(&tmpxdrs);
6078f55a568SDoug Rabson 	XDR_DESTROY(&tmpxdrs);
6088f55a568SDoug Rabson 
6098f55a568SDoug Rabson 	if (!XDR_PUTBYTES(xdrs, tmpheader, headerlen)) {
6108f55a568SDoug Rabson 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
6118f55a568SDoug Rabson 		return (FALSE);
6128f55a568SDoug Rabson 	}
6138f55a568SDoug Rabson 
6148f55a568SDoug Rabson 	if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT ||
6158f55a568SDoug Rabson 	    gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
6168f55a568SDoug Rabson 		if (!xdr_opaque_auth(xdrs, &_null_auth)) {
6178f55a568SDoug Rabson 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
6188f55a568SDoug Rabson 			return (FALSE);
6198f55a568SDoug Rabson 		}
6208f55a568SDoug Rabson 	} else {
6218f55a568SDoug Rabson 		/*
6228f55a568SDoug Rabson 		 * Checksum serialized RPC header, up to and including
6238f55a568SDoug Rabson 		 * credential.
6248f55a568SDoug Rabson 		 */
6258f55a568SDoug Rabson 		rpcbuf.length = headerlen;
6268f55a568SDoug Rabson 		rpcbuf.value = tmpheader;
6278f55a568SDoug Rabson 
6288f55a568SDoug Rabson 		maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop,
6298f55a568SDoug Rabson 		    &rpcbuf, &checksum);
6308f55a568SDoug Rabson 
6318f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
6328f55a568SDoug Rabson 			log_status("gss_get_mic", gd->gd_mech,
6338f55a568SDoug Rabson 			    maj_stat, min_stat);
6348f55a568SDoug Rabson 			if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
6358f55a568SDoug Rabson 				rpc_gss_destroy_context(auth, TRUE);
6368f55a568SDoug Rabson 			}
6378f55a568SDoug Rabson 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
6388f55a568SDoug Rabson 			return (FALSE);
6398f55a568SDoug Rabson 		}
6408f55a568SDoug Rabson 
6418f55a568SDoug Rabson 		verf.oa_flavor = RPCSEC_GSS;
6428f55a568SDoug Rabson 		verf.oa_base = checksum.value;
6438f55a568SDoug Rabson 		verf.oa_length = checksum.length;
6448f55a568SDoug Rabson 
6458f55a568SDoug Rabson 		xdr_stat = xdr_opaque_auth(xdrs, &verf);
6468f55a568SDoug Rabson 		gss_release_buffer(&min_stat, &checksum);
6478f55a568SDoug Rabson 		if (!xdr_stat) {
6488f55a568SDoug Rabson 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
6498f55a568SDoug Rabson 			return (FALSE);
6508f55a568SDoug Rabson 		}
6518f55a568SDoug Rabson 	}
6528f55a568SDoug Rabson 
6538f55a568SDoug Rabson 	if (gd->gd_state != RPCSEC_GSS_ESTABLISHED ||
6548f55a568SDoug Rabson 	    gd->gd_cred.gc_svc == rpc_gss_svc_none) {
6558f55a568SDoug Rabson 		return (xdr_args(xdrs, args_ptr));
6568f55a568SDoug Rabson 	}
6578f55a568SDoug Rabson 	return (xdr_rpc_gss_wrap_data(xdrs, xdr_args, args_ptr,
6588f55a568SDoug Rabson 		gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc,
6598f55a568SDoug Rabson 		gd->gd_cred.gc_seq));
6608f55a568SDoug Rabson }
6618f55a568SDoug Rabson 
6628f55a568SDoug Rabson bool_t
__rpc_gss_unwrap(AUTH * auth,XDR * xdrs,xdrproc_t xdr_func,void * xdr_ptr)6638f55a568SDoug Rabson __rpc_gss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, void *xdr_ptr)
6648f55a568SDoug Rabson {
6658f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
6668f55a568SDoug Rabson 
6678f55a568SDoug Rabson 	log_debug("in rpc_gss_unwrap()");
6688f55a568SDoug Rabson 
6698f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
6708f55a568SDoug Rabson 
6718f55a568SDoug Rabson 	if (gd->gd_state != RPCSEC_GSS_ESTABLISHED ||
6728f55a568SDoug Rabson 	    gd->gd_cred.gc_svc == rpc_gss_svc_none) {
6738f55a568SDoug Rabson 		return (xdr_func(xdrs, xdr_ptr));
6748f55a568SDoug Rabson 	}
6758f55a568SDoug Rabson 	return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
6768f55a568SDoug Rabson 		gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc,
6778f55a568SDoug Rabson 		gd->gd_cred.gc_seq));
6788f55a568SDoug Rabson }
6798f55a568SDoug Rabson 
6808f55a568SDoug Rabson int
rpc_gss_max_data_length(AUTH * auth,int max_tp_unit_len)6818f55a568SDoug Rabson rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len)
6828f55a568SDoug Rabson {
6838f55a568SDoug Rabson 	struct rpc_gss_data	*gd;
6848f55a568SDoug Rabson 	int			want_conf;
6858f55a568SDoug Rabson 	OM_uint32		max;
6868f55a568SDoug Rabson 	OM_uint32		maj_stat, min_stat;
6878f55a568SDoug Rabson 	int			result;
6888f55a568SDoug Rabson 
6898f55a568SDoug Rabson 	gd = AUTH_PRIVATE(auth);
6908f55a568SDoug Rabson 
6918f55a568SDoug Rabson 	switch (gd->gd_cred.gc_svc) {
6928f55a568SDoug Rabson 	case rpc_gss_svc_none:
6938f55a568SDoug Rabson 		return (max_tp_unit_len);
6948f55a568SDoug Rabson 		break;
6958f55a568SDoug Rabson 
6968f55a568SDoug Rabson 	case rpc_gss_svc_default:
6978f55a568SDoug Rabson 	case rpc_gss_svc_integrity:
6988f55a568SDoug Rabson 		want_conf = FALSE;
6998f55a568SDoug Rabson 		break;
7008f55a568SDoug Rabson 
7018f55a568SDoug Rabson 	case rpc_gss_svc_privacy:
7028f55a568SDoug Rabson 		want_conf = TRUE;
7038f55a568SDoug Rabson 		break;
7048f55a568SDoug Rabson 
7058f55a568SDoug Rabson 	default:
7068f55a568SDoug Rabson 		return (0);
7078f55a568SDoug Rabson 	}
7088f55a568SDoug Rabson 
7098f55a568SDoug Rabson 	maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf,
7108f55a568SDoug Rabson 	    gd->gd_qop, max_tp_unit_len, &max);
7118f55a568SDoug Rabson 
7128f55a568SDoug Rabson 	if (maj_stat == GSS_S_COMPLETE) {
7138f55a568SDoug Rabson 		result = (int) max;
7148f55a568SDoug Rabson 		if (result < 0)
7158f55a568SDoug Rabson 			result = 0;
7168f55a568SDoug Rabson 		return (result);
7178f55a568SDoug Rabson 	} else {
7188f55a568SDoug Rabson 		log_status("gss_wrap_size_limit", gd->gd_mech,
7198f55a568SDoug Rabson 		    maj_stat, min_stat);
7208f55a568SDoug Rabson 		return (0);
7218f55a568SDoug Rabson 	}
7228f55a568SDoug Rabson }
723