changeset 10598:6f30db2c2cd0

PSARC 2009/418 Kerberos V5 PAC API 6283931 SPNEGO needs to follow latest RFC 6808598 krb5 APIs needed to create and parse PAC data 6817447 libgss and various mechs are hiding both the real minor_status and the error token
author Glenn Barry <Glenn.Barry@Sun.COM>
date Mon, 21 Sep 2009 16:47:51 -0700
parents 67b207a9aeb8
children 28d1f04d24a6
files usr/src/cmd/gss/gssd/gssd_clnt_stubs.c usr/src/cmd/gss/gssd/gssd_proc.c usr/src/cmd/krb5/kadmin/server/Makefile usr/src/cmd/krb5/krb5kdc/kdc_preauth.c usr/src/lib/gss_mechs/mech_krb5/Makefile.com usr/src/lib/gss_mechs/mech_krb5/include/k5-utf8.h usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.c usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.h usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.c usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.h usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krb5_encode.c usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krbasn1.h usr/src/lib/gss_mechs/mech_krb5/krb5/krb/chpw.c usr/src/lib/gss_mechs/mech_krb5/krb5/krb/pac.c usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_req_dec.c usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_safe.c usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c usr/src/lib/gss_mechs/mech_krb5/krb5/os/accessor.c usr/src/lib/gss_mechs/mech_krb5/mapfile-vers usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c usr/src/lib/gss_mechs/mech_krb5/mech/get_tkt_flags.c usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c usr/src/lib/gss_mechs/mech_krb5/mech/lucid_context.c usr/src/lib/gss_mechs/mech_krb5/mech/oid_ops.c usr/src/lib/gss_mechs/mech_krb5/mech/rel_buffer.c usr/src/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c usr/src/lib/gss_mechs/mech_krb5/support/utf8.c usr/src/lib/gss_mechs/mech_krb5/support/utf8_conv.c usr/src/lib/gss_mechs/mech_spnego/Makefile.com usr/src/lib/gss_mechs/mech_spnego/amd64/Makefile usr/src/lib/gss_mechs/mech_spnego/i386/Makefile usr/src/lib/gss_mechs/mech_spnego/mapfile-vers usr/src/lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c usr/src/lib/gss_mechs/mech_spnego/sparc/Makefile usr/src/lib/gss_mechs/mech_spnego/sparcv9/Makefile usr/src/lib/krb5/kadm5/clnt/Makefile.com usr/src/lib/krb5/kadm5/srv/Makefile.com usr/src/lib/libgss/Makefile.com usr/src/lib/libgss/g_accept_sec_context.c usr/src/lib/libgss/g_buffer_set.c usr/src/lib/libgss/g_glue.c usr/src/lib/libgss/g_inq_context_oid.c usr/src/lib/libgss/mapfile-vers usr/src/lib/libkrb5/common/mapfile-vers usr/src/uts/common/gssapi/gen_oids.c usr/src/uts/common/gssapi/gssapi_ext.h usr/src/uts/common/gssapi/gssd_clnt_stubs.c usr/src/uts/common/gssapi/include/mechglueP.h usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_generic.h usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_krb5.h usr/src/uts/common/gssapi/mechs/krb5/include/gssapi_krb5.h usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h usr/src/uts/common/gssapi/mechs/krb5/include/k5-platform.h usr/src/uts/common/gssapi/mechs/krb5/include/krb5.h usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/copy_auth.c usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/parse.c usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/unparse.c usr/src/uts/common/gssapi/mechs/krb5/mech/delete_sec_context.c usr/src/uts/common/gssapi/mechs/krb5/mech/gssapi_krb5.c
diffstat 61 files changed, 11050 insertions(+), 5605 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/gss/gssd/gssd_clnt_stubs.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/cmd/gss/gssd/gssd_clnt_stubs.c	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  *  GSSAPI library stub module for gssd.
  */
@@ -163,7 +160,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (output_cred_handle != NULL)
 			*output_cred_handle = NULL;
 		if (actual_mechs != NULL)
@@ -511,7 +508,7 @@
 		 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (cred_handle != NULL)
 			*cred_handle = NULL;
 
@@ -686,7 +683,7 @@
 
 	/* initialize the output parameters to empty values */
 	if (minor_status != NULL)
-		*minor_status = 0xffffffff;
+		*minor_status = DEFAULT_MINOR_STAT;
 	if (actual_mech_type != NULL)
 		*actual_mech_type = NULL;
 	if (output_token != NULL)
@@ -706,6 +703,21 @@
 		return (GSS_S_FAILURE);
 	}
 
+	/*
+	 * We could return from a GSS error here and need to return both the
+	 * minor_status and output_token, back to the caller if applicable.
+	 */
+	if (minor_status != NULL)
+		*minor_status = res.minor_status;
+
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
+		output_token->length =
+			(size_t)res.output_token.GSS_BUFFER_T_len;
+		output_token->value =
+			(void *)res.output_token.GSS_BUFFER_T_val;
+		res.output_token.GSS_BUFFER_T_val = NULL;
+		res.output_token.GSS_BUFFER_T_len = 0;
+	}
 
 	/* free the allocated memory for the flattened name */
 	gss_release_buffer(&minor_status_temp, &external_name);
@@ -714,30 +726,15 @@
 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
 		res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
 		/*
-		 * copy the rpc results into the return arguments
-		 * on CONTINUE_NEEDED only the output token, minor
-		 * code and ctxt handle are ready.
+		 * copy the rpc results into the return argument
+		 * on CONTINUE_NEEDED only ctx handle is ready.
 		 */
-		if (minor_status != NULL)
-			*minor_status = res.minor_status;
 		/*LINTED*/
 		*context_handle = *((OM_uint32 *)
 			res.context_handle.GSS_CTX_ID_T_val);
 
-		/*LINTED*/
-		*context_handle = *((OM_uint32 *)
-			res.context_handle.GSS_CTX_ID_T_val);
 		*gssd_context_verifier = res.gssd_context_verifier;
 
-		if (output_token != NULL) {
-			output_token->length =
-				(size_t)res.output_token.GSS_BUFFER_T_len;
-			output_token->value =
-				(void *)res.output_token.GSS_BUFFER_T_val;
-			res.output_token.GSS_BUFFER_T_val = NULL;
-			res.output_token.GSS_BUFFER_T_len = 0;
-		}
-
 		/* the rest of the parameters is only ready on COMPLETE */
 		if (res.status == GSS_S_COMPLETE) {
 			if (actual_mech_type != NULL) {
@@ -925,7 +922,7 @@
 
 	/* set the output parameters to empty values.... */
 	if (minor_status != NULL)
-		*minor_status = 0xffffffff;
+		*minor_status = DEFAULT_MINOR_STAT;
 	if (src_name != NULL) {
 		src_name->length = 0;
 		src_name->value = NULL;
@@ -947,31 +944,33 @@
 		return (GSS_S_FAILURE);
 	}
 
+	/*
+	 * We could return from a GSS error here and need to return both the
+	 * minor_status and output_token, back to the caller if applicable.
+	 */
+	if (minor_status != NULL)
+		*minor_status = res.minor_status;
+
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
+		output_token->length =
+			res.output_token.GSS_BUFFER_T_len;
+		output_token->value =
+			(void *) res.output_token.GSS_BUFFER_T_val;
+		res.output_token.GSS_BUFFER_T_val = 0;
+		res.output_token.GSS_BUFFER_T_len = 0;
+	}
 
 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
 		res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
 		/*
 		 * when gss returns CONTINUE_NEEDED we can only
-		 * use the context, minor, and output token
-		 * parameters.
+		 * use the context parameter.
 		 */
 		/*LINTED*/
 		*context_handle = *((gssd_ctx_id_t *)
 			res.context_handle.GSS_CTX_ID_T_val);
 		*gssd_context_verifier = res.gssd_context_verifier;
 
-		if (output_token != NULL) {
-			output_token->length =
-				res.output_token.GSS_BUFFER_T_len;
-			output_token->value =
-				(void *) res.output_token.GSS_BUFFER_T_val;
-			res.output_token.GSS_BUFFER_T_val = 0;
-			res.output_token.GSS_BUFFER_T_len = 0;
-		}
-
-		if (minor_status != NULL)
-			*minor_status = res.minor_status;
-
 		/* the other parameters are ready on for COMPLETE */
 		if (res.status == GSS_S_COMPLETE)
 		{
@@ -1127,7 +1126,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 
 		return (GSS_S_FAILURE);
 	}
@@ -1182,7 +1181,7 @@
 		 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (context_handle != NULL)
 			*context_handle = NULL;
 		if (output_token != NULL)
@@ -1203,7 +1202,7 @@
 		*context_handle = *((gssd_ctx_id_t *)
 			res.context_handle.GSS_CTX_ID_T_val);
 
-	if (output_token != NULL) {
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
 		output_token->length = res.output_token.GSS_BUFFER_T_len;
 		output_token->value = res.output_token.GSS_BUFFER_T_val;
 		res.output_token.GSS_BUFFER_T_len = 0;
@@ -1309,7 +1308,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (msg_token != NULL)
 			msg_token->length = 0;
 
@@ -1402,7 +1401,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (qop_state != NULL)
 			*qop_state = 0;
 
@@ -1498,7 +1497,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (conf_state != NULL)
 			*conf_state = 0;
 		if (output_message_buffer != NULL)
@@ -1604,7 +1603,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (output_message_buffer != NULL)
 			output_message_buffer->length = 0;
 		if (conf_state != NULL)
@@ -1723,17 +1722,17 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 
 		return (GSS_S_FAILURE);
 	}
 
+	if (minor_status != NULL)
+		*minor_status = res.minor_status;
 
 	/* now process the results and pass them back to the caller */
 
 	if (res.status == GSS_S_COMPLETE) {
-		if (minor_status != NULL)
-			*minor_status = res.minor_status;
 		if (message_context != NULL)
 			*message_context = res.message_context;
 		if (status_string != NULL) {
@@ -1780,7 +1779,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (mech_set != NULL)
 			*mech_set = NULL;
 
@@ -1873,7 +1872,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		if (name != NULL)
 			*name = NULL;
 		if (lifetime != NULL)
@@ -2042,7 +2041,7 @@
 	 */
 
 		if (minor_status != NULL)
-			*minor_status = 0xffffffff;
+			*minor_status = DEFAULT_MINOR_STAT;
 		return (GSS_S_FAILURE);
 	}
 
@@ -2348,7 +2347,7 @@
 		*context_handle =
 		    *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
 
-	if (output_token != NULL) {
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
 		output_token->length = res.output_token.GSS_BUFFER_T_len;
 		output_token->value =
 			(void *) MALLOC(output_token->length);
--- a/usr/src/cmd/gss/gssd/gssd_proc.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/cmd/gss/gssd/gssd_proc.c	Mon Sep 21 16:47:51 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  *  RPC server procedures for the gssapi usermode daemon gssd.
  */
@@ -1145,15 +1143,11 @@
 			return (TRUE);
 		}
 
-	if (argp->input_token_buffer.GSS_BUFFER_T_len == 0) {
-		input_token_buffer_ptr = GSS_C_NO_BUFFER;
-	} else {
-		input_token_buffer_ptr = &input_token_buffer;
-		input_token_buffer.length = (size_t)argp->input_token_buffer.
-						GSS_BUFFER_T_len;
-		input_token_buffer.value = (void *)argp->input_token_buffer.
-						GSS_BUFFER_T_val;
-	}
+	input_token_buffer_ptr = &input_token_buffer;
+	input_token_buffer.length = (size_t)argp->input_token_buffer.
+		GSS_BUFFER_T_len;
+	input_token_buffer.value = (void *)argp->input_token_buffer.
+		GSS_BUFFER_T_val;
 
 	if (argp->input_chan_bindings.present == YES) {
 		input_chan_bindings_ptr = &input_chan_bindings;
@@ -1318,9 +1312,13 @@
 		}
 		res->src_name.GSS_BUFFER_T_len = 0;
 		res->context_handle.GSS_CTX_ID_T_len = 0;
-		res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
-		res->output_token.GSS_BUFFER_T_len = 0;
-		res->mech_type.GSS_OID_len = 0;
+                res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
+                res->output_token.GSS_BUFFER_T_len =
+			(uint_t)output_token.length;
+                res->output_token.GSS_BUFFER_T_val =
+			(char *)output_token.value;
+
+                res->mech_type.GSS_OID_len = 0;
 	}
 
 /* return to caller */
@@ -1495,6 +1493,7 @@
 
 	/* return to caller */
 
+
 	return (TRUE);
 }
 
--- a/usr/src/cmd/krb5/kadmin/server/Makefile	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/cmd/krb5/kadmin/server/Makefile	Mon Sep 21 16:47:51 2009 -0700
@@ -1,9 +1,7 @@
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG= kadmind
 MANIFEST=	kadmin.xml
@@ -34,6 +32,7 @@
 DEFS = -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_COMPILE=1 -DHAVE_STEP=1  -DKRB5_KRB4_COMPAT
 
 CPPFLAGS += -I. -I$(SRC)/uts/common/gssapi/mechs/krb5/include \
+		-I$(SRC)/uts/common/gssapi \
 		-I$(SRC)/lib/krb5 \
 		-I$(SRC)/lib/krb5/kadm5 \
 		-I$(SRC)/lib/krb5/kadm5/srv \
--- a/usr/src/cmd/krb5/krb5kdc/kdc_preauth.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/cmd/krb5/krb5kdc/kdc_preauth.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -852,7 +852,7 @@
 			  "%spreauth required but hint list is empty",
 			  hw_only ? "hw" : "");
     }
-    retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data,
+    retval = encode_krb5_padata_sequence((krb5_pa_data * const *) pa_data,
 					 &edat);
     if (retval)
 	goto errout;
@@ -1461,9 +1461,9 @@
 	}
     }
     if (etype_info2)
-	retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry,
+	retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry,
 				    &scratch);
-    else 	retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry,
+    else 	retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry,
 				    &scratch);
     if (retval)
 	goto cleanup;
@@ -1556,9 +1556,9 @@
 	goto cleanup;
 
     if (etype_info2)
-	retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, &scratch);
+	retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry, &scratch);
     else
-	retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, &scratch);
+	retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry, &scratch);
 
     if (retval)
 	goto cleanup;
--- a/usr/src/lib/gss_mechs/mech_krb5/Makefile.com	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/Makefile.com	Mon Sep 21 16:47:51 2009 -0700
@@ -137,7 +137,7 @@
 	enc_helper.o gic_keytab.o gic_opt.o gic_pwd.o preauth2.o \
 	preauth.o vfy_increds.o vic_opt.o set_realm.o krb5_libinit.o chpw.o \
 	init_keyblock.o init_allocated_keyblock.o get_set_keyblock.o kerrs.o \
-	getuid.o
+	getuid.o pac.o
 
 K5_KRB_UTS= copy_athctr.o copy_auth.o copy_cksum.o copy_key.o \
 	copy_princ.o init_ctx.o kfree.o parse.o ser_actx.o \
@@ -175,7 +175,8 @@
 	util_dup.o util_localhost.o \
 	util_cksum.o acquire_cred.o init_sec_context.o \
 	set_ccache.o acquire_cred_with_pw.o lucid_context.o \
-	set_allowable_enctypes.o oid_ops.o export_name.o gss_libinit.o
+	set_allowable_enctypes.o oid_ops.o export_name.o gss_libinit.o \
+	util_buffer_set.o
 
 MECH_UTS= delete_sec_context.o gssapi_krb5.o \
 	import_sec_context.o k5seal.o k5sealv3.o \
@@ -190,7 +191,8 @@
 PROFILE_OBJS= prof_tree.o prof_file.o prof_parse.o prof_init.o \
 	prof_set.o prof_get.o
 
-SUPPORT_OBJS= fake-addrinfo.o init-addrinfo.o threads.o errors.o plugins.o
+SUPPORT_OBJS= fake-addrinfo.o init-addrinfo.o threads.o errors.o plugins.o \
+	      utf8_conv.o utf8.o
 
 KWARN_OBJS= kwarnd_clnt_stubs.o kwarnd_clnt.o kwarnd_handle.o kwarnd_xdr.o
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/gss_mechs/mech_krb5/include/k5-utf8.h	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2008 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2008 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* This notice applies to changes, created by or for Novell, Inc.,
+ * to preexisting works for which notices appear elsewhere in this file.
+ *
+ * Copyright (C) 2000 Novell, Inc. All Rights Reserved.
+ *
+ * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
+ * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
+ * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
+ * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
+ * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
+ * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
+ * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
+ * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ */
+
+#ifndef K5_UTF8_H
+#define K5_UTF8_H
+
+#include "autoconf.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if INT_MAX == 0x7fff
+typedef	unsigned int	krb5_ucs2;
+#elif SHRT_MAX == 0x7fff
+typedef	unsigned short	krb5_ucs2;
+#else
+#error undefined 16 bit type
+#endif
+
+#if INT_MAX == 0x7fffffffL
+typedef int	krb5_ucs4;
+#elif LONG_MAX == 0x7fffffffL
+typedef long	krb5_ucs4;
+#elif SHRT_MAX == 0x7fffffffL
+typedef short	krb5_ucs4;
+#else
+#error: undefined 32 bit type
+#endif
+
+#define KRB5_MAX_UTF8_LEN   (sizeof(krb5_ucs2) * 3/2)
+
+int krb5int_utf8_to_ucs2(const char *p, krb5_ucs2 *out);
+size_t krb5int_ucs2_to_utf8(krb5_ucs2 c, char *buf);
+
+int krb5int_utf8_to_ucs4(const char *p, krb5_ucs4 *out);
+size_t krb5int_ucs4_to_utf8(krb5_ucs4 c, char *buf);
+
+int
+krb5int_ucs2s_to_utf8s(const krb5_ucs2 *ucs2s,
+		       char **utf8s,
+		       size_t *utf8slen);
+
+int
+krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s,
+			size_t ucs2slen,
+		        char **utf8s,
+		        size_t *utf8slen);
+
+int
+krb5int_ucs2les_to_utf8s(const unsigned char *ucs2les,
+			 char **utf8s,
+			 size_t *utf8slen);
+
+int
+krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les,
+			  size_t ucs2leslen,
+			  char **utf8s,
+			  size_t *utf8slen);
+
+int
+krb5int_utf8s_to_ucs2s(const char *utf8s,
+		       krb5_ucs2 **ucs2s,
+		       size_t *ucs2chars);
+
+int
+krb5int_utf8cs_to_ucs2s(const char *utf8s,
+			size_t utf8slen,
+		        krb5_ucs2 **ucs2s,
+		        size_t *ucs2chars);
+
+int
+krb5int_utf8s_to_ucs2les(const char *utf8s,
+			 unsigned char **ucs2les,
+		         size_t *ucs2leslen);
+
+int
+krb5int_utf8cs_to_ucs2les(const char *utf8s,
+			  size_t utf8slen,
+		          unsigned char **ucs2les,
+			  size_t *ucs2leslen);
+
+/* returns the number of bytes in the UTF-8 string */
+size_t krb5int_utf8_bytes(const char *);
+/* returns the number of UTF-8 characters in the string */
+size_t krb5int_utf8_chars(const char *);
+/* returns the number of UTF-8 characters in the counted string */
+size_t krb5int_utf8c_chars(const char *, size_t);
+/* returns the length (in bytes) of the UTF-8 character */
+int krb5int_utf8_offset(const char *);
+/* returns the length (in bytes) indicated by the UTF-8 character */
+int krb5int_utf8_charlen(const char *);
+
+/* returns the length (in bytes) indicated by the UTF-8 character
+ * also checks that shortest possible encoding was used
+ */
+int krb5int_utf8_charlen2(const char *);
+
+/* copies a UTF-8 character and returning number of bytes copied */
+int krb5int_utf8_copy(char *, const char *);
+
+/* returns pointer of next UTF-8 character in string */
+char *krb5int_utf8_next( const char *);
+/* returns pointer of previous UTF-8 character in string */
+char *krb5int_utf8_prev( const char *);
+
+/* primitive ctype routines -- not aware of non-ascii characters */
+int krb5int_utf8_isascii( const char *);
+int krb5int_utf8_isalpha( const char *);
+int krb5int_utf8_isalnum( const char *);
+int krb5int_utf8_isdigit( const char *);
+int krb5int_utf8_isxdigit( const char *);
+int krb5int_utf8_isspace( const char *);
+
+/* span characters not in set, return bytes spanned */
+size_t krb5int_utf8_strcspn( const char* str, const char *set);
+/* span characters in set, return bytes spanned */
+size_t krb5int_utf8_strspn( const char* str, const char *set);
+/* return first occurance of character in string */
+char *krb5int_utf8_strchr( const char* str, const char *chr);
+/* return first character of set in string */
+char *krb5int_utf8_strpbrk( const char* str, const char *set);
+/* reentrant tokenizer */
+char *krb5int_utf8_strtok( char* sp, const char* sep, char **last);
+
+/* Optimizations */
+extern const char krb5int_utf8_lentab[128];
+extern const char krb5int_utf8_mintab[32];
+
+#define KRB5_UTF8_ISASCII(p) ( !(*(const unsigned char *)(p) & 0x80 ) )
+#define KRB5_UTF8_CHARLEN(p) ( KRB5_UTF8_ISASCII(p) \
+	? 1 : krb5int_utf8_lentab[*(const unsigned char *)(p) ^ 0x80] )
+
+/* This is like CHARLEN but additionally validates to make sure
+ * the char used the shortest possible encoding.
+ * 'l' is used to temporarily hold the result of CHARLEN.
+ */
+#define KRB5_UTF8_CHARLEN2(p, l) ( ( ( l = KRB5_UTF8_CHARLEN( p )) < 3 || \
+	( krb5int_utf8_mintab[*(const unsigned char *)(p) & 0x1f] & (p)[1] ) ) ? \
+	l : 0 )
+
+#define KRB5_UTF8_OFFSET(p) ( KRB5_UTF8_ISASCII(p) \
+	? 1 : krb5int_utf8_offset((p)) )
+
+#define KRB5_UTF8_COPY(d,s) ( KRB5_UTF8_ISASCII(s) \
+	? (*(d) = *(s), 1) : krb5int_utf8_copy((d),(s)) )
+
+#define KRB5_UTF8_NEXT(p) (	KRB5_UTF8_ISASCII(p) \
+	? (char *)(p)+1 : krb5int_utf8_next((p)) )
+
+#define KRB5_UTF8_INCR(p) ((p) = KRB5_UTF8_NEXT(p))
+
+/* For symmetry */
+#define KRB5_UTF8_PREV(p) (krb5int_utf8_prev((p)))
+#define KRB5_UTF8_DECR(p) ((p)=KRB5_UTF8_PREV((p)))
+
+/*
+ * these macros assume 'x' is an ASCII x
+ * and assume the "C" locale
+ */
+#define KRB5_ASCII(c)		(!((c) & 0x80))
+#define KRB5_SPACE(c)		((c) == ' ' || (c) == '\t' || (c) == '\n')
+#define KRB5_DIGIT(c)		((c) >= '0' && (c) <= '9')
+#define KRB5_LOWER(c)		((c) >= 'a' && (c) <= 'z')
+#define KRB5_UPPER(c)		((c) >= 'A' && (c) <= 'Z')
+#define KRB5_ALPHA(c)		(KRB5_LOWER(c) || KRB5_UPPER(c))
+#define KRB5_ALNUM(c)		(KRB5_ALPHA(c) || KRB5_DIGIT(c))
+
+#define KRB5_LDH(c)		(KRB5_ALNUM(c) || (c) == '-')
+
+#define KRB5_HEXLOWER(c)	((c) >= 'a' && (c) <= 'f')
+#define KRB5_HEXUPPER(c)	((c) >= 'A' && (c) <= 'F')
+#define KRB5_HEX(c)		(KRB5_DIGIT(c) || \
+				KRB5_HEXLOWER(c) || KRB5_HEXUPPER(c))
+
+#endif /* K5_UTF8_H */
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,20 +1,15 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * src/lib/krb5/asn.1/asn1_encode.c
- * 
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -35,269 +30,671 @@
 #include "asn1_encode.h"
 #include "asn1_make.h"
 
-static asn1_error_code asn1_encode_integer_internal(asn1buf *buf,  long val,
-						    unsigned int *retlen)
+asn1_error_code asn1_encode_boolean(asn1buf *buf, asn1_intmax val,
+                                    unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length = 0;
-  long valcopy;
-  int digit;
-  
-  valcopy = val;
-  do {
-    digit = (int) (valcopy&0xFF);
-    retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
-    if(retval) return retval;
-    length++;
-    valcopy = valcopy >> 8;
-  } while (valcopy != 0 && valcopy != ~0);
+    asn1_error_code retval;
+    unsigned int length = 0;
+    unsigned int partlen = 1;
+    asn1_octet bval;
+
+    bval = val ? 0xFF : 0x00;
+
+    retval = asn1buf_insert_octet(buf, bval);
+    if (retval) return retval;
+
+    length = partlen;
+    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BOOLEAN, length, &partlen);
+    if (retval) return retval;
+    length += partlen;
+
+    *retlen = length;
+    return 0;
+}
 
-  if((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
-    retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
-    if(retval) return retval;
-    length++;
-  }else if((val < 0) && ((digit&0x80) != 0x80)){
-    retval = asn1buf_insert_octet(buf,0xFF);
-    if(retval) return retval;
-    length++;
-  }
+static asn1_error_code asn1_encode_integer_internal(asn1buf *buf,
+                                                    asn1_intmax val,
+                                                    unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int length = 0;
+    long valcopy;
+    int digit;
+
+    valcopy = val;
+    do {
+        digit = (int) (valcopy&0xFF);
+        retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
+        if (retval) return retval;
+        length++;
+        valcopy = valcopy >> 8;
+    } while (valcopy != 0 && valcopy != ~0);
+
+    if ((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
+        retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
+        if (retval) return retval;
+        length++;
+    } else if ((val < 0) && ((digit&0x80) != 0x80)) {
+        retval = asn1buf_insert_octet(buf,0xFF);
+        if (retval) return retval;
+        length++;
+    }
 
 
-  *retlen = length;
-  return 0;
-}
-
-asn1_error_code asn1_encode_integer(asn1buf * buf,  long val,
- unsigned int *retlen)
-{
-  asn1_error_code retval;
-  unsigned int length = 0;
-  unsigned  int partlen;
-  retval = asn1_encode_integer_internal(buf, val, &partlen);
-  if (retval) return retval;
-
-  length = partlen;
-    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 
-  if(retval) return retval;
-  length += partlen;
-
-  *retlen = length;
-  return 0;
+    *retlen = length;
+    return 0;
 }
 
-asn1_error_code
-asn1_encode_enumerated(asn1buf * buf, const long val,
-		       unsigned int *retlen)
+asn1_error_code asn1_encode_integer(asn1buf * buf, asn1_intmax val,
+                                    unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length = 0;
-  unsigned  int partlen;
-  retval = asn1_encode_integer_internal(buf, val, &partlen);
-  if (retval) return retval;
+    asn1_error_code retval;
+    unsigned int length = 0;
+    unsigned  int partlen;
+    retval = asn1_encode_integer_internal(buf, val, &partlen);
+    if (retval) return retval;
 
-  length = partlen;
-    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen); 
-  if(retval) return retval;
-  length += partlen;
+    length = partlen;
+    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
+    if (retval) return retval;
+    length += partlen;
 
-  *retlen = length;
-  return 0;
+    *retlen = length;
+    return 0;
 }
 
-asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val,
-					     unsigned int *retlen)
+#if 0
+asn1_error_code
+asn1_encode_enumerated(asn1buf * buf, long val,
+                       unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int length = 0;
+    unsigned  int partlen;
+    retval = asn1_encode_integer_internal(buf, val, &partlen);
+    if (retval) return retval;
+
+    length = partlen;
+    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen);
+    if (retval) return retval;
+    length += partlen;
+
+    *retlen = length;
+    return 0;
+}
+#endif
+
+asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
+                                             unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length = 0;
-  unsigned int partlen;
-  unsigned long valcopy;
-  int digit;
-  
-  valcopy = val;
-  do {
-    digit = (int) (valcopy&0xFF);
-    retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
-    if(retval) return retval;
-    length++;
-    valcopy = valcopy >> 8;
-  } while (valcopy != 0 && valcopy != ~0);
+    asn1_error_code retval;
+    unsigned int length = 0;
+    unsigned int partlen;
+    unsigned long valcopy;
+    int digit;
+
+    valcopy = val;
+    do {
+        digit = (int) (valcopy&0xFF);
+        retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
+        if (retval) return retval;
+        length++;
+        valcopy = valcopy >> 8;
+    } while (valcopy != 0);
+
+    if (digit&0x80) {                     /* make sure the high bit is */
+        retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
+        if (retval) return retval;
+        length++;
+    }
 
-  if(digit&0x80) {		          /* make sure the high bit is */
-    retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
-    if(retval) return retval;
-    length++;
-  }
+    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
+    if (retval) return retval;
+    length += partlen;
+
+    *retlen = length;
+    return 0;
+}
 
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 
-  if(retval) return retval;
-  length += partlen;
+static asn1_error_code
+encode_bytestring_with_tag(asn1buf *buf, unsigned int len,
+                           const void *val, int tag,
+                           unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int length;
 
-  *retlen = length;
-  return 0;
+    if (len > 0 && val == 0) return ASN1_MISSING_FIELD;
+    retval = asn1buf_insert_octetstring(buf, len, val);
+    if (retval) return retval;
+    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, tag,
+                           len, &length);
+    if (retval) return retval;
+
+    *retlen = len + length;
+    return 0;
 }
 
 asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
-				const asn1_octet *val,
-				unsigned int *retlen)
+                                const asn1_octet *val,
+                                unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length;
-
-  retval = asn1buf_insert_octetstring(buf, len, val);
-  if (retval) return retval;
-  retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_OBJECTIDENTIFIER,
-			 len, &length);
-  if (retval) return retval;
-
-  *retlen = len + length;
-  return 0;
+    return encode_bytestring_with_tag(buf, len, val, ASN1_OBJECTIDENTIFIER,
+                                      retlen);
 }
 
 asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
-					const asn1_octet *val,
-					unsigned int *retlen)
+                                        const void *val,
+                                        unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length;
-
-  retval = asn1buf_insert_octetstring(buf,len,val);
-  if(retval) return retval;
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
-  if(retval) return retval;
-
-  *retlen = len + length;
-  return 0;
+    return encode_bytestring_with_tag(buf, len, val, ASN1_OCTETSTRING,
+                                      retlen);
 }
 
-asn1_error_code asn1_encode_charstring(asn1buf *buf, unsigned int len,
-				       const char *val, unsigned int *retlen)
-{
-  asn1_error_code retval;
-  unsigned int length;
-
-  retval = asn1buf_insert_charstring(buf,len,val);
-  if(retval) return retval;
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
-  if(retval) return retval;
-
-  *retlen = len + length;
-  return 0;
-}
-
+#if 0
 asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen)
 {
-  asn1_error_code retval;
-  
-  retval = asn1buf_insert_octet(buf,0x00);
-  if(retval) return retval;
-  retval = asn1buf_insert_octet(buf,0x05);
-  if(retval) return retval;
+    asn1_error_code retval;
 
-  *retlen = 2;
-  return 0;
+    retval = asn1buf_insert_octet(buf,0x00);
+    if (retval) return retval;
+    retval = asn1buf_insert_octet(buf,0x05);
+    if (retval) return retval;
+
+    *retlen = 2;
+    return 0;
 }
 
 asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
-					    const char *val, int *retlen)
+                                            const char *val, int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length;
-
-  retval = asn1buf_insert_charstring(buf,len,val);
-  if(retval) return retval;
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_PRINTABLESTRING,len,			 &length);
-  if(retval) return retval;
-
-  *retlen = len + length;
-  return 0;
+    return encode_bytestring_with_tag(buf, len, val, ASN1_PRINTABLESTRING,
+                                      retlen);
 }
 
 asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
-				      const char *val, int *retlen)
+                                      const char *val, int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length;
-
-  retval = asn1buf_insert_charstring(buf,len,val);
-  if(retval) return retval;
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_IA5STRING,len,			 &length);
-  if(retval) return retval;
-
-  *retlen = len + length;
-  return 0;
+    return encode_bytestring_with_tag(buf, len, val, ASN1_IA5STRING,
+                                      retlen);
 }
+#endif
 
 asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
-					unsigned int *retlen)
+                                        unsigned int *retlen)
 {
-  asn1_error_code retval;
-  struct tm *gtime, gtimebuf;
-  char s[16], *sp;
-  unsigned int length, sum=0;
-  time_t gmt_time = val;
+    struct tm *gtime, gtimebuf;
+    char s[16], *sp;
+    time_t gmt_time = val;
 
-  /*
-   * Time encoding: YYYYMMDDhhmmssZ
-   */
-  if (gmt_time == 0) {
-      sp = "19700101000000Z";
-  } else {
+    /*
+     * Time encoding: YYYYMMDDhhmmssZ
+     */
+    if (gmt_time == 0) {
+        sp = "19700101000000Z";
+    } else {
+        int len;
 
-      /*
-       * Sanity check this just to be paranoid, as gmtime can return NULL,
-       * and some bogus implementations might overrun on the sprintf.
-       */
+        /*
+         * Sanity check this just to be paranoid, as gmtime can return NULL,
+         * and some bogus implementations might overrun on the sprintf.
+         */
 #ifdef HAVE_GMTIME_R
 # ifdef GMTIME_R_RETURNS_INT
-      if (gmtime_r(&gmt_time, &gtimebuf) != 0)
-	  return ASN1_BAD_GMTIME;
+        if (gmtime_r(&gmt_time, &gtimebuf) != 0)
+            return ASN1_BAD_GMTIME;
 # else
-      if (gmtime_r(&gmt_time, &gtimebuf) == NULL)
-	  return ASN1_BAD_GMTIME;
+        if (gmtime_r(&gmt_time, &gtimebuf) == NULL)
+            return ASN1_BAD_GMTIME;
 # endif
 #else
-      gtime = gmtime(&gmt_time);
-      if (gtime == NULL)
-	  return ASN1_BAD_GMTIME;
-      memcpy(&gtimebuf, gtime, sizeof(gtimebuf));
+        gtime = gmtime(&gmt_time);
+        if (gtime == NULL)
+            return ASN1_BAD_GMTIME;
+        memcpy(&gtimebuf, gtime, sizeof(gtimebuf));
 #endif
-      gtime = &gtimebuf;
+        gtime = &gtimebuf;
 
-      if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
-	  gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
-	  gtime->tm_min > 59 || gtime->tm_sec > 59)
-	  return ASN1_BAD_GMTIME;
-      sprintf(s, "%04d%02d%02d%02d%02d%02dZ",
-	      1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday,
-	      gtime->tm_hour, gtime->tm_min, gtime->tm_sec);
-      sp = s;
-  }
+        if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
+            gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
+            gtime->tm_min > 59 || gtime->tm_sec > 59)
+            return ASN1_BAD_GMTIME;
+        len = snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ",
+                       1900+gtime->tm_year, gtime->tm_mon+1,
+                       gtime->tm_mday, gtime->tm_hour,
+                       gtime->tm_min, gtime->tm_sec);
+        if (SNPRINTF_OVERFLOW(len, sizeof(s)))
+            /* Shouldn't be possible given above tests.  */
+            return ASN1_BAD_GMTIME;
+        sp = s;
+    }
 
-  retval = asn1buf_insert_charstring(buf,15,sp);
-  if(retval) return retval;
-  sum = 15;
-
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALTIME,sum,&length);
-  if(retval) return retval;
-  sum += length;
-
-  *retlen = sum;
-  return 0;
+    return encode_bytestring_with_tag(buf, 15, sp, ASN1_GENERALTIME,
+                                      retlen);
 }
 
 asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len,
-					  const char *val,
-					  unsigned int *retlen)
+                                          const void *val,
+                                          unsigned int *retlen)
+{
+    return encode_bytestring_with_tag(buf, len, val, ASN1_GENERALSTRING,
+                                      retlen);
+}
+
+asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
+                                      const void *val,
+                                      unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int length;
+
+    retval = asn1buf_insert_octetstring(buf, len, val);
+    if (retval) return retval;
+    retval = asn1buf_insert_octet(buf, 0);
+    if (retval) return retval;
+    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BITSTRING,
+                           len+1, &length);
+    if (retval) return retval;
+    *retlen = len + 1 + length;
+    return 0;
+}
+
+asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
+                                   const void *val, unsigned int *retlen)
+{
+    asn1_error_code retval;
+
+    retval = asn1buf_insert_octetstring(buf, len, val);
+    if (retval) return retval;
+    *retlen = len;
+    return 0;
+}
+
+/* ASN.1 constructed type encoder engine
+
+   Two entry points here:
+
+   krb5int_asn1_encode_a_thing: Incrementally adds the partial
+   encoding of an object to an already-initialized asn1buf.
+
+   krb5int_asn1_do_full_encode: Returns a completed encoding, in the
+   correct byte order, in an allocated krb5_data.  */
+
+#ifdef POINTERS_ARE_ALL_THE_SAME
+#define LOADPTR(PTR,TYPE)       \
+    (assert((TYPE)->loadptr != NULL), (TYPE)->loadptr(PTR))
+#else
+#define LOADPTR(PTR,TYPE)       \
+    (*(const void *const *)(PTR))
+#endif
+
+static int
+get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
+{
+    int i;
+    const struct atype_info *a;
+    const void *elt, *eltptr;
+
+    a = seq;
+    i = 0;
+    assert(a->type == atype_ptr);
+    assert(seq->size != 0);
+
+    while (1) {
+        eltptr = (const char *) valp + i * seq->size;
+        elt = LOADPTR(eltptr, a);
+        if (elt == NULL)
+            break;
+        i++;
+    }
+    return i;
+}
+static asn1_error_code
+encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
+                   const struct atype_info *eltinfo,
+                   unsigned int *retlen);
+
+static asn1_error_code
+encode_nullterm_sequence_of(asn1buf *buf, const void *val,
+                            const struct atype_info *type,
+                            int can_be_empty,
+                            unsigned int *retlen)
 {
-  asn1_error_code retval;
-  unsigned int length;
+    int length = get_nullterm_sequence_len(val, type);
+    if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD;
+    return encode_sequence_of(buf, length, val, type, retlen);
+}
+
+static asn1_error_code
+just_encode_sequence(asn1buf *buf, const void *val,
+                     const struct seq_info *seq,
+                     unsigned int *retlen);
+static asn1_error_code
+encode_a_field(asn1buf *buf, const void *val,
+               const struct field_info *field,
+               unsigned int *retlen);
+
+asn1_error_code
+krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
+                            const struct atype_info *a, unsigned int *retlen)
+{
+    switch (a->type) {
+    case atype_fn:
+        assert(a->enc != NULL);
+        return a->enc(buf, val, retlen);
+    case atype_sequence:
+        assert(a->seq != NULL);
+        return just_encode_sequence(buf, val, a->seq, retlen);
+    case atype_ptr:
+        assert(a->basetype != NULL);
+        return krb5int_asn1_encode_a_thing(buf, LOADPTR(val, a),
+                                           a->basetype, retlen);
+    case atype_field:
+        assert(a->field != NULL);
+        return encode_a_field(buf, val, a->field, retlen);
+    case atype_nullterm_sequence_of:
+    case atype_nonempty_nullterm_sequence_of:
+        assert(a->basetype != NULL);
+        return encode_nullterm_sequence_of(buf, val, a->basetype,
+                                           a->type == atype_nullterm_sequence_of,
+                                           retlen);
+    case atype_tagged_thing:
+    {
+        asn1_error_code retval;
+        unsigned int length, sum = 0;
+        retval = krb5int_asn1_encode_a_thing(buf, val, a->basetype, &length);
+        if (retval) return retval;
+        sum = length;
+        retval = asn1_make_etag(buf, a->tagtype, a->tagval, sum, &length);
+        if (retval) return retval;
+        sum += length;
+        *retlen = sum;
+        return 0;
+    }
+    case atype_int:
+        assert(a->loadint != NULL);
+        return asn1_encode_integer(buf, a->loadint(val), retlen);
+    case atype_uint:
+        assert(a->loaduint != NULL);
+        return asn1_encode_unsigned_integer(buf, a->loaduint(val), retlen);
+    case atype_min:
+    case atype_max:
+    case atype_fn_len:
+    default:
+        assert(a->type > atype_min);
+        assert(a->type < atype_max);
+        assert(a->type != atype_fn_len);
+        abort();
+    }
+}
+
+static asn1_error_code
+encode_a_field(asn1buf *buf, const void *val,
+               const struct field_info *field,
+               unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int sum = 0;
+
+    if (val == NULL) return ASN1_MISSING_FIELD;
+
+    switch (field->ftype) {
+    case field_immediate:
+    {
+        unsigned int length;
+
+        retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff,
+                                     &length);
+        if (retval) return retval;
+        sum += length;
+        break;
+    }
+    case field_sequenceof_len:
+    {
+        const void *dataptr, *lenptr;
+        int slen;
+        unsigned int length;
+        const struct atype_info *a;
 
-  retval = asn1buf_insert_charstring(buf,len,val);
-  if(retval) return retval;
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALSTRING,len,
-			 &length);
-  if(retval) return retval;
+        /* The field holds a pointer to the array of objects.  So the
+           address we compute is a pointer-to-pointer, and that's what
+           field->atype must help us dereference.  */
+        dataptr = (const char *)val + field->dataoff;
+        lenptr = (const char *)val + field->lenoff;
+        assert(field->atype->type == atype_ptr);
+        dataptr = LOADPTR(dataptr, field->atype);
+        a = field->atype->basetype;
+        assert(field->lentype != 0);
+        assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
+        assert(sizeof(int) <= sizeof(asn1_intmax));
+        assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
+        if (field->lentype->type == atype_int) {
+            asn1_intmax xlen = field->lentype->loadint(lenptr);
+            if (xlen < 0)
+                return EINVAL;
+            if ((unsigned int) xlen != (asn1_uintmax) xlen)
+                return EINVAL;
+            if ((unsigned int) xlen > INT_MAX)
+                return EINVAL;
+            slen = (int) xlen;
+        } else {
+            asn1_uintmax xlen = field->lentype->loaduint(lenptr);
+            if ((unsigned int) xlen != xlen)
+                return EINVAL;
+            if (xlen > INT_MAX)
+                return EINVAL;
+            slen = (int) xlen;
+        }
+        if (slen != 0 && dataptr == NULL)
+            return ASN1_MISSING_FIELD;
+        retval = encode_sequence_of(buf, slen, dataptr, a, &length);
+        if (retval) return retval;
+        sum += length;
+        break;
+    }
+    case field_normal:
+    {
+        const void *dataptr;
+        const struct atype_info *a;
+        unsigned int length;
+
+        dataptr = (const char *)val + field->dataoff;
+
+        a = field->atype;
+        assert(a->type != atype_fn_len);
+        retval = krb5int_asn1_encode_a_thing(buf, dataptr, a, &length);
+        if (retval) {
+            return retval;
+        }
+        sum += length;
+        break;
+    }
+    case field_string:
+    {
+        const void *dataptr, *lenptr;
+        const struct atype_info *a;
+        size_t slen;
+        unsigned int length;
+
+        dataptr = (const char *)val + field->dataoff;
+        lenptr = (const char *)val + field->lenoff;
+
+        a = field->atype;
+        assert(a->type == atype_fn_len);
+        assert(field->lentype != 0);
+        assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
+        assert(sizeof(int) <= sizeof(asn1_intmax));
+        assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
+        if (field->lentype->type == atype_int) {
+            asn1_intmax xlen = field->lentype->loadint(lenptr);
+            if (xlen < 0)
+                return EINVAL;
+            if ((size_t) xlen != (asn1_uintmax) xlen)
+                return EINVAL;
+            slen = (size_t) xlen;
+        } else {
+            asn1_uintmax xlen = field->lentype->loaduint(lenptr);
+            if ((size_t) xlen != xlen)
+                return EINVAL;
+            slen = (size_t) xlen;
+        }
+
+        dataptr = LOADPTR(dataptr, a);
+        if (slen == SIZE_MAX)
+            /* Error - negative or out of size_t range.  */
+            return EINVAL;
+        if (dataptr == NULL && slen != 0)
+            return ASN1_MISSING_FIELD;
+        /* Currently our string encoders want "unsigned int" for
+           lengths.  */
+        if (slen != (unsigned int) slen)
+            return EINVAL;
+        assert(a->enclen != NULL);
+        retval = a->enclen(buf, (unsigned int) slen, dataptr, &length);
+        if (retval) {
+            return retval;
+        }
+        sum += length;
+        break;
+    }
+    default:
+        assert(field->ftype > field_min);
+        assert(field->ftype < field_max);
+        assert(__LINE__ == 0);
+        abort();
+    }
+    if (field->tag >= 0) {
+        unsigned int length;
+        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, field->tag, sum,
+                                &length);
+        if (retval) {
+            return retval;
+        }
+        sum += length;
+    }
+    *retlen = sum;
+    return 0;
+}
 
-  *retlen = len + length;
-  return 0;
+static asn1_error_code
+encode_fields(asn1buf *buf, const void *val,
+              const struct field_info *fields, size_t nfields,
+              unsigned int optional,
+              unsigned int *retlen)
+{
+    size_t i;
+    unsigned int sum = 0;
+    for (i = nfields; i > 0; i--) {
+        const struct field_info *f = fields+i-1;
+        unsigned int length;
+        asn1_error_code retval;
+        int present;
+
+        if (f->opt == -1)
+            present = 1;
+        else if ((1u << f->opt) & optional)
+            present = 1;
+        else
+            present = 0;
+        if (present) {
+            retval = encode_a_field(buf, val, f, &length);
+            if (retval) return retval;
+            sum += length;
+        }
+    }
+    *retlen = sum;
+    return 0;
 }
+
+static asn1_error_code
+just_encode_sequence(asn1buf *buf, const void *val,
+                     const struct seq_info *seq,
+                     unsigned int *retlen)
+{
+    const struct field_info *fields = seq->fields;
+    size_t nfields = seq->n_fields;
+    unsigned int optional;
+    asn1_error_code retval;
+    unsigned int sum = 0;
+
+    if (seq->optional)
+        optional = seq->optional(val);
+    else
+        /* In this case, none of the field descriptors should indicate
+           that we examine any bits of this value.  */
+        optional = 0;
+    {
+        unsigned int length;
+        retval = encode_fields(buf, val, fields, nfields, optional, &length);
+        if (retval) return retval;
+        sum += length;
+    }
+    {
+        unsigned int length;
+        retval = asn1_make_sequence(buf, sum, &length);
+        if (retval) return retval;
+        sum += length;
+    }
+    *retlen = sum;
+    return 0;
+}
+
+static asn1_error_code
+encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
+                   const struct atype_info *eltinfo,
+                   unsigned int *retlen)
+{
+    asn1_error_code retval;
+    unsigned int sum = 0;
+    int i;
+
+    for (i = seqlen-1; i >= 0; i--) {
+        const void *eltptr;
+        unsigned int length;
+        const struct atype_info *a = eltinfo;
+
+        assert(eltinfo->size != 0);
+        eltptr = (const char *)val + i * eltinfo->size;
+        retval = krb5int_asn1_encode_a_thing(buf, eltptr, a, &length);
+        if (retval) return retval;
+        sum += length;
+    }
+    {
+        unsigned int length;
+        retval = asn1_make_sequence(buf, sum, &length);
+        if (retval) return retval;
+        sum += length;
+    }
+    *retlen = sum;
+    return 0;
+}
+
+krb5_error_code
+krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
+                            const struct atype_info *a)
+{
+    unsigned int length;
+    asn1_error_code retval;
+    asn1buf *buf = NULL;
+    krb5_data *d;
+
+    *code = NULL;
+
+    if (rep == NULL)
+        return ASN1_MISSING_FIELD;
+
+    retval = asn1buf_create(&buf);
+    if (retval)
+        return retval;
+
+    retval = krb5int_asn1_encode_a_thing(buf, rep, a, &length);
+    if (retval)
+        goto cleanup;
+    retval = asn12krb5_buf(buf, &d);
+    if (retval)
+        goto cleanup;
+    *code = d;
+cleanup:
+    asn1buf_destroy(&buf);
+    return retval;
+}
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,16 +1,15 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * src/lib/krb5/asn.1/asn1_encode.h
- * 
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -42,103 +41,96 @@
 
    Operations
 
+     asn1_encode_boolean
      asn1_encode_integer
+     asn1_encode_unsigned_integer
      asn1_encode_octetstring
-     asn1_encode_null
-     asn1_encode_printablestring
-     asn1_encode_ia5string
      asn1_encode_generaltime
      asn1_encode_generalstring
+     asn1_encode_bitstring
+     asn1_encode_oid
 */
 
+asn1_error_code asn1_encode_boolean
+        (asn1buf *buf, asn1_intmax val, unsigned int *retlen);
 asn1_error_code asn1_encode_integer
-	(asn1buf *buf, const long val, unsigned int *retlen);
+        (asn1buf *buf, asn1_intmax val, unsigned int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_enumerated
-(asn1buf *buf, const long val, unsigned int *retlen);
+(asn1buf *buf, long val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_unsigned_integer
-	(asn1buf *buf, const unsigned long val, 
-		   unsigned int *retlen);
+        (asn1buf *buf, asn1_uintmax val,
+                   unsigned int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_octetstring
-	(asn1buf *buf,
-		   const unsigned int len, const asn1_octet *val,
-		   unsigned int *retlen);
+        (asn1buf *buf,
+                   unsigned int len, const void *val,
+                   unsigned int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
+#define asn1_encode_charstring asn1_encode_octetstring
 
 asn1_error_code asn1_encode_oid
-	(asn1buf *buf,
-		   const unsigned int len, const asn1_octet *val,
-		   unsigned int *retlen);
+        (asn1buf *buf,
+                   unsigned int len, const asn1_octet *val,
+                   unsigned int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
-              the length of the encoding in *retlen.
-             Returns ENOMEM to signal an unsuccesful attempt
-              to expand the buffer. */
-
-asn1_error_code asn1_encode_charstring
-	(asn1buf *buf,
-		   const unsigned int len, const char *val,
-		   unsigned int *retlen);
-/* requires  *buf is allocated
-   modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_null
-	(asn1buf *buf, int *retlen);
+        (asn1buf *buf, int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of NULL into *buf and returns 
+   effects   Inserts the encoding of NULL into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_printablestring
-	(asn1buf *buf,
-		   const unsigned int len, const char *val,
-		   int *retlen);
+        (asn1buf *buf,
+                   unsigned int len, const char *val,
+                   int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_ia5string
-	(asn1buf *buf,
-		   const unsigned int len, const char *val,
-		   int *retlen);
+        (asn1buf *buf,
+                   unsigned int len, const char *val,
+                   int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
 asn1_error_code asn1_encode_generaltime
-	(asn1buf *buf, const time_t val, unsigned int *retlen);
+        (asn1buf *buf, time_t val, unsigned int *retlen);
 /* requires  *buf is allocated
    modifies  *buf, *retlen
    effects   Inserts the encoding of val into *buf and returns
@@ -148,14 +140,525 @@
    Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ */
 
 asn1_error_code asn1_encode_generalstring
-	(asn1buf *buf,
-		   const unsigned int len, const char *val,
-		   unsigned int *retlen);
+        (asn1buf *buf,
+                   unsigned int len, const void *val,
+                   unsigned int *retlen);
 /* requires  *buf is allocated,  val has a length of len characters
    modifies  *buf, *retlen
-   effects   Inserts the encoding of val into *buf and returns 
+   effects   Inserts the encoding of val into *buf and returns
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
+                                      const void *val,
+                                      unsigned int *retlen);
+/* requires  *buf is allocated,  val has a length of len characters
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
+                                   const void *val,
+                                   unsigned int *retlen);
+/* requires  *buf is allocated,  val has a length of len characters
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns
               the length of the encoding in *retlen.
              Returns ENOMEM to signal an unsuccesful attempt
               to expand the buffer. */
 
+/* Type descriptor info.
+
+   In this context, a "type" is a combination of a C data type
+   and an ASN.1 encoding scheme for it.  So we would have to define
+   different "types" for:
+
+   * unsigned char* encoded as octet string
+   * char* encoded as octet string
+   * char* encoded as generalstring
+   * krb5_data encoded as octet string
+   * krb5_data encoded as generalstring
+   * int32_t encoded as integer
+   * unsigned char encoded as integer
+
+   Perhaps someday some kind of flags could be defined so that minor
+   variations on the C types could be handled via common routines.
+
+   The handling of strings is pretty messy.  Currently, we have a
+   separate kind of encoder function that takes an extra length
+   parameter.  Perhaps we should just give up on that, always deal
+   with just a single location, and handle strings by via encoder
+   functions for krb5_data, keyblock, etc.
+
+   We wind up with a lot of load-time relocations being done, which is
+   a bit annoying.  Be careful about "fixing" that at the cost of too
+   much run-time performance.  It might work to have a master "module"
+   descriptor with pointers to various arrays (type descriptors,
+   strings, field descriptors, functions) most of which don't need
+   relocation themselves, and replace most of the pointers with table
+   indices.
+
+   It's a work in progress.  */
+
+enum atype_type {
+    /* For bounds checking only.  By starting with values above 1, we
+       guarantee that zero-initialized storage will be recognized as
+       invalid.  */
+    atype_min = 1,
+    /* Encoder function to be called with address of <thing>.  */
+    atype_fn,
+    /* Encoder function to be called with address of <thing> and a
+       length (unsigned int).  */
+    atype_fn_len,
+    /* Pointer to actual thing to be encoded.
+
+       Most of the fields are related only to the C type -- size, how
+       to fetch a pointer in a type-safe fashion -- but since the base
+       type descriptor encapsulates the encoding as well, different
+       encodings for the same C type may require different pointer-to
+       types as well.
+
+       Must not refer to atype_fn_len.  */
+    atype_ptr,
+    /* Sequence, with pointer to sequence descriptor header.  */
+    atype_sequence,
+    /* Sequence-of, with pointer to base type descriptor, represented
+       as a null-terminated array of pointers (and thus the "base"
+       type descriptor is actually an atype_ptr node).  */
+    atype_nullterm_sequence_of,
+    atype_nonempty_nullterm_sequence_of,
+    /* Encode this object using a single field descriptor.  This may
+       mean the atype/field breakdown needs revision....
+
+       Main expected uses: Encode realm component of principal as a
+       GENERALSTRING.  Pluck data and length fields out of a structure
+       and encode a counted SEQUENCE OF.  */
+    atype_field,
+    /* Tagged version of another type.  */
+    atype_tagged_thing,
+    /* Integer types.  */
+    atype_int,
+    atype_uint,
+    /* Unused except for bounds checking.  */
+    atype_max
+};
+
+/* Initialized structures could be a lot smaller if we could use C99
+   designated initializers, and a union for all the type-specific
+   stuff.  Maybe use the hack we use for krb5int_access, where we use
+   a run-time initialize if the compiler doesn't support designated
+   initializers?  That's a lot of work here, though, with so many
+   little structures.  Maybe if/when these get auto-generated.  */
+struct atype_info {
+    enum atype_type type;
+    /* used for sequence-of processing */
+    unsigned int size;
+    /* atype_fn */
+    asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *);
+    /* atype_fn_len */
+    asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *,
+                              unsigned int *);
+    /* atype_ptr, atype_fn_len */
+    const void *(*loadptr)(const void *);
+    /* atype_ptr, atype_nullterm_sequence_of */
+    const struct atype_info *basetype;
+    /* atype_sequence */
+    const struct seq_info *seq;
+    /* atype_field */
+    const struct field_info *field;
+    /* atype_tagged_thing */
+    unsigned int tagval : 8, tagtype : 8;
+    /* atype_[u]int */
+    asn1_intmax (*loadint)(const void *);
+    asn1_uintmax (*loaduint)(const void *);
+};
+
+/* The various DEF*TYPE macros must:
+
+   + Define a type named aux_typedefname_##DESCNAME, for use in any
+     types derived from the type being defined.
+
+   + Define an atype_info struct named krb5int_asn1type_##DESCNAME.
+
+   + Define any extra stuff needed in the type descriptor, like
+     pointer-load functions.
+
+   + Accept a following semicolon syntactically, to keep Emacs parsing
+     (and indentation calculating) code happy.
+
+   Nothing else should directly define the atype_info structures.  */
+
+/* Define a type for which we must use an explicit encoder function.
+   The DEFFNTYPE variant uses a function taking a void*, the
+   DEFFNXTYPE form wants a function taking a pointer to the actual C
+   type to be encoded; you should use the latter unless you've already
+   got the void* function supplied elsewhere.
+
+   Of course, we need a single, consistent type for the descriptor
+   structure field, so we use the function pointer type that uses
+   void*, and create a wrapper function in DEFFNXTYPE.  However, in
+   all our cases so far, the supplied function is static and not used
+   otherwise, so the compiler can merge it with the wrapper function
+   if the optimizer is good enough.  */
+#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN)                   \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_fn, sizeof(CTYPENAME), ENCFN,                     \
+    }
+#define DEFFNXTYPE(DESCNAME, CTYPENAME, ENCFN)                  \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    static asn1_error_code                                      \
+    aux_encfn_##DESCNAME(asn1buf *buf, const void *val,         \
+                         unsigned int *retlen)                  \
+    {                                                           \
+        return ENCFN(buf,                                       \
+                     (const aux_typedefname_##DESCNAME *)val,   \
+                     retlen);                                   \
+    }                                                           \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_fn, sizeof(CTYPENAME), aux_encfn_##DESCNAME,      \
+    }
+/* XXX The handling of data+length fields really needs reworking.
+   A type descriptor probably isn't the right way.
+
+   Also, the C type is likely to be one of char*, unsigned char*,
+   or (maybe) void*.  An enumerator or reference to an external
+   function would be more compact.
+
+   The supplied encoder function takes as an argument the data pointer
+   loaded from the indicated location, not the address of the field.
+   This isn't consistent with DEFFN[X]TYPE above, but all of the uses
+   of DEFFNLENTYPE are for string encodings, and that's how our
+   string-encoding primitives work.  So be it.  */
+#ifdef POINTERS_ARE_ALL_THE_SAME
+#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN)                \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_fn_len, 0, 0, ENCFN,                              \
+    }
+#else
+#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN)                \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    static const void *loadptr_for_##DESCNAME(const void *pv)   \
+    {                                                           \
+        const aux_typedefname_##DESCNAME *p = pv;               \
+        return *p;                                              \
+    }                                                           \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_fn_len, 0, 0, ENCFN,                              \
+        loadptr_for_##DESCNAME                                  \
+    }
 #endif
+/* A sequence, defined by the indicated series of fields, and an
+   optional function indicating which fields are present.  */
+#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT)            \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    static const struct seq_info aux_seqinfo_##DESCNAME = {     \
+        OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0])           \
+    };                                                          \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_sequence, sizeof(CTYPENAME), 0,0,0,0,             \
+        &aux_seqinfo_##DESCNAME,                                \
+    }
+/* Integer types.  */
+#define DEFINTTYPE(DESCNAME, CTYPENAME)                         \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    static asn1_intmax loadint_##DESCNAME(const void *p)        \
+    {                                                           \
+        assert(sizeof(CTYPENAME) <= sizeof(asn1_intmax));       \
+        return *(const aux_typedefname_##DESCNAME *)p;          \
+    }                                                           \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_int, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0,   \
+        loadint_##DESCNAME, 0,                                  \
+    }
+#define DEFUINTTYPE(DESCNAME, CTYPENAME)                        \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    static asn1_uintmax loaduint_##DESCNAME(const void *p)      \
+    {                                                           \
+        assert(sizeof(CTYPENAME) <= sizeof(asn1_uintmax));      \
+        return *(const aux_typedefname_##DESCNAME *)p;          \
+    }                                                           \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0,  \
+        0, loaduint_##DESCNAME,                                 \
+    }
+/* Pointers to other types, to be encoded as those other types.  */
+#ifdef POINTERS_ARE_ALL_THE_SAME
+#define DEFPTRTYPE(DESCNAME,BASEDESCNAME)                               \
+    typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, 0,         \
+        &krb5int_asn1type_##BASEDESCNAME, 0                             \
+    }
+#else
+#define DEFPTRTYPE(DESCNAME,BASEDESCNAME)                               \
+    typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
+    static const void *                                                 \
+    loadptr_for_##BASEDESCNAME##_from_##DESCNAME(const void *p)         \
+    {                                                                   \
+        const aux_typedefname_##DESCNAME *inptr = p;                    \
+        const aux_typedefname_##BASEDESCNAME *retptr;                   \
+        retptr = *inptr;                                                \
+        return retptr;                                                  \
+    }                                                                   \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0,            \
+        loadptr_for_##BASEDESCNAME##_from_##DESCNAME,                   \
+        &krb5int_asn1type_##BASEDESCNAME, 0                             \
+    }
+#endif
+/* This encodes a pointer-to-pointer-to-thing where the passed-in
+   value points to a null-terminated list of pointers to objects to be
+   encoded, and encodes a (possibly empty) SEQUENCE OF these objects.
+
+   BASEDESCNAME is a descriptor name for the pointer-to-thing
+   type.
+
+   When dealing with a structure containing a
+   pointer-to-pointer-to-thing field, make a DEFPTRTYPE of this type,
+   and use that type for the structure field.  */
+#define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME)                     \
+    typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME;  \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_nullterm_sequence_of, sizeof(aux_typedefname_##DESCNAME), \
+        0, 0,                                                           \
+        0 /* loadptr */,                                                \
+        &krb5int_asn1type_##BASEDESCNAME, 0                             \
+    }
+#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME)             \
+    typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME;  \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_nonempty_nullterm_sequence_of,                            \
+        sizeof(aux_typedefname_##DESCNAME),                             \
+        0, 0,                                                           \
+        0 /* loadptr */,                                                \
+        &krb5int_asn1type_##BASEDESCNAME, 0                             \
+    }
+/* Encode a thing (probably sub-fields within the structure) as a
+   single object.  */
+#define DEFFIELDTYPE(DESCNAME, CTYPENAME, FIELDINFO)                    \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;                       \
+    static const struct field_info aux_fieldinfo_##DESCNAME = FIELDINFO; \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0,                  \
+        &aux_fieldinfo_##DESCNAME                                       \
+    }
+/* Objects with an APPLICATION tag added.  */
+#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC)                       \
+    typedef aux_typedefname_##BASEDESC aux_typedefname_##DESCNAME;      \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_tagged_thing, sizeof(aux_typedefname_##DESCNAME),         \
+        0, 0, 0, &krb5int_asn1type_##BASEDESC, 0, 0, TAG, APPLICATION   \
+    }
+
+/* Declare an externally-defined type.  This is a hack we should do
+   away with once we move to generating code from a script.  For now,
+   this macro is unfortunately not compatible with the defining macros
+   above, since you can't do the typedefs twice and we need the
+   declarations to produce typedefs.  (We could eliminate the typedefs
+   from the DEF* macros, but then every DEF* macro use, even the ones
+   for internal type nodes we only use to build other types, would
+   need an accompanying declaration which explicitly lists the
+   type.)  */
+#define IMPORT_TYPE(DESCNAME, CTYPENAME)                        \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;               \
+    extern const struct atype_info krb5int_asn1type_##DESCNAME
+
+/* Create a partial-encoding function by the indicated name, for the
+   indicated type.  Should only be needed until we've converted all of
+   the encoders, then everything should use descriptor tables.  */
+extern asn1_error_code
+krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
+                            const struct atype_info *a, unsigned int *retlen);
+#define MAKE_ENCFN(FNAME,DESC)                                          \
+   static asn1_error_code FNAME (asn1buf *buf,                          \
+                           const aux_typedefname_##DESC *val,           \
+                           unsigned int *retlen)                        \
+    {                                                                   \
+        return krb5int_asn1_encode_a_thing(buf, val,                    \
+                                           &krb5int_asn1type_##DESC,    \
+                                           retlen);                     \
+    }                                                                   \
+    extern int dummy /* gobble semicolon */
+
+/* Sequence field descriptor.
+
+   Currently we assume everything is a single object with a type
+   descriptor, and then we bolt on some ugliness on the side for
+   handling strings with length fields.
+
+   Anything with "interesting" encoding handling, like a sequence-of
+   or a pointer to the actual value to encode, is handled via opaque
+   types with their own encoder functions.  Most of that should
+   eventually change.  */
+
+enum field_type {
+    /* Unused except for range checking.  */
+    field_min = 1,
+    /* Field ATYPE describes processing of field at DATAOFF.  */
+    field_normal,
+    /* Encode an "immediate" integer value stored in DATAOFF, with no
+       reference to the data structure.  */
+    field_immediate,
+    /* Encode some kind of string field encoded with pointer and
+       length.  (A GENERALSTRING represented as a null-terminated C
+       string would be handled as field_normal.)  */
+    field_string,
+    /* LENOFF indicates a value describing the length of the array at
+       DATAOFF, encoded as a sequence-of with the element type
+       described by ATYPE.  */
+    field_sequenceof_len,
+    /* Unused except for range checking.  */
+    field_max
+};
+/* To do: Consider using bitfields.  */
+struct field_info {
+    /* Type of the field.  */
+    unsigned int /* enum field_type */ ftype : 3;
+
+    /* Use of DATAOFF and LENOFF are described by the value in FTYPE.
+       Generally DATAOFF will be the offset from the supplied pointer
+       at which we find the object to be encoded.  */
+    unsigned int dataoff : 9, lenoff : 9;
+
+    /* If TAG is non-negative, a context tag with that value is added
+       to the encoding of the thing.  (XXX This would encode more
+       compactly as an unsigned bitfield value tagnum+1, with 0=no
+       tag.)  The tag is omitted for optional fields that are not
+       present.
+
+       It's a bit illogical to combine the tag and other field info,
+       since really a sequence field could have zero or several
+       context tags, and of course a tag could be used elsewhere.  But
+       the normal mode in the Kerberos ASN.1 description is to use one
+       context tag on each sequence field, so for now let's address
+       that case primarily and work around the other cases (thus tag<0
+       means skip tagging).  */
+    signed int tag : 5;
+
+    /* If OPT is non-negative and the sequence header structure has a
+       function pointer describing which fields are present, OPT is
+       the bit position indicating whether the currently-described
+       element is present.  (XXX Similar encoding issue.)
+
+       Note: Most of the time, I'm using the same number here as for
+       the context tag.  This is just because it's easier for me to
+       keep track while working on the code by hand.  The *only*
+       meaningful correlation is of this value and the bits set by the
+       "optional" function when examining the data structure.  */
+    signed int opt : 5;
+
+    /* For some values of FTYPE, this describes the type of the
+       object(s) to be encoded.  */
+    const struct atype_info *atype;
+
+    /* We use different types for "length" fields in different places.
+       So we need a good way to retrieve the various kinds of lengths
+       in a compatible way.  This may be a string length, or the
+       length of an array of objects to encode in a SEQUENCE OF.
+
+       In case the field is signed and negative, or larger than
+       size_t, return SIZE_MAX as an error indication.  We'll assume
+       for now that we'll never have 4G-1 (or 2**64-1, or on tiny
+       systems, 65535) sized values.  On most if not all systems we
+       care about, SIZE_MAX is equivalent to "all of addressable
+       memory" minus one byte.  That wouldn't leave enough extra room
+       for the structure we're encoding, so it's pretty safe to assume
+       SIZE_MAX won't legitimately come up on those systems.
+
+       If this code gets ported to a segmented architecture or other
+       system where it might be possible... figure it out then.  */
+    const struct atype_info *lentype;
+};
+
+/* Normal or optional sequence fields at a particular offset, encoded
+   as indicated by the listed DESCRiptor.  */
+#define FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,OPT)                       \
+    {                                                                   \
+        field_normal, OFFOF(TYPE, FIELDNAME, aux_typedefname_##DESCR),  \
+        0, TAG, OPT, &krb5int_asn1type_##DESCR                          \
+    }
+#define FIELDOF_NORM(TYPE,DESCR,FIELDNAME,TAG)  \
+    FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,-1)
+/* If encoding a subset of the fields of the current structure (for
+   example, a flat structure describing data that gets encoded as a
+   sequence containing one or more sequences), use ENCODEAS, no struct
+   field name(s), and the indicated type descriptor must support the
+   current struct type.  */
+#define FIELDOF_ENCODEAS(TYPE,DESCR,TAG) \
+    FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,-1)
+#define FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,OPT)                        \
+    {                                                                   \
+        field_normal,                                                   \
+        0 * sizeof(0 ? (TYPE *)0 : (aux_typedefname_##DESCR *) 0),      \
+        0, TAG, OPT, &krb5int_asn1type_##DESCR                          \
+    }
+
+/* Reinterpret some subset of the structure itself as something
+   else.  */
+#define FIELD_SELF(DESCR, TAG) \
+    { field_normal, 0, 0, TAG, -1, &krb5int_asn1type_##DESCR }
+
+#define FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,OPT) \
+   {                                                                    \
+       field_string,                                                    \
+       OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC),                  \
+       OFFOF(STYPE, LENFIELD, aux_typedefname_##LENDESC),               \
+       TAG, OPT, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENDESC  \
+   }
+#define FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,OPT)         \
+    FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,uint,LENFIELD,TAG,OPT)
+#define FIELDOF_STRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG)       \
+    FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,-1)
+#define FIELDOF_STRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \
+    FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,-1)
+#define FIELD_INT_IMM(VALUE,TAG)   \
+    { field_immediate, VALUE, 0, TAG, -1, 0, }
+
+#define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG)     \
+    {                                                                   \
+        field_sequenceof_len,                                           \
+        OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC),                 \
+        OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE),              \
+        TAG, -1, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE  \
+    }
+#define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG)   \
+    FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG)
+
+struct seq_info {
+    /* If present, returns a bitmask indicating which fields are
+       present.  See the "opt" field in struct field_info.  */
+    unsigned int (*optional)(const void *);
+    /* Indicates an array of sequence field descriptors.  */
+    const struct field_info *fields;
+    size_t n_fields;
+    /* Missing: Extensibility handling.  (New field type?)  */
+};
+
+extern krb5_error_code
+krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
+                            const struct atype_info *a);
+
+#define MAKE_FULL_ENCODER(FNAME, DESC)                                  \
+    krb5_error_code FNAME(const aux_typedefname_##DESC *rep,            \
+                          krb5_data **code)                             \
+    {                                                                   \
+        return krb5int_asn1_do_full_encode(rep, code,                   \
+                                           &krb5int_asn1type_##DESC);   \
+    }                                                                   \
+    extern int dummy /* gobble semicolon */
+
+#include <stddef.h>
+/* Ugly hack!
+   Like "offsetof", but with type checking.  */
+#define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE)  \
+    (sizeof(0 ? (TYPE *) 0 : &(LVALUE)))
+#define OFFOF(TYPE,FIELD,FTYPE)                                 \
+    (offsetof(TYPE, FIELD)                                      \
+     + 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE))
+
+#endif
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,14 +1,23 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 /*
  * src/lib/krb5/asn.1/asn1_k_encode.c
- * 
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -28,6 +37,1323 @@
 #include "asn1_make.h"
 #include "asn1_encode.h"
 #include <assert.h>
+#include "k5-platform-store_32.h" /* Solaris Kerberos */
+
+/* helper macros
+
+   These are mostly only needed for PKINIT, but there are three
+   basic-krb5 encoders not converted yet.  */
+
+/* setup() -- create and initialize bookkeeping variables
+     retval: stores error codes returned from subroutines
+     length: length of the most-recently produced encoding
+     sum: cumulative length of the entire encoding */
+#define asn1_setup()\
+  asn1_error_code retval;\
+  unsigned int sum=0
+
+/* form a sequence (by adding a sequence header to the current encoding) */
+#define asn1_makeseq()\
+{ unsigned int length;\
+  retval = asn1_make_sequence(buf,sum,&length);\
+  if (retval) {\
+    return retval; }\
+  sum += length; }
+
+/* produce the final output and clean up the workspace */
+#define asn1_cleanup()\
+  *retlen = sum;\
+  return 0
+
+/* asn1_addfield -- add a field, or component, to the encoding */
+#define asn1_addfield(value,tag,encoder)\
+{ unsigned int length; \
+  retval = encoder(buf,value,&length);  \
+  if (retval) {\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if (retval) {\
+    return retval; }\
+  sum += length; }
+
+DEFINTTYPE(int32, krb5_int32);
+DEFPTRTYPE(int32_ptr, int32);
+
+DEFUINTTYPE(uint, unsigned int);
+DEFUINTTYPE(octet, krb5_octet);
+DEFUINTTYPE(ui_4, krb5_ui_4);
+
+DEFFNLENTYPE(octetstring, unsigned char *, asn1_encode_octetstring);
+DEFFNLENTYPE(s_octetstring, char *, asn1_encode_octetstring);
+DEFFNLENTYPE(charstring, char *, asn1_encode_charstring);
+DEFFNLENTYPE(generalstring, char *, asn1_encode_generalstring);
+DEFFNLENTYPE(u_generalstring, unsigned char *, asn1_encode_generalstring);
+DEFFNLENTYPE(opaque, char *, asn1_encode_opaque);
+
+DEFFIELDTYPE(gstring_data, krb5_data,
+             FIELDOF_STRING(krb5_data, generalstring, data, length, -1));
+DEFPTRTYPE(gstring_data_ptr,gstring_data);
+
+DEFFIELDTYPE(ostring_data, krb5_data,
+             FIELDOF_STRING(krb5_data, s_octetstring, data, length, -1));
+DEFPTRTYPE(ostring_data_ptr,ostring_data);
+
+DEFFIELDTYPE(opaque_data, krb5_data,
+             FIELDOF_STRING(krb5_data, opaque, data, length, -1));
+
+DEFFIELDTYPE(realm_of_principal_data, krb5_principal_data,
+             FIELDOF_NORM(krb5_principal_data, gstring_data, realm, -1));
+DEFPTRTYPE(realm_of_principal, realm_of_principal_data);
+
+
+static const struct field_info princname_fields[] = {
+    FIELDOF_NORM(krb5_principal_data, int32, type, 0),
+    FIELDOF_SEQOF_INT32(krb5_principal_data, gstring_data_ptr, data, length, 1),
+};
+/* krb5_principal is a typedef for krb5_principal_data*, so this is
+   effectively "encode_principal_data_at" with an address arg.  */
+DEFSEQTYPE(principal_data, krb5_principal_data, princname_fields, 0);
+DEFPTRTYPE(principal, principal_data);
+
+static asn1_error_code
+asn1_encode_kerberos_time_at(asn1buf *buf, const krb5_timestamp *val,
+                             unsigned int *retlen)
+{
+    /* Range checking for time_t vs krb5_timestamp?  */
+    time_t tval = *val;
+    return asn1_encode_generaltime(buf, tval, retlen);
+}
+DEFFNXTYPE(kerberos_time, krb5_timestamp, asn1_encode_kerberos_time_at);
+
+static const struct field_info address_fields[] = {
+    FIELDOF_NORM(krb5_address, int32, addrtype, 0),
+    FIELDOF_STRING(krb5_address, octetstring, contents, length, 1),
+};
+DEFSEQTYPE(address, krb5_address, address_fields, 0);
+DEFPTRTYPE(address_ptr, address);
+
+DEFNULLTERMSEQOFTYPE(seq_of_host_addresses, address_ptr);
+DEFPTRTYPE(ptr_seqof_host_addresses, seq_of_host_addresses);
+
+static unsigned int
+optional_encrypted_data (const void *vptr)
+{
+    const krb5_enc_data *val = vptr;
+    unsigned int optional = 0;
+
+    if (val->kvno != 0)
+        optional |= (1u << 1);
+
+    return optional;
+}
+
+static const struct field_info encrypted_data_fields[] = {
+    FIELDOF_NORM(krb5_enc_data, int32, enctype, 0),
+    FIELDOF_OPT(krb5_enc_data, uint, kvno, 1, 1),
+    FIELDOF_NORM(krb5_enc_data, ostring_data, ciphertext, 2),
+};
+DEFSEQTYPE(encrypted_data, krb5_enc_data, encrypted_data_fields,
+           optional_encrypted_data);
+
+/* The encode_bitstring function wants an array of bytes (since PKINIT
+   may provide something that isn't 32 bits), but krb5_flags is stored
+   as a 32-bit integer in host order.  */
+static asn1_error_code
+asn1_encode_krb5_flags_at(asn1buf *buf, const krb5_flags *val,
+                          unsigned int *retlen)
+{
+    unsigned char cbuf[4];
+    store_32_be((krb5_ui_4) *val, cbuf);
+    return asn1_encode_bitstring(buf, 4, cbuf, retlen);
+}
+DEFFNXTYPE(krb5_flags, krb5_flags, asn1_encode_krb5_flags_at);
+
+static const struct field_info authdata_elt_fields[] = {
+    /* ad-type[0]               INTEGER */
+    FIELDOF_NORM(krb5_authdata, int32, ad_type, 0),
+    /* ad-data[1]               OCTET STRING */
+    FIELDOF_STRING(krb5_authdata, octetstring, contents, length, 1),
+};
+DEFSEQTYPE(authdata_elt, krb5_authdata, authdata_elt_fields, 0);
+DEFPTRTYPE(authdata_elt_ptr, authdata_elt);
+DEFNONEMPTYNULLTERMSEQOFTYPE(auth_data, authdata_elt_ptr);
+DEFPTRTYPE(auth_data_ptr, auth_data);
+
+static const struct field_info encryption_key_fields[] = {
+    FIELDOF_NORM(krb5_keyblock, int32, enctype, 0),
+    FIELDOF_STRING(krb5_keyblock, octetstring, contents, length, 1),
+};
+DEFSEQTYPE(encryption_key, krb5_keyblock, encryption_key_fields, 0);
+DEFPTRTYPE(ptr_encryption_key, encryption_key);
+
+static const struct field_info checksum_fields[] = {
+    FIELDOF_NORM(krb5_checksum, int32, checksum_type, 0),
+    FIELDOF_STRING(krb5_checksum, octetstring, contents, length, 1),
+};
+DEFSEQTYPE(checksum, krb5_checksum, checksum_fields, 0);
+DEFPTRTYPE(checksum_ptr, checksum);
+DEFNULLTERMSEQOFTYPE(seq_of_checksum, checksum_ptr);
+DEFPTRTYPE(ptr_seqof_checksum, seq_of_checksum);
+
+static const struct field_info lr_fields[] = {
+    FIELDOF_NORM(krb5_last_req_entry, int32, lr_type, 0),
+    FIELDOF_NORM(krb5_last_req_entry, kerberos_time, value, 1),
+};
+DEFSEQTYPE(last_req_ent, krb5_last_req_entry, lr_fields, 0);
+
+DEFPTRTYPE(last_req_ent_ptr, last_req_ent);
+DEFNONEMPTYNULLTERMSEQOFTYPE(last_req, last_req_ent_ptr);
+DEFPTRTYPE(last_req_ptr, last_req);
+
+static const struct field_info ticket_fields[] = {
+    FIELD_INT_IMM(KVNO, 0),
+    FIELDOF_NORM(krb5_ticket, realm_of_principal, server, 1),
+    FIELDOF_NORM(krb5_ticket, principal, server, 2),
+    FIELDOF_NORM(krb5_ticket, encrypted_data, enc_part, 3),
+};
+DEFSEQTYPE(untagged_ticket, krb5_ticket, ticket_fields, 0);
+DEFAPPTAGGEDTYPE(ticket, 1, untagged_ticket);
+
+static const struct field_info pa_data_fields[] = {
+    FIELDOF_NORM(krb5_pa_data, int32, pa_type, 1),
+    FIELDOF_STRING(krb5_pa_data, octetstring, contents, length, 2),
+};
+DEFSEQTYPE(pa_data, krb5_pa_data, pa_data_fields, 0);
+DEFPTRTYPE(pa_data_ptr, pa_data);
+
+DEFNULLTERMSEQOFTYPE(seq_of_pa_data, pa_data_ptr);
+DEFPTRTYPE(ptr_seqof_pa_data, seq_of_pa_data);
+
+DEFPTRTYPE(ticket_ptr, ticket);
+DEFNONEMPTYNULLTERMSEQOFTYPE(seq_of_ticket,ticket_ptr);
+DEFPTRTYPE(ptr_seqof_ticket, seq_of_ticket);
+
+/* EncKDCRepPart ::= SEQUENCE */
+static const struct field_info enc_kdc_rep_part_fields[] = {
+    /* key[0]           EncryptionKey */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, ptr_encryption_key, session, 0),
+    /* last-req[1]      LastReq */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, last_req_ptr, last_req, 1),
+    /* nonce[2]         INTEGER */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, int32, nonce, 2),
+    /* key-expiration[3]        KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, key_exp, 3, 3),
+    /* flags[4]         TicketFlags */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, krb5_flags, flags, 4),
+    /* authtime[5]      KerberosTime */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, kerberos_time, times.authtime, 5),
+    /* starttime[6]     KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, times.starttime, 6, 6),
+    /* endtime[7]               KerberosTime */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, kerberos_time, times.endtime, 7),
+    /* renew-till[8]    KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, times.renew_till, 8, 8),
+    /* srealm[9]                Realm */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, realm_of_principal, server, 9),
+    /* sname[10]                PrincipalName */
+    FIELDOF_NORM(krb5_enc_kdc_rep_part, principal, server, 10),
+    /* caddr[11]                HostAddresses OPTIONAL */
+    FIELDOF_OPT(krb5_enc_kdc_rep_part, ptr_seqof_host_addresses, caddrs,
+                11, 11),
+    /* encrypted-pa-data[12]    SEQUENCE OF PA-DATA OPTIONAL */
+    FIELDOF_OPT(krb5_enc_kdc_rep_part, ptr_seqof_pa_data, enc_padata, 12, 12),
+};
+static unsigned int optional_enc_kdc_rep_part(const void *p)
+{
+    const krb5_enc_kdc_rep_part *val = p;
+    unsigned int optional = 0;
+
+    if (val->key_exp)
+        optional |= (1u << 3);
+    if (val->times.starttime)
+        optional |= (1u << 6);
+    if (val->flags & TKT_FLG_RENEWABLE)
+        optional |= (1u << 8);
+    if (val->caddrs != NULL && val->caddrs[0] != NULL)
+        optional |= (1u << 11);
+
+    return optional;
+}
+DEFSEQTYPE(enc_kdc_rep_part, krb5_enc_kdc_rep_part, enc_kdc_rep_part_fields,
+           optional_enc_kdc_rep_part);
+
+/* Yuck!  Eventually push this *up* above the encoder API and make the
+   rest of the library put the realm name in one consistent place.  At
+   the same time, might as well add the msg-type field and encode both
+   AS-REQ and TGS-REQ through the same descriptor.  */
+struct kdc_req_hack {
+    krb5_kdc_req v;
+    krb5_data *server_realm;
+};
+static const struct field_info kdc_req_hack_fields[] = {
+    FIELDOF_NORM(struct kdc_req_hack, krb5_flags, v.kdc_options, 0),
+    FIELDOF_OPT(struct kdc_req_hack, principal, v.client, 1, 1),
+    FIELDOF_NORM(struct kdc_req_hack, gstring_data_ptr, server_realm, 2),
+    FIELDOF_OPT(struct kdc_req_hack, principal, v.server, 3, 3),
+    FIELDOF_OPT(struct kdc_req_hack, kerberos_time, v.from, 4, 4),
+    FIELDOF_NORM(struct kdc_req_hack, kerberos_time, v.till, 5),
+    FIELDOF_OPT(struct kdc_req_hack, kerberos_time, v.rtime, 6, 6),
+    FIELDOF_NORM(struct kdc_req_hack, int32, v.nonce, 7),
+    FIELDOF_SEQOF_INT32(struct kdc_req_hack, int32_ptr, v.ktype, v.nktypes, 8),
+    FIELDOF_OPT(struct kdc_req_hack, ptr_seqof_host_addresses, v.addresses, 9, 9),
+    FIELDOF_OPT(struct kdc_req_hack, encrypted_data, v.authorization_data, 10, 10),
+    FIELDOF_OPT(struct kdc_req_hack, ptr_seqof_ticket, v.second_ticket, 11, 11),
+};
+static unsigned int optional_kdc_req_hack(const void *p)
+{
+    const struct kdc_req_hack *val2 = p;
+    const krb5_kdc_req *val = &val2->v;
+    unsigned int optional = 0;
+
+    if (val->second_ticket != NULL && val->second_ticket[0] != NULL)
+        optional |= (1u << 11);
+    if (val->authorization_data.ciphertext.data != NULL)
+        optional |= (1u << 10);
+    if (val->addresses != NULL && val->addresses[0] != NULL)
+        optional |= (1u << 9);
+    if (val->rtime)
+        optional |= (1u << 6);
+    if (val->from)
+        optional |= (1u << 4);
+    if (val->server != NULL)
+        optional |= (1u << 3);
+    if (val->client != NULL)
+        optional |= (1u << 1);
+
+    return optional;
+}
+DEFSEQTYPE(kdc_req_body_hack, struct kdc_req_hack, kdc_req_hack_fields,
+           optional_kdc_req_hack);
+static asn1_error_code
+asn1_encode_kdc_req_hack(asn1buf *, const struct kdc_req_hack *,
+                         unsigned int *);
+MAKE_ENCFN(asn1_encode_kdc_req_hack, kdc_req_body_hack);
+static asn1_error_code
+asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *val,
+                         unsigned int *retlen)
+{
+    struct kdc_req_hack val2;
+    val2.v = *val;
+    if (val->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
+        if (val->second_ticket != NULL && val->second_ticket[0] != NULL) {
+            val2.server_realm = &val->second_ticket[0]->server->realm;
+        } else return ASN1_MISSING_FIELD;
+    } else if (val->server != NULL) {
+        val2.server_realm = &val->server->realm;
+    } else return ASN1_MISSING_FIELD;
+    return asn1_encode_kdc_req_hack(buf, &val2, retlen);
+}
+DEFFNXTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body);
+/* end ugly hack */
+
+DEFPTRTYPE(ptr_kdc_req_body,kdc_req_body);
+
+static const struct field_info transited_fields[] = {
+    FIELDOF_NORM(krb5_transited, octet, tr_type, 0),
+    FIELDOF_NORM(krb5_transited, ostring_data, tr_contents, 1),
+};
+DEFSEQTYPE(transited, krb5_transited, transited_fields, 0);
+
+static const struct field_info krb_safe_body_fields[] = {
+    FIELDOF_NORM(krb5_safe, ostring_data, user_data, 0),
+    FIELDOF_OPT(krb5_safe, kerberos_time, timestamp, 1, 1),
+    FIELDOF_OPT(krb5_safe, int32, usec, 2, 2),
+    FIELDOF_OPT(krb5_safe, uint, seq_number, 3, 3),
+    FIELDOF_NORM(krb5_safe, address_ptr, s_address, 4),
+    FIELDOF_OPT(krb5_safe, address_ptr, r_address, 5, 5),
+};
+static unsigned int optional_krb_safe_body(const void *p)
+{
+    const krb5_safe *val = p;
+    unsigned int optional = 0;
+
+    if (val->timestamp) {
+        optional |= (1u << 1);
+        optional |= (1u << 2);
+    }
+    if (val->seq_number)
+        optional |= (1u << 3);
+    if (val->r_address != NULL)
+        optional |= (1u << 5);
+
+    return optional;
+}
+DEFSEQTYPE(krb_safe_body, krb5_safe, krb_safe_body_fields,
+           optional_krb_safe_body);
+
+static const struct field_info krb_cred_info_fields[] = {
+    FIELDOF_NORM(krb5_cred_info, ptr_encryption_key, session, 0),
+    FIELDOF_OPT(krb5_cred_info, realm_of_principal, client, 1, 1),
+    FIELDOF_OPT(krb5_cred_info, principal, client, 2, 2),
+    FIELDOF_OPT(krb5_cred_info, krb5_flags, flags, 3, 3),
+    FIELDOF_OPT(krb5_cred_info, kerberos_time, times.authtime, 4, 4),
+    FIELDOF_OPT(krb5_cred_info, kerberos_time, times.starttime, 5, 5),
+    FIELDOF_OPT(krb5_cred_info, kerberos_time, times.endtime, 6, 6),
+    FIELDOF_OPT(krb5_cred_info, kerberos_time, times.renew_till, 7, 7),
+    FIELDOF_OPT(krb5_cred_info, realm_of_principal, server, 8, 8),
+    FIELDOF_OPT(krb5_cred_info, principal, server, 9, 9),
+    FIELDOF_OPT(krb5_cred_info, ptr_seqof_host_addresses, caddrs, 10, 10),
+};
+static unsigned int optional_krb_cred_info(const void *p)
+{
+    const krb5_cred_info *val = p;
+    unsigned int optional = 0;
+
+    if (val->caddrs != NULL && val->caddrs[0] != NULL)
+        optional |= (1u << 10);
+    if (val->server != NULL) {
+        optional |= (1u << 9);
+        optional |= (1u << 8);
+    }
+    if (val->times.renew_till)
+        optional |= (1u << 7);
+    if (val->times.endtime)
+        optional |= (1u << 6);
+    if (val->times.starttime)
+        optional |= (1u << 5);
+    if (val->times.authtime)
+        optional |= (1u << 4);
+    if (val->flags)
+        optional |= (1u << 3);
+    if (val->client != NULL) {
+        optional |= (1u << 2);
+        optional |= (1u << 1);
+    }
+
+    return optional;
+}
+DEFSEQTYPE(cred_info, krb5_cred_info, krb_cred_info_fields,
+           optional_krb_cred_info);
+DEFPTRTYPE(cred_info_ptr, cred_info);
+DEFNULLTERMSEQOFTYPE(seq_of_cred_info, cred_info_ptr);
+
+DEFPTRTYPE(ptrseqof_cred_info, seq_of_cred_info);
+
+
+
+static unsigned int
+optional_etype_info_entry(const void *vptr)
+{
+    const krb5_etype_info_entry *val = vptr;
+    unsigned int optional = 0;
+
+    if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT)
+        optional |= (1u << 1);
+
+    return optional;
+}
+static const struct field_info etype_info_entry_fields[] = {
+    FIELDOF_NORM(krb5_etype_info_entry, int32, etype, 0),
+    FIELDOF_OPTSTRING(krb5_etype_info_entry, octetstring, salt, length, 1, 1),
+};
+DEFSEQTYPE(etype_info_entry, krb5_etype_info_entry, etype_info_entry_fields,
+           optional_etype_info_entry);
+
+static unsigned int
+optional_etype_info2_entry(const void *vptr)
+{
+    const krb5_etype_info_entry *val = vptr;
+    unsigned int optional = 0;
+
+    if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT)
+        optional |= (1u << 1);
+    if (val->s2kparams.data)
+        optional |= (1u << 2);
+
+    return optional;
+}
+
+static const struct field_info etype_info2_entry_fields[] = {
+    FIELDOF_NORM(krb5_etype_info_entry, int32, etype, 0),
+    FIELDOF_OPTSTRING(krb5_etype_info_entry, u_generalstring, salt, length,
+                      1, 1),
+    FIELDOF_OPT(krb5_etype_info_entry, ostring_data, s2kparams, 2, 2),
+};
+DEFSEQTYPE(etype_info2_entry, krb5_etype_info_entry, etype_info2_entry_fields,
+           optional_etype_info2_entry);
+
+DEFPTRTYPE(etype_info_entry_ptr, etype_info_entry);
+DEFNULLTERMSEQOFTYPE(etype_info, etype_info_entry_ptr);
+
+DEFPTRTYPE(etype_info2_entry_ptr, etype_info2_entry);
+DEFNULLTERMSEQOFTYPE(etype_info2, etype_info2_entry_ptr);
+
+static const struct field_info passwdsequence_fields[] = {
+    FIELDOF_NORM(passwd_phrase_element, ostring_data_ptr, passwd, 0),
+    FIELDOF_NORM(passwd_phrase_element, ostring_data_ptr, phrase, 1),
+};
+DEFSEQTYPE(passwdsequence, passwd_phrase_element, passwdsequence_fields, 0);
+
+DEFPTRTYPE(passwdsequence_ptr, passwdsequence);
+DEFNONEMPTYNULLTERMSEQOFTYPE(seqof_passwdsequence, passwdsequence_ptr);
+DEFPTRTYPE(ptr_seqof_passwdsequence, seqof_passwdsequence);
+
+
+static const struct field_info sam_challenge_fields[] = {
+    FIELDOF_NORM(krb5_sam_challenge, int32, sam_type, 0),
+    FIELDOF_NORM(krb5_sam_challenge, krb5_flags, sam_flags, 1),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_type_name, 2, 2),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_track_id,3, 3),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_challenge_label,4, 4),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_challenge,5, 5),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_response_prompt,6, 6),
+    FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_pk_for_sad,7, 7),
+    FIELDOF_OPT(krb5_sam_challenge, int32, sam_nonce, 8, 8),
+    FIELDOF_OPT(krb5_sam_challenge, checksum, sam_cksum, 9, 9),
+};
+static unsigned int optional_sam_challenge(const void *p)
+{
+    const krb5_sam_challenge *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_cksum.length)
+        optional |= (1u << 9);
+
+    if (val->sam_nonce)
+        optional |= (1u << 8);
+
+    if (val->sam_pk_for_sad.length > 0) optional |= (1u << 7);
+    if (val->sam_response_prompt.length > 0) optional |= (1u << 6);
+    if (val->sam_challenge.length > 0) optional |= (1u << 5);
+    if (val->sam_challenge_label.length > 0) optional |= (1u << 4);
+    if (val->sam_track_id.length > 0) optional |= (1u << 3);
+    if (val->sam_type_name.length > 0) optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(sam_challenge,krb5_sam_challenge,sam_challenge_fields,
+           optional_sam_challenge);
+
+#if 0 /* encoders not used! */
+MAKE_ENCFN(asn1_encode_sequence_of_checksum, seq_of_checksum);
+static asn1_error_code
+asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val,
+                            unsigned int *retlen)
+{
+    asn1_setup();
+    if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0]))
+        return ASN1_MISSING_FIELD;
+
+    asn1_addfield(val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
+
+    {
+        unsigned int length;
+
+        retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length,
+                                            (unsigned char *)val->sam_challenge_2_body.data);
+        if (retval) {
+            return retval;
+        }
+        sum += val->sam_challenge_2_body.length;
+        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
+                                val->sam_challenge_2_body.length, &length);
+        if (retval) {
+            return retval;
+        }
+        sum += length;
+    }
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
+DEFFNXTYPE(sam_challenge_2, krb5_sam_challenge_2, asn1_encode_sam_challenge_2);
+
+static const struct field_info sam_challenge_2_body_fields[] = {
+    FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_type, 0),
+    FIELDOF_NORM(krb5_sam_challenge_2_body, krb5_flags, sam_flags, 1),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_type_name, 2, 2),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_track_id,3, 3),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_challenge_label,4, 4),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_challenge,5, 5),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_response_prompt,6, 6),
+    FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_pk_for_sad,7, 7),
+    FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_nonce, 8),
+    FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_etype, 9),
+};
+static unsigned int optional_sam_challenge_2_body(const void *p)
+{
+    const krb5_sam_challenge_2_body *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_pk_for_sad.length > 0) optional |= (1u << 7);
+    if (val->sam_response_prompt.length > 0) optional |= (1u << 6);
+    if (val->sam_challenge.length > 0) optional |= (1u << 5);
+    if (val->sam_challenge_label.length > 0) optional |= (1u << 4);
+    if (val->sam_track_id.length > 0) optional |= (1u << 3);
+    if (val->sam_type_name.length > 0) optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(sam_challenge_2_body,krb5_sam_challenge_2_body,sam_challenge_2_body_fields,
+           optional_sam_challenge_2_body);
+#endif
+
+static const struct field_info sam_key_fields[] = {
+    FIELDOF_NORM(krb5_sam_key, encryption_key, sam_key, 0),
+};
+DEFSEQTYPE(sam_key, krb5_sam_key, sam_key_fields, 0);
+
+static const struct field_info enc_sam_response_enc_fields[] = {
+    FIELDOF_NORM(krb5_enc_sam_response_enc, int32, sam_nonce, 0),
+    FIELDOF_NORM(krb5_enc_sam_response_enc, kerberos_time, sam_timestamp, 1),
+    FIELDOF_NORM(krb5_enc_sam_response_enc, int32, sam_usec, 2),
+    FIELDOF_OPT(krb5_enc_sam_response_enc, ostring_data, sam_sad, 3, 3),
+};
+static unsigned int optional_enc_sam_response_enc(const void *p)
+{
+    const krb5_enc_sam_response_enc *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_sad.length > 0) optional |= (1u << 3);
+
+    return optional;
+}
+DEFSEQTYPE(enc_sam_response_enc, krb5_enc_sam_response_enc,
+           enc_sam_response_enc_fields, optional_enc_sam_response_enc);
+
+static const struct field_info enc_sam_response_enc_2_fields[] = {
+    FIELDOF_NORM(krb5_enc_sam_response_enc_2, int32, sam_nonce, 0),
+    FIELDOF_OPT(krb5_enc_sam_response_enc_2, ostring_data, sam_sad, 1, 1),
+};
+static unsigned int optional_enc_sam_response_enc_2(const void *p)
+{
+    const krb5_enc_sam_response_enc_2 *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_sad.length > 0) optional |= (1u << 1);
+
+    return optional;
+}
+DEFSEQTYPE(enc_sam_response_enc_2, krb5_enc_sam_response_enc_2,
+           enc_sam_response_enc_2_fields, optional_enc_sam_response_enc_2);
+
+static const struct field_info sam_response_fields[] = {
+    FIELDOF_NORM(krb5_sam_response, int32, sam_type, 0),
+    FIELDOF_NORM(krb5_sam_response, krb5_flags, sam_flags, 1),
+    FIELDOF_OPT(krb5_sam_response, ostring_data, sam_track_id, 2, 2),
+    FIELDOF_OPT(krb5_sam_response, encrypted_data, sam_enc_key, 3, 3),
+    FIELDOF_NORM(krb5_sam_response, encrypted_data, sam_enc_nonce_or_ts, 4),
+    FIELDOF_OPT(krb5_sam_response, int32, sam_nonce, 5, 5),
+    FIELDOF_OPT(krb5_sam_response, kerberos_time, sam_patimestamp, 6, 6),
+};
+static unsigned int optional_sam_response(const void *p)
+{
+    const krb5_sam_response *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_patimestamp)
+        optional |= (1u << 6);
+    if (val->sam_nonce)
+        optional |= (1u << 5);
+    if (val->sam_enc_key.ciphertext.length)
+        optional |= (1u << 3);
+    if (val->sam_track_id.length > 0) optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(sam_response, krb5_sam_response, sam_response_fields,
+           optional_sam_response);
+
+static const struct field_info sam_response_2_fields[] = {
+    FIELDOF_NORM(krb5_sam_response_2, int32, sam_type, 0),
+    FIELDOF_NORM(krb5_sam_response_2, krb5_flags, sam_flags, 1),
+    FIELDOF_OPT(krb5_sam_response_2, ostring_data, sam_track_id, 2, 2),
+    FIELDOF_NORM(krb5_sam_response_2, encrypted_data, sam_enc_nonce_or_sad, 3),
+    FIELDOF_NORM(krb5_sam_response_2, int32, sam_nonce, 4),
+};
+static unsigned int optional_sam_response_2(const void *p)
+{
+    const krb5_sam_response_2 *val = p;
+    unsigned int optional = 0;
+
+    if (val->sam_track_id.length > 0) optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(sam_response_2, krb5_sam_response_2, sam_response_2_fields,
+           optional_sam_response_2);
+
+static const struct field_info predicted_sam_response_fields[] = {
+    FIELDOF_NORM(krb5_predicted_sam_response, encryption_key, sam_key, 0),
+    FIELDOF_NORM(krb5_predicted_sam_response, krb5_flags, sam_flags, 1),
+    FIELDOF_NORM(krb5_predicted_sam_response, kerberos_time, stime, 2),
+    FIELDOF_NORM(krb5_predicted_sam_response, int32, susec, 3),
+    FIELDOF_NORM(krb5_predicted_sam_response, realm_of_principal, client, 4),
+    FIELDOF_NORM(krb5_predicted_sam_response, principal, client, 5),
+    FIELDOF_OPT(krb5_predicted_sam_response, ostring_data, msd, 6, 6),
+};
+static unsigned int optional_predicted_sam_response(const void *p)
+{
+    const krb5_predicted_sam_response *val = p;
+    unsigned int optional = 0;
+
+    if (val->msd.length > 0) optional |= (1u << 6);
+
+    return optional;
+}
+DEFSEQTYPE(predicted_sam_response, krb5_predicted_sam_response,
+           predicted_sam_response_fields,
+           optional_predicted_sam_response);
+
+static const struct field_info krb5_authenticator_fields[] = {
+    /* Authenticator ::= [APPLICATION 2] SEQUENCE */
+    /* authenticator-vno[0]     INTEGER */
+    FIELD_INT_IMM(KVNO, 0),
+    /* crealm[1]                        Realm */
+    FIELDOF_NORM(krb5_authenticator, realm_of_principal, client, 1),
+    /* cname[2]                 PrincipalName */
+    FIELDOF_NORM(krb5_authenticator, principal, client, 2),
+    /* cksum[3]                 Checksum OPTIONAL */
+    FIELDOF_OPT(krb5_authenticator, checksum_ptr, checksum, 3, 3),
+    /* cusec[4]                 INTEGER */
+    FIELDOF_NORM(krb5_authenticator, int32, cusec, 4),
+    /* ctime[5]                 KerberosTime */
+    FIELDOF_NORM(krb5_authenticator, kerberos_time, ctime, 5),
+    /* subkey[6]                        EncryptionKey OPTIONAL */
+    FIELDOF_OPT(krb5_authenticator, ptr_encryption_key, subkey, 6, 6),
+    /* seq-number[7]            INTEGER OPTIONAL */
+    FIELDOF_OPT(krb5_authenticator, uint, seq_number, 7, 7),
+    /* authorization-data[8]    AuthorizationData OPTIONAL */
+    FIELDOF_OPT(krb5_authenticator, auth_data_ptr, authorization_data, 8, 8),
+};
+static unsigned int optional_krb5_authenticator(const void *p)
+{
+    const krb5_authenticator *val = p;
+    unsigned int optional = 0;
+
+    if (val->authorization_data != NULL && val->authorization_data[0] != NULL)
+        optional |= (1u << 8);
+
+    if (val->seq_number != 0)
+        optional |= (1u << 7);
+
+    if (val->subkey != NULL)
+        optional |= (1u << 6);
+
+    if (val->checksum != NULL)
+        optional |= (1u << 3);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_krb5_authenticator, krb5_authenticator, krb5_authenticator_fields,
+           optional_krb5_authenticator);
+DEFAPPTAGGEDTYPE(krb5_authenticator, 2, untagged_krb5_authenticator);
+
+static const struct field_info enc_tkt_part_fields[] = {
+    /* EncTicketPart ::= [APPLICATION 3] SEQUENCE */
+    /* flags[0]                 TicketFlags */
+    FIELDOF_NORM(krb5_enc_tkt_part, krb5_flags, flags, 0),
+    /* key[1]                   EncryptionKey */
+    FIELDOF_NORM(krb5_enc_tkt_part, ptr_encryption_key, session, 1),
+    /* crealm[2]                        Realm */
+    FIELDOF_NORM(krb5_enc_tkt_part, realm_of_principal, client, 2),
+    /* cname[3]                 PrincipalName */
+    FIELDOF_NORM(krb5_enc_tkt_part, principal, client, 3),
+    /* transited[4]             TransitedEncoding */
+    FIELDOF_NORM(krb5_enc_tkt_part, transited, transited, 4),
+    /* authtime[5]              KerberosTime */
+    FIELDOF_NORM(krb5_enc_tkt_part, kerberos_time, times.authtime, 5),
+    /* starttime[6]             KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_enc_tkt_part, kerberos_time, times.starttime, 6, 6),
+    /* endtime[7]                       KerberosTime */
+    FIELDOF_NORM(krb5_enc_tkt_part, kerberos_time, times.endtime, 7),
+    /* renew-till[8]            KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_enc_tkt_part, kerberos_time, times.renew_till, 8, 8),
+    /* caddr[9]                 HostAddresses OPTIONAL */
+    FIELDOF_OPT(krb5_enc_tkt_part, ptr_seqof_host_addresses, caddrs, 9, 9),
+    /* authorization-data[10]   AuthorizationData OPTIONAL */
+    FIELDOF_OPT(krb5_enc_tkt_part, auth_data_ptr, authorization_data, 10, 10),
+};
+static unsigned int optional_enc_tkt_part(const void *p)
+{
+    const krb5_enc_tkt_part *val = p;
+    unsigned int optional = 0;
+
+    if (val->authorization_data != NULL && val->authorization_data[0] != NULL)
+        optional |= (1u << 10);
+    if (val->caddrs != NULL && val->caddrs[0] != NULL)
+        optional |= (1u << 9);
+    if (val->times.renew_till)
+        optional |= (1u << 8);
+    if (val->times.starttime)
+        optional |= (1u << 6);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_enc_tkt_part, krb5_enc_tkt_part, enc_tkt_part_fields,
+           optional_enc_tkt_part);
+DEFAPPTAGGEDTYPE(enc_tkt_part, 3, untagged_enc_tkt_part);
+
+DEFAPPTAGGEDTYPE(enc_tgs_rep_part, 26, enc_kdc_rep_part);
+
+static const struct field_info as_rep_fields[] = {
+    /* AS-REP ::= [APPLICATION 11] KDC-REP */
+    /* But KDC-REP needs to know what type it's being encapsulated
+       in, so expand each version.  */
+    FIELD_INT_IMM(KVNO, 0),
+    FIELD_INT_IMM(KRB5_AS_REP, 1),
+    FIELDOF_OPT(krb5_kdc_rep, ptr_seqof_pa_data, padata, 2, 2),
+    FIELDOF_NORM(krb5_kdc_rep, realm_of_principal, client, 3),
+    FIELDOF_NORM(krb5_kdc_rep, principal, client, 4),
+    FIELDOF_NORM(krb5_kdc_rep, ticket_ptr, ticket, 5),
+    FIELDOF_NORM(krb5_kdc_rep, encrypted_data, enc_part, 6),
+};
+static unsigned int optional_as_rep(const void *p)
+{
+    const krb5_kdc_rep *val = p;
+    unsigned int optional = 0;
+
+    if (val->padata != NULL && val->padata[0] != NULL)
+        optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_as_rep, krb5_kdc_rep, as_rep_fields, optional_as_rep);
+DEFAPPTAGGEDTYPE(as_rep, 11, untagged_as_rep);
+
+static const struct field_info tgs_rep_fields[] = {
+    /* TGS-REP ::= [APPLICATION 13] KDC-REP */
+    /* But KDC-REP needs to know what type it's being encapsulated
+       in, so expand each version.  */
+    FIELD_INT_IMM(KVNO, 0),
+    FIELD_INT_IMM(KRB5_TGS_REP, 1),
+    FIELDOF_OPT(krb5_kdc_rep, ptr_seqof_pa_data, padata, 2, 2),
+    FIELDOF_NORM(krb5_kdc_rep, realm_of_principal, client, 3),
+    FIELDOF_NORM(krb5_kdc_rep, principal, client, 4),
+    FIELDOF_NORM(krb5_kdc_rep, ticket_ptr, ticket, 5),
+    FIELDOF_NORM(krb5_kdc_rep, encrypted_data, enc_part, 6),
+};
+static unsigned int optional_tgs_rep(const void *p)
+{
+    const krb5_kdc_rep *val = p;
+    unsigned int optional = 0;
+
+    if (val->padata != NULL && val->padata[0] != NULL)
+        optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_tgs_rep, krb5_kdc_rep, tgs_rep_fields, optional_tgs_rep);
+DEFAPPTAGGEDTYPE(tgs_rep, 13, untagged_tgs_rep);
+
+static const struct field_info ap_req_fields[] = {
+    /* AP-REQ ::=       [APPLICATION 14] SEQUENCE */
+    /* pvno[0]          INTEGER */
+    FIELD_INT_IMM(KVNO, 0),
+    /* msg-type[1]      INTEGER */
+    FIELD_INT_IMM(ASN1_KRB_AP_REQ, 1),
+    /* ap-options[2]    APOptions */
+    FIELDOF_NORM(krb5_ap_req, krb5_flags, ap_options, 2),
+    /* ticket[3]                Ticket */
+    FIELDOF_NORM(krb5_ap_req, ticket_ptr, ticket, 3),
+    /* authenticator[4] EncryptedData */
+    FIELDOF_NORM(krb5_ap_req, encrypted_data, authenticator, 4),
+};
+DEFSEQTYPE(untagged_ap_req, krb5_ap_req, ap_req_fields, 0);
+DEFAPPTAGGEDTYPE(ap_req, 14, untagged_ap_req);
+
+static const struct field_info ap_rep_fields[] = {
+    /* AP-REP ::=       [APPLICATION 15] SEQUENCE */
+    /* pvno[0]          INTEGER */
+    FIELD_INT_IMM(KVNO, 0),
+    /* msg-type[1]      INTEGER */
+    FIELD_INT_IMM(ASN1_KRB_AP_REP, 1),
+    /* enc-part[2]      EncryptedData */
+    FIELDOF_NORM(krb5_ap_rep, encrypted_data, enc_part, 2),
+};
+DEFSEQTYPE(untagged_ap_rep, krb5_ap_rep, ap_rep_fields, 0);
+DEFAPPTAGGEDTYPE(ap_rep, 15, untagged_ap_rep);
+
+static const struct field_info ap_rep_enc_part_fields[] = {
+    /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE */
+    /* ctime[0]         KerberosTime */
+    FIELDOF_NORM(krb5_ap_rep_enc_part, kerberos_time, ctime, 0),
+    /* cusec[1]         INTEGER */
+    FIELDOF_NORM(krb5_ap_rep_enc_part, int32, cusec, 1),
+    /* subkey[2]                EncryptionKey OPTIONAL */
+    FIELDOF_OPT(krb5_ap_rep_enc_part, ptr_encryption_key, subkey, 2, 2),
+    /* seq-number[3]    INTEGER OPTIONAL */
+    FIELDOF_OPT(krb5_ap_rep_enc_part, uint, seq_number, 3, 3),
+};
+static unsigned int optional_ap_rep_enc_part(const void *p)
+{
+    const krb5_ap_rep_enc_part *val = p;
+    unsigned int optional = 0;
+
+    if (val->seq_number)
+        optional |= (1u << 3);
+    if (val->subkey != NULL)
+        optional |= (1u << 2);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_ap_rep_enc_part, krb5_ap_rep_enc_part,
+           ap_rep_enc_part_fields, optional_ap_rep_enc_part);
+DEFAPPTAGGEDTYPE(ap_rep_enc_part, 27, untagged_ap_rep_enc_part);
+
+static const struct field_info as_req_fields[] = {
+    /* AS-REQ ::= [APPLICATION 10] KDC-REQ */
+    FIELD_INT_IMM(KVNO, 1),
+    FIELD_INT_IMM(KRB5_AS_REQ, 2),
+    FIELDOF_OPT(krb5_kdc_req, ptr_seqof_pa_data, padata, 3, 3),
+    FIELDOF_ENCODEAS(krb5_kdc_req, kdc_req_body, 4),
+};
+static unsigned int optional_as_req(const void *p)
+{
+    const krb5_kdc_req *val = p;
+    unsigned int optional = 0;
+
+    if (val->padata != NULL && val->padata[0] != NULL)
+        optional |= (1u << 3);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_as_req, krb5_kdc_req, as_req_fields, optional_as_req);
+DEFAPPTAGGEDTYPE(as_req, 10, untagged_as_req);
+
+static const struct field_info tgs_req_fields[] = {
+    /* TGS-REQ ::= [APPLICATION 12] KDC-REQ */
+    FIELD_INT_IMM(KVNO, 1),
+    FIELD_INT_IMM(KRB5_TGS_REQ, 2),
+    FIELDOF_OPT(krb5_kdc_req, ptr_seqof_pa_data, padata, 3, 3),
+    FIELDOF_ENCODEAS(krb5_kdc_req, kdc_req_body, 4),
+};
+static unsigned int optional_tgs_req(const void *p)
+{
+    const krb5_kdc_req *val = p;
+    unsigned int optional = 0;
+
+    if (val->padata != NULL && val->padata[0] != NULL)
+        optional |= (1u << 3);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_tgs_req, krb5_kdc_req, tgs_req_fields,
+           optional_tgs_req);
+DEFAPPTAGGEDTYPE(tgs_req, 12, untagged_tgs_req);
+
+static const struct field_info krb5_safe_fields[] = {
+    FIELD_INT_IMM(KVNO, 0),
+    FIELD_INT_IMM(ASN1_KRB_SAFE,1),
+    FIELD_SELF(krb_safe_body, 2),
+    FIELDOF_NORM(krb5_safe, checksum_ptr, checksum, 3),
+};
+DEFSEQTYPE(untagged_krb5_safe, krb5_safe, krb5_safe_fields, 0);
+DEFAPPTAGGEDTYPE(krb5_safe, 20, untagged_krb5_safe);
+
+DEFPTRTYPE(krb_saved_safe_body_ptr, opaque_data);
+DEFFIELDTYPE(krb5_safe_checksum_only, krb5_safe,
+             FIELDOF_NORM(krb5_safe, checksum_ptr, checksum, -1));
+DEFPTRTYPE(krb5_safe_checksum_only_ptr, krb5_safe_checksum_only);
+static const struct field_info krb5_safe_with_body_fields[] = {
+    FIELD_INT_IMM(KVNO, 0),
+    FIELD_INT_IMM(ASN1_KRB_SAFE,1),
+    FIELDOF_NORM(struct krb5_safe_with_body, krb_saved_safe_body_ptr, body, 2),
+    FIELDOF_NORM(struct krb5_safe_with_body, krb5_safe_checksum_only_ptr, safe, 3),
+};
+DEFSEQTYPE(untagged_krb5_safe_with_body, struct krb5_safe_with_body,
+           krb5_safe_with_body_fields, 0);
+DEFAPPTAGGEDTYPE(krb5_safe_with_body, 20, untagged_krb5_safe_with_body);
+
+static const struct field_info priv_fields[] = {
+    FIELD_INT_IMM(KVNO, 0),
+    FIELD_INT_IMM(ASN1_KRB_PRIV, 1),
+    FIELDOF_NORM(krb5_priv, encrypted_data, enc_part, 3),
+};
+DEFSEQTYPE(untagged_priv, krb5_priv, priv_fields, 0);
+DEFAPPTAGGEDTYPE(krb5_priv, 21, untagged_priv);
+
+static const struct field_info priv_enc_part_fields[] = {
+    FIELDOF_NORM(krb5_priv_enc_part, ostring_data, user_data, 0),
+    FIELDOF_OPT(krb5_priv_enc_part, kerberos_time, timestamp, 1, 1),
+    FIELDOF_OPT(krb5_priv_enc_part, int32, usec, 2, 2),
+    FIELDOF_OPT(krb5_priv_enc_part, uint, seq_number, 3, 3),
+    FIELDOF_NORM(krb5_priv_enc_part, address_ptr, s_address, 4),
+    FIELDOF_OPT(krb5_priv_enc_part, address_ptr, r_address, 5, 5),
+};
+static unsigned int optional_priv_enc_part(const void *p)
+{
+    const krb5_priv_enc_part *val = p;
+    unsigned int optional = 0;
+
+    if (val->timestamp) {
+        optional |= (1u << 2);
+        optional |= (1u << 1);
+    }
+    if (val->seq_number)
+        optional |= (1u << 3);
+    if (val->r_address)
+        optional |= (1u << 5);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_priv_enc_part, krb5_priv_enc_part, priv_enc_part_fields,
+           optional_priv_enc_part);
+DEFAPPTAGGEDTYPE(priv_enc_part, 28, untagged_priv_enc_part);
+
+static const struct field_info cred_fields[] = {
+    /* KRB-CRED ::= [APPLICATION 22] SEQUENCE */
+    /* pvno[0]          INTEGER */
+    FIELD_INT_IMM(KVNO, 0),
+    /* msg-type[1]      INTEGER, -- KRB_CRED */
+    FIELD_INT_IMM(ASN1_KRB_CRED, 1),
+    /* tickets[2]       SEQUENCE OF Ticket */
+    FIELDOF_NORM(krb5_cred, ptr_seqof_ticket, tickets, 2),
+    /* enc-part[3]      EncryptedData */
+    FIELDOF_NORM(krb5_cred, encrypted_data, enc_part, 3),
+};
+DEFSEQTYPE(untagged_cred, krb5_cred, cred_fields, 0);
+DEFAPPTAGGEDTYPE(krb5_cred, 22, untagged_cred);
+
+static const struct field_info enc_cred_part_fields[] = {
+    /* EncKrbCredPart ::= [APPLICATION 29] SEQUENCE */
+    /* ticket-info[0]   SEQUENCE OF KrbCredInfo */
+    FIELDOF_NORM(krb5_cred_enc_part, ptrseqof_cred_info, ticket_info, 0),
+    /* nonce[1]         INTEGER OPTIONAL */
+    FIELDOF_OPT(krb5_cred_enc_part, int32, nonce, 1, 1),
+    /* timestamp[2]     KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_cred_enc_part, kerberos_time, timestamp, 2, 2),
+    /* usec[3]          INTEGER OPTIONAL */
+    FIELDOF_OPT(krb5_cred_enc_part, int32, usec, 3, 3),
+    /* s-address[4]     HostAddress OPTIONAL */
+    FIELDOF_OPT(krb5_cred_enc_part, address_ptr, s_address, 4, 4),
+    /* r-address[5]     HostAddress OPTIONAL */
+    FIELDOF_OPT(krb5_cred_enc_part, address_ptr, r_address, 5, 5),
+};
+static unsigned int optional_enc_cred_part(const void *p)
+{
+    const krb5_cred_enc_part *val = p;
+    unsigned int optional = 0;
+
+    if (val->r_address != NULL)
+        optional |= (1u << 5);
+
+    if (val->s_address != NULL)
+        optional |= (1u << 4);
+
+    if (val->timestamp) {
+        optional |= (1u << 2);
+        optional |= (1u << 3);
+    }
+
+    if (val->nonce)
+        optional |= (1u << 1);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_enc_cred_part, krb5_cred_enc_part, enc_cred_part_fields,
+           optional_enc_cred_part);
+DEFAPPTAGGEDTYPE(enc_cred_part, 29, untagged_enc_cred_part);
+
+static const struct field_info error_fields[] = {
+    /* KRB-ERROR ::= [APPLICATION 30] SEQUENCE */
+    /* pvno[0]          INTEGER */
+    FIELD_INT_IMM(KVNO, 0),
+    /* msg-type[1]      INTEGER */
+    FIELD_INT_IMM(ASN1_KRB_ERROR, 1),
+    /* ctime[2]         KerberosTime OPTIONAL */
+    FIELDOF_OPT(krb5_error, kerberos_time, ctime, 2, 2),
+    /* cusec[3]         INTEGER OPTIONAL */
+    FIELDOF_OPT(krb5_error, int32, cusec, 3, 3),
+    /* stime[4]         KerberosTime */
+    FIELDOF_NORM(krb5_error, kerberos_time, stime, 4),
+    /* susec[5]         INTEGER */
+    FIELDOF_NORM(krb5_error, int32, susec, 5),
+    /* error-code[6]    INTEGER */
+    FIELDOF_NORM(krb5_error, ui_4, error, 6),
+    /* crealm[7]        Realm OPTIONAL */
+    FIELDOF_OPT(krb5_error, realm_of_principal, client, 7, 7),
+    /* cname[8]         PrincipalName OPTIONAL */
+    FIELDOF_OPT(krb5_error, principal, client, 8, 8),
+    /* realm[9]         Realm -- Correct realm */
+    FIELDOF_NORM(krb5_error, realm_of_principal, server, 9),
+    /* sname[10]        PrincipalName -- Correct name */
+    FIELDOF_NORM(krb5_error, principal, server, 10),
+    /* e-text[11]       GeneralString OPTIONAL */
+    FIELDOF_OPT(krb5_error, gstring_data, text, 11, 11),
+    /* e-data[12]       OCTET STRING OPTIONAL */
+    FIELDOF_OPT(krb5_error, ostring_data, e_data, 12, 12),
+};
+static unsigned int optional_error(const void *p)
+{
+    const krb5_error *val = p;
+    unsigned int optional = 0;
+
+    if (val->ctime)
+        optional |= (1u << 2);
+    if (val->cusec)
+        optional |= (1u << 3);
+    if (val->client) {
+        optional |= (1u << 7);
+        optional |= (1u << 8);
+    }
+    if (val->text.data != NULL && val->text.length > 0)
+        optional |= (1u << 11);
+    if (val->e_data.data != NULL && val->e_data.length > 0)
+        optional |= (1u << 12);
+
+    return optional;
+}
+DEFSEQTYPE(untagged_krb5_error, krb5_error, error_fields, optional_error);
+DEFAPPTAGGEDTYPE(krb5_error, 30, untagged_krb5_error);
+
+static const struct field_info alt_method_fields[] = {
+    FIELDOF_NORM(krb5_alt_method, int32, method, 0),
+    FIELDOF_OPTSTRING(krb5_alt_method, octetstring, data, length, 1, 1),
+};
+static unsigned int
+optional_alt_method(const void *p)
+{
+    const krb5_alt_method *a = p;
+    unsigned int optional = 0;
+
+    if (a->data != NULL && a->length > 0)
+        optional |= (1u << 1);
+
+    return optional;
+}
+DEFSEQTYPE(alt_method, krb5_alt_method, alt_method_fields, optional_alt_method);
+
+static const struct field_info pa_enc_ts_fields[] = {
+    FIELDOF_NORM(krb5_pa_enc_ts, kerberos_time, patimestamp, 0),
+    FIELDOF_OPT(krb5_pa_enc_ts, int32, pausec, 1, 1),
+};
+static unsigned int
+optional_pa_enc_ts(const void *p)
+{
+    const krb5_pa_enc_ts *val = p;
+    unsigned int optional = 0;
+
+    if (val->pausec)
+        optional |= (1u << 1);
+
+    return optional;
+}
+DEFSEQTYPE(pa_enc_ts, krb5_pa_enc_ts, pa_enc_ts_fields, optional_pa_enc_ts);
+
+static const struct field_info pwd_data_fields[] = {
+    FIELDOF_NORM(krb5_pwd_data, int32, sequence_count, 0),
+    FIELDOF_NORM(krb5_pwd_data, ptr_seqof_passwdsequence, element, 1),
+};
+DEFSEQTYPE(pwd_data, krb5_pwd_data, pwd_data_fields, 0);
+
+static const struct field_info setpw_req_fields[] = {
+    FIELDOF_NORM(struct krb5_setpw_req, ostring_data, password, 0),
+    FIELDOF_NORM(struct krb5_setpw_req, principal, target, 1),
+    FIELDOF_NORM(struct krb5_setpw_req, realm_of_principal, target, 2),
+};
+
+DEFSEQTYPE(setpw_req, struct krb5_setpw_req, setpw_req_fields, 0);
+
+/* [MS-SFU] Section 2.2.1. */
+static const struct field_info pa_for_user_fields[] = {
+    FIELDOF_NORM(krb5_pa_for_user, principal, user, 0),
+    FIELDOF_NORM(krb5_pa_for_user, realm_of_principal, user, 1),
+    FIELDOF_NORM(krb5_pa_for_user, checksum, cksum, 2),
+    FIELDOF_NORM(krb5_pa_for_user, gstring_data, auth_package, 3),
+};
+
+DEFSEQTYPE(pa_for_user, krb5_pa_for_user, pa_for_user_fields, 0);
+
+/* draft-ietf-krb-wg-kerberos-referrals Appendix A. */
+static const struct field_info pa_svr_referral_data_fields[] = {
+    FIELDOF_NORM(krb5_pa_svr_referral_data, realm_of_principal, principal, 0),
+    FIELDOF_OPT(krb5_pa_svr_referral_data, principal, principal, 1, 1),
+};
+
+DEFSEQTYPE(pa_svr_referral_data, krb5_pa_svr_referral_data, pa_svr_referral_data_fields, 0);
+
+/* draft-ietf-krb-wg-kerberos-referrals Section 8. */
+static const struct field_info pa_server_referral_data_fields[] = {
+    FIELDOF_OPT(krb5_pa_server_referral_data, gstring_data_ptr, referred_realm, 0, 0),
+    FIELDOF_OPT(krb5_pa_server_referral_data, principal, true_principal_name, 1, 1),
+    FIELDOF_OPT(krb5_pa_server_referral_data, principal, requested_principal_name, 2, 2),
+    FIELDOF_OPT(krb5_pa_server_referral_data, kerberos_time, referral_valid_until, 3, 3),
+    FIELDOF_NORM(krb5_pa_server_referral_data, checksum, rep_cksum, 4),
+};
+
+DEFSEQTYPE(pa_server_referral_data, krb5_pa_server_referral_data, pa_server_referral_data_fields, 0);
+
+#if 0
+/* draft-brezak-win2k-krb-authz Section 6. */
+static const struct field_info pa_pac_request_fields[] = {
+    FIELDOF_NORM(krb5_pa_pac_req, boolean, include_pac, 0),
+};
+
+DEFSEQTYPE(pa_pac_request, krb5_pa_pac_req, pa_pac_request_fields, 0);
+#endif
+
+/* RFC 4537 */
+DEFFIELDTYPE(etype_list, krb5_etype_list,
+             FIELDOF_SEQOF_INT32(krb5_etype_list, int32_ptr, etypes, length, -1));
+
+/* draft-ietf-krb-wg-preauth-framework-09 */
+static const struct field_info fast_armor_fields[] = {
+    FIELDOF_NORM(krb5_fast_armor, int32, armor_type, 0),
+    FIELDOF_NORM( krb5_fast_armor, ostring_data, armor_value, 1),
+};
+
+DEFSEQTYPE( fast_armor, krb5_fast_armor, fast_armor_fields, 0);
+DEFPTRTYPE( ptr_fast_armor, fast_armor);
+
+static const struct field_info fast_armored_req_fields[] = {
+    FIELDOF_OPT( krb5_fast_armored_req, ptr_fast_armor, armor, 0, 0),
+    FIELDOF_NORM( krb5_fast_armored_req, checksum, req_checksum, 1),
+    FIELDOF_NORM( krb5_fast_armored_req, encrypted_data, enc_part, 2),
+};
+
+static unsigned int fast_armored_req_optional (const void *p) {
+    const krb5_fast_armored_req *val = p;
+    unsigned int optional = 0;
+    if (val->armor)
+        optional |= (1u)<<0;
+    return optional;
+}
+
+DEFSEQTYPE( fast_armored_req, krb5_fast_armored_req, fast_armored_req_fields, fast_armored_req_optional);
+DEFFIELDTYPE( pa_fx_fast_request, krb5_fast_armored_req,
+              FIELDOF_ENCODEAS( krb5_fast_armored_req, fast_armored_req, 0));
+
+DEFFIELDTYPE(fast_req_padata, krb5_kdc_req,
+             FIELDOF_NORM(krb5_kdc_req, ptr_seqof_pa_data, padata, -1));
+DEFPTRTYPE(ptr_fast_req_padata, fast_req_padata);
+
+static const struct field_info fast_req_fields[] = {
+    FIELDOF_NORM(krb5_fast_req, krb5_flags, fast_options, 0),
+    FIELDOF_NORM( krb5_fast_req, ptr_fast_req_padata, req_body, 1),
+    FIELDOF_NORM( krb5_fast_req, ptr_kdc_req_body, req_body, 2),
+};
+
+DEFSEQTYPE(fast_req, krb5_fast_req, fast_req_fields, 0);
+
+
+static const struct field_info fast_finished_fields[] = {
+    FIELDOF_NORM( krb5_fast_finished, kerberos_time, timestamp, 0),
+    FIELDOF_NORM( krb5_fast_finished, int32, usec, 1),
+    FIELDOF_NORM( krb5_fast_finished, realm_of_principal, client, 2),
+    FIELDOF_NORM(krb5_fast_finished, principal, client, 3),
+    FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 4),
+};
+
+DEFSEQTYPE( fast_finished, krb5_fast_finished, fast_finished_fields, 0);
+
+DEFPTRTYPE( ptr_fast_finished, fast_finished);
+
+static const struct field_info fast_response_fields[] = {
+    FIELDOF_NORM(krb5_fast_response, ptr_seqof_pa_data, padata, 0),
+    FIELDOF_OPT( krb5_fast_response, ptr_encryption_key, strengthen_key, 1, 1),
+    FIELDOF_OPT( krb5_fast_response, ptr_fast_finished, finished, 2, 2),
+    FIELDOF_NORM(krb5_fast_response, int32, nonce, 3),
+};
+
+static unsigned int fast_response_optional (const void *p)
+{
+    unsigned int optional = 0;
+    const krb5_fast_response *val = p;
+    if (val->strengthen_key)
+        optional |= (1u <<1);
+    if (val->finished)
+        optional |= (1u<<2);
+    return optional;
+}
+DEFSEQTYPE( fast_response, krb5_fast_response, fast_response_fields, fast_response_optional);
+
+static const struct field_info fast_rep_fields[] = {
+  FIELDOF_ENCODEAS(krb5_enc_data, encrypted_data, 0),
+};
+DEFSEQTYPE(fast_rep, krb5_enc_data, fast_rep_fields, 0);
+
+DEFFIELDTYPE(pa_fx_fast_reply, krb5_enc_data,
+             FIELDOF_ENCODEAS(krb5_enc_data, fast_rep, 0));
+
+
+
+
+/* Exported complete encoders -- these produce a krb5_data with
+   the encoding in the correct byte order.  */
+
+MAKE_FULL_ENCODER(encode_krb5_authenticator, krb5_authenticator);
+MAKE_FULL_ENCODER(encode_krb5_ticket, ticket);
+MAKE_FULL_ENCODER(encode_krb5_encryption_key, encryption_key);
+MAKE_FULL_ENCODER(encode_krb5_enc_tkt_part, enc_tkt_part);
+/* XXX We currently (for backwards compatibility) encode both
+   EncASRepPart and EncTGSRepPart with application tag 26.  */
+MAKE_FULL_ENCODER(encode_krb5_enc_kdc_rep_part, enc_tgs_rep_part);
+MAKE_FULL_ENCODER(encode_krb5_as_rep, as_rep);
+MAKE_FULL_ENCODER(encode_krb5_tgs_rep, tgs_rep);
+MAKE_FULL_ENCODER(encode_krb5_ap_req, ap_req);
+MAKE_FULL_ENCODER(encode_krb5_ap_rep, ap_rep);
+MAKE_FULL_ENCODER(encode_krb5_ap_rep_enc_part, ap_rep_enc_part);
+MAKE_FULL_ENCODER(encode_krb5_as_req, as_req);
+MAKE_FULL_ENCODER(encode_krb5_tgs_req, tgs_req);
+MAKE_FULL_ENCODER(encode_krb5_kdc_req_body, kdc_req_body);
+MAKE_FULL_ENCODER(encode_krb5_safe, krb5_safe);
+
+/*
+ * encode_krb5_safe_with_body
+ *
+ * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY
+ * encoding to avoid problems with re-encoding.
+ */
+MAKE_FULL_ENCODER(encode_krb5_safe_with_body, krb5_safe_with_body);
+
+MAKE_FULL_ENCODER(encode_krb5_priv, krb5_priv);
+MAKE_FULL_ENCODER(encode_krb5_enc_priv_part, priv_enc_part);
+MAKE_FULL_ENCODER(encode_krb5_cred, krb5_cred);
+MAKE_FULL_ENCODER(encode_krb5_enc_cred_part, enc_cred_part);
+MAKE_FULL_ENCODER(encode_krb5_error, krb5_error);
+MAKE_FULL_ENCODER(encode_krb5_authdata, auth_data);
+MAKE_FULL_ENCODER(encode_krb5_authdata_elt, authdata_elt);
+MAKE_FULL_ENCODER(encode_krb5_alt_method, alt_method);
+MAKE_FULL_ENCODER(encode_krb5_etype_info, etype_info);
+MAKE_FULL_ENCODER(encode_krb5_etype_info2, etype_info2);
+MAKE_FULL_ENCODER(encode_krb5_enc_data, encrypted_data);
+MAKE_FULL_ENCODER(encode_krb5_pa_enc_ts, pa_enc_ts);
+/* Sandia Additions */
+MAKE_FULL_ENCODER(encode_krb5_pwd_sequence, passwdsequence);
+MAKE_FULL_ENCODER(encode_krb5_pwd_data, pwd_data);
+MAKE_FULL_ENCODER(encode_krb5_padata_sequence, seq_of_pa_data);
+/* sam preauth additions */
+MAKE_FULL_ENCODER(encode_krb5_sam_challenge, sam_challenge);
+#if 0 /* encoders not used! */
+MAKE_FULL_ENCODER(encode_krb5_sam_challenge_2, sam_challenge_2);
+MAKE_FULL_ENCODER(encode_krb5_sam_challenge_2_body,
+                  sam_challenge_2_body);
+#endif
+MAKE_FULL_ENCODER(encode_krb5_sam_key, sam_key);
+MAKE_FULL_ENCODER(encode_krb5_enc_sam_response_enc,
+                  enc_sam_response_enc);
+MAKE_FULL_ENCODER(encode_krb5_enc_sam_response_enc_2,
+                  enc_sam_response_enc_2);
+MAKE_FULL_ENCODER(encode_krb5_sam_response, sam_response);
+MAKE_FULL_ENCODER(encode_krb5_sam_response_2, sam_response_2);
+MAKE_FULL_ENCODER(encode_krb5_predicted_sam_response,
+                  predicted_sam_response);
+MAKE_FULL_ENCODER(encode_krb5_setpw_req, setpw_req);
+MAKE_FULL_ENCODER(encode_krb5_pa_for_user, pa_for_user);
+MAKE_FULL_ENCODER(encode_krb5_pa_svr_referral_data, pa_svr_referral_data);
+MAKE_FULL_ENCODER(encode_krb5_pa_server_referral_data, pa_server_referral_data);
+MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list);
+
+MAKE_FULL_ENCODER(encode_krb5_pa_fx_fast_request, pa_fx_fast_request);
+MAKE_FULL_ENCODER( encode_krb5_fast_req, fast_req);
+MAKE_FULL_ENCODER( encode_krb5_pa_fx_fast_reply, pa_fx_fast_reply);
+MAKE_FULL_ENCODER(encode_krb5_fast_response, fast_response);
+
+
+
+
+
+
+/*
+ * PKINIT
+ */
+
+/* This code hasn't been converted to use the above framework yet,
+   because we currently have no test cases to validate the new
+   version.  It *also* appears that some of the encodings may disagree
+   with the specifications, but that's a separate problem.  */
 
 /**** asn1 macros ****/
 #if 0
@@ -44,20 +1370,20 @@
      ...
 
      /* for OPTIONAL fields */
-     if(rep->field_i == should_not_be_omitted)
+     if (rep->field_i == should_not_be_omitted)
        asn1_addfield(rep->field_i, i, asn1_type);
 
      /* for string fields (these encoders take an additional argument,
-	the length of the string) */
+        the length of the string) */
      addlenfield(rep->field_length, rep->field, i-1, asn1_type);
 
      /* if you really have to do things yourself... */
      retval = asn1_encode_asn1_type(buf,rep->field,&length);
-     if(retval) return retval;
+     if (retval) return retval;
      sum += length;
      retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag_number, length,
-			     &length);
-     if(retval) return retval;
+                             &length);
+     if (retval) return retval;
      sum += length;
 
      ...
@@ -69,1331 +1395,467 @@
    }
 #endif
 
-/* setup() -- create and initialize bookkeeping variables
-     retval: stores error codes returned from subroutines
-     length: length of the most-recently produced encoding
-     sum: cumulative length of the entire encoding */
-#define asn1_setup()\
-  asn1_error_code retval;\
-  unsigned int length, sum=0
-  
-/* asn1_addfield -- add a field, or component, to the encoding */
-#define asn1_addfield(value,tag,encoder)\
-{ retval = encoder(buf,value,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+/* asn1_addlenfield -- add a field whose length must be separately specified */
+#define asn1_addlenfield(len,value,tag,encoder)\
+{ unsigned int length; \
+  retval = encoder(buf,len,value,&length);      \
+  if (retval) {\
     return retval; }\
   sum += length;\
   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length; }
-
-/* asn1_addlenfield -- add a field whose length must be separately specified */
-#define asn1_addlenfield(len,value,tag,encoder)\
-{ retval = encoder(buf,len,value,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length;\
-  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+  if (retval) {\
     return retval; }\
   sum += length; }
 
 /* asn1_addfield_implicit -- add an implicitly tagged field, or component, to the encoding */
 #define asn1_addfield_implicit(value,tag,encoder)\
-{ retval = encoder(buf,value,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+{ unsigned int length;\
+  retval = encoder(buf,value,&length);\
+  if (retval) {\
     return retval; }\
   sum += length;\
   retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,length,&length); \
-  if(retval){\
-    asn1buf_destroy(&buf);\
+  if (retval) {\
     return retval; }\
   sum += length; }
 
 /* asn1_insert_implicit_octetstring -- add an octet string with implicit tagging */
 #define asn1_insert_implicit_octetstring(len,value,tag)\
-{ retval = asn1buf_insert_octetstring(buf,len,value);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+{ unsigned int length;\
+  retval = asn1buf_insert_octetstring(buf,len,value);\
+  if (retval) {\
     return retval; }\
   sum += len;\
   retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,len,&length); \
-  if(retval){\
-    asn1buf_destroy(&buf);\
+  if (retval) {\
     return retval; }\
   sum += length; }
 
 /* asn1_insert_implicit_bitstring -- add a bitstring with implicit tagging */
+/* needs "length" declared in enclosing context */
 #define asn1_insert_implicit_bitstring(len,value,tag)\
-{ retval = asn1buf_insert_octetstring(buf,len,value);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+{ retval = asn1buf_insert_octetstring(buf,len,value); \
+  if (retval) {\
     return retval; }\
   sum += len;\
   retval = asn1buf_insert_octet(buf, 0);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
+  if (retval) {\
     return retval; }\
   sum++;\
   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,tag,len+1,&length); \
-  if(retval){\
-    asn1buf_destroy(&buf);\
+  if (retval) {\
     return retval; }\
   sum += length; }
 
-/* form a sequence (by adding a sequence header to the current encoding) */
-#define asn1_makeseq()\
-  retval = asn1_make_sequence(buf,sum,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length
+#ifndef DISABLE_PKINIT
+
+/* Callable encoders for the types defined above, until the PKINIT
+   encoders get converted.  */
+MAKE_ENCFN(asn1_encode_realm, realm_of_principal_data);
+MAKE_ENCFN(asn1_encode_principal_name, principal_data);
+MAKE_ENCFN(asn1_encode_encryption_key, encryption_key);
+MAKE_ENCFN(asn1_encode_checksum, checksum);
+
+static asn1_error_code
+asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val,
+                          unsigned int *retlen)
+{
+    return asn1_encode_kerberos_time_at(buf,&val,retlen);
+}
 
-/* add an APPLICATION class tag to the current encoding */
-#define asn1_apptag(num)\
-  retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length
+/* Now the real PKINIT encoder functions.  */
+asn1_error_code asn1_encode_pk_authenticator(asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen)
+{
+    asn1_setup();
+    asn1_addlenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_encode_octetstring);
+    asn1_addfield(val->nonce, 2, asn1_encode_integer);
+    asn1_addfield(val->ctime, 1, asn1_encode_kerberos_time);
+    asn1_addfield(val->cusec, 0, asn1_encode_integer);
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
 
-/* produce the final output and clean up the workspace */
-#define asn1_cleanup()\
-  *retlen = sum;\
-  return 0
+asn1_error_code asn1_encode_pk_authenticator_draft9(asn1buf *buf, const krb5_pk_authenticator_draft9 *val, unsigned int *retlen)
+{
+    asn1_setup();
 
-asn1_error_code asn1_encode_ui_4(asn1buf *buf, const krb5_ui_4 val, unsigned int *retlen)
-{
-  return asn1_encode_unsigned_integer(buf,val,retlen);
+    asn1_addfield(val->nonce, 4, asn1_encode_integer);
+    asn1_addfield(val->ctime, 3, asn1_encode_kerberos_time);
+    asn1_addfield(val->cusec, 2, asn1_encode_integer);
+    asn1_addfield(val->kdcName, 1, asn1_encode_realm);
+    asn1_addfield(val->kdcName, 0, asn1_encode_principal_name);
+
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 
-asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
-{
-  if (val == NULL ||
-      (val->realm.length && val->realm.data == NULL))
-	  return ASN1_MISSING_FIELD;
-  return asn1_encode_generalstring(buf,val->realm.length,val->realm.data,
-				   retlen);
-}
-
-asn1_error_code asn1_encode_principal_name(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
+asn1_error_code asn1_encode_algorithm_identifier(asn1buf *buf, const krb5_algorithm_identifier *val, unsigned int *retlen)
 {
-  asn1_setup();
-  int n;
-
-  if (val == NULL || val->data == NULL) return ASN1_MISSING_FIELD;
-
-  for(n = (int) ((val->length)-1); n >= 0; n--){
-    if (val->data[n].length &&
-	val->data[n].data == NULL)
-	    return ASN1_MISSING_FIELD;
-    retval = asn1_encode_generalstring(buf,
-				       (val->data)[n].length,
-				       (val->data)[n].data,
-				       &length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,1,sum,&length);
-  if(retval) return retval;
-  sum += length;
-
-  asn1_addfield(val->type,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen)
-{
-  return asn1_encode_generaltime(buf,val,retlen);
-}
-
-asn1_error_code asn1_encode_host_address(asn1buf *buf, const krb5_address *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val == NULL || val->contents == NULL) return ASN1_MISSING_FIELD;
-
-  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
-  asn1_addfield(val->addrtype,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_host_addresses(asn1buf *buf, const krb5_address **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+    asn1_setup();
 
-  for(i=0; val[i] != NULL; i++); /* go to end of array */
-  for(i--; i>=0; i--){
-    retval = asn1_encode_host_address(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_encrypted_data(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL ||
-     (val->ciphertext.length && val->ciphertext.data == NULL))
-	  return ASN1_MISSING_FIELD;
-
-  asn1_addlenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_encode_charstring);
-  /* krb5_kvno should be int */
-  if(val->kvno)
-    asn1_addfield((int) val->kvno,1,asn1_encode_integer);
-  asn1_addfield(val->enctype,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_krb5_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
-  asn1_setup();
-  krb5_flags valcopy = val;
-  int i;
-
-  for(i=0; i<4; i++){
-    retval = asn1buf_insert_octet(buf,(asn1_octet) (valcopy&0xFF));
-    if(retval) return retval;
-    valcopy >>= 8;
-  }
-  retval = asn1buf_insert_octet(buf,0);	/* 0 padding bits */
-  if(retval) return retval;
-  sum = 5;
-
-  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_BITSTRING,sum,
-			 &length);
-  if(retval) return retval;
-  sum += length;
-
-  *retlen = sum;
-  return 0;
-}
-
-asn1_error_code asn1_encode_ap_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
-  return asn1_encode_krb5_flags(buf,val,retlen);
-}
-
-asn1_error_code asn1_encode_ticket_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
-  return asn1_encode_krb5_flags(buf,val,retlen);
-}
+    if (val->parameters.length != 0) {
+        retval = asn1buf_insert_octetstring(buf, val->parameters.length,
+                                            val->parameters.data);
+        if (retval)
+            return retval;
+        sum += val->parameters.length;
+    }
 
-asn1_error_code asn1_encode_kdc_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
-  return asn1_encode_krb5_flags(buf,val,retlen);
-}
-
-asn1_error_code asn1_encode_authorization_data(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-  
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-  
-  for(i=0; val[i] != NULL; i++); /* get to the end of the array */
-  for(i--; i>=0; i--){
-    retval = asn1_encode_krb5_authdata_elt(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_krb5_authdata_elt(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val == NULL ||
-     (val->length && val->contents == NULL))
-	  return ASN1_MISSING_FIELD;
-
-  /* ad-data[1]		OCTET STRING */
-  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
-  /* ad-type[0]		INTEGER */
-  asn1_addfield(val->ad_type,0,asn1_encode_integer);
-  /* SEQUENCE */
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_kdc_rep(int msg_type, asn1buf *buf, const krb5_kdc_rep *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  asn1_addfield(&(val->enc_part),6,asn1_encode_encrypted_data);
-  asn1_addfield(val->ticket,5,asn1_encode_ticket);
-  asn1_addfield(val->client,4,asn1_encode_principal_name);
-  asn1_addfield(val->client,3,asn1_encode_realm);
-  if(val->padata != NULL && val->padata[0] != NULL)
-    asn1_addfield((const krb5_pa_data**)val->padata,2,asn1_encode_sequence_of_pa_data);
-  if (msg_type != KRB5_AS_REP && msg_type != KRB5_TGS_REP)
-	  return KRB5_BADMSGTYPE;
-  asn1_addfield(msg_type,1,asn1_encode_integer);
-  asn1_addfield(KVNO,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
+    {
+        unsigned int length;
+        retval = asn1_encode_oid(buf, val->algorithm.length,
+                                 val->algorithm.data,
+                                 &length);
 
-asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_rep_part *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  /* caddr[11]		HostAddresses OPTIONAL */
-  if(val->caddrs != NULL && val->caddrs[0] != NULL)
-    asn1_addfield((const krb5_address**)(val->caddrs),11,asn1_encode_host_addresses);
-
-  /* sname[10]		PrincipalName */
-  asn1_addfield(val->server,10,asn1_encode_principal_name);
-
-  /* srealm[9]		Realm */
-  asn1_addfield(val->server,9,asn1_encode_realm);
-
-  /* renew-till[8]	KerberosTime OPTIONAL */
-  if(val->flags & TKT_FLG_RENEWABLE)
-    asn1_addfield(val->times.renew_till,8,asn1_encode_kerberos_time);
-
-  /* endtime[7]		KerberosTime */
-  asn1_addfield(val->times.endtime,7,asn1_encode_kerberos_time);
-
-  /* starttime[6]	KerberosTime OPTIONAL */
-  if(val->times.starttime)
-    asn1_addfield(val->times.starttime,6,asn1_encode_kerberos_time);
-
-  /* authtime[5]	KerberosTime */
-  asn1_addfield(val->times.authtime,5,asn1_encode_kerberos_time);
-
-  /* flags[4]		TicketFlags */
-  asn1_addfield(val->flags,4,asn1_encode_ticket_flags);
+        if (retval)
+            return retval;
+        sum += length;
+    }
 
-  /* key-expiration[3]	KerberosTime OPTIONAL */
-  if(val->key_exp)
-    asn1_addfield(val->key_exp,3,asn1_encode_kerberos_time);
-
-  /* nonce[2]		INTEGER */
-  asn1_addfield(val->nonce,2,asn1_encode_integer);
-
-  /* last-req[1]	LastReq */
-  asn1_addfield((const krb5_last_req_entry**)val->last_req,1,asn1_encode_last_req);
-
-  /* key[0]		EncryptionKey */
-  asn1_addfield(val->session,0,asn1_encode_encryption_key);
-
-  /* EncKDCRepPart ::= SEQUENCE */
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  for (i=0; val[i] != NULL; i++);
-  for (i--; i>=0; i--){
-    retval = asn1_encode_checksum(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
-asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen)
+asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_info *val, unsigned int *retlen)
 {
-  asn1_setup();
-  
-  if(rep == NULL) return ASN1_MISSING_FIELD;
-
-  /* additional-tickets[11]	SEQUENCE OF Ticket OPTIONAL */
-  if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL)
-    asn1_addfield((const krb5_ticket**)rep->second_ticket,
-		  11,asn1_encode_sequence_of_ticket);
-
-  /* enc-authorization-data[10]	EncryptedData OPTIONAL, */
-  /* 				-- Encrypted AuthorizationData encoding */
-  if(rep->authorization_data.ciphertext.data != NULL)
-    asn1_addfield(&(rep->authorization_data),10,asn1_encode_encrypted_data);
-
-  /* addresses[9]		HostAddresses OPTIONAL, */
-  if(rep->addresses != NULL && rep->addresses[0] != NULL)
-    asn1_addfield((const krb5_address**)rep->addresses,9,asn1_encode_host_addresses);
+    asn1_setup();
 
-  /* etype[8]			SEQUENCE OF INTEGER, -- EncryptionType, */
-  /* 				-- in preference order */
-  asn1_addlenfield(rep->nktypes,rep->ktype,8,asn1_encode_sequence_of_enctype);
-
-  /* nonce[7]			INTEGER, */
-  asn1_addfield(rep->nonce,7,asn1_encode_integer);
-
-  /* rtime[6]			KerberosTime OPTIONAL, */
-  if(rep->rtime)
-    asn1_addfield(rep->rtime,6,asn1_encode_kerberos_time);
-
-  /* till[5]			KerberosTime, */
-  asn1_addfield(rep->till,5,asn1_encode_kerberos_time);
-
-  /* from[4]			KerberosTime OPTIONAL, */
-  if(rep->from)
-  asn1_addfield(rep->from,4,asn1_encode_kerberos_time);
-
-  /* sname[3]			PrincipalName OPTIONAL, */
-  if(rep->server != NULL)
-    asn1_addfield(rep->server,3,asn1_encode_principal_name);
+    {
+        unsigned int length;
+        asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,ASN1_BITSTRING);
+    }
 
-  /* realm[2]			Realm, -- Server's realm */
-  /* 				-- Also client's in AS-REQ */
-  if(rep->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY){
-    if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL){
-      asn1_addfield(rep->second_ticket[0]->server,2,asn1_encode_realm)
-    } else return ASN1_MISSING_FIELD;
-  }else if(rep->server != NULL){
-    asn1_addfield(rep->server,2,asn1_encode_realm);
-  }else return ASN1_MISSING_FIELD;
-
-  /* cname[1]			PrincipalName OPTIONAL, */
-  /* 				-- Used only in AS-REQ */
-  if(rep->client != NULL)
-    asn1_addfield(rep->client,1,asn1_encode_principal_name);
-
-  /* kdc-options[0]		KDCOptions, */
-  asn1_addfield(rep->kdc_options,0,asn1_encode_kdc_options);
-
-  /* KDC-REQ-BODY ::= SEQUENCE */
-  asn1_makeseq();
+    if (val->algorithm.parameters.length != 0) {
+        unsigned int length;
 
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_encryption_key(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val == NULL ||
-      (val->length && val->contents == NULL))
-	  return ASN1_MISSING_FIELD;
-
-  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
-  asn1_addfield(val->enctype,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_checksum(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen)
-{
-  asn1_setup();
+        retval = asn1buf_insert_octetstring(buf, val->algorithm.parameters.length,
+                                            val->algorithm.parameters.data);
+        if (retval)
+            return retval;
+        sum += val->algorithm.parameters.length;
 
-  if (val == NULL ||
-     (val->length && val->contents == NULL))
-	  return ASN1_MISSING_FIELD;
-
-  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
-  asn1_addfield(val->checksum_type,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_transited_encoding(asn1buf *buf, const krb5_transited *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL ||
-     (val->tr_contents.length != 0 && val->tr_contents.data == NULL))
-    return ASN1_MISSING_FIELD;
+        retval = asn1_encode_oid(buf, val->algorithm.algorithm.length,
+                                 val->algorithm.algorithm.data,
+                                 &length);
 
-  asn1_addlenfield(val->tr_contents.length,val->tr_contents.data,
-		   1,asn1_encode_charstring);
-  asn1_addfield(val->tr_type,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
+        if (retval)
+            return retval;
+        sum += length;
 
-asn1_error_code asn1_encode_last_req(asn1buf *buf, const krb5_last_req_entry **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++); /* go to end of array */
-  for(i--; i>=0; i--){
-    retval = asn1_encode_last_req_entry(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
 
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_last_req_entry(asn1buf *buf, const krb5_last_req_entry *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  asn1_addfield(val->value,1,asn1_encode_kerberos_time);
-  asn1_addfield(val->lr_type,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_pa_data(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if (val == NULL) return ASN1_MISSING_FIELD;
+        retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE,
+                                val->algorithm.parameters.length + length,
+                                &length);
 
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_pa_data(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
+        if (retval)
+            return retval;
+        sum += length;
+    }
 
-asn1_error_code asn1_encode_pa_data(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL || (val->length != 0 && val->contents == NULL))
-     return ASN1_MISSING_FIELD;
-
-  asn1_addlenfield(val->length,val->contents,2,asn1_encode_octetstring);
-  asn1_addfield(val->pa_type,1,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
-asn1_error_code asn1_encode_sequence_of_ticket(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_ticket(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_ticket(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  asn1_addfield(&(val->enc_part),3,asn1_encode_encrypted_data);
-  asn1_addfield(val->server,2,asn1_encode_principal_name);
-  asn1_addfield(val->server,1,asn1_encode_realm);
-  asn1_addfield(KVNO,0,asn1_encode_integer);
-  asn1_makeseq();
-  asn1_apptag(1);
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_enctype(asn1buf *buf, const int len, const krb5_enctype *val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=len-1; i>=0; i--){
-    retval = asn1_encode_integer(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_kdc_req(int msg_type, asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  asn1_addfield(val,4,asn1_encode_kdc_req_body);
-  if(val->padata != NULL && val->padata[0] != NULL)
-    asn1_addfield((const krb5_pa_data**)val->padata,3,asn1_encode_sequence_of_pa_data);
-  if (msg_type != KRB5_AS_REQ && msg_type != KRB5_TGS_REQ)
-	  return KRB5_BADMSGTYPE;
-  asn1_addfield(msg_type,2,asn1_encode_integer);
-  asn1_addfield(KVNO,1,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_krb_safe_body(asn1buf *buf, const krb5_safe *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  if(val->r_address != NULL)
-    asn1_addfield(val->r_address,5,asn1_encode_host_address);
-  asn1_addfield(val->s_address,4,asn1_encode_host_address);
-  if(val->seq_number)
-    asn1_addfield(val->seq_number,3,asn1_encode_unsigned_integer);
-  if(val->timestamp){
-    asn1_addfield(val->usec,2,asn1_encode_integer);
-    asn1_addfield(val->timestamp,1,asn1_encode_kerberos_time);
-  }
-  if (val->user_data.length && val->user_data.data == NULL)
-	  return ASN1_MISSING_FIELD;
-  asn1_addlenfield(val->user_data.length,val->user_data.data,0,asn1_encode_charstring)
-;
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_krb_cred_info(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_krb_cred_info(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_krb_cred_info(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if(val == NULL) return ASN1_MISSING_FIELD;
-
-  if(val->caddrs != NULL && val->caddrs[0] != NULL)
-    asn1_addfield((const krb5_address**)val->caddrs,10,asn1_encode_host_addresses);
-  if(val->server != NULL){
-    asn1_addfield(val->server,9,asn1_encode_principal_name);
-    asn1_addfield(val->server,8,asn1_encode_realm);
-  }
-  if(val->times.renew_till)
-    asn1_addfield(val->times.renew_till,7,asn1_encode_kerberos_time);
-  if(val->times.endtime)
-    asn1_addfield(val->times.endtime,6,asn1_encode_kerberos_time);
-  if(val->times.starttime)
-    asn1_addfield(val->times.starttime,5,asn1_encode_kerberos_time);
-  if(val->times.authtime)
-    asn1_addfield(val->times.authtime,4,asn1_encode_kerberos_time);
-  if(val->flags)
-    asn1_addfield(val->flags,3,asn1_encode_ticket_flags);
-  if(val->client != NULL){
-    asn1_addfield(val->client,2,asn1_encode_principal_name);
-    asn1_addfield(val->client,1,asn1_encode_realm);
-  }
-  asn1_addfield(val->session,0,asn1_encode_encryption_key);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_etype_info_entry(asn1buf *buf, const krb5_etype_info_entry *val,
-					     unsigned int *retlen, int etype_info2)
-{
-  asn1_setup();
-
-  assert(val->s2kparams.data == NULL || etype_info2);
-  if(val == NULL || (val->length > 0 && val->length != KRB5_ETYPE_NO_SALT &&
-		     val->salt == NULL))
-     return ASN1_MISSING_FIELD;
-  if(val->s2kparams.data != NULL) {
-      /* Solaris Kerberos */
-      asn1_addlenfield(val->s2kparams.length, (const uchar_t *)val->s2kparams.data, 2,
-		       asn1_encode_octetstring);
-  }
-  if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT){
-      if (etype_info2) {
-          /* Solaris Kerberos */
-	  asn1_addlenfield(val->length, (const char *)val->salt,1,
-			   asn1_encode_generalstring)
-      }
-      else 	  asn1_addlenfield(val->length,val->salt,1,
-				   asn1_encode_octetstring);
-  }
-asn1_addfield(val->etype,0,asn1_encode_integer);
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_etype_info(asn1buf *buf, const krb5_etype_info_entry **val,
-				       unsigned int *retlen, int etype_info2)
+asn1_error_code asn1_encode_sequence_of_algorithm_identifier(asn1buf *buf, const krb5_algorithm_identifier **val, unsigned int *retlen)
 {
     asn1_setup();
     int i;
-  
-    if (val == NULL) return ASN1_MISSING_FIELD;
-  
-    for(i=0; val[i] != NULL; i++); /* get to the end of the array */
-    for(i--; i>=0; i--){
-	retval = asn1_encode_etype_info_entry(buf,val[i],&length, etype_info2);
-	if(retval) return retval;
-	sum += length;
+
+    if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+    for (i=0; val[i] != NULL; i++);
+    for (i--; i>=0; i--) {
+        unsigned int length;
+        retval = asn1_encode_algorithm_identifier(buf,val[i],&length);
+        if (retval) return retval;
+        sum += length;
+    }
+    asn1_makeseq();
+
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_auth_pack(asn1buf *buf, const krb5_auth_pack *val, unsigned int *retlen)
+{
+    asn1_setup();
+
+    if (val->clientDHNonce.length != 0)
+        asn1_addlenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_encode_octetstring);
+    if (val->supportedCMSTypes != NULL)
+        asn1_addfield((const krb5_algorithm_identifier **)val->supportedCMSTypes,2,asn1_encode_sequence_of_algorithm_identifier);
+    if (val->clientPublicValue != NULL)
+        asn1_addfield(val->clientPublicValue,1,asn1_encode_subject_pk_info);
+    asn1_addfield(&(val->pkAuthenticator),0,asn1_encode_pk_authenticator);
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_auth_pack_draft9(asn1buf *buf, const krb5_auth_pack_draft9 *val, unsigned int *retlen)
+{
+    asn1_setup();
+
+    if (val->clientPublicValue != NULL)
+        asn1_addfield(val->clientPublicValue, 1, asn1_encode_subject_pk_info);
+    asn1_addfield(&(val->pkAuthenticator), 0, asn1_encode_pk_authenticator_draft9);
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_external_principal_identifier(asn1buf *buf, const krb5_external_principal_identifier *val, unsigned int *retlen)
+{
+    asn1_setup();
+
+    /* Verify there is something to encode */
+    if (val->subjectKeyIdentifier.length == 0 && val->issuerAndSerialNumber.length == 0 && val->subjectName.length == 0)
+        return ASN1_MISSING_FIELD;
+
+    if (val->subjectKeyIdentifier.length != 0)
+        asn1_insert_implicit_octetstring(val->subjectKeyIdentifier.length,val->subjectKeyIdentifier.data,2);
+
+    if (val->issuerAndSerialNumber.length != 0)
+        asn1_insert_implicit_octetstring(val->issuerAndSerialNumber.length,val->issuerAndSerialNumber.data,1);
+
+    if (val->subjectName.length != 0)
+        asn1_insert_implicit_octetstring(val->subjectName.length,val->subjectName.data,0);
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_external_principal_identifier(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen)
+{
+    asn1_setup();
+    int i;
+
+    if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+    for (i=0; val[i] != NULL; i++);
+    for (i--; i>=0; i--) {
+        unsigned int length;
+        retval = asn1_encode_external_principal_identifier(buf,val[i],&length);
+        if (retval) return retval;
+        sum += length;
+    }
+    asn1_makeseq();
+
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_pa_pk_as_req(asn1buf *buf, const krb5_pa_pk_as_req *val, unsigned int *retlen)
+{
+    asn1_setup();
+
+    if (val->kdcPkId.length != 0)
+        asn1_insert_implicit_octetstring(val->kdcPkId.length,val->kdcPkId.data,2);
+
+    if (val->trustedCertifiers != NULL)
+        asn1_addfield((const krb5_external_principal_identifier **)val->trustedCertifiers,1,asn1_encode_sequence_of_external_principal_identifier);
+
+    asn1_insert_implicit_octetstring(val->signedAuthPack.length,val->signedAuthPack.data,0);
+
+    asn1_makeseq();
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_trusted_ca(asn1buf *buf, const krb5_trusted_ca *val, unsigned int *retlen)
+{
+    asn1_setup();
+
+    switch (val->choice) {
+    case choice_trusted_cas_issuerAndSerial:
+        asn1_insert_implicit_octetstring(val->u.issuerAndSerial.length,val->u.issuerAndSerial.data,2);
+        break;
+    case choice_trusted_cas_caName:
+        asn1_insert_implicit_octetstring(val->u.caName.length,val->u.caName.data,1);
+        break;
+    case choice_trusted_cas_principalName:
+        asn1_addfield_implicit(val->u.principalName,0,asn1_encode_principal_name);
+        break;
+    default:
+        return ASN1_MISSING_FIELD;
+    }
+
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_trusted_ca(asn1buf *buf, const krb5_trusted_ca **val, unsigned int *retlen)
+{
+    asn1_setup();
+    int i;
+
+    if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+    for (i=0; val[i] != NULL; i++);
+    for (i--; i>=0; i--) {
+        unsigned int length;
+        retval = asn1_encode_trusted_ca(buf,val[i],&length);
+        if (retval) return retval;
+        sum += length;
     }
     asn1_makeseq();
     asn1_cleanup();
 }
 
-asn1_error_code asn1_encode_sequence_of_passwdsequence(asn1buf *buf, const passwd_phrase_element **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-  
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-  
-  for(i=0; val[i] != NULL; i++); /* get to the end of the array */
-  for(i--; i>=0; i--){
-    retval = asn1_encode_passwdsequence(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_passwdsequence(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen)
-{
-  asn1_setup();
-  asn1_addlenfield(val->phrase->length,val->phrase->data,1,asn1_encode_charstring);
-  asn1_addlenfield(val->passwd->length,val->passwd->data,0,asn1_encode_charstring);
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
-  return asn1_encode_krb5_flags(buf,val,retlen);
-}
-
-#define add_optstring(val,n,fn) \
-     if ((val).length > 0) {asn1_addlenfield((val).length,(val).data,n,fn);}
-
-asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge *val, unsigned int *retlen)
-{
-  asn1_setup();
-  /* possibly wrong */
-  if (val->sam_cksum.length)
-    asn1_addfield(&(val->sam_cksum),9,asn1_encode_checksum);
-
-  if (val->sam_nonce)
-    asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
-
-  add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
-  add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
-  add_optstring(val->sam_challenge,5,asn1_encode_charstring);
-  add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
-  add_optstring(val->sam_track_id,3,asn1_encode_charstring);
-  add_optstring(val->sam_type_name,2,asn1_encode_charstring);
-
-  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
-  asn1_addfield(val->sam_type,0,asn1_encode_integer);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, unsigned int *retlen)
-{
-  asn1_setup();
-  if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0]))
-      return ASN1_MISSING_FIELD;
-
-  asn1_addfield((const krb5_checksum **) val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
-  retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length,
-				      (unsigned char *)val->sam_challenge_2_body.data);
-  if(retval){
-	  asn1buf_destroy(&buf);
-	  return retval; 
-  }
-  sum += val->sam_challenge_2_body.length;
-  retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
-			  val->sam_challenge_2_body.length, &length);
-  if(retval) {
-	  asn1buf_destroy(&buf);
-	  return retval;
-  }
-  sum += length;
-  
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  asn1_addfield(val->sam_etype, 9, asn1_encode_integer);
-  asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
-  add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
-  add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
-  add_optstring(val->sam_challenge,5,asn1_encode_charstring);
-  add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
-  add_optstring(val->sam_track_id,3,asn1_encode_charstring);
-  add_optstring(val->sam_type_name,2,asn1_encode_charstring);
-
-  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
-  asn1_addfield(val->sam_type,0,asn1_encode_integer);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_key(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen)
-{
-  asn1_setup();
-  asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-
-asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sam_response_enc *val, unsigned int *retlen)
-{
-  asn1_setup();
-  add_optstring(val->sam_sad,3,asn1_encode_charstring);
-  asn1_addfield(val->sam_usec,2,asn1_encode_integer);
-  asn1_addfield(val->sam_timestamp,1,asn1_encode_kerberos_time);
-  asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, unsigned int *retlen)
-{
-  asn1_setup();
-  add_optstring(val->sam_sad,1,asn1_encode_charstring);
-  asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val->sam_patimestamp)
-    asn1_addfield(val->sam_patimestamp,6,asn1_encode_kerberos_time);
-  if (val->sam_nonce)
-    asn1_addfield(val->sam_nonce,5,asn1_encode_integer);
-  asn1_addfield(&(val->sam_enc_nonce_or_ts),4,asn1_encode_encrypted_data);
-  if (val->sam_enc_key.ciphertext.length)
-    asn1_addfield(&(val->sam_enc_key),3,asn1_encode_encrypted_data);
-  add_optstring(val->sam_track_id,2,asn1_encode_charstring);
-  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
-  asn1_addfield(val->sam_type,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  asn1_addfield(val->sam_nonce,4,asn1_encode_integer);
-  asn1_addfield(&(val->sam_enc_nonce_or_sad),3,asn1_encode_encrypted_data);
-  add_optstring(val->sam_track_id,2,asn1_encode_charstring);
-  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
-  asn1_addfield(val->sam_type,0,asn1_encode_integer);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  add_optstring(val->msd,6,asn1_encode_charstring);
-  asn1_addfield(val->client,5,asn1_encode_principal_name);
-  asn1_addfield(val->client,4,asn1_encode_realm);
-  asn1_addfield(val->susec,3,asn1_encode_integer);
-  asn1_addfield(val->stime,2,asn1_encode_kerberos_time);
-  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
-  asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
-
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-/*
- * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY.
- */
-asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen)
-{
-  asn1_error_code retval;
-
-  retval = asn1buf_insert_octetstring(buf, body->length,
-				      (krb5_octet *)body->data);
-  if (retval){
-    asn1buf_destroy(&buf);
-    return retval; 
-  }
-  *retlen = body->length;
-  return 0;
-}
-
-/*
- * PKINIT
- */
-
-asn1_error_code asn1_encode_pk_authenticator(asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen)
-{
-  asn1_setup();
-  asn1_addlenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_encode_octetstring);
-  asn1_addfield(val->nonce, 2, asn1_encode_integer);
-  asn1_addfield(val->ctime, 1, asn1_encode_kerberos_time);
-  asn1_addfield(val->cusec, 0, asn1_encode_integer);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_pk_authenticator_draft9(asn1buf *buf, const krb5_pk_authenticator_draft9 *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  asn1_addfield(val->nonce, 4, asn1_encode_integer);
-  asn1_addfield(val->ctime, 3, asn1_encode_kerberos_time);
-  asn1_addfield(val->cusec, 2, asn1_encode_integer);
-  asn1_addfield(val->kdcName, 1, asn1_encode_realm);
-  asn1_addfield(val->kdcName, 0, asn1_encode_principal_name);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-
-asn1_error_code asn1_encode_algorithm_identifier(asn1buf *buf, const krb5_algorithm_identifier *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val->parameters.length != 0) {
-    retval = asn1buf_insert_octetstring(buf, val->parameters.length, 
-					val->parameters.data);
-    if(retval) {
-      asn1buf_destroy(&buf);
-      return retval;
-    }
-    sum += val->parameters.length;
-  }
-  
-  retval = asn1_encode_oid(buf, val->algorithm.length, 
-			   val->algorithm.data,
-			   &length);
-  
-  if(retval) {
-    asn1buf_destroy(&buf);
-    return retval;
-  }
-  sum += length;  
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_info *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,ASN1_BITSTRING);
-
-  if (val->algorithm.parameters.length != 0) {
-    retval = asn1buf_insert_octetstring(buf, val->algorithm.parameters.length, 
-					val->algorithm.parameters.data);
-    if(retval) {
-      asn1buf_destroy(&buf);
-      return retval;
-    }
-    sum += val->algorithm.parameters.length;
-  }
-  
-  retval = asn1_encode_oid(buf, val->algorithm.algorithm.length, 
-			   val->algorithm.algorithm.data,
-			   &length);
-  
-  if(retval) {
-    asn1buf_destroy(&buf);
-    return retval;
-  }
-  sum += length;  
-  
-  retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE, 
-			  val->algorithm.parameters.length + length, 
-			  &length);
-
-  if(retval) {
-    asn1buf_destroy(&buf);
-    return retval;
-  }
-  sum += length;  
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_algorithm_identifier(asn1buf *buf, const krb5_algorithm_identifier **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_algorithm_identifier(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_auth_pack(asn1buf *buf, const krb5_auth_pack *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val->clientDHNonce.length != 0)
-    asn1_addlenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_encode_octetstring);
-  if (val->supportedCMSTypes != NULL)
-    asn1_addfield((const krb5_algorithm_identifier **)val->supportedCMSTypes,2,asn1_encode_sequence_of_algorithm_identifier);
-  if (val->clientPublicValue != NULL)
-    asn1_addfield(val->clientPublicValue,1,asn1_encode_subject_pk_info);
-  asn1_addfield(&(val->pkAuthenticator),0,asn1_encode_pk_authenticator);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_auth_pack_draft9(asn1buf *buf, const krb5_auth_pack_draft9 *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val->clientPublicValue != NULL)
-    asn1_addfield(val->clientPublicValue, 1, asn1_encode_subject_pk_info);
-  asn1_addfield(&(val->pkAuthenticator), 0, asn1_encode_pk_authenticator_draft9);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_external_principal_identifier(asn1buf *buf, const krb5_external_principal_identifier *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  /* Verify there is something to encode */
-  if (val->subjectKeyIdentifier.length == 0 && val->issuerAndSerialNumber.length == 0 && val->subjectName.length == 0)
-    return ASN1_MISSING_FIELD;
-
-  if (val->subjectKeyIdentifier.length != 0) 
-    asn1_insert_implicit_octetstring(val->subjectKeyIdentifier.length,val->subjectKeyIdentifier.data,2);
-
-  if (val->issuerAndSerialNumber.length != 0) 
-    asn1_insert_implicit_octetstring(val->issuerAndSerialNumber.length,val->issuerAndSerialNumber.data,1);
-
-  if (val->subjectName.length != 0) 
-    asn1_insert_implicit_octetstring(val->subjectName.length,val->subjectName.data,0);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_external_principal_identifier(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_external_principal_identifier(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_pa_pk_as_req(asn1buf *buf, const krb5_pa_pk_as_req *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  if (val->kdcPkId.length != 0) 
-    asn1_insert_implicit_octetstring(val->kdcPkId.length,val->kdcPkId.data,2);
-
-  if (val->trustedCertifiers != NULL)
-    asn1_addfield((const krb5_external_principal_identifier **)val->trustedCertifiers,1,asn1_encode_sequence_of_external_principal_identifier);
-
-  asn1_insert_implicit_octetstring(val->signedAuthPack.length,val->signedAuthPack.data,0);
-
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_trusted_ca(asn1buf *buf, const krb5_trusted_ca *val, unsigned int *retlen)
-{
-  asn1_setup();
-
-  switch (val->choice) {
-    case choice_trusted_cas_issuerAndSerial:
-      asn1_insert_implicit_octetstring(val->u.issuerAndSerial.length,val->u.issuerAndSerial.data,2);
-      break;
-    case choice_trusted_cas_caName:
-      asn1_insert_implicit_octetstring(val->u.caName.length,val->u.caName.data,1);
-      break;
-    case choice_trusted_cas_principalName:
-      asn1_addfield_implicit(val->u.principalName,0,asn1_encode_principal_name);
-      break;
-    default:
-      return ASN1_MISSING_FIELD;
-  }
-
-  asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_trusted_ca(asn1buf *buf, const krb5_trusted_ca **val, unsigned int *retlen)
-{
-  asn1_setup();
-  int i;
-
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
-
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_trusted_ca(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
-  asn1_cleanup();
-}
-
 asn1_error_code asn1_encode_pa_pk_as_req_draft9(asn1buf *buf, const krb5_pa_pk_as_req_draft9 *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  if (val->encryptionCert.length != 0)
-    asn1_insert_implicit_octetstring(val->encryptionCert.length,val->encryptionCert.data,3);
+    if (val->encryptionCert.length != 0)
+        asn1_insert_implicit_octetstring(val->encryptionCert.length,val->encryptionCert.data,3);
 
-  if (val->kdcCert.length != 0) 
-    asn1_insert_implicit_octetstring(val->kdcCert.length,val->kdcCert.data,2);
+    if (val->kdcCert.length != 0)
+        asn1_insert_implicit_octetstring(val->kdcCert.length,val->kdcCert.data,2);
 
-  if (val->trustedCertifiers != NULL)
-    asn1_addfield((const krb5_trusted_ca **)val->trustedCertifiers,1,asn1_encode_sequence_of_trusted_ca);
+    if (val->trustedCertifiers != NULL)
+        asn1_addfield((const krb5_trusted_ca **)val->trustedCertifiers,1,asn1_encode_sequence_of_trusted_ca);
 
-  asn1_insert_implicit_octetstring(val->signedAuthPack.length,val->signedAuthPack.data,0);
+    asn1_insert_implicit_octetstring(val->signedAuthPack.length,val->signedAuthPack.data,0);
 
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_dh_rep_info(asn1buf *buf, const krb5_dh_rep_info *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
+
+    if (val->serverDHNonce.length != 0)
+        asn1_insert_implicit_octetstring(val->serverDHNonce.length,val->serverDHNonce.data,1);
 
-  if (val->serverDHNonce.length != 0)
-    asn1_insert_implicit_octetstring(val->serverDHNonce.length,val->serverDHNonce.data,1);
-  
-  asn1_insert_implicit_octetstring(val->dhSignedData.length,val->dhSignedData.data,0);
+    asn1_insert_implicit_octetstring(val->dhSignedData.length,val->dhSignedData.data,0);
 
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_kdc_dh_key_info(asn1buf *buf, const krb5_kdc_dh_key_info *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  if (val->dhKeyExpiration != 0) 
-    asn1_addfield(val->dhKeyExpiration, 2, asn1_encode_kerberos_time);
-  asn1_addfield(val->nonce, 1, asn1_encode_integer);
+    if (val->dhKeyExpiration != 0)
+        asn1_addfield(val->dhKeyExpiration, 2, asn1_encode_kerberos_time);
+    asn1_addfield(val->nonce, 1, asn1_encode_integer);
+
+    {
+        unsigned int length;
 
-  asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,3);
-  retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, 
-			  val->subjectPublicKey.length + 1 + length,
-			  &length);
-  if(retval) {
-    asn1buf_destroy(&buf);
-    return retval;
-  }
-  sum += length; 
+        asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,3);
+        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
+                                val->subjectPublicKey.length + 1 + length,
+                                &length);
+        if (retval)
+            return retval;
+        sum += length;
+    }
 
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_reply_key_pack(asn1buf *buf, const krb5_reply_key_pack *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  asn1_addfield(&(val->asChecksum), 1, asn1_encode_checksum);
-  asn1_addfield(&(val->replyKey), 0, asn1_encode_encryption_key);
+    asn1_addfield(&(val->asChecksum), 1, asn1_encode_checksum);
+    asn1_addfield(&(val->replyKey), 0, asn1_encode_encryption_key);
 
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_reply_key_pack_draft9(asn1buf *buf, const krb5_reply_key_pack_draft9 *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  asn1_addfield(val->nonce, 1, asn1_encode_integer);
-  asn1_addfield(&(val->replyKey), 0, asn1_encode_encryption_key);
+    asn1_addfield(val->nonce, 1, asn1_encode_integer);
+    asn1_addfield(&(val->replyKey), 0, asn1_encode_encryption_key);
 
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_makeseq();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_pa_pk_as_rep(asn1buf *buf, const krb5_pa_pk_as_rep *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  switch (val->choice)
-  {
+    switch (val->choice)
+    {
     case choice_pa_pk_as_rep_dhInfo:
-      asn1_addfield(&(val->u.dh_Info), choice_pa_pk_as_rep_dhInfo, asn1_encode_dh_rep_info);
-      break;
+        asn1_addfield(&(val->u.dh_Info), choice_pa_pk_as_rep_dhInfo, asn1_encode_dh_rep_info);
+        break;
     case choice_pa_pk_as_rep_encKeyPack:
-      asn1_insert_implicit_octetstring(val->u.encKeyPack.length,val->u.encKeyPack.data,1);
-      break;
+        asn1_insert_implicit_octetstring(val->u.encKeyPack.length,val->u.encKeyPack.data,1);
+        break;
     default:
-      return ASN1_MISSING_FIELD;
-  }
+        return ASN1_MISSING_FIELD;
+    }
 
-  asn1_cleanup();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_pa_pk_as_rep_draft9(asn1buf *buf, const krb5_pa_pk_as_rep_draft9 *val, unsigned int *retlen)
 {
-  asn1_setup();
+    asn1_setup();
 
-  switch (val->choice)
-  {
+    switch (val->choice)
+    {
     case choice_pa_pk_as_rep_draft9_dhSignedData:
-      asn1_insert_implicit_octetstring(val->u.dhSignedData.length,val->u.dhSignedData.data,0);
-      break;
+        asn1_insert_implicit_octetstring(val->u.dhSignedData.length,val->u.dhSignedData.data,0);
+        break;
     case choice_pa_pk_as_rep_encKeyPack:
-      asn1_insert_implicit_octetstring(val->u.encKeyPack.length,val->u.encKeyPack.data,1);
-      break;
+        asn1_insert_implicit_octetstring(val->u.encKeyPack.length,val->u.encKeyPack.data,1);
+        break;
     default:
-      return ASN1_MISSING_FIELD;
-  }
+        return ASN1_MISSING_FIELD;
+    }
 
-  asn1_cleanup();
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_td_trusted_certifiers(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen)
 {
-  asn1_setup();
-  retval = asn1_encode_sequence_of_external_principal_identifier(buf, val, &length);
-  if (retval) {
-    asn1buf_destroy(&buf);
-    return retval;
-  }
-  asn1_cleanup();
+    asn1_setup();
+    {
+        unsigned int length;
+        retval = asn1_encode_sequence_of_external_principal_identifier(buf, val, &length);
+        if (retval)
+            return retval;
+        /* length set but ignored?  sum not updated?  */
+    }
+    asn1_cleanup();
 }
 
+#endif /* DISABLE_PKINIT */
+
 asn1_error_code asn1_encode_sequence_of_typed_data(asn1buf *buf, const krb5_typed_data **val, unsigned int *retlen)
 {
-  asn1_setup();
-  int i;
+    asn1_setup();
+    int i;
 
-  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+    if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
 
-  for(i=0; val[i] != NULL; i++);
-  for(i--; i>=0; i--){
-    retval = asn1_encode_typed_data(buf,val[i],&length);
-    if(retval) return retval;
-    sum += length;
-  }
-  asn1_makeseq();
+    for (i=0; val[i] != NULL; i++);
+    for (i--; i>=0; i--) {
+        unsigned int length;
 
-  asn1_cleanup();
+        retval = asn1_encode_typed_data(buf,val[i],&length);
+        if (retval) return retval;
+        sum += length;
+    }
+    asn1_makeseq();
+
+    asn1_cleanup();
 }
 
 asn1_error_code asn1_encode_typed_data(asn1buf *buf, const krb5_typed_data *val, unsigned int *retlen)
 {
-  asn1_setup();
-  asn1_addlenfield(val->length, val->data, 1, asn1_encode_octetstring);
-  asn1_addfield(val->type, 0, asn1_encode_integer);
-  asn1_makeseq();
-  asn1_cleanup();
+    asn1_setup();
+    asn1_addlenfield(val->length, val->data, 1, asn1_encode_octetstring);
+    asn1_addfield(val->type, 0, asn1_encode_integer);
+    asn1_makeseq();
+    asn1_cleanup();
 }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_k_encode.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,14 +1,15 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * src/lib/krb5/asn.1/asn1_k_encode.h
- * 
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -32,308 +33,104 @@
 #include "asn1buf.h"
 
 /*
-   Overview
-
-     Encoding routines for various ASN.1 "substructures" as defined in
-     the krb5 protocol.
-
-   Operations
-
-    asn1_encode_krb5_flags
-    asn1_encode_ap_options
-    asn1_encode_ticket_flags
-    asn1_encode_kdc_options
-    asn1_encode_kerberos_time
-
-    asn1_encode_realm
-    asn1_encode_principal_name
-    asn1_encode_encrypted_data
-    asn1_encode_authorization_data
-    asn1_encode_krb5_authdata_elt
-    asn1_encode_kdc_rep
-    asn1_encode_ticket
-    asn1_encode_encryption_key
-    asn1_encode_checksum
-    asn1_encode_host_address
-    asn1_encode_transited_encoding
-    asn1_encode_enc_kdc_rep_part
-    asn1_encode_kdc_req
-    asn1_encode_kdc_req_body
-    asn1_encode_krb_safe_body
-    asn1_encode_krb_cred_info
-    asn1_encode_last_req_entry
-    asn1_encode_pa_data
-
-    asn1_encode_host_addresses
-    asn1_encode_last_req
-    asn1_encode_sequence_of_pa_data
-    asn1_encode_sequence_of_ticket
-    asn1_encode_sequence_of_enctype
-    asn1_encode_sequence_of_checksum
-    asn1_encode_sequence_of_krb_cred_info
-*/
-
-/*
 **** for simple val's ****
 asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
                                       const krb5_type val,
-				      int *retlen);
+                                      int *retlen);
    requires  *buf is allocated
    effects   Inserts the encoding of val into *buf and
               returns the length of this encoding in *retlen.
-	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
-	     Returns ENOMEM if memory runs out.
+             Returns ASN1_MISSING_FIELD if a required field is empty in val.
+             Returns ENOMEM if memory runs out.
 
 **** for struct val's ****
 asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
                                       const krb5_type *val,
-				      int *retlen);
+                                      int *retlen);
    requires  *buf is allocated
    effects   Inserts the encoding of *val into *buf and
               returns the length of this encoding in *retlen.
-	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
-	     Returns ENOMEM if memory runs out.
+             Returns ASN1_MISSING_FIELD if a required field is empty in val.
+             Returns ENOMEM if memory runs out.
 
 **** for array val's ****
 asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
                                       const krb5_type **val,
-				      int *retlen);
+                                      int *retlen);
    requires  *buf is allocated, **val != NULL, *val[0] != NULL,
               **val is a NULL-terminated array of pointers to krb5_type
    effects   Inserts the encoding of **val into *buf and
               returns the length of this encoding in *retlen.
-	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
-	     Returns ENOMEM if memory runs out.
+             Returns ASN1_MISSING_FIELD if a required field is empty in val.
+             Returns ENOMEM if memory runs out.
 */
 
-asn1_error_code asn1_encode_ui_4 (asn1buf *buf,
-					    const krb5_ui_4 val,
-					    unsigned int *retlen);
-
-asn1_error_code asn1_encode_msgtype (asn1buf *buf,
-					       const /*krb5_msgtype*/int val,
-					       unsigned int *retlen);
-
-asn1_error_code asn1_encode_realm
-	(asn1buf *buf, const krb5_principal val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_principal_name
-	(asn1buf *buf, const krb5_principal val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_encrypted_data
-	(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_krb5_flags
-	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_ap_options
-	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_ticket_flags
-	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_kdc_options
-	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_authorization_data
-	(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_krb5_authdata_elt
-	(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_kdc_rep
-	(int msg_type, asn1buf *buf, const krb5_kdc_rep *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_enc_kdc_rep_part
-	(asn1buf *buf, const krb5_enc_kdc_rep_part *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_ticket
-	(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_encryption_key
-	(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_kerberos_time
-	(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_checksum
-	(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_host_address
-	(asn1buf *buf, const krb5_address *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_host_addresses
-	(asn1buf *buf, const krb5_address **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_transited_encoding
-	(asn1buf *buf, const krb5_transited *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_last_req
-	(asn1buf *buf, const krb5_last_req_entry **val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_pa_data
-	(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_ticket
-	(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_enctype
-	(asn1buf *buf,
-		   const int len, const krb5_enctype *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_checksum
-	(asn1buf *buf, const krb5_checksum **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_kdc_req
-	(int msg_type,
-		   asn1buf *buf,
-		   const krb5_kdc_req *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_kdc_req_body
-	(asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_krb_safe_body
-	(asn1buf *buf, const krb5_safe *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_krb_cred_info
-	(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_krb_cred_info
-	(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_last_req_entry
-	(asn1buf *buf, const krb5_last_req_entry *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_pa_data
-	(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_alt_method
-	(asn1buf *buf, const krb5_alt_method *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_etype_info_entry
-	(asn1buf *buf, const krb5_etype_info_entry *val,
-		   unsigned int *retlen, int etype_info2);
-
-asn1_error_code asn1_encode_etype_info
-	(asn1buf *buf, const krb5_etype_info_entry **val,
-		   unsigned int *retlen, int etype_info2);
-
-asn1_error_code asn1_encode_passwdsequence
-	(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sequence_of_passwdsequence
-	(asn1buf *buf, const passwd_phrase_element **val,
-	unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_flags
-	(asn1buf * buf, const krb5_flags val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_challenge
-	(asn1buf *buf, const krb5_sam_challenge * val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_challenge_2
-	(asn1buf *buf, const krb5_sam_challenge_2 * val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_challenge_2_body
-	(asn1buf *buf, const krb5_sam_challenge_2_body * val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_key
-	(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_enc_sam_response_enc
-	(asn1buf *buf, const krb5_enc_sam_response_enc *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_enc_sam_response_enc_2
-	(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val,
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_response
-	(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_sam_response_2
-	(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen);
-
-asn1_error_code asn1_encode_predicted_sam_response
-	(asn1buf *buf, const krb5_predicted_sam_response *val, 
-		   unsigned int *retlen);
-
-asn1_error_code asn1_encode_krb_saved_safe_body
-	(asn1buf *buf, const krb5_data *body, unsigned int *retlen);
-
 /* PKINIT */
 
 asn1_error_code asn1_encode_pk_authenticator
-	(asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_pk_authenticator_draft9
-	(asn1buf *buf, const krb5_pk_authenticator_draft9 *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pk_authenticator_draft9 *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_algorithm_identifier
-	(asn1buf *buf, const krb5_algorithm_identifier *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_algorithm_identifier *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_subject_pk_info
-	(asn1buf *buf, const krb5_subject_pk_info *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_subject_pk_info *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_sequence_of_algorithm_identifier
-	(asn1buf *buf, const krb5_algorithm_identifier **val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_algorithm_identifier **val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_auth_pack
-	(asn1buf *buf, const krb5_auth_pack *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_auth_pack *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_auth_pack_draft9
-	(asn1buf *buf, const krb5_auth_pack_draft9 *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_auth_pack_draft9 *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_external_principal_identifier
-	(asn1buf *buf, const krb5_external_principal_identifier *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_external_principal_identifier *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_sequence_of_external_principal_identifier
-	(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_pa_pk_as_req
-	(asn1buf *buf, const krb5_pa_pk_as_req *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pa_pk_as_req *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_trusted_ca
-	(asn1buf *buf, const krb5_trusted_ca *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_trusted_ca *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_sequence_of_trusted_ca
-	(asn1buf *buf, const krb5_trusted_ca **val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_trusted_ca **val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_pa_pk_as_req_draft9
-	(asn1buf *buf, const krb5_pa_pk_as_req_draft9 *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pa_pk_as_req_draft9 *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_dh_rep_info
-	(asn1buf *buf, const krb5_dh_rep_info *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_dh_rep_info *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_kdc_dh_key_info
-	(asn1buf *buf, const krb5_kdc_dh_key_info *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_kdc_dh_key_info *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_reply_key_pack
-	(asn1buf *buf, const krb5_reply_key_pack *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_reply_key_pack *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_reply_key_pack_draft9
-	(asn1buf *buf, const krb5_reply_key_pack_draft9 *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_reply_key_pack_draft9 *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_pa_pk_as_rep
-	(asn1buf *buf, const krb5_pa_pk_as_rep *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pa_pk_as_rep *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_pa_pk_as_rep_draft9
-	(asn1buf *buf, const krb5_pa_pk_as_rep_draft9 *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_pa_pk_as_rep_draft9 *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_td_trusted_certifiers
-	(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_typed_data
-	(asn1buf *buf, const krb5_typed_data *val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_typed_data *val, unsigned int *retlen);
 
 asn1_error_code asn1_encode_sequence_of_typed_data
-	(asn1buf *buf, const krb5_typed_data **val, unsigned int *retlen);
+        (asn1buf *buf, const krb5_typed_data **val, unsigned int *retlen);
+
 #endif
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krb5_encode.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krb5_encode.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,15 +1,15 @@
-
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * src/lib/krb5/asn.1/krb5_encode.c
- * 
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -34,47 +34,6 @@
 
 /**************** Macros (these save a lot of typing) ****************/
 
-/**** krb5 macros ****/
-#if 0
-   How to write a krb5 encoder function using these macros:
-
-   asn1_error_code encode_krb5_structure(const krb5_type *rep,
-                                         krb5_data **code)
-   {
-     krb5_setup();
-
-     krb5_addfield(rep->last_field, n, asn1_type);
-     krb5_addfield(rep->next_to_last_field, n-1, asn1_type);
-     ...
-
-     /* for OPTIONAL fields */
-     if(rep->field_i == should_not_be_omitted)
-       krb5_addfield(rep->field_i, i, asn1_type);
-
-     /* for string fields (these encoders take an additional argument,
-	the length of the string) */
-     addlenfield(rep->field_length, rep->field, i-1, asn1_type);
-
-     /* if you really have to do things yourself... */
-     retval = asn1_encode_asn1_type(buf,rep->field,&length);
-     if(retval) return retval;
-     sum += length;
-     retval = asn1_make_etag(buf,
-			    [UNIVERSAL/APPLICATION/CONTEXT_SPECIFIC/PRIVATE],
-			    tag_number, length, &length);
-     if(retval) return retval;
-     sum += length;
-
-     ...
-     krb5_addfield(rep->second_field, 1, asn1_type);
-     krb5_addfield(rep->first_field, 0, asn1_type);
-     krb5_makeseq();
-     krb5_apptag(tag_number);
-
-     krb5_cleanup();
-   }
-#endif
-
 /* setup() -- create and initialize bookkeeping variables
      retval: stores error codes returned from subroutines
      buf: the coding buffer
@@ -82,935 +41,134 @@
      sum: cumulative length of the entire encoding */
 #define krb5_setup()\
   asn1_error_code retval;\
+  unsigned int length, sum = 0;\
   asn1buf *buf=NULL;\
-  unsigned int length, sum=0;\
+  krb5_data *tmpcode;\
 \
-  if(rep == NULL) return ASN1_MISSING_FIELD;\
+  *code = NULL;\
+\
+  if (rep == NULL) return ASN1_MISSING_FIELD;\
 \
   retval = asn1buf_create(&buf);\
-  if(retval) return retval
-  
-/* krb5_addfield -- add a field, or component, to the encoding */
-#define krb5_addfield(value,tag,encoder)\
-{ retval = encoder(buf,value,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length;\
-  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length; }
-
-/* krb5_addlenfield -- add a field whose length must be separately specified */
-#define krb5_addlenfield(len,value,tag,encoder)\
-{ retval = encoder(buf,len,value,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length;\
-  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length; }
-
-/* form a sequence (by adding a sequence header to the current encoding) */
-#define krb5_makeseq()\
-  retval = asn1_make_sequence(buf,sum,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length
-
-/* add an APPLICATION class tag to the current encoding */
-#define krb5_apptag(num)\
-  retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  sum += length
+  if (retval) return retval
 
 /* produce the final output and clean up the workspace */
 #define krb5_cleanup()\
-  retval = asn12krb5_buf(buf,code);\
-  if(retval){\
-    asn1buf_destroy(&buf);\
-    return retval; }\
-  retval = asn1buf_destroy(&buf);\
-  if(retval){\
-    return retval; }\
-\
+  retval = asn12krb5_buf(buf,&tmpcode);\
+error:\
+  asn1buf_destroy(&buf);\
+  if (retval)\
+    return retval;\
+  *code = tmpcode;\
   return 0
 
-krb5_error_code encode_krb5_authenticator(const krb5_authenticator *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* authorization-data[8]	AuthorizationData OPTIONAL */
-  if(rep->authorization_data != NULL &&
-     rep->authorization_data[0] != NULL){
-    retval = asn1_encode_authorization_data(buf, (const krb5_authdata **)
-					    rep->authorization_data,
-					    &length);
-    if(retval){
-      asn1buf_destroy(&buf);
-      return retval; }
-    sum += length;
-    retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,8,length,&length);
-    if(retval){
-      asn1buf_destroy(&buf);
-      return retval; }
-    sum += length;
-  }
-
-  /* seq-number[7]		INTEGER OPTIONAL */
-  if(rep->seq_number != 0)
-    krb5_addfield(rep->seq_number,7,asn1_encode_unsigned_integer);
-
-  /* subkey[6]			EncryptionKey OPTIONAL */
-  if(rep->subkey != NULL)
-    krb5_addfield(rep->subkey,6,asn1_encode_encryption_key);
-
-  /* ctime[5]			KerberosTime */
-  krb5_addfield(rep->ctime,5,asn1_encode_kerberos_time);
-
-  /* cusec[4]			INTEGER */
-  krb5_addfield(rep->cusec,4,asn1_encode_integer);
-
-  /* cksum[3]			Checksum OPTIONAL */
-  if(rep->checksum != NULL)
-    krb5_addfield(rep->checksum,3,asn1_encode_checksum);
-
-  /* cname[2]			PrincipalName */
-  krb5_addfield(rep->client,2,asn1_encode_principal_name);
-
-  /* crealm[1]			Realm */
-  krb5_addfield(rep->client,1,asn1_encode_realm);
-
-  /* authenticator-vno[0]	INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* Authenticator ::= [APPLICATION 2] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(2);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* enc-part[3]	EncryptedData */
-  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
-
-  /* sname [2]		PrincipalName */
-  krb5_addfield(rep->server,2,asn1_encode_principal_name);
-
-  /* realm [1]		Realm */
-  krb5_addfield(rep->server,1,asn1_encode_realm);
-
-  /* tkt-vno [0]	INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* Ticket ::= [APPLICATION 1] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(1);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_encryption_key(const krb5_keyblock *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* keyvalue[1]	OCTET STRING */
-  krb5_addlenfield(rep->length,rep->contents,1,asn1_encode_octetstring);
-
-  /* enctype[0]		INTEGER */
-  krb5_addfield(rep->enctype,0,asn1_encode_integer);
-
-  /* EncryptionKey ::= SEQUENCE */
-  krb5_makeseq();
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* authorization-data[10]	AuthorizationData OPTIONAL */
-  if(rep->authorization_data != NULL &&
-     rep->authorization_data[0] != NULL)
-    krb5_addfield((const krb5_authdata**)rep->authorization_data,
-		  10,asn1_encode_authorization_data);
-
-  /* caddr[9]			HostAddresses OPTIONAL */
-  if(rep->caddrs != NULL && rep->caddrs[0] != NULL)
-    krb5_addfield((const krb5_address**)rep->caddrs,9,asn1_encode_host_addresses);
-
-  /* renew-till[8]		KerberosTime OPTIONAL */
-  if(rep->times.renew_till)
-    krb5_addfield(rep->times.renew_till,8,asn1_encode_kerberos_time);
-
-  /* endtime[7]			KerberosTime */
-  krb5_addfield(rep->times.endtime,7,asn1_encode_kerberos_time);
-
-  /* starttime[6]		KerberosTime OPTIONAL */
-  if(rep->times.starttime)
-    krb5_addfield(rep->times.starttime,6,asn1_encode_kerberos_time);
-
-  /* authtime[5]		KerberosTime */
-  krb5_addfield(rep->times.authtime,5,asn1_encode_kerberos_time);
-
-  /* transited[4]		TransitedEncoding */
-  krb5_addfield(&(rep->transited),4,asn1_encode_transited_encoding);
-
-  /* cname[3]			PrincipalName */
-  krb5_addfield(rep->client,3,asn1_encode_principal_name);
-
-  /* crealm[2]			Realm */
-  krb5_addfield(rep->client,2,asn1_encode_realm);
-
-  /* key[1]			EncryptionKey */
-  krb5_addfield(rep->session,1,asn1_encode_encryption_key);
-
-  /* flags[0]			TicketFlags */
-  krb5_addfield(rep->flags,0,asn1_encode_ticket_flags);
-
-  /* EncTicketPart ::= [APPLICATION 3] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(3);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_kdc_rep_part(const krb5_enc_kdc_rep_part *rep, krb5_data **code)
-{
-  asn1_error_code retval;
-  asn1buf *buf=NULL;
-  unsigned int length, sum=0;
-
-  if(rep == NULL) return ASN1_MISSING_FIELD;
-
-  retval = asn1buf_create(&buf);
-  if(retval) return retval;
-
-  retval = asn1_encode_enc_kdc_rep_part(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-#ifdef KRB5_ENCKRB5KDCREPPART_COMPAT
-  krb5_apptag(26);
-#else
-  /* XXX WRONG!!! Should use 25 || 26, not the outer KDC_REP tags! */
-  if (rep->msg_type == KRB5_AS_REP) { krb5_apptag(ASN1_KRB_AS_REP); }
-  else if (rep->msg_type == KRB5_TGS_REP) { krb5_apptag(ASN1_KRB_TGS_REP); }
-  else return KRB5_BADMSGTYPE;
-#endif
-  krb5_cleanup();
-}
-
-/* yes, the translation is identical to that used for KDC__REP */ 
-krb5_error_code encode_krb5_as_rep(const krb5_kdc_rep *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* AS-REP ::= [APPLICATION 11] KDC-REP */
-  retval = asn1_encode_kdc_rep(KRB5_AS_REP,buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_apptag(11);
-
-  krb5_cleanup();
-}
-
-/* yes, the translation is identical to that used for KDC__REP */ 
-krb5_error_code encode_krb5_tgs_rep(const krb5_kdc_rep *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* TGS-REP ::= [APPLICATION 13] KDC-REP */
-  retval = asn1_encode_kdc_rep(KRB5_TGS_REP,buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_apptag(13);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_ap_req(const krb5_ap_req *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* authenticator[4]	EncryptedData */
-  krb5_addfield(&(rep->authenticator),4,asn1_encode_encrypted_data);
-
-  /* ticket[3]		Ticket */
-  krb5_addfield(rep->ticket,3,asn1_encode_ticket);
-
-  /* ap-options[2]	APOptions */
-  krb5_addfield(rep->ap_options,2,asn1_encode_ap_options);
-
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_AP_REQ,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* AP-REQ ::=	[APPLICATION 14] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(14);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_ap_rep(const krb5_ap_rep *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* enc-part[2]	EncryptedData */
-  krb5_addfield(&(rep->enc_part),2,asn1_encode_encrypted_data);
-  
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_AP_REP,1,asn1_encode_integer);
-  
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-  
-  /* AP-REP ::=	[APPLICATION 15] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(15);
-  
-  krb5_cleanup();
-}
-
-
-krb5_error_code encode_krb5_ap_rep_enc_part(const krb5_ap_rep_enc_part *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* seq-number[3]	INTEGER OPTIONAL */
-  if(rep->seq_number)
-    krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer);
-
-  /* subkey[2]		EncryptionKey OPTIONAL */
-  if(rep->subkey != NULL)
-    krb5_addfield(rep->subkey,2,asn1_encode_encryption_key);
-
-  /* cusec[1]		INTEGER */
-  krb5_addfield(rep->cusec,1,asn1_encode_integer);
-
-  /* ctime[0]		KerberosTime */
-  krb5_addfield(rep->ctime,0,asn1_encode_kerberos_time);
-
-  /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(27);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_as_req(const krb5_kdc_req *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* AS-REQ ::= [APPLICATION 10] KDC-REQ */
-  retval = asn1_encode_kdc_req(KRB5_AS_REQ,buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_apptag(10);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_tgs_req(const krb5_kdc_req *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* TGS-REQ ::= [APPLICATION 12] KDC-REQ */
-  retval = asn1_encode_kdc_req(KRB5_TGS_REQ,buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_apptag(12);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_kdc_req_body(const krb5_kdc_req *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  retval = asn1_encode_kdc_req_body(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_cleanup();
-}
-
-
-krb5_error_code encode_krb5_safe(const krb5_safe *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* cksum[3]		Checksum */
-  krb5_addfield(rep->checksum,3,asn1_encode_checksum);
-
-  /* safe-body[2]	KRB-SAFE-BODY */
-  krb5_addfield(rep,2,asn1_encode_krb_safe_body);
-
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(20);
-
-  krb5_cleanup();
-}
-
-/*
- * encode_krb5_safe_with_body
- *
- * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY
- * encoding to avoid problems with re-encoding.
- */
-krb5_error_code encode_krb5_safe_with_body(
-  const krb5_safe *rep,
-  const krb5_data *body,
-  krb5_data **code)
-{
-  krb5_setup();
-
-  if (body == NULL) {
-      asn1buf_destroy(&buf);
-      return ASN1_MISSING_FIELD;
-  }
-
-  /* cksum[3]		Checksum */
-  krb5_addfield(rep->checksum,3,asn1_encode_checksum);
-
-  /* safe-body[2]	KRB-SAFE-BODY */
-  krb5_addfield(body,2,asn1_encode_krb_saved_safe_body);
-
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(20);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_priv(const krb5_priv *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* enc-part[3]	EncryptedData */
-  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
-
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_PRIV,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* KRB-PRIV ::= [APPLICATION 21] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(21);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_priv_part(const krb5_priv_enc_part *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* r-address[5]	HostAddress OPTIONAL -- recip's addr */
-  if(rep->r_address)
-    krb5_addfield(rep->r_address,5,asn1_encode_host_address);
-
-  /* s-address[4]	HostAddress -- sender's addr */
-  krb5_addfield(rep->s_address,4,asn1_encode_host_address);
-
-  /* seq-number[3]	INTEGER OPTIONAL */
-  if(rep->seq_number)
-    krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer);
-
-  /* usec[2]		INTEGER OPTIONAL */
-  if(rep->timestamp){
-    krb5_addfield(rep->usec,2,asn1_encode_integer);
-    /* timestamp[1]	KerberosTime OPTIONAL */
-    krb5_addfield(rep->timestamp,1,asn1_encode_kerberos_time);
-  }
-
-  /* user-data[0]	OCTET STRING */
-  krb5_addlenfield(rep->user_data.length,rep->user_data.data,0,asn1_encode_charstring);
-
-  /* EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(28);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_cred(const krb5_cred *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* enc-part[3]	EncryptedData */
-  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
-
-  /* tickets[2]		SEQUENCE OF Ticket */
-  krb5_addfield((const krb5_ticket**)rep->tickets,2,asn1_encode_sequence_of_ticket);
-
-  /* msg-type[1]	INTEGER, -- KRB_CRED */
-  krb5_addfield(ASN1_KRB_CRED,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* KRB-CRED ::= [APPLICATION 22] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(22);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_cred_part(const krb5_cred_enc_part *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* r-address[5]	HostAddress OPTIONAL */
-  if(rep->r_address != NULL)
-    krb5_addfield(rep->r_address,5,asn1_encode_host_address);
-
-  /* s-address[4]	HostAddress OPTIONAL */
-  if(rep->s_address != NULL)
-    krb5_addfield(rep->s_address,4,asn1_encode_host_address);
-
-  /* usec[3]		INTEGER OPTIONAL */
-  if(rep->timestamp){
-    krb5_addfield(rep->usec,3,asn1_encode_integer);
-    /* timestamp[2]	KerberosTime OPTIONAL */
-    krb5_addfield(rep->timestamp,2,asn1_encode_kerberos_time);
-  }
-
-  /* nonce[1]		INTEGER OPTIONAL */
-  if(rep->nonce)
-    krb5_addfield(rep->nonce,1,asn1_encode_integer);
-
-  /* ticket-info[0]	SEQUENCE OF KrbCredInfo */
-  krb5_addfield((const krb5_cred_info**)rep->ticket_info,
-		0,asn1_encode_sequence_of_krb_cred_info);
-
-  /* EncKrbCredPart ::= [APPLICATION 29] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(29);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_error(const krb5_error *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* e-data[12]		OCTET STRING OPTIONAL */
-  if(rep->e_data.data != NULL && rep->e_data.length > 0)
-    krb5_addlenfield(rep->e_data.length,rep->e_data.data,12,asn1_encode_charstring);
-
-  /* e-text[11]		GeneralString OPTIONAL */
-  if(rep->text.data != NULL && rep->text.length > 0)
-    krb5_addlenfield(rep->text.length,rep->text.data,11,asn1_encode_generalstring);
-
-  /* sname[10]		PrincipalName -- Correct name */
-  krb5_addfield(rep->server,10,asn1_encode_principal_name);
-
-  /* realm[9]		Realm -- Correct realm */
-  krb5_addfield(rep->server,9,asn1_encode_realm);
-
-  /* cname[8]		PrincipalName OPTIONAL */
-  if(rep->client != NULL){
-    krb5_addfield(rep->client,8,asn1_encode_principal_name);
-    /* crealm[7]		Realm OPTIONAL */
-    krb5_addfield(rep->client,7,asn1_encode_realm);
-  }
-
-  /* error-code[6]	INTEGER */
-  krb5_addfield(rep->error,6,asn1_encode_ui_4);
-
-  /* susec[5]		INTEGER */
-  krb5_addfield(rep->susec,5,asn1_encode_integer);
-
-  /* stime[4]		KerberosTime */
-  krb5_addfield(rep->stime,4,asn1_encode_kerberos_time);
-
-  /* cusec[3]		INTEGER OPTIONAL */
-  if(rep->cusec)
-    krb5_addfield(rep->cusec,3,asn1_encode_integer);
-
-  /* ctime[2]		KerberosTime OPTIONAL */
-  if(rep->ctime)
-    krb5_addfield(rep->ctime,2,asn1_encode_kerberos_time);
-
-  /* msg-type[1]	INTEGER */
-  krb5_addfield(ASN1_KRB_ERROR,1,asn1_encode_integer);
-
-  /* pvno[0]		INTEGER */
-  krb5_addfield(KVNO,0,asn1_encode_integer);
-
-  /* KRB-ERROR ::= [APPLICATION 30] SEQUENCE */
-  krb5_makeseq();
-  krb5_apptag(30);
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_authdata(const krb5_authdata **rep, krb5_data **code)
-{
-  asn1_error_code retval;
-  asn1buf *buf=NULL;
-  unsigned int length;
-  
-  if(rep == NULL) return ASN1_MISSING_FIELD;
-
-  retval = asn1buf_create(&buf);
-  if(retval) return retval;
-
-  retval = asn1_encode_authorization_data(buf,(const krb5_authdata**)rep,
-					  &length);
-  if(retval) return retval;
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_authdata_elt(const krb5_authdata *rep, krb5_data **code)
-{
-  asn1_error_code retval;
-  asn1buf *buf=NULL;
-  unsigned int length;
-  
-  if(rep == NULL) return ASN1_MISSING_FIELD;
-
-  retval = asn1buf_create(&buf);
-  if(retval) return retval;
-
-  retval = asn1_encode_krb5_authdata_elt(buf,rep, &length);
-  if(retval) return retval;
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_alt_method(const krb5_alt_method *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* method-data[1]		OctetString OPTIONAL */
-  if(rep->data != NULL && rep->length > 0)
-    krb5_addlenfield(rep->length,rep->data,1,asn1_encode_octetstring);
-
-  /* method-type[0]		Integer */
-  krb5_addfield(rep->method,0,asn1_encode_integer);
-
-  krb5_makeseq();
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_etype_info(const krb5_etype_info_entry **rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_etype_info(buf,rep,&length, 0);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_etype_info2(const krb5_etype_info_entry **rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_etype_info(buf,rep,&length, 1);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-  
-
-krb5_error_code encode_krb5_enc_data(const krb5_enc_data *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  retval = asn1_encode_encrypted_data(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_pa_enc_ts(const krb5_pa_enc_ts *rep, krb5_data **code)
-{
-  krb5_setup();
-
-  /* pausec[1]                    INTEGER OPTIONAL */
-  if (rep->pausec)
-	  krb5_addfield(rep->pausec,1,asn1_encode_integer);
-
-  /* patimestamp[0]               KerberosTime, -- client's time */
-  krb5_addfield(rep->patimestamp,0,asn1_encode_kerberos_time);
-
-  krb5_makeseq();
-
-  krb5_cleanup();
-}
-
-/* Sandia Additions */
-krb5_error_code encode_krb5_pwd_sequence(const passwd_phrase_element *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_passwdsequence(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_pwd_data(const krb5_pwd_data *rep, krb5_data **code)
-{
-  krb5_setup();
-  krb5_addfield((const passwd_phrase_element**)rep->element,1,asn1_encode_sequence_of_passwdsequence);
-  krb5_addfield(rep->sequence_count,0,asn1_encode_integer);
-  krb5_makeseq();
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_padata_sequence(const krb5_pa_data **rep, krb5_data **code)
-{
-  krb5_setup();
-
-  retval = asn1_encode_sequence_of_pa_data(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-
-  krb5_cleanup();
-}
-
-/* sam preauth additions */
-krb5_error_code encode_krb5_sam_challenge(const krb5_sam_challenge *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_challenge(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_sam_challenge_2(const krb5_sam_challenge_2 *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_challenge_2(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_sam_challenge_2_body(const krb5_sam_challenge_2_body *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_challenge_2_body(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_sam_key(const krb5_sam_key *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_key(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_sam_response_enc(const krb5_enc_sam_response_enc *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_enc_sam_response_enc(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_enc_sam_response_enc_2(const krb5_enc_sam_response_enc_2 *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_enc_sam_response_enc_2(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_sam_response(const krb5_sam_response *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_response(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_sam_response_2(const krb5_sam_response_2 *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sam_response_2(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_predicted_sam_response(const krb5_predicted_sam_response *rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_predicted_sam_response(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_setpw_req(const krb5_principal target,
-				      char *password, krb5_data **code)
-{
-  /* Macros really want us to have a variable called rep which we do not need*/
-  const char *rep = "dummy string";
-
-  krb5_setup();
-
-  krb5_addfield(target,2,asn1_encode_realm);
-  krb5_addfield(target,1,asn1_encode_principal_name);
-  /* Solaris Kerberos */
-  krb5_addlenfield(strlen(password), (const unsigned char *)password,0,asn1_encode_octetstring);
-  krb5_makeseq();
-
-
-  krb5_cleanup();
-}
-
+#ifndef DISABLE_PKINIT
 krb5_error_code encode_krb5_pa_pk_as_req(const krb5_pa_pk_as_req *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_pa_pk_as_req(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_pa_pk_as_req(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_pa_pk_as_req_draft9(const krb5_pa_pk_as_req_draft9 *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_pa_pk_as_req_draft9(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_pa_pk_as_req_draft9(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_pa_pk_as_rep(const krb5_pa_pk_as_rep *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_pa_pk_as_rep(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_pa_pk_as_rep(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_pa_pk_as_rep_draft9(const krb5_pa_pk_as_rep_draft9 *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_pa_pk_as_rep_draft9(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_pa_pk_as_rep_draft9(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_auth_pack(const krb5_auth_pack *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_auth_pack(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_auth_pack(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_auth_pack_draft9(const krb5_auth_pack_draft9 *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_auth_pack_draft9(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_auth_pack_draft9(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_kdc_dh_key_info(const krb5_kdc_dh_key_info *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_kdc_dh_key_info(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_kdc_dh_key_info(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_reply_key_pack(const krb5_reply_key_pack *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_reply_key_pack(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_reply_key_pack(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_reply_key_pack_draft9(const krb5_reply_key_pack_draft9 *rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_reply_key_pack_draft9(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_reply_key_pack_draft9(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_td_trusted_certifiers(const krb5_external_principal_identifier **rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_td_trusted_certifiers(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
-}
-
-krb5_error_code encode_krb5_typed_data(const krb5_typed_data **rep, krb5_data **code)
-{
-  krb5_setup();
-  retval = asn1_encode_sequence_of_typed_data(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_td_trusted_certifiers(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
 
 krb5_error_code encode_krb5_td_dh_parameters(const krb5_algorithm_identifier **rep, krb5_data **code)
 {
-  krb5_setup();
-  retval = asn1_encode_sequence_of_algorithm_identifier(buf,rep,&length);
-  if(retval) return retval;
-  sum += length;
-  krb5_cleanup();
+    krb5_setup();
+    retval = asn1_encode_sequence_of_algorithm_identifier(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
 }
+#endif /* DISABLE_PKINIT */
+
+krb5_error_code encode_krb5_typed_data(const krb5_typed_data **rep, krb5_data **code)
+{
+    krb5_setup();
+    retval = asn1_encode_sequence_of_typed_data(buf,rep,&length);
+    if (retval) goto error;
+    sum += length;
+    krb5_cleanup();
+}
+
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krbasn1.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/krbasn1.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,23 +1,14 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 #ifndef __KRBASN1_H__
 #define __KRBASN1_H__
 
 #include "k5-int.h"
 #include <stdio.h>
 #include <errno.h>
-#include <limits.h>		/* For INT_MAX */
+#include <limits.h>             /* For INT_MAX */
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
-/*
- * Older versions of the Kerberos are always sending the
- * enc_kdc_rep_part structure with an application tag of #26, instead
- * of using the application tag of #25 (AS REP) or #26 (AS REP) as
- * necessary.  Worse yet, they will only accept a tag of #26, so we
- * need to follow this for backwards compatibility.  #defining
- * KRB5_ENCKRB5KDCREPPART_COMPAT will preserve this wrong (but
- * compatible) behavior.
- */
-#define KRB5_ENCKRB5KDCREPPART_COMPAT
 
 /*
  * If KRB5_MSGTYPE_STRICT is defined, then be strict about checking
@@ -42,7 +33,10 @@
 typedef enum { PRIMITIVE = 0x00, CONSTRUCTED = 0x20 } asn1_construction;
 
 typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40,
-		 CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class;
+                 CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class;
+
+typedef INT64_TYPE asn1_intmax;
+typedef UINT64_TYPE asn1_uintmax;
 
 typedef int asn1_tagnum;
 #define ASN1_TAGNUM_CEILING INT_MAX
@@ -52,30 +46,31 @@
 #define KVNO 5
 
 /* Universal Tag Numbers */
-#define ASN1_INTEGER		2
-#define ASN1_BITSTRING		3
-#define ASN1_OCTETSTRING	4
-#define ASN1_NULL		5
-#define ASN1_OBJECTIDENTIFIER	6
-#define ASN1_ENUMERATED 10
-#define ASN1_SEQUENCE		16
-#define ASN1_SET		17
-#define ASN1_PRINTABLESTRING	19
-#define ASN1_IA5STRING		22
-#define ASN1_UTCTIME		23
-#define ASN1_GENERALTIME	24
-#define ASN1_GENERALSTRING	27
+#define ASN1_BOOLEAN            1
+#define ASN1_INTEGER            2
+#define ASN1_BITSTRING          3
+#define ASN1_OCTETSTRING        4
+#define ASN1_NULL               5
+#define ASN1_OBJECTIDENTIFIER   6
+#define ASN1_ENUMERATED         10
+#define ASN1_SEQUENCE           16
+#define ASN1_SET                17
+#define ASN1_PRINTABLESTRING    19
+#define ASN1_IA5STRING          22
+#define ASN1_UTCTIME            23
+#define ASN1_GENERALTIME        24
+#define ASN1_GENERALSTRING      27
 
 /* Kerberos Message Types */
-#define ASN1_KRB_AS_REQ		10
-#define ASN1_KRB_AS_REP		11
-#define ASN1_KRB_TGS_REQ	12
-#define ASN1_KRB_TGS_REP	13
-#define ASN1_KRB_AP_REQ		14
-#define ASN1_KRB_AP_REP		15
-#define ASN1_KRB_SAFE		20
-#define ASN1_KRB_PRIV		21
-#define ASN1_KRB_CRED		22
-#define ASN1_KRB_ERROR		30
+#define ASN1_KRB_AS_REQ         10
+#define ASN1_KRB_AS_REP         11
+#define ASN1_KRB_TGS_REQ        12
+#define ASN1_KRB_TGS_REP        13
+#define ASN1_KRB_AP_REQ         14
+#define ASN1_KRB_AP_REP         15
+#define ASN1_KRB_SAFE           20
+#define ASN1_KRB_PRIV           21
+#define ASN1_KRB_CRED           22
+#define ASN1_KRB_ERROR          30
 
 #endif
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/chpw.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/chpw.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 /*
 ** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
 */
@@ -281,17 +285,21 @@
     krb5_error_code ret;
     krb5_data	cipherpw;
     krb5_data	*encoded_setpw;
+    struct krb5_setpw_req req;
 
     char *ptr;
 
-     cipherpw.data = NULL;
-     cipherpw.length = 0;
+    cipherpw.data = NULL;
+    cipherpw.length = 0;
      
     if ((ret = krb5_auth_con_setflags(context, auth_context,
 				      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
 		return(ret);
 
-    ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
+    req.target = targprinc;
+    req.password.data = passwd;
+    req.password.length = strlen(passwd);
+    ret = encode_krb5_setpw_req(&req, &encoded_setpw);
     if (ret) {
 	return ret;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/pac.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,975 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * lib/krb5/krb/pac.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "k5-int.h"
+#include "k5-utf8.h"
+
+/* draft-brezak-win2k-krb-authz-00 */
+
+/*
+ * A PAC consists of a sequence of PAC_INFO_BUFFERs, preceeded by
+ * a PACTYPE header. Decoding the contents of the buffers is left
+ * to the application (notwithstanding signature verification).
+ */
+
+/*
+ * SUNW17PACresync
+ * These should eventually go to k5-platform.h or equiv.
+ */
+static inline unsigned short
+load_16_le (const void *cvp)
+{
+    const unsigned char *p = cvp;
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(16,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
+    return GETSWAPPED(16,p);
+#else
+    return (p[0] | (p[1] << 8));
+#endif
+}
+
+static inline unsigned int
+load_32_le (const void *cvp)
+{
+    const unsigned char *p = cvp;
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(32,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
+    return GETSWAPPED(32,p);
+#else
+    return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
+#endif
+}
+static inline UINT64_TYPE
+load_64_le (const void *cvp)
+{
+    const unsigned char *p = cvp;
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(64,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
+    return GETSWAPPED(64,p);
+#else
+    return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
+#endif
+}
+
+static inline void
+store_16_le (unsigned int val, void *vp)
+{
+    unsigned char *p = vp;
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(16,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
+    PUTSWAPPED(16,p,val);
+#else
+    p[1] = (val >>  8) & 0xff;
+    p[0] = (val      ) & 0xff;
+#endif
+}
+
+static inline void
+store_32_le (unsigned int val, void *vp)
+{
+    unsigned char *p = vp;
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(32,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
+    PUTSWAPPED(32,p,val);
+#else
+    p[3] = (val >> 24) & 0xff;
+    p[2] = (val >> 16) & 0xff;
+    p[1] = (val >>  8) & 0xff;
+    p[0] = (val      ) & 0xff;
+#endif
+}
+static inline void
+store_64_le (UINT64_TYPE val, void *vp)
+{
+    unsigned char *p = vp;
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(64,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
+    PUTSWAPPED(64,p,val);
+#else
+    p[7] = (unsigned char)((val >> 56) & 0xff);
+    p[6] = (unsigned char)((val >> 48) & 0xff);
+    p[5] = (unsigned char)((val >> 40) & 0xff);
+    p[4] = (unsigned char)((val >> 32) & 0xff);
+    p[3] = (unsigned char)((val >> 24) & 0xff);
+    p[2] = (unsigned char)((val >> 16) & 0xff);
+    p[1] = (unsigned char)((val >>  8) & 0xff);
+    p[0] = (unsigned char)((val      ) & 0xff);
+#endif
+}
+
+
+typedef struct _PAC_INFO_BUFFER {
+    krb5_ui_4 ulType;
+    krb5_ui_4 cbBufferSize;
+    krb5_ui_8 Offset;
+} PAC_INFO_BUFFER;
+
+#define PAC_INFO_BUFFER_LENGTH	16
+
+/* ulType */
+#define PAC_LOGON_INFO		1
+#define PAC_SERVER_CHECKSUM	6
+#define PAC_PRIVSVR_CHECKSUM	7
+#define PAC_CLIENT_INFO		10
+
+typedef struct _PACTYPE {
+    krb5_ui_4 cBuffers;
+    krb5_ui_4 Version;
+    PAC_INFO_BUFFER Buffers[1];
+} PACTYPE;
+
+#define PAC_ALIGNMENT		    8
+#define PACTYPE_LENGTH		    8U
+#define PAC_SIGNATURE_DATA_LENGTH   4U
+#define PAC_CLIENT_INFO_LENGTH	    10U
+
+#define NT_TIME_EPOCH		    11644473600LL
+
+struct krb5_pac_data {
+    PACTYPE *pac;	/* PAC header + info buffer array */
+    krb5_data data;	/* PAC data (including uninitialised header) */
+};
+
+static krb5_error_code
+k5_pac_locate_buffer(krb5_context context,
+		     const krb5_pac pac,
+		     krb5_ui_4 type,
+		     krb5_data *data);
+
+/*
+ * Add a buffer to the provided PAC and update header.
+ */
+static krb5_error_code
+k5_pac_add_buffer(krb5_context context,
+		  krb5_pac pac,
+		  krb5_ui_4 type,
+		  const krb5_data *data,
+		  krb5_boolean zerofill,
+		  krb5_data *out_data)
+{
+    PACTYPE *header;
+    size_t header_len, i, pad = 0;
+    char *pac_data;
+
+    assert((data->data == NULL) == zerofill);
+
+    /* Check there isn't already a buffer of this type */
+    if (k5_pac_locate_buffer(context, pac, type, NULL) == 0) {
+	return EINVAL;
+    }
+
+    header = (PACTYPE *)realloc(pac->pac,
+				sizeof(PACTYPE) +
+				(pac->pac->cBuffers * sizeof(PAC_INFO_BUFFER)));
+    if (header == NULL) {
+	return ENOMEM;
+    }
+    pac->pac = header;
+
+    header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
+
+    if (data->length % PAC_ALIGNMENT)
+	pad = PAC_ALIGNMENT - (data->length % PAC_ALIGNMENT);
+
+    pac_data = realloc(pac->data.data,
+		       pac->data.length + PAC_INFO_BUFFER_LENGTH + data->length + pad);
+    if (pac_data == NULL) {
+	return ENOMEM;
+    }
+    pac->data.data = pac_data;
+
+    /* Update offsets of existing buffers */
+    for (i = 0; i < pac->pac->cBuffers; i++)
+	pac->pac->Buffers[i].Offset += PAC_INFO_BUFFER_LENGTH;
+
+    /* Make room for new PAC_INFO_BUFFER */
+    memmove(pac->data.data + header_len + PAC_INFO_BUFFER_LENGTH,
+	    pac->data.data + header_len,
+	    pac->data.length - header_len);
+    memset(pac->data.data + header_len, 0, PAC_INFO_BUFFER_LENGTH);
+
+    /* Initialise new PAC_INFO_BUFFER */
+    pac->pac->Buffers[i].ulType = type;
+    pac->pac->Buffers[i].cbBufferSize = data->length;
+    pac->pac->Buffers[i].Offset = pac->data.length + PAC_INFO_BUFFER_LENGTH;
+    assert((pac->pac->Buffers[i].Offset % PAC_ALIGNMENT) == 0);
+
+    /* Copy in new PAC data and zero padding bytes */
+    if (zerofill)
+	memset(pac->data.data + pac->pac->Buffers[i].Offset, 0, data->length);
+    else
+	memcpy(pac->data.data + pac->pac->Buffers[i].Offset, data->data, data->length);
+
+    memset(pac->data.data + pac->pac->Buffers[i].Offset + data->length, 0, pad);
+
+    pac->pac->cBuffers++;
+    pac->data.length += PAC_INFO_BUFFER_LENGTH + data->length + pad;
+
+    if (out_data != NULL) {
+	out_data->data = pac->data.data + pac->pac->Buffers[i].Offset;
+	out_data->length = data->length;
+    }
+
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_add_buffer(krb5_context context,
+		    krb5_pac pac,
+		    krb5_ui_4 type,
+		    const krb5_data *data)
+{
+    return k5_pac_add_buffer(context, pac, type, data, FALSE, NULL);
+}
+
+/*
+ * Free a PAC
+ */
+void KRB5_CALLCONV
+krb5_pac_free(krb5_context context,
+	      krb5_pac pac)
+{
+    if (pac != NULL) {
+	if (pac->data.data != NULL) {
+	    memset(pac->data.data, 0, pac->data.length);
+	    free(pac->data.data);
+	}
+	if (pac->pac != NULL)
+	    free(pac->pac);
+	memset(pac, 0, sizeof(*pac));
+	free(pac);
+    }
+}
+
+static krb5_error_code
+k5_pac_locate_buffer(krb5_context context,
+		     const krb5_pac pac,
+		     krb5_ui_4 type,
+		     krb5_data *data)
+{
+    PAC_INFO_BUFFER *buffer = NULL;
+    size_t i;
+
+    if (pac == NULL)
+	return EINVAL;
+
+    for (i = 0; i < pac->pac->cBuffers; i++) {
+	if (pac->pac->Buffers[i].ulType == type) {
+	    if (buffer == NULL)
+		buffer = &pac->pac->Buffers[i];
+	    else
+		return EINVAL;
+	}
+    }
+
+    if (buffer == NULL)
+	return ENOENT;
+
+    assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
+
+    if (data != NULL) {
+	data->length = buffer->cbBufferSize;
+	data->data = pac->data.data + buffer->Offset;
+    }
+
+    return 0;
+}
+
+/*
+ * Find a buffer and copy data into output
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_get_buffer(krb5_context context,
+		    krb5_pac pac,
+		    krb5_ui_4 type,
+		    krb5_data *data)
+{
+    krb5_data d;
+    krb5_error_code ret;
+
+    ret = k5_pac_locate_buffer(context, pac, type, &d);
+    if (ret != 0)
+	return ret;
+ 
+    data->data = malloc(d.length);
+    if (data->data == NULL)
+	return ENOMEM;
+
+    data->length = d.length;
+    memcpy(data->data, d.data, d.length);
+
+    return 0;
+}
+
+/*
+ * Return an array of the types of data in the PAC
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_get_types(krb5_context context,
+		   krb5_pac pac,
+		   size_t *len,
+		   krb5_ui_4 **types)
+{
+    size_t i;
+
+    *types = (krb5_ui_4 *)malloc(pac->pac->cBuffers * sizeof(krb5_ui_4));
+    if (*types == NULL)
+	return ENOMEM;
+
+    *len = pac->pac->cBuffers;
+
+    for (i = 0; i < pac->pac->cBuffers; i++)
+	(*types)[i] = pac->pac->Buffers[i].ulType;
+
+    return 0;
+}
+
+/*
+ * Initialize PAC
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_init(krb5_context context,
+	      krb5_pac *ppac)
+{
+    krb5_pac pac;
+
+    pac = (krb5_pac)malloc(sizeof(*pac));
+    if (pac == NULL)
+	return ENOMEM;
+
+    pac->pac = (PACTYPE *)malloc(sizeof(PACTYPE));
+    if (pac->pac == NULL) {
+	free( pac);
+	return ENOMEM;
+    }
+
+    pac->pac->cBuffers = 0;
+    pac->pac->Version = 0;
+
+    pac->data.length = PACTYPE_LENGTH;
+    pac->data.data = calloc(1, pac->data.length);
+    if (pac->data.data == NULL) {
+	krb5_pac_free(context, pac);
+	return ENOMEM;
+    }
+
+    *ppac = pac;
+
+    return 0;
+}
+
+/*
+ * Parse the supplied data into the PAC allocated by this function
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_parse(krb5_context context,
+	       const void *ptr,
+	       size_t len,
+	       krb5_pac *ppac)
+{
+    krb5_error_code ret;
+    size_t i;
+    const unsigned char *p = (const unsigned char *)ptr;
+    krb5_pac pac;
+    size_t header_len;
+    krb5_ui_4 cbuffers, version;
+
+    *ppac = NULL;
+
+    if (len < PACTYPE_LENGTH)
+	return ERANGE;
+
+    cbuffers = load_32_le(p);
+    p += 4;
+    version = load_32_le(p);
+    p += 4;
+
+    if (version != 0)
+	return EINVAL;
+
+    header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
+    if (len < header_len)
+	return ERANGE;
+
+    ret = krb5_pac_init(context, &pac);
+    if (ret != 0)
+	return ret;
+
+    pac->pac = (PACTYPE *)realloc(pac->pac,
+	sizeof(PACTYPE) + ((cbuffers - 1) * sizeof(PAC_INFO_BUFFER)));
+    if (pac->pac == NULL) {
+	krb5_pac_free(context, pac);
+	return ENOMEM;
+    }
+
+    pac->pac->cBuffers = cbuffers;
+    pac->pac->Version = version;
+
+    for (i = 0; i < pac->pac->cBuffers; i++) {
+	PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
+
+	buffer->ulType = load_32_le(p);
+	p += 4;
+	buffer->cbBufferSize = load_32_le(p);
+	p += 4;
+	buffer->Offset = load_64_le(p);
+	p += 8;
+
+	if (buffer->Offset % PAC_ALIGNMENT) {
+	    krb5_pac_free(context, pac);
+	    return EINVAL;
+	}
+	if (buffer->Offset < header_len ||
+	    buffer->Offset + buffer->cbBufferSize > len) {
+	    krb5_pac_free(context, pac);
+	    return ERANGE;
+	}
+    }
+
+    pac->data.data = realloc(pac->data.data, len);
+    if (pac->data.data == NULL) {
+	krb5_pac_free(context, pac);
+	return ENOMEM;
+    }
+    memcpy(pac->data.data, ptr, len);
+
+    pac->data.length = len;
+
+    *ppac = pac;
+
+    return 0;
+}
+
+static krb5_error_code
+k5_time_to_seconds_since_1970(krb5_int64 ntTime, krb5_timestamp *elapsedSeconds)
+{
+    krb5_ui_8 abstime;
+
+    ntTime /= 10000000;
+
+    abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime;
+
+    if (abstime > KRB5_INT32_MAX)
+	return ERANGE;
+
+    *elapsedSeconds = abstime;
+
+    return 0;
+}    
+
+static krb5_error_code
+k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, krb5_ui_8 *ntTime)
+{
+    *ntTime = elapsedSeconds;
+
+    if (elapsedSeconds > 0)
+	*ntTime += NT_TIME_EPOCH;
+
+    *ntTime *= 10000000;
+   
+    return 0;
+}
+
+static krb5_error_code
+k5_pac_validate_client(krb5_context context,
+		       const krb5_pac pac,
+		       krb5_timestamp authtime,
+		       krb5_const_principal principal)
+{
+    krb5_error_code ret;
+    krb5_data client_info;
+    char *pac_princname;
+    unsigned char *p;
+    krb5_timestamp pac_authtime;
+    krb5_ui_2 pac_princname_length;
+    krb5_int64 pac_nt_authtime;
+    krb5_principal pac_principal;
+
+    ret = k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info);
+    if (ret != 0)
+	return ret;
+
+    if (client_info.length < PAC_CLIENT_INFO_LENGTH)
+	return ERANGE;
+
+    p = (unsigned char *)client_info.data;
+    pac_nt_authtime = load_64_le(p);
+    p += 8;
+    pac_princname_length = load_16_le(p);
+    p += 2;
+
+    ret = k5_time_to_seconds_since_1970(pac_nt_authtime, &pac_authtime);
+    if (ret != 0)
+	return ret;
+
+    if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length ||
+        pac_princname_length % 2)
+	return ERANGE;
+
+    ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, &pac_princname, NULL);
+    if (ret != 0)
+	return ret;
+
+    ret = krb5_parse_name_flags(context, pac_princname, 0, &pac_principal);
+    if (ret != 0) {
+	free(pac_princname);
+	return ret;
+    }
+
+    free(pac_princname);
+
+    if (pac_authtime != authtime ||
+	krb5_principal_compare(context, pac_principal, principal) == FALSE)
+	ret = KRB5KRB_AP_WRONG_PRINC;
+
+    krb5_free_principal(context, pac_principal);
+
+    return ret;
+}
+
+static krb5_error_code
+k5_pac_zero_signature(krb5_context context,
+		      const krb5_pac pac,
+		      krb5_ui_4 type,
+		      krb5_data *data)
+{
+    PAC_INFO_BUFFER *buffer = NULL;
+    size_t i;
+
+    assert(type == PAC_SERVER_CHECKSUM || type == PAC_PRIVSVR_CHECKSUM);
+    assert(data->length >= pac->data.length);
+
+    for (i = 0; i < pac->pac->cBuffers; i++) {
+	if (pac->pac->Buffers[i].ulType == type) {
+	    buffer = &pac->pac->Buffers[i];
+	    break;
+	}
+    }
+
+    if (buffer == NULL)
+	return ENOENT;
+
+    if (buffer->Offset + buffer->cbBufferSize > pac->data.length)
+	return ERANGE;
+
+    if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH)
+	return KRB5_BAD_MSIZE;
+
+    /* Zero out the data portion of the checksum only */
+    memset(data->data + buffer->Offset + PAC_SIGNATURE_DATA_LENGTH,
+	   0,
+	   buffer->cbBufferSize - PAC_SIGNATURE_DATA_LENGTH);
+
+    return 0;
+}
+
+static krb5_error_code
+k5_pac_verify_server_checksum(krb5_context context,
+			      const krb5_pac pac,
+			      const krb5_keyblock *server)
+{
+    krb5_error_code ret;
+    krb5_data pac_data; /* PAC with zeroed checksums */
+    krb5_checksum checksum;
+    krb5_data checksum_data;
+    krb5_boolean valid;
+    krb5_octet *p;
+
+    ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &checksum_data);
+    if (ret != 0)
+	return ret;
+
+    if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
+	return KRB5_BAD_MSIZE;
+
+    p = (krb5_octet *)checksum_data.data;
+    checksum.checksum_type = load_32_le(p);
+    checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
+    checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
+
+    pac_data.length = pac->data.length;
+    pac_data.data = malloc(pac->data.length);
+    if (pac_data.data == NULL)
+	return ENOMEM;
+
+    memcpy(pac_data.data, pac->data.data, pac->data.length);
+
+    /* Zero out both checksum buffers */
+    ret = k5_pac_zero_signature(context, pac, PAC_SERVER_CHECKSUM, &pac_data);
+    if (ret != 0) {
+	free(pac_data.data);
+	return ret;
+    }
+
+    ret = k5_pac_zero_signature(context, pac, PAC_PRIVSVR_CHECKSUM, &pac_data);
+    if (ret != 0) {
+	free(pac_data.data);
+	return ret;
+    }
+
+    ret = krb5_c_verify_checksum(context, server, KRB5_KEYUSAGE_APP_DATA_CKSUM,
+				 &pac_data, &checksum, &valid);
+    if (ret != 0) {
+        free(pac_data.data);
+	return ret;
+    }
+
+    if (valid == FALSE)
+	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+    free(pac_data.data); /* SUNW17PACresync - mem leak fix */
+    return ret;
+}
+
+static krb5_error_code
+k5_pac_verify_kdc_checksum(krb5_context context,
+			   const krb5_pac pac,
+			   const krb5_keyblock *privsvr)
+{
+    krb5_error_code ret;
+    krb5_data server_checksum, privsvr_checksum;
+    krb5_checksum checksum;
+    krb5_boolean valid;
+    krb5_octet *p;
+
+    ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_checksum);
+    if (ret != 0)
+	return ret;
+
+    if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
+	return KRB5_BAD_MSIZE;
+
+    ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_checksum);
+    if (ret != 0)
+	return ret;
+
+    if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
+	return KRB5_BAD_MSIZE;
+
+    p = (krb5_octet *)privsvr_checksum.data;
+    checksum.checksum_type = load_32_le(p);
+    checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
+    checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
+
+    server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
+    server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
+
+    ret = krb5_c_verify_checksum(context, privsvr, KRB5_KEYUSAGE_APP_DATA_CKSUM,
+				 &server_checksum, &checksum, &valid);
+    if (ret != 0)
+	return ret;
+
+    if (valid == FALSE)
+	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+    return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_verify(krb5_context context,
+		const krb5_pac pac,
+		krb5_timestamp authtime,
+		krb5_const_principal principal,
+		const krb5_keyblock *server,
+		const krb5_keyblock *privsvr)
+{
+    krb5_error_code ret;
+
+    if (server == NULL)
+	return EINVAL;
+
+    ret = k5_pac_verify_server_checksum(context, pac, server);
+    if (ret != 0)
+	return ret;
+
+    if (privsvr != NULL) {
+	ret = k5_pac_verify_kdc_checksum(context, pac, privsvr);
+	if (ret != 0)
+	    return ret;
+    }
+
+    if (principal != NULL) {
+	ret = k5_pac_validate_client(context, pac, authtime, principal);
+	if (ret != 0)
+	    return ret;
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+k5_insert_client_info(krb5_context context,
+		      krb5_pac pac,
+		      krb5_timestamp authtime,
+		      krb5_const_principal principal)
+{
+    krb5_error_code ret;
+    krb5_data client_info;
+    char *princ_name_utf8 = NULL;
+    unsigned char *princ_name_ucs2 = NULL, *p;
+    size_t princ_name_ucs2_len = 0;
+    krb5_ui_8 nt_authtime;
+
+    /* If we already have a CLIENT_INFO buffer, then just validate it */
+    if (k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info) == 0) {
+	return k5_pac_validate_client(context, pac, authtime, principal);
+    }
+
+    ret = krb5_unparse_name_flags(context, principal,
+				  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_name_utf8);
+    if (ret != 0)
+	goto cleanup;
+
+    ret = krb5int_utf8s_to_ucs2les(princ_name_utf8,
+				   &princ_name_ucs2,
+				   &princ_name_ucs2_len);
+    if (ret != 0)
+	goto cleanup;
+
+    client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len;
+    client_info.data = NULL;
+
+    ret = k5_pac_add_buffer(context, pac, PAC_CLIENT_INFO, &client_info, TRUE, &client_info);
+    if (ret != 0)
+	goto cleanup;
+
+    p = (unsigned char *)client_info.data;
+
+    /* copy in authtime converted to a 64-bit NT time */
+    k5_seconds_since_1970_to_time(authtime, &nt_authtime);
+    store_64_le(nt_authtime, p);
+    p += 8;
+
+    /* copy in number of UCS-2 characters in principal name */
+    store_16_le(princ_name_ucs2_len, p);
+    p += 2;
+
+    /* copy in principal name */
+    memcpy(p, princ_name_ucs2, princ_name_ucs2_len);
+ 
+cleanup:
+    if (princ_name_utf8 != NULL)
+	free(princ_name_utf8);
+    if (princ_name_ucs2 != NULL)
+	free(princ_name_ucs2);
+
+    return ret;
+}
+
+static krb5_error_code
+k5_insert_checksum(krb5_context context,
+		   krb5_pac pac,
+		   krb5_ui_4 type,
+		   const krb5_keyblock *key,
+		   krb5_cksumtype *cksumtype)
+{
+    krb5_error_code ret;
+    size_t len;
+    krb5_data cksumdata;
+
+    ret = krb5int_c_mandatory_cksumtype(context, key->enctype, cksumtype);
+    if (ret != 0)
+	return ret;
+
+    ret = krb5_c_checksum_length(context, *cksumtype, &len);
+    if (ret != 0)
+	return ret;
+
+    ret = k5_pac_locate_buffer(context, pac, type, &cksumdata);
+    if (ret == 0) {
+	/* If we're resigning PAC, make sure we can fit checksum into existing buffer */
+	if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len)
+	    return ERANGE;
+
+	memset(cksumdata.data, 0, cksumdata.length);
+    } else {
+	/* Add a zero filled buffer */
+	cksumdata.length = PAC_SIGNATURE_DATA_LENGTH + len;
+	cksumdata.data = NULL;
+
+	ret = k5_pac_add_buffer(context, pac, type, &cksumdata, TRUE, &cksumdata);
+	if (ret != 0)
+	    return ret;
+    }
+
+    /* Encode checksum type into buffer */
+    store_32_le((krb5_ui_4)*cksumtype, cksumdata.data);
+
+    return 0;
+}
+
+/* in-place encoding of PAC header */
+static krb5_error_code
+k5_pac_encode_header(krb5_context context, krb5_pac pac)
+{
+    size_t i;
+    unsigned char *p;
+    size_t header_len;
+
+    header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
+    assert(pac->data.length >= header_len);
+
+    p = (unsigned char *)pac->data.data;
+
+    store_32_le(pac->pac->cBuffers, p);
+    p += 4;
+    store_32_le(pac->pac->Version, p);
+    p += 4;
+
+    for (i = 0; i < pac->pac->cBuffers; i++) {
+	PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
+
+	store_32_le(buffer->ulType, p);
+	p += 4;
+	store_32_le(buffer->cbBufferSize, p);
+	p += 4;
+	store_64_le(buffer->Offset, p);
+	p += 8;
+
+	assert((buffer->Offset % PAC_ALIGNMENT) == 0);
+	assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
+	assert(buffer->Offset >= header_len);
+
+	if (buffer->Offset % PAC_ALIGNMENT ||
+	    buffer->Offset + buffer->cbBufferSize > pac->data.length ||
+	    buffer->Offset < header_len)
+	    return ERANGE;
+    }
+
+    return 0;
+}
+
+
+#if 0
+/*
+ * SUNW17PACresync
+ * We don't have the new MIT iov interfaces yet and don't need them yet.
+ * We'll need this for full 1.7 resync.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5int_pac_sign(krb5_context context,
+		 krb5_pac pac,
+		 krb5_timestamp authtime,
+		 krb5_const_principal principal,
+		 const krb5_keyblock *server_key,
+		 const krb5_keyblock *privsvr_key,
+		 krb5_data *data)
+{
+    krb5_error_code ret;
+    krb5_data server_cksum, privsvr_cksum;
+    krb5_cksumtype server_cksumtype, privsvr_cksumtype;
+    krb5_crypto_iov iov[2];
+
+    data->length = 0;
+    data->data = NULL;
+
+    if (principal != NULL) {
+	ret = k5_insert_client_info(context, pac, authtime, principal);
+	if (ret != 0)
+	    return ret;
+    }
+
+    /* Create zeroed buffers for both checksums */
+    ret = k5_insert_checksum(context, pac, PAC_SERVER_CHECKSUM,
+			     server_key, &server_cksumtype);
+    if (ret != 0)
+	return ret;
+
+    ret = k5_insert_checksum(context, pac, PAC_PRIVSVR_CHECKSUM,
+			     privsvr_key, &privsvr_cksumtype);
+    if (ret != 0)
+	return ret;
+
+    /* Now, encode the PAC header so that the checksums will include it */
+    ret = k5_pac_encode_header(context, pac);
+    if (ret != 0)
+	return ret;
+
+    /* Generate the server checksum over the entire PAC */
+    ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_cksum);
+    if (ret != 0)
+	return ret;
+
+    assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
+
+    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[0].data = pac->data;
+
+    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+    iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
+    iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
+
+    ret = krb5_c_make_checksum_iov(context, server_cksumtype,
+				   server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
+				   iov, sizeof(iov)/sizeof(iov[0]));
+    if (ret != 0)
+	return ret;
+
+    /* Generate the privsvr checksum over the server checksum buffer */
+    ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_cksum);
+    if (ret != 0)
+	return ret;
+
+    assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
+
+    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
+    iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
+
+    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+    iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
+    iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
+
+    ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,
+				   privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
+				   iov, sizeof(iov)/sizeof(iov[0]));
+    if (ret != 0)
+	return ret;
+
+    data->data = malloc(pac->data.length);
+    if (data->data == NULL)
+	return ENOMEM;
+
+    data->length = pac->data.length;
+
+    memcpy(data->data, pac->data.data, pac->data.length);
+    memset(pac->data.data, 0, PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH));
+
+    return 0;
+}
+#endif
+
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_req_dec.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_req_dec.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -487,3 +487,17 @@
     clean_scratch();
     return retval;
 }
+
+krb5_error_code
+krb5int_check_clockskew(krb5_context context, krb5_timestamp date)
+{
+    krb5_timestamp currenttime;
+    krb5_error_code retval;
+
+    retval = krb5_timeofday(context, &currenttime);
+    if (retval)
+        return retval;
+    if (!(labs((date)-currenttime) < context->clockskew))
+        return KRB5KRB_AP_ERR_SKEW;
+    return 0;
+}
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_safe.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_safe.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,13 +1,7 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-
 /*
  * lib/krb5/krb/rd_safe.c
  *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2007,2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -37,8 +31,6 @@
 #include "cleanup.h"
 #include "auth_con.h"
 
-#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
-
 /*
  parses a KRB_SAFE message from inbuf, placing the integrity-protected user
  data in *outbuf.
@@ -53,7 +45,11 @@
  returns system errors, integrity errors
  */
 static krb5_error_code
-krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyblock *keyblock, const krb5_address *recv_addr, const krb5_address *sender_addr, krb5_replay_data *replaydata, krb5_data *outbuf)
+krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf,
+		   const krb5_keyblock *keyblock,
+		   const krb5_address *recv_addr,
+		   const krb5_address *sender_addr,
+		   krb5_replay_data *replaydata, krb5_data *outbuf)
 {
     krb5_error_code 	  retval;
     krb5_safe 		* message;
@@ -62,45 +58,26 @@
     krb5_octet zero_octet = 0;
     krb5_data *scratch;
     krb5_boolean valid;
-
-    /* Solaris Kerberos */
-    KRB5_LOG0(KRB5_INFO, "krb5_rd_safe_basic() start");
+    struct krb5_safe_with_body swb;
 
-    if (!krb5_is_krb_safe(inbuf)) {
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() end, error retval=%d", 
-		    KRB5KRB_AP_ERR_MSG_TYPE);
+    if (!krb5_is_krb_safe(inbuf))
 	return KRB5KRB_AP_ERR_MSG_TYPE;
-    }
 
-    if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body))) {
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() end, error retval=%d", 
-		    retval);
+    if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body)))
 	return retval;
-    }
 
     if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) {
 	retval = KRB5_PROG_SUMTYPE_NOSUPP;
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-		    retval);
 	goto cleanup;
     }
     if (!krb5_c_is_coll_proof_cksum(message->checksum->checksum_type) ||
 	!krb5_c_is_keyed_cksum(message->checksum->checksum_type)) {
 	retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-		    retval);
 	goto cleanup;
     }
 
     if (!krb5_address_compare(context, sender_addr, message->s_address)) {
 	retval = KRB5KRB_AP_ERR_BADADDR;
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-		    retval);
 	goto cleanup;
     }
 
@@ -108,26 +85,17 @@
 	if (recv_addr) {
 	    if (!krb5_address_compare(context, recv_addr, message->r_address)) {
 		retval = KRB5KRB_AP_ERR_BADADDR;
-		/* Solaris Kerberos */
-		KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-			retval);
 		goto cleanup;
 	    }
 	} else {
 	    krb5_address **our_addrs;
 	
-	    if ((retval = krb5_os_localaddr(context, &our_addrs))) {
-		/* Solaris Kerberos */
-		KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-			retval);
+	    if ((retval = krb5_os_localaddr(context, &our_addrs)))
 		goto cleanup;
-	    }
+	    
 	    if (!krb5_address_search(context, message->r_address, our_addrs)) {
 		krb5_free_addresses(context, our_addrs);
 		retval = KRB5KRB_AP_ERR_BADADDR;
-		/* Solaris Kerberos */
-		KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-			retval);
 		goto cleanup;
 	    }
 	    krb5_free_addresses(context, our_addrs);
@@ -149,15 +117,13 @@
 
     message->checksum = &our_cksum;
 
-    if ((retval = encode_krb5_safe_with_body(message, &safe_body, &scratch))) {
-	/* Solaris Kerberos */
-	KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-		retval);
+    swb.body = &safe_body;
+    swb.safe = message;
+    retval = encode_krb5_safe_with_body(&swb, &scratch);
+    message->checksum = his_cksum;
+    if (retval)
 	goto cleanup;
-    }
 
-    message->checksum = his_cksum;
-			 
     retval = krb5_c_verify_checksum(context, keyblock,
 				    KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
 				    scratch, his_cksum, &valid);
@@ -175,9 +141,6 @@
 					&safe_body, his_cksum, &valid);
 	if (!valid) {
 	    retval = KRB5KRB_AP_ERR_MODIFIED;
-	    /* Solaris Kerberos */
-	    KRB5_LOG(KRB5_ERR, "krb5_rd_safe_basic() error retval=%d", 
-			retval);
 	    goto cleanup;
 	}
     }
@@ -192,14 +155,13 @@
     
 cleanup:
     krb5_free_safe(context, message);
-    /* Solaris Kerberos */
-    KRB5_LOG(KRB5_INFO, "krb5_rd_safe_basic() end, retval=%d", 
-		    retval);
     return retval;
 }
 
 krb5_error_code KRB5_CALLCONV
-krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata)
+krb5_rd_safe(krb5_context context, krb5_auth_context auth_context,
+	     const krb5_data *inbuf, krb5_data *outbuf,
+	     krb5_replay_data *outdata)
 {
     krb5_error_code 	  retval;
     krb5_keyblock	* keyblock;
@@ -215,12 +177,15 @@
       (auth_context->rcache == NULL)) 
 	return KRB5_RC_REQUIRED;
 
+    if (!auth_context->remote_addr)
+	return KRB5_REMOTE_ADDR_REQUIRED;
+
     /* Get keyblock */
     if ((keyblock = auth_context->recv_subkey) == NULL)
 	keyblock = auth_context->keyblock;
 
 {
-    krb5_address * premote_fulladdr = NULL;
+    krb5_address * premote_fulladdr;
     krb5_address * plocal_fulladdr = NULL;
     krb5_address remote_fulladdr;
     krb5_address local_fulladdr;
@@ -241,21 +206,20 @@
         }
     }
 
-    if (auth_context->remote_addr) {
-    	if (auth_context->remote_port) {
-            if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
-                                 	      auth_context->remote_port, 
-					      &remote_fulladdr))){
-                CLEANUP_PUSH(remote_fulladdr.contents, free);
-	        premote_fulladdr = &remote_fulladdr;
-            } else {
-	        return retval;
-            }
+    if (auth_context->remote_port) {
+	if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+					  auth_context->remote_port, 
+					  &remote_fulladdr))){
+	    CLEANUP_PUSH(remote_fulladdr.contents, free);
+	    premote_fulladdr = &remote_fulladdr;
 	} else {
-            premote_fulladdr = auth_context->remote_addr;
-        }
+	    return retval;
+	}
+    } else {
+	premote_fulladdr = auth_context->remote_addr;
     }
 
+    memset(&replaydata, 0, sizeof(replaydata));
     if ((retval = krb5_rd_safe_basic(context, inbuf, keyblock,
 				     plocal_fulladdr, premote_fulladdr,
 				     &replaydata, outbuf))) {
@@ -269,28 +233,23 @@
 
     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
 	krb5_donot_replay replay;
-    	krb5_timestamp currenttime;
 
-	if ((retval = krb5_timeofday(context, &currenttime)))
+	if ((retval = krb5int_check_clockskew(context, replaydata.timestamp)))
 	    goto error;
 
-	if (!in_clock_skew(replaydata.timestamp)) {
-	    retval =  KRB5KRB_AP_ERR_SKEW;
-	    goto error;
-	}
-
 	if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 
 					   "_safe", &replay.client)))
 	    goto error;
 
 	replay.server = "";		/* XXX */
+	replay.msghash = NULL;
 	replay.cusec = replaydata.usec;
 	replay.ctime = replaydata.timestamp;
 	if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
-	    krb5_xfree(replay.client);
+	    free(replay.client);
 	    goto error;
 	}
-	krb5_xfree(replay.client);
+	free(replay.client);
     }
 
     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
@@ -313,7 +272,7 @@
     return 0;
 
 error:
-    krb5_xfree(outbuf->data);
+    free(outbuf->data);
     return retval;
 
 }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -173,7 +173,7 @@
     if (authorization_data) {
 	/* need to encrypt it in the request */
 
-	if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data,
+	if ((retval = encode_krb5_authdata(authorization_data,
 					   &scratch)))
 	    return(retval);
 
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/os/accessor.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/os/accessor.c	Mon Sep 21 16:47:51 2009 -0700
@@ -63,6 +63,8 @@
 	    S (free_srv_dns_data, 0),
 	    S (use_dns_kdc, 0),
 #endif
+            S (clean_hostname, krb5int_clean_hostname),
+
 #ifdef KRB5_KRB4_COMPAT
 	    S (krb_life_to_time, krb5int_krb_life_to_time),
 	    S (krb_time_to_life, krb5int_krb_time_to_life),
--- a/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers	Mon Sep 21 16:47:51 2009 -0700
@@ -112,55 +112,6 @@
 	asn1_decode_ui_2;
 	asn1_decode_ui_4;
 	asn1_decode_unsigned_integer;
-	asn1_encode_ap_options;
-	asn1_encode_authorization_data;
-	asn1_encode_charstring;
-	asn1_encode_checksum;
-	asn1_encode_enc_kdc_rep_part;
-	asn1_encode_enc_sam_response_enc;
-	asn1_encode_encrypted_data;
-	asn1_encode_encryption_key;
-	asn1_encode_etype_info;
-	asn1_encode_etype_info_entry;
-	asn1_encode_generalstring;
-	asn1_encode_generaltime;
-	asn1_encode_host_address;
-	asn1_encode_host_addresses;
-	asn1_encode_ia5string;
-	asn1_encode_integer;
-	asn1_encode_kdc_options;
-	asn1_encode_kdc_rep;
-	asn1_encode_kdc_req;
-	asn1_encode_kdc_req_body;
-	asn1_encode_kerberos_time;
-	asn1_encode_krb5_authdata_elt;
-	asn1_encode_krb5_flags;
-	asn1_encode_krb_cred_info;
-	asn1_encode_krb_safe_body;
-	asn1_encode_last_req;
-	asn1_encode_last_req_entry;
-	asn1_encode_null;
-	asn1_encode_octetstring;
-	asn1_encode_pa_data;
-	asn1_encode_passwdsequence;
-	asn1_encode_predicted_sam_response;
-	asn1_encode_principal_name;
-	asn1_encode_printablestring;
-	asn1_encode_realm;
-	asn1_encode_sam_challenge;
-	asn1_encode_sam_flags;
-	asn1_encode_sam_key;
-	asn1_encode_sam_response;
-	asn1_encode_sequence_of_enctype;
-	asn1_encode_sequence_of_krb_cred_info;
-	asn1_encode_sequence_of_pa_data;
-	asn1_encode_sequence_of_passwdsequence;
-	asn1_encode_sequence_of_ticket;
-	asn1_encode_ticket;
-	asn1_encode_ticket_flags;
-	asn1_encode_transited_encoding;
-	asn1_encode_ui_4;
-	asn1_encode_unsigned_integer;
 	asn1_error_table;
 	asn1_get_sequence;
 	asn1_get_tag_2;
@@ -263,6 +214,7 @@
 	error_message;
 	ggss_error_table;
 	gss_krb5int_get_tkt_flags;
+	gsskrb5_extract_authz_data_from_sec_context;
 	gss_krb5_ccache_name;
 	gss_krb5_copy_ccache;
 	gss_mech_krb5;
@@ -404,6 +356,7 @@
 	krb5_copy_ticket;
 	krb5_create_secure_file;
 	krb5_crypto_us_timeofday;
+	krb5_decode_authdata_container;
 	krb5_decode_kdc_rep;
 	krb5_decode_ticket;
 	krb5_decrypt_tkt_part;
@@ -411,6 +364,7 @@
 	krb5_default_pwd_prompt2;
 	krb5_defkeyname;
 	krb5_do_preauth;
+	krb5_encode_authdata_container;
 	krb5_encode_kdc_rep;
 	krb5_encrypt_helper;
 	krb5_encrypt_tkt_part;
@@ -613,6 +567,13 @@
 	krb5_os_init_context;
 	krb5_os_localaddr;
 	krb5_overridekeyname;
+	krb5_pac_add_buffer;
+	krb5_pac_free;
+	krb5_pac_get_buffer;
+	krb5_pac_get_types;
+	krb5_pac_init;
+	krb5_pac_parse;
+	krb5_pac_verify;
 	krb5_parse_name;
 	krb5_pname_to_uid;
 	krb5_principal2salt;
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,9 +1,7 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-
 /*
  * Copyright 2000, 2004  by the Massachusetts Institute of Technology.
  * All Rights Reserved.
@@ -286,6 +284,7 @@
 {
    krb5_context context;
    unsigned char *ptr, *ptr2;
+   krb5_gss_ctx_id_rec *ctx = 0;
    char *sptr;
    long tmp;
    size_t md5len;
@@ -300,7 +299,6 @@
    krb5_checksum reqcksum;
    krb5_principal name = NULL;
    krb5_ui_4 gss_flags = 0;
-   krb5_gss_ctx_id_rec *ctx = 0;
    krb5_timestamp now;
    gss_buffer_desc token;
    krb5_auth_context auth_context = NULL;
@@ -316,6 +314,8 @@
    OM_uint32 saved_ap_options = 0;
    krb5int_access kaccess;
    int cred_rcache = 0;
+   int no_encap;
+   OM_uint32 t_minor_status = 0;
 
    KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
 
@@ -393,9 +393,20 @@
 	* old behavior.
 	*/
        mech_used = gss_mech_krb5_old;
+  } else if (code == G_WRONG_TOKID) {
+	major_status = GSS_S_CONTINUE_NEEDED;
+        code = KRB5KRB_AP_ERR_MSG_TYPE;
+        mech_used = gss_mech_krb5;
+        goto fail;
+   } else if (code == G_BAD_TOK_HEADER) {
+	/* DCE style not encapsulated */
+        ap_req.length = input_token->length;
+        ap_req.data = input_token->value;
+        mech_used = gss_mech_krb5;
+        no_encap = 1;
    } else {
-       major_status = GSS_S_DEFECTIVE_TOKEN;
-       goto fail;
+	major_status = GSS_S_DEFECTIVE_TOKEN;
+        goto fail;
    }
 
    sptr = (char *) ptr;
@@ -552,7 +563,7 @@
 
    if ((code = krb5_rd_req_decoded(context, &auth_context, request,
 			   cred->princ, cred->keytab, NULL, &ticket))) {
-       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
+      KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 	      "krb5_rd_req() error code %d", code);
        if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) {
            major_status = GSS_S_DEFECTIVE_CREDENTIAL;
@@ -802,6 +813,15 @@
        goto fail;
    }
 
+   /* XXX move this into gss_name_t */
+   if ((code = krb5_merge_authdata(context,
+				ticket->enc_part2->authorization_data,
+				authdat->authorization_data,
+				&ctx->authdata))) {
+	major_status = GSS_S_FAILURE;
+        goto fail;
+   }
+
    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
 	/* Solaris Kerberos */
        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
@@ -1081,6 +1101,7 @@
    major_status = GSS_S_COMPLETE;
 
  fail:
+
    if (authdat)
        krb5_free_authenticator(context, authdat);
    /* The ctx structure has the handle of the auth_context */
@@ -1157,6 +1178,25 @@
 				&krb_error_data.susec);
        krb_error_data.server = cred->princ;
 
+       if (code == KRB5KRB_AP_ERR_SKEW) {
+	    /*
+	     * SUNW17PACresync / Solaris Kerberos
+	     * Set e-data to Windows constant.
+	     * (verified by MSFT)
+	     * 
+	     * This facilitates the Windows CIFS client clock skew
+	     * recovery feature.
+	     */
+	    char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
+	    int len = strlen(ms_e_data);
+
+	    krb_error_data.e_data.data = malloc(len);
+	    if (krb_error_data.e_data.data) {
+		    (void) memcpy(krb_error_data.e_data.data, ms_e_data, len);
+		    krb_error_data.e_data.length = len;
+	    }
+       }
+
        code = krb5_mk_error(context, &krb_error_data, &scratch);
        if (code)
            goto cleanup;
@@ -1180,7 +1220,7 @@
 
 cleanup:
    if (!verifier_cred_handle && cred_handle) {
-	   krb5_gss_release_cred(minor_status, &cred_handle);
+	krb5_gss_release_cred(&t_minor_status, &cred_handle);
    }
    krb5_free_context(context);
 
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/get_tkt_flags.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/get_tkt_flags.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,8 +1,11 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
- * 
+ *
  * Permission to use, copy, modify, distribute, and sell this software
  * and its documentation for any purpose is hereby granted without fee,
  * provided that the above copyright notice appears in all copies and
@@ -12,7 +15,7 @@
  * without specific, written prior permission. OpenVision makes no
  * representations about the suitability of this software for any
  * purpose.  It is provided "as is" without express or implied warranty.
- * 
+ *
  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
@@ -23,35 +26,25 @@
  */
 
 #include "gssapiP_krb5.h"
+#include "mechglueP.h" /* SUNW17PACresync */
 
 /*
- * $Id: get_tkt_flags.c 18131 2006-06-14 22:27:54Z tlyu $
+ * $Id: get_tkt_flags.c 21778 2009-01-22 23:21:11Z tlyu $
  */
 
-OM_uint32 KRB5_CALLCONV 
-gss_krb5int_get_tkt_flags(minor_status, context_handle, ticket_flags)
-     OM_uint32 *minor_status;
-     gss_ctx_id_t context_handle;
-     krb5_flags *ticket_flags;
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_get_tkt_flags(OM_uint32 *minor_status,
+                          const gss_ctx_id_t context_handle,
+                          const gss_OID desired_object,
+                          gss_buffer_set_t *data_set)
 {
-   krb5_gss_ctx_id_rec *ctx;
-
-   /* validate the context handle */
-   if (! kg_validate_ctx_id(context_handle)) {
-      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
-      return(GSS_S_NO_CONTEXT);
-   }
+    krb5_gss_ctx_id_rec *ctx;
+    gss_buffer_desc rep;
 
-   ctx = (krb5_gss_ctx_id_rec *) context_handle;
-
-   if (! ctx->established) {
-      *minor_status = KG_CTX_INCOMPLETE;
-      return(GSS_S_NO_CONTEXT);
-   }
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-   if (ticket_flags)
-      *ticket_flags = ctx->krb_flags;
+    rep.value = &ctx->krb_flags;
+    rep.length = sizeof(ctx->krb_flags);
 
-   *minor_status = 0;
-   return(GSS_S_COMPLETE);
+    return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
 }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,8 +1,11 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
- * 
+ *
  * Permission to use, copy, modify, distribute, and sell this software
  * and its documentation for any purpose is hereby granted without fee,
  * provided that the above copyright notice appears in all copies and
@@ -12,7 +15,7 @@
  * without specific, written prior permission. OpenVision makes no
  * representations about the suitability of this software for any
  * purpose.  It is provided "as is" without express or implied warranty.
- * 
+ *
  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
@@ -21,114 +24,298 @@
  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 #include "gssapiP_krb5.h"
+#include "mechglueP.h" /* SUNW17PACresync */
 
 OM_uint32
-krb5_gss_inquire_context(minor_status, context_handle, initiator_name, 
-			 acceptor_name, lifetime_rec, mech_type, ret_flags,
-			 locally_initiated, open)
-     OM_uint32 *minor_status;
-     gss_ctx_id_t context_handle;
-     gss_name_t *initiator_name;
-     gss_name_t *acceptor_name;
-     OM_uint32 *lifetime_rec;
-     gss_OID *mech_type;
-     OM_uint32 *ret_flags;
-     int *locally_initiated;
-     int *open;
+krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
+                         acceptor_name, lifetime_rec, mech_type, ret_flags,
+                         locally_initiated, opened)
+    OM_uint32 *minor_status;
+    gss_ctx_id_t context_handle;
+    gss_name_t *initiator_name;
+    gss_name_t *acceptor_name;
+    OM_uint32 *lifetime_rec;
+    gss_OID *mech_type;
+    OM_uint32 *ret_flags;
+    int *locally_initiated;
+    int *opened;
 {
-   krb5_context context;
-   krb5_error_code code;
-   krb5_gss_ctx_id_rec *ctx;
-   krb5_principal init, accept;
-   krb5_timestamp now;
-   krb5_deltat lifetime;
+    krb5_context context;
+    krb5_error_code code;
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_principal initiator, acceptor;
+    krb5_timestamp now;
+    krb5_deltat lifetime;
+
+    if (initiator_name)
+        *initiator_name = (gss_name_t) NULL;
+    if (acceptor_name)
+        *acceptor_name = (gss_name_t) NULL;
+
+    /* validate the context handle */
+    if (! kg_validate_ctx_id(context_handle)) {
+        *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+        return(GSS_S_NO_CONTEXT);
+    }
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-   if (initiator_name)
-      *initiator_name = (gss_name_t) NULL;
-   if (acceptor_name)
-      *acceptor_name = (gss_name_t) NULL;
+    if (! ctx->established) {
+        *minor_status = KG_CTX_INCOMPLETE;
+        return(GSS_S_NO_CONTEXT);
+    }
+
+    initiator = NULL;
+    acceptor = NULL;
+    context = ctx->k5_context;
+
+    if ((code = krb5_timeofday(context, &now))) {
+        *minor_status = code;
+        save_error_info(*minor_status, context);
+        return(GSS_S_FAILURE);
+    }
+
+
+    /* SUNW17PACresync - should be krb_times.endtime (revisit) */
+    if ((lifetime = ctx->endtime - now) < 0)
+        lifetime = 0;
 
-   /* validate the context handle */
-   if (! kg_validate_ctx_id(context_handle)) {
-      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
-      return(GSS_S_NO_CONTEXT);
-   }
-
-   ctx = (krb5_gss_ctx_id_rec *) context_handle;
+    if (initiator_name) {
+        if ((code = krb5_copy_principal(context,
+                                        ctx->initiate?ctx->here:ctx->there,
+                                        &initiator))) {
+            *minor_status = code;
+            save_error_info(*minor_status, context);
+            return(GSS_S_FAILURE);
+        }
+        if (! kg_save_name((gss_name_t) initiator)) {
+            krb5_free_principal(context, initiator);
+            *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+            return(GSS_S_FAILURE);
+        }
+    }
 
-   if (! ctx->established) {
-      *minor_status = KG_CTX_INCOMPLETE;
-      return(GSS_S_NO_CONTEXT);
-   }
+    if (acceptor_name) {
+        if ((code = krb5_copy_principal(context,
+                                        ctx->initiate?ctx->there:ctx->here,
+                                        &acceptor))) {
+            if (initiator) krb5_free_principal(context, initiator);
+            *minor_status = code;
+            save_error_info(*minor_status, context);
+            return(GSS_S_FAILURE);
+        }
+        if (! kg_save_name((gss_name_t) acceptor)) {
+            krb5_free_principal(context, acceptor);
+            if (initiator) {
+                kg_delete_name((gss_name_t) initiator);
+                krb5_free_principal(context, initiator);
+            }
+            *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+            return(GSS_S_FAILURE);
+        }
+    }
+
+    if (initiator_name)
+        *initiator_name = (gss_name_t) initiator;
 
-   init = NULL;
-   accept = NULL;
-   context = ctx->k5_context;
+    if (acceptor_name)
+        *acceptor_name = (gss_name_t) acceptor;
+
+    if (lifetime_rec)
+        *lifetime_rec = lifetime;
+
+    if (mech_type)
+        *mech_type = (gss_OID) ctx->mech_used;
 
-   if ((code = krb5_timeofday(context, &now))) {
-      *minor_status = code;
-      return(GSS_S_FAILURE);
-   }
+    if (ret_flags)
+        *ret_flags = ctx->gss_flags;
+
+    if (locally_initiated)
+        *locally_initiated = ctx->initiate;
 
-   if ((lifetime = ctx->endtime - now) < 0)
-      lifetime = 0;
+    if (opened)
+        *opened = ctx->established;
+
+    *minor_status = 0;
+
+    return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+}
 
-   if (initiator_name) {
-      if ((code = krb5_copy_principal(context, 
-				      ctx->initiate?ctx->here:ctx->there,
-				      &init))) {
-	 *minor_status = code;
-	 return(GSS_S_FAILURE);
-      }
-      if (! kg_save_name((gss_name_t) init)) {
-	 krb5_free_principal(context, init);
-	 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
-	 return(GSS_S_FAILURE);
-      }
-   }
+OM_uint32
+gss_krb5int_inq_session_key(
+    OM_uint32 *minor_status,
+    const gss_ctx_id_t context_handle,
+    const gss_OID desired_object,
+    gss_buffer_set_t *data_set)
+{
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_keyblock *key;
+    gss_buffer_desc keyvalue, keyinfo;
+    OM_uint32 major_status, minor;
+    unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
+    gss_OID_desc oid;
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
+    key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
+
+    keyvalue.value = key->contents;
+    keyvalue.length = key->length;
+
+    major_status = generic_gss_add_buffer_set_member(minor_status, &keyvalue, data_set);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    oid.elements = oid_buf;
+    oid.length = sizeof(oid_buf);
+
+    major_status = generic_gss_oid_compose(minor_status,
+                                           GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
+                                           GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
+                                           key->enctype,
+                                           &oid);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    keyinfo.value = oid.elements;
+    keyinfo.length = oid.length;
+
+    major_status = generic_gss_add_buffer_set_member(minor_status, &keyinfo, data_set);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    return GSS_S_COMPLETE;
+
+cleanup:
+    if (*data_set != GSS_C_NO_BUFFER_SET) {
+        if ((*data_set)->count != 0)
+            memset((*data_set)->elements[0].value, 0, (*data_set)->elements[0].length);
+        gss_release_buffer_set(&minor, data_set);
+    }
+
+    return major_status;
+}
 
-   if (acceptor_name) {
-      if ((code = krb5_copy_principal(context, 
-				      ctx->initiate?ctx->there:ctx->here,
-				      &accept))) {
-	 if (init) krb5_free_principal(context, init);
-	 *minor_status = code;
-	 return(GSS_S_FAILURE);
-      }
-      if (! kg_save_name((gss_name_t) accept)) {
-	 krb5_free_principal(context, accept);
-	 if (init) {
-	    kg_delete_name((gss_name_t) accept);
-	    krb5_free_principal(context, init);
-	 }
-	 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
-	 return(GSS_S_FAILURE);
-      }
-   }
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(
+   OM_uint32 *minor_status,
+   const gss_ctx_id_t context_handle,
+   const gss_OID desired_object,
+   gss_buffer_set_t *data_set)
+{
+    OM_uint32 major_status;
+    krb5_gss_ctx_id_rec *ctx;
+    int ad_type = 0;
+    size_t i;
+
+    *data_set = GSS_C_NO_BUFFER_SET;
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-   if (initiator_name)
-      *initiator_name = (gss_name_t) init;
+    major_status = generic_gss_oid_decompose(minor_status,
+                                             GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+                                             GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+                                             desired_object,
+                                             &ad_type);
+    if (major_status != GSS_S_COMPLETE || ad_type == 0) {
+        *minor_status = ENOENT;
+        return major_status; /* SUNW17PACresync */
+    }
+
+    if (ctx->authdata != NULL) {
+        for (i = 0; ctx->authdata[i] != NULL; i++) {
+            if (ctx->authdata[i]->ad_type == ad_type) {
+                gss_buffer_desc ad_data;
+
+                ad_data.length = ctx->authdata[i]->length;
+                ad_data.value = ctx->authdata[i]->contents;
 
-   if (acceptor_name)
-      *acceptor_name = (gss_name_t) accept;
+                major_status = generic_gss_add_buffer_set_member(minor_status,
+                                                                 &ad_data, data_set);
+                if (GSS_ERROR(major_status))
+                    break;
+            }
+        }
+    }
 
-   if (lifetime_rec)
-      *lifetime_rec = lifetime;
+    if (GSS_ERROR(major_status)) {
+        OM_uint32 tmp;
 
-   if (mech_type)
-      *mech_type = (gss_OID) ctx->mech_used;
+        generic_gss_release_buffer_set(&tmp, data_set);
+    }
+
+    return major_status;
+}
 
-   if (ret_flags)
-      *ret_flags = ctx->gss_flags;
-
-   if (locally_initiated)
-      *locally_initiated = ctx->initiate;
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+                                              const gss_ctx_id_t context_handle,
+                                              const gss_OID desired_oid,
+                                              gss_buffer_set_t *data_set)
+{
+    krb5_gss_ctx_id_rec *ctx;
+    gss_buffer_desc rep;
 
-   if (open)
-      *open = ctx->established;
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-   *minor_status = 0;
-   return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+    rep.value = &ctx->krb_times.authtime;
+    rep.length = sizeof(ctx->krb_times.authtime);
+
+    return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
 }
+
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,9 +1,7 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
  * 
@@ -340,6 +338,14 @@
 	    gss_cred_usage_t *      /* cred_usage_stored */
 	   );
 
+/* SUNW17PACresync - this decl not needed in MIT but is for Sol */
+/* Note code is in gsspi_krb5.c */
+OM_uint32 krb5_gss_inquire_sec_context_by_oid(
+	OM_uint32 *,
+	const gss_ctx_id_t,
+	const gss_OID,
+	gss_buffer_set_t *);
+
 static OM_uint32
 k5glue_userok(
 		    void *,		/* context */
@@ -443,7 +449,8 @@
 /* EXPORT DELETE END */
     k5glue_sign,
     k5glue_verify,
-    k5glue_store_cred
+    k5glue_store_cred,
+    krb5_gss_inquire_sec_context_by_oid
 };
 
 static struct gss_config krb5_mechanism_old = {
@@ -495,7 +502,8 @@
 /* EXPORT DELETE END */
     k5glue_sign,
     k5glue_verify,
-    k5glue_store_cred
+    k5glue_store_cred,
+    krb5_gss_inquire_sec_context_by_oid
 };
 
 static struct gss_config krb5_mechanism_wrong = {
@@ -547,7 +555,8 @@
 /* EXPORT DELETE END */
     k5glue_sign,
     k5glue_verify,
-    k5glue_store_cred
+    k5glue_store_cred,
+    krb5_gss_inquire_sec_context_by_oid
 };
 
 static gss_mechanism krb5_mech_configs[] = {
@@ -1236,21 +1245,6 @@
 }
 #endif
 
-OM_uint32 KRB5_CALLCONV
-gss_krb5_get_tkt_flags(
-    OM_uint32 *minor_status,
-    gss_ctx_id_t context_handle,
-    krb5_flags *ticket_flags)
-{
-    gss_union_ctx_id_t uctx;
-
-    uctx = (gss_union_ctx_id_t)context_handle;
-    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
-	!g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
-	return GSS_S_BAD_MECH;
-    return gss_krb5int_get_tkt_flags(minor_status, uctx->internal_ctx_id,
-				     ticket_flags);
-}
 
 OM_uint32 KRB5_CALLCONV 
 gss_krb5_copy_ccache(
@@ -1274,25 +1268,6 @@
     return GSS_S_DEFECTIVE_CREDENTIAL;
 }
 
-/* XXX need to delete mechglue ctx too */
-OM_uint32 KRB5_CALLCONV
-gss_krb5_export_lucid_sec_context(
-    OM_uint32 *minor_status,
-    gss_ctx_id_t *context_handle,
-    OM_uint32 version,
-    void **kctx)
-{
-    gss_union_ctx_id_t uctx;
-
-    uctx = (gss_union_ctx_id_t)*context_handle;
-    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
-	!g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
-	return GSS_S_BAD_MECH;
-    return gss_krb5int_export_lucid_sec_context(minor_status,
-						&uctx->internal_ctx_id,
-						version, kctx);
-}
-
 OM_uint32 KRB5_CALLCONV
 gss_krb5_set_allowable_enctypes(
     OM_uint32 *minor_status, 
@@ -1366,3 +1341,104 @@
     return (&krb5_mechanism);
 }
 
+/*
+ * This API should go away and be replaced with an accessor
+ * into a gss_name_t.
+ */
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(
+    OM_uint32 *minor_status,
+    gss_ctx_id_t context_handle,
+    int ad_type,
+    gss_buffer_t ad_data)
+{
+    gss_OID_desc req_oid;
+    unsigned char oid_buf[GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH + 6];
+    OM_uint32 major_status;
+    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+    if (ad_data == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    req_oid.elements = oid_buf;
+    req_oid.length = sizeof(oid_buf);
+
+    major_status = generic_gss_oid_compose(minor_status,
+                                           GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+                                           GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+                                           ad_type,
+                                           &req_oid);
+    if (GSS_ERROR(major_status))
+        return major_status;
+
+    major_status = gss_inquire_sec_context_by_oid(minor_status,
+                                                  context_handle,
+                                                  (gss_OID)&req_oid,
+                                                  &data_set);
+    if (major_status != GSS_S_COMPLETE) {
+        return major_status;
+    }
+
+
+    /*
+     * SUNW17PACresync / Solaris Kerberos
+     * MIT17 expects just 1 but our testing with Win2008 shows
+     * it returns 2.  So we now handle that and rewhack mem mgmt as appro.
+     */
+    if (data_set == GSS_C_NO_BUFFER_SET ||
+        (data_set->count != 1 && data_set->count != 2)) {
+	    gss_release_buffer_set(minor_status, &data_set);
+
+	    return GSS_S_FAILURE;
+    }
+
+    ad_data->length = data_set->elements[0].length;
+    ad_data->value = malloc(ad_data->length);
+    if (!ad_data->value) {
+	    gss_release_buffer_set(minor_status, &data_set);
+	    return ENOMEM;
+    }
+    bcopy(data_set->elements[0].value, ad_data->value, ad_data->length);
+
+    gss_release_buffer_set(minor_status, &data_set);
+
+    return GSS_S_COMPLETE;
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+                                          gss_ctx_id_t context_handle,
+                                          krb5_timestamp *authtime)
+{
+    static const gss_OID_desc req_oid = {
+        GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
+        GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID };
+    OM_uint32 major_status;
+    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+    if (authtime == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    major_status = gss_inquire_sec_context_by_oid(minor_status,
+                                                  context_handle,
+                                                  (gss_OID)&req_oid,
+                                                  &data_set);
+    if (major_status != GSS_S_COMPLETE)
+        return major_status;
+
+    if (data_set == GSS_C_NO_BUFFER_SET ||
+        data_set->count != 1 ||
+        data_set->elements[0].length != sizeof(*authtime)) {
+        *minor_status = EINVAL;
+        return GSS_S_FAILURE;
+    }
+
+    *authtime = *((krb5_timestamp *)data_set->elements[0].value);
+
+    gss_release_buffer_set(minor_status, &data_set);
+
+    *minor_status = 0;
+
+    return GSS_S_COMPLETE;
+}
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/lucid_context.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/lucid_context.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,9 +1,12 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* -*- mode: c; indent-tabs-mode: nil -*- */
 /*
  * lib/gssapi/krb5/lucid_context.c
  *
- * Copyright 2004 by the Massachusetts Institute of Technology.
+ * Copyright 2004, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -33,6 +36,7 @@
  */
 #include "gssapiP_krb5.h"
 #include "gssapi_krb5.h"
+#include "mechglueP.h" /* SUNW17PACresync */
 
 /*
  * Local routine prototypes
@@ -53,7 +57,7 @@
 static krb5_error_code
 make_external_lucid_ctx_v1(
     krb5_gss_ctx_id_rec * gctx,
-    unsigned int version,
+    int version,
     void **out_ptr);
 
 
@@ -63,72 +67,61 @@
 
 OM_uint32 KRB5_CALLCONV
 gss_krb5int_export_lucid_sec_context(
-    OM_uint32		*minor_status,
-    gss_ctx_id_t	*context_handle,
-    OM_uint32		version,
-    void		**kctx)
+    OM_uint32           *minor_status,
+    gss_ctx_id_t        context_handle,
+    const gss_OID       desired_object,
+    gss_buffer_set_t    *data_set)
 {
-    krb5_error_code	kret = 0;
-    OM_uint32		retval;
-    krb5_gss_ctx_id_t	ctx;
-    void		*lctx = NULL;
+    krb5_error_code     kret = 0;
+    OM_uint32           retval;
+    krb5_gss_ctx_id_t   ctx = (krb5_gss_ctx_id_t)context_handle;
+    void                *lctx = NULL;
+    int                 version = 0;
+    gss_buffer_desc     rep;
 
     /* Assume failure */
     retval = GSS_S_FAILURE;
     *minor_status = 0;
-
-    if (kctx)
-	*kctx = NULL;
-    else {
-	kret = EINVAL;
-    	goto error_out;
-    }
+    *data_set = GSS_C_NO_BUFFER_SET;
 
-    if (!kg_validate_ctx_id(*context_handle)) {
-	    kret = (OM_uint32) G_VALIDATE_FAILED;
-	    retval = GSS_S_NO_CONTEXT;
-	    goto error_out;
-    }
-
-    ctx = (krb5_gss_ctx_id_t) *context_handle;
-    if (kret)
-	goto error_out;
+    retval = generic_gss_oid_decompose(minor_status,
+                                       GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
+                                       GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
+                                       desired_object,
+                                       &version);
+    if (GSS_ERROR(retval))
+        return retval;
 
     /* Externalize a structure of the right version */
     switch (version) {
     case 1:
-	kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
-					      version, &lctx);
+        kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
+                                          version, &lctx);
         break;
     default:
-	kret = (OM_uint32) KG_LUCID_VERSION;
-	break;
+        kret = (OM_uint32) KG_LUCID_VERSION;
+        break;
     }
 
     if (kret)
-	goto error_out;
+        goto error_out;
 
     /* Success!  Record the context and return the buffer */
     if (! kg_save_lucidctx_id((void *)lctx)) {
-	kret = G_VALIDATE_FAILED;
-	goto error_out;
+        kret = G_VALIDATE_FAILED;
+        goto error_out;
     }
 
-    *kctx = lctx;
-    *minor_status = 0;
-    retval = GSS_S_COMPLETE;
+    rep.value = &lctx;
+    rep.length = sizeof(lctx);
 
-    /* Clean up the context state (it is an error for
-     * someone to attempt to use this context again)
-     */
-    (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
-    *context_handle = GSS_C_NO_CONTEXT;
-
-    return (retval);
+    retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+    if (GSS_ERROR(retval))
+        goto error_out;
 
 error_out:
-    if (*minor_status == 0) 
-	    *minor_status = (OM_uint32) kret;
+    if (*minor_status == 0)
+        *minor_status = (OM_uint32) kret;
     return(retval);
 }
 
@@ -136,54 +129,58 @@
  * Frees the storage associated with an
  * exported lucid context structure.
  */
-OM_uint32 KRB5_CALLCONV
-gss_krb5_free_lucid_sec_context(
+OM_uint32
+gss_krb5int_free_lucid_sec_context(
     OM_uint32 *minor_status,
-    void *kctx)
+    const gss_OID desired_mech,
+    const gss_OID desired_object,
+    gss_buffer_t value)
 {
-    OM_uint32		retval;
-    krb5_error_code	kret = 0;
-    int			version;
+    OM_uint32           retval;
+    krb5_error_code     kret = 0;
+    int                 version;
+    void                *kctx;
 
     /* Assume failure */
     retval = GSS_S_FAILURE;
     *minor_status = 0;
 
+    kctx = value->value;
     if (!kctx) {
-	kret = EINVAL;
-	goto error_out;
+        kret = EINVAL;
+        goto error_out;
     }
 
     /* Verify pointer is valid lucid context */
     if (! kg_validate_lucidctx_id(kctx)) {
-	kret = G_VALIDATE_FAILED;
-	goto error_out;
+        kret = G_VALIDATE_FAILED;
+        goto error_out;
     }
 
     /* Determine version and call correct free routine */
     version = ((gss_krb5_lucid_context_version_t *)kctx)->version;
     switch (version) {
     case 1:
-	free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
-	break;
+        (void)kg_delete_lucidctx_id(kctx);
+        free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
+        break;
     default:
-	kret = EINVAL;
-	break;
+        kret = EINVAL;
+        break;
     }
 
     if (kret)
-	goto error_out;
+        goto error_out;
 
     /* Success! */
-    (void)kg_delete_lucidctx_id(kctx);
     *minor_status = 0;
     retval = GSS_S_COMPLETE;
 
     return (retval);
 
 error_out:
-    if (*minor_status == 0) 
-	    *minor_status = (OM_uint32) kret;
+    if (*minor_status == 0)
+        *minor_status = (OM_uint32) kret;
     return(retval);
 }
 
@@ -194,7 +191,7 @@
 static krb5_error_code
 make_external_lucid_ctx_v1(
     krb5_gss_ctx_id_rec * gctx,
-    unsigned int version,
+    int version,
     void **out_ptr)
 {
     gss_krb5_lucid_context_v1_t *lctx = NULL;
@@ -203,44 +200,44 @@
 
     /* Allocate the structure */
     if ((lctx = xmalloc(bufsize)) == NULL) {
-    	retval = ENOMEM;
-	goto error_out;
+        retval = ENOMEM;
+        goto error_out;
     }
 
     memset(lctx, 0, bufsize);
 
     lctx->version = 1;
     lctx->initiate = gctx->initiate ? 1 : 0;
-    lctx->endtime = gctx->endtime;
+    lctx->endtime = gctx->krb_times.endtime;
     lctx->send_seq = gctx->seq_send;
     lctx->recv_seq = gctx->seq_recv;
     lctx->protocol = gctx->proto;
     /* gctx->proto == 0 ==> rfc1964-style key information
        gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */
     if (gctx->proto == 0) {
-	lctx->rfc1964_kd.sign_alg = gctx->signalg;
-	lctx->rfc1964_kd.seal_alg = gctx->sealalg;
-	/* Copy key */
-	if ((retval = copy_keyblock_to_lucid_key(gctx->subkey,
-	    				&lctx->rfc1964_kd.ctx_key)))
-	    goto error_out;
+        lctx->rfc1964_kd.sign_alg = gctx->signalg;
+        lctx->rfc1964_kd.seal_alg = gctx->sealalg;
+        /* Copy key */
+        if ((retval = copy_keyblock_to_lucid_key(gctx->seq,
+                                                 &lctx->rfc1964_kd.ctx_key)))
+            goto error_out;
     }
     else if (gctx->proto == 1) {
-	/* Copy keys */
-	/* (subkey is always present, either a copy of the kerberos
-	   session key or a subkey) */
-	if ((retval = copy_keyblock_to_lucid_key(gctx->subkey,
-	    				&lctx->cfx_kd.ctx_key)))
-	    goto error_out;
-	if (gctx->have_acceptor_subkey) {
-	    if ((retval = copy_keyblock_to_lucid_key(gctx->enc,
-	    				&lctx->cfx_kd.acceptor_subkey)))
-		goto error_out;
-	    lctx->cfx_kd.have_acceptor_subkey = 1;
-	}
+        /* Copy keys */
+        /* (subkey is always present, either a copy of the kerberos
+           session key or a subkey) */
+        if ((retval = copy_keyblock_to_lucid_key(gctx->subkey,
+                                                 &lctx->cfx_kd.ctx_key)))
+            goto error_out;
+        if (gctx->have_acceptor_subkey) {
+            if ((retval = copy_keyblock_to_lucid_key(gctx->acceptor_subkey,
+                                                     &lctx->cfx_kd.acceptor_subkey)))
+                goto error_out;
+            lctx->cfx_kd.have_acceptor_subkey = 1;
+        }
     }
     else {
-	return EINVAL;	/* XXX better error code? */
+        return EINVAL;  /* XXX better error code? */
     }
 
     /* Success! */
@@ -249,7 +246,7 @@
 
 error_out:
     if (lctx) {
-	free_external_lucid_ctx_v1(lctx);
+        free_external_lucid_ctx_v1(lctx);
     }
     return retval;
 
@@ -262,13 +259,13 @@
     gss_krb5_lucid_key_t *lkey)
 {
     if (!k5key || !k5key->contents || k5key->length == 0)
-	return EINVAL;
+        return EINVAL;
 
     memset(lkey, 0, sizeof(gss_krb5_lucid_key_t));
 
     /* Allocate storage for the key data */
     if ((lkey->data = xmalloc(k5key->length)) == NULL) {
-	return ENOMEM;
+        return ENOMEM;
     }
     memcpy(lkey->data, k5key->contents, k5key->length);
     lkey->length = k5key->length;
@@ -284,11 +281,11 @@
     gss_krb5_lucid_key_t *key)
 {
     if (key) {
-	if (key->data && key->length) {
-	    memset(key->data, 0, key->length);
-	    xfree(key->data);
-	    memset(key, 0, sizeof(gss_krb5_lucid_key_t));
-	}
+        if (key->data && key->length) {
+            memset(key->data, 0, key->length);
+            xfree(key->data);
+            memset(key, 0, sizeof(gss_krb5_lucid_key_t));
+        }
     }
 }
 /* Free any storage associated with a gss_krb5_lucid_context_v1 structure */
@@ -297,15 +294,15 @@
     gss_krb5_lucid_context_v1_t *ctx)
 {
     if (ctx) {
-	if (ctx->protocol == 0) {
-	    free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
-	}
-	if (ctx->protocol == 1) {
-	    free_lucid_key_data(&ctx->cfx_kd.ctx_key);
-	    if (ctx->cfx_kd.have_acceptor_subkey)
-		free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
-	}
-	xfree(ctx);
-	ctx = NULL;
+        if (ctx->protocol == 0) {
+            free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
+        }
+        if (ctx->protocol == 1) {
+            free_lucid_key_data(&ctx->cfx_kd.ctx_key);
+            if (ctx->cfx_kd.have_acceptor_subkey)
+                free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
+        }
+        xfree(ctx);
+        ctx = NULL;
     }
 }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/oid_ops.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/oid_ops.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,3 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * lib/gssapi/generic/oid_ops.c
  *
@@ -436,6 +434,92 @@
     return(GSS_S_FAILURE);
 }
 
+/* Compose an OID of a prefix and an integer suffix */
+OM_uint32
+generic_gss_oid_compose(
+    OM_uint32 *minor_status,
+    const char *prefix,
+    size_t prefix_len,
+    int suffix,
+    gss_OID_desc *oid)
+{
+    int osuffix, i;
+    size_t nbytes;
+    unsigned char *op;
+
+    if (oid == GSS_C_NO_OID) {
+	*minor_status = EINVAL;
+	return GSS_S_FAILURE;
+    }
+    if (oid->length < prefix_len) {
+	*minor_status = ERANGE;
+	return GSS_S_FAILURE;
+    }
+
+    memcpy(oid->elements, prefix, prefix_len);
+
+    nbytes = 0;
+    osuffix = suffix;
+    while (suffix) {
+	nbytes++;
+	suffix >>= 7;
+    }
+    suffix = osuffix;
+
+    if (oid->length < prefix_len + nbytes) {
+	*minor_status = ERANGE;
+	return GSS_S_FAILURE;
+    }
+
+    op = (unsigned char *) oid->elements + prefix_len + nbytes;
+    i = -1;
+    while (suffix) {
+	op[i] = (unsigned char)suffix & 0x7f;
+	if (i != -1) 
+	    op[i] |= 0x80;
+	i--;
+	suffix >>= 7;
+    }
+
+    oid->length = prefix_len + nbytes;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+generic_gss_oid_decompose(
+    OM_uint32 *minor_status,
+    const char *prefix,
+    size_t prefix_len,
+    gss_OID_desc *oid,
+    int *suffix)
+{
+    size_t i, slen;
+    unsigned char *op;
+
+    if (oid->length < prefix_len ||
+	memcmp(oid->elements, prefix, prefix_len) != 0) {
+	return GSS_S_BAD_MECH;
+    }
+
+    op = (unsigned char *) oid->elements + prefix_len;
+
+    *suffix = 0;
+
+    slen = oid->length - prefix_len;
+
+    for (i = 0; i < slen; i++) {
+	*suffix = (*suffix << 7) | (op[i] & 0x7f);
+	if (i + 1 != slen && (op[i] & 0x80) == 0) {
+	    *minor_status = EINVAL;
+	    return GSS_S_FAILURE;
+	}
+    }
+
+    return GSS_S_COMPLETE;
+}
+
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
  *
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/rel_buffer.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/rel_buffer.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,7 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
  * 
@@ -26,7 +28,8 @@
  *  glue routine for gss_release_buffer
  */
 
-#include "gssapiP_generic.h"
+/* SUNW17PACresync - gssapi.h allows us to build in libgss also */
+#include "gssapi.h"
 
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "gssapiP_generic.h"
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 generic_gss_create_empty_buffer_set
+	   (OM_uint32 * minor_status,
+	    gss_buffer_set_t *buffer_set)
+{
+    gss_buffer_set_t set;
+
+    set = (gss_buffer_set_desc *) malloc(sizeof(*set));
+    if (set == GSS_C_NO_BUFFER_SET) {
+	*minor_status = ENOMEM;
+	return GSS_S_FAILURE;
+    }
+
+    set->count = 0;
+    set->elements = NULL;
+
+    *buffer_set = set;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 generic_gss_add_buffer_set_member
+	   (OM_uint32 * minor_status,
+	    const gss_buffer_t member_buffer,
+	    gss_buffer_set_t *buffer_set)
+{
+    gss_buffer_set_t set;
+    gss_buffer_t p;
+    OM_uint32 ret;
+
+    if (*buffer_set == GSS_C_NO_BUFFER_SET) {
+	ret = generic_gss_create_empty_buffer_set(minor_status,
+						  buffer_set);
+	if (ret) {
+	    return ret;
+	}
+    }
+
+    set = *buffer_set;
+    set->elements = (gss_buffer_desc *)realloc(set->elements,
+					       (set->count + 1) *
+						sizeof(gss_buffer_desc));
+    if (set->elements == NULL) {
+	free(set);  /* SUNW17PACresync - MIT17 bug */
+	*minor_status = ENOMEM;
+	return GSS_S_FAILURE;
+    }
+
+    p = &set->elements[set->count];
+
+    p->value = malloc(member_buffer->length);
+    if (p->value == NULL) {
+	free(set->elements); /* SUNW17PACresync - MIT17 bug */
+	free(set); /* SUNW17PACresync - MIT17 bug */
+	*minor_status = ENOMEM;
+	return GSS_S_FAILURE;
+    }
+    (void) memcpy(p->value, member_buffer->value, member_buffer->length);
+    p->length = member_buffer->length;
+
+    set->count++;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 generic_gss_release_buffer_set
+	   (OM_uint32 * minor_status,
+	    gss_buffer_set_t *buffer_set)
+{
+    int i;
+    OM_uint32 minor;
+
+    *minor_status = 0;
+
+    if (*buffer_set == GSS_C_NO_BUFFER_SET) {
+	return GSS_S_COMPLETE;
+    }
+
+    for (i = 0; i < (*buffer_set)->count; i++) {
+      (void) generic_gss_release_buffer(&minor, &((*buffer_set)->elements[i]));
+    }
+
+    if ((*buffer_set)->elements != NULL) {
+	free((*buffer_set)->elements);
+	(*buffer_set)->elements = NULL;
+    }
+
+    (*buffer_set)->count = 0;
+
+    free(*buffer_set);
+    *buffer_set = GSS_C_NO_BUFFER_SET;
+
+    return GSS_S_COMPLETE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/gss_mechs/mech_krb5/support/utf8.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,549 @@
+/*
+ * util/support/utf8.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2008 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Basic UTF-8 routines
+ *
+ * These routines are "dumb".  Though they understand UTF-8,
+ * they don't grok Unicode.  That is, they can push bits,
+ * but don't have a clue what the bits represent.  That's
+ * good enough for use with the KRB5 Client SDK.
+ *
+ * These routines are not optimized.
+ */
+
+#include "k5-platform.h"
+#include "k5-utf8.h"
+#include "supp-int.h"
+
+/*
+ * return the number of bytes required to hold the
+ * NULL-terminated UTF-8 string NOT INCLUDING the
+ * termination.
+ */
+size_t krb5int_utf8_bytes(const char *p)
+{
+    size_t bytes;
+
+    for (bytes = 0; p[bytes]; bytes++)
+	;
+
+    return bytes;
+}
+
+size_t krb5int_utf8_chars(const char *p)
+{
+    /* could be optimized and could check for invalid sequences */
+    size_t chars = 0;
+
+    for ( ; *p ; KRB5_UTF8_INCR(p))
+	chars++;
+
+    return chars;
+}
+
+size_t krb5int_utf8c_chars(const char *p, size_t length)
+{
+    /* could be optimized and could check for invalid sequences */
+    size_t chars = 0;
+    const char *end = p + length;
+
+    for ( ; p < end; KRB5_UTF8_INCR(p))
+	chars++;
+
+    return chars;
+}
+
+/* return offset to next character */
+int krb5int_utf8_offset(const char *p)
+{
+    return KRB5_UTF8_NEXT(p) - p;
+}
+
+/*
+ * Returns length indicated by first byte.
+ */
+const char krb5int_utf8_lentab[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 };
+
+int krb5int_utf8_charlen(const char *p)
+{
+    if (!(*p & 0x80))
+	return 1;
+
+    return krb5int_utf8_lentab[*(const unsigned char *)p ^ 0x80];
+}
+
+/*
+ * Make sure the UTF-8 char used the shortest possible encoding
+ * returns charlen if valid, 0 if not. 
+ *
+ * Here are the valid UTF-8 encodings, taken from RFC 2279 page 4.
+ * The table is slightly modified from that of the RFC.
+ *
+ * UCS-4 range (hex)      UTF-8 sequence (binary)
+ * 0000 0000-0000 007F   0.......
+ * 0000 0080-0000 07FF   110++++. 10......
+ * 0000 0800-0000 FFFF   1110++++ 10+..... 10......
+ * 0001 0000-001F FFFF   11110+++ 10++.... 10...... 10......
+ * 0020 0000-03FF FFFF   111110++ 10+++... 10...... 10...... 10......
+ * 0400 0000-7FFF FFFF   1111110+ 10++++.. 10...... 10...... 10...... 10......
+ *
+ * The '.' bits are "don't cares". When validating a UTF-8 sequence,
+ * at least one of the '+' bits must be set, otherwise the character
+ * should have been encoded in fewer octets. Note that in the two-octet
+ * case, only the first octet needs to be validated, and this is done
+ * in the krb5int_utf8_lentab[] above.
+ */
+
+/* mask of required bits in second octet */
+#undef c
+#define c const char
+c krb5int_utf8_mintab[] = {
+    (c)0x20, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
+    (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
+    (c)0x30, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
+    (c)0x38, (c)0x80, (c)0x80, (c)0x80, (c)0x3c, (c)0x80, (c)0x00, (c)0x00 };
+#undef c
+
+int krb5int_utf8_charlen2(const char *p)
+{
+    int i = KRB5_UTF8_CHARLEN(p);
+
+    if (i > 2) {
+	if (!(krb5int_utf8_mintab[*p & 0x1f] & p[1]))
+	    i = 0;
+    }
+
+    return i;
+}
+
+/*
+ * Convert a UTF8 character to a UCS4 character.  Return 0 on success,
+ * -1 on failure.
+ */
+int krb5int_utf8_to_ucs4(const char *p, krb5_ucs4 *out)
+{
+    const unsigned char *c = (const unsigned char *) p;
+    krb5_ucs4 ch;
+    int len, i;
+    static unsigned char mask[] = {
+	0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+
+    *out = 0;
+    len = KRB5_UTF8_CHARLEN2(p, len);
+
+    if (len == 0)
+	return -1;
+
+    ch = c[0] & mask[len];
+
+    for (i = 1; i < len; i++) {
+	if ((c[i] & 0xc0) != 0x80)
+	    return -1;
+
+	ch <<= 6;
+	ch |= c[i] & 0x3f;
+    }
+
+    *out = ch;
+    return 0;
+}
+
+int krb5int_utf8_to_ucs2(const char *p, krb5_ucs2 *out)
+{
+    krb5_ucs4 ch;
+
+    *out = 0;
+    if (krb5int_utf8_to_ucs4(p, &ch) == -1 || ch > 0xFFFF)
+	return -1;
+    *out = (krb5_ucs2) ch;
+    return 0;
+}
+
+/* conv UCS-2 to UTF-8, not used */
+size_t krb5int_ucs4_to_utf8(krb5_ucs4 c, char *buf)
+{
+    size_t len = 0;
+    unsigned char *p = (unsigned char *) buf;
+
+    /* not a valid Unicode character */
+    if (c < 0)
+	return 0;
+
+    /* Just return length, don't convert */
+    if (buf == NULL) {
+	if (c < 0x80) return 1;
+	else if (c < 0x800) return 2;
+	else if (c < 0x10000) return 3;
+	else if (c < 0x200000) return 4;
+	else if (c < 0x4000000) return 5;
+	else return 6;
+    }
+
+    if (c < 0x80) {
+	p[len++] = c;
+    } else if (c < 0x800) {
+	p[len++] = 0xc0 | ( c >> 6 );
+	p[len++] = 0x80 | ( c & 0x3f );
+    } else if (c < 0x10000) {
+	p[len++] = 0xe0 | ( c >> 12 );
+	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
+	p[len++] = 0x80 | ( c & 0x3f );
+    } else if (c < 0x200000) {
+	p[len++] = 0xf0 | ( c >> 18 );
+	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
+	p[len++] = 0x80 | ( c & 0x3f );
+    } else if (c < 0x4000000) {
+	p[len++] = 0xf8 | ( c >> 24 );
+	p[len++] = 0x80 | ( (c >> 18) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
+	p[len++] = 0x80 | ( c & 0x3f );
+    } else /* if( c < 0x80000000 ) */ {
+	p[len++] = 0xfc | ( c >> 30 );
+	p[len++] = 0x80 | ( (c >> 24) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 18) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
+	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
+	p[len++] = 0x80 | ( c & 0x3f );
+    }
+
+    return len;
+}
+
+size_t krb5int_ucs2_to_utf8(krb5_ucs2 c, char *buf)
+{
+    return krb5int_ucs4_to_utf8((krb5_ucs4)c, buf);
+}
+
+#define KRB5_UCS_UTF8LEN(c)	\
+    c < 0 ? 0 : (c < 0x80 ? 1 : (c < 0x800 ? 2 : (c < 0x10000 ? 3 : \
+    (c < 0x200000 ? 4 : (c < 0x4000000 ? 5 : 6)))))
+
+/*
+ * Advance to the next UTF-8 character
+ *
+ * Ignores length of multibyte character, instead rely on
+ * continuation markers to find start of next character.
+ * This allows for "resyncing" of when invalid characters
+ * are provided provided the start of the next character
+ * is appears within the 6 bytes examined.
+ */
+char *krb5int_utf8_next(const char *p)
+{
+    int i;
+    const unsigned char *u = (const unsigned char *) p;
+
+    if (KRB5_UTF8_ISASCII(u)) {
+	return (char *) &p[1];
+    }
+
+    for (i = 1; i < 6; i++) {
+	if ((u[i] & 0xc0) != 0x80) {
+	    return (char *) &p[i];
+	}
+    }
+
+    return (char *) &p[i];
+}
+
+/*
+ * Advance to the previous UTF-8 character
+ *
+ * Ignores length of multibyte character, instead rely on
+ * continuation markers to find start of next character.
+ * This allows for "resyncing" of when invalid characters
+ * are provided provided the start of the next character
+ * is appears within the 6 bytes examined.
+ */
+char *krb5int_utf8_prev(const char *p)
+{
+    int i;
+    const unsigned char *u = (const unsigned char *) p;
+
+    for (i = -1; i>-6 ; i--) {
+	if ((u[i] & 0xc0 ) != 0x80) {
+	    return (char *) &p[i];
+	}
+    }
+
+    return (char *) &p[i];
+}
+
+/*
+ * Copy one UTF-8 character from src to dst returning
+ * number of bytes copied.
+ *
+ * Ignores length of multibyte character, instead rely on
+ * continuation markers to find start of next character.
+ * This allows for "resyncing" of when invalid characters
+ * are provided provided the start of the next character
+ * is appears within the 6 bytes examined.
+ */
+int krb5int_utf8_copy(char* dst, const char *src)
+{
+    int i;
+    const unsigned char *u = (const unsigned char *) src;
+
+    dst[0] = src[0];
+
+    if (KRB5_UTF8_ISASCII(u)) {
+	return 1;
+    }
+
+    for (i=1; i<6; i++) {
+	if ((u[i] & 0xc0) != 0x80) {
+	    return i; 
+	}
+	dst[i] = src[i];
+    }
+
+    return i;
+}
+
+#ifndef UTF8_ALPHA_CTYPE
+/*
+ * UTF-8 ctype routines
+ * Only deals with characters < 0x80 (ie: US-ASCII)
+ */
+
+int krb5int_utf8_isascii(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    return KRB5_ASCII(c);
+}
+
+int krb5int_utf8_isdigit(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_DIGIT( c );
+}
+
+int krb5int_utf8_isxdigit(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_HEX(c);
+}
+
+int krb5int_utf8_isspace(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    switch(c) {
+    case ' ':
+    case '\t':
+    case '\n':
+    case '\r':
+    case '\v':
+    case '\f':
+	return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * These are not needed by the C SDK and are
+ * not "good enough" for general use.
+ */
+int krb5int_utf8_isalpha(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_ALPHA(c);
+}
+
+int krb5int_utf8_isalnum(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_ALNUM(c);
+}
+
+#if 0
+int krb5int_utf8_islower(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_LOWER(c);
+}
+
+int krb5int_utf8_isupper(const char * p)
+{
+    unsigned c = * (const unsigned char *) p;
+
+    if (!KRB5_ASCII(c))
+	return 0;
+
+    return KRB5_UPPER(c);
+}
+#endif
+#endif
+
+
+/*
+ * UTF-8 string routines
+ */
+
+/* like strchr() */
+char *krb5int_utf8_strchr(const char *str, const char *chr)
+{
+    krb5_ucs4 chs, ch;
+
+    if (krb5int_utf8_to_ucs4(chr, &ch) == -1)
+	return NULL;
+    for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
+	if (krb5int_utf8_to_ucs4(str, &chs) == 0 && chs == ch)
+	    return (char *)str;
+    }
+
+    return NULL;
+}
+
+/* like strcspn() but returns number of bytes, not characters */
+size_t krb5int_utf8_strcspn(const char *str, const char *set)
+{
+    const char *cstr, *cset;
+    krb5_ucs4 chstr, chset;
+
+    for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
+	for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
+	    if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
+		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
+		return cstr - str;
+	}
+    }
+
+    return cstr - str;
+}
+
+/* like strspn() but returns number of bytes, not characters */
+size_t krb5int_utf8_strspn(const char *str, const char *set)
+{
+    const char *cstr, *cset;
+    krb5_ucs4 chstr, chset;
+
+    for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
+	for (cset = set; ; KRB5_UTF8_INCR(cset)) {
+	    if (*cset == '\0')
+		return cstr - str;
+	    if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
+		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
+		break;
+	}
+    }
+
+    return cstr - str;
+}
+
+/* like strpbrk(), replaces strchr() as well */
+char *krb5int_utf8_strpbrk(const char *str, const char *set)
+{
+    const char *cset;
+    krb5_ucs4 chstr, chset;
+
+    for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
+	for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
+	    if (krb5int_utf8_to_ucs4(str, &chstr) == 0
+		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
+		return (char *)str;
+	}
+    }
+
+    return NULL;
+}
+
+/* like strtok_r(), not strtok() */
+char *krb5int_utf8_strtok(char *str, const char *sep, char **last)
+{
+    char *begin;
+    char *end;
+
+    if (last == NULL)
+	return NULL;
+
+    begin = str ? str : *last;
+
+    begin += krb5int_utf8_strspn(begin, sep);
+
+    if (*begin == '\0') {
+	*last = NULL;
+	return NULL;
+    }
+
+    end = &begin[krb5int_utf8_strcspn(begin, sep)];
+
+    if (*end != '\0') {
+	char *next = KRB5_UTF8_NEXT(end);
+	*end = '\0';
+	end = next;
+    }
+
+    *last = end;
+
+    return begin;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/gss_mechs/mech_krb5/support/utf8_conv.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * util/support/utf8_conv.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2008 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
+ * 
+ * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
+ * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
+ * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
+ * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
+ * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
+ * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
+ * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
+ * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
+ */
+
+/*
+ * UTF-8 Conversion Routines
+ *
+ * These routines convert between Wide Character and UTF-8,
+ * or between MultiByte and UTF-8 encodings.
+ *
+ * Both single character and string versions of the functions are provided.
+ * All functions return -1 if the character or string cannot be converted.
+ */
+
+#include "k5-platform.h"
+#include "k5-utf8.h"
+#include "supp-int.h"
+#include "errno.h"  /* SUNW17PACresync */
+
+static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+
+static ssize_t
+k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str,
+		  const char *utf8str,
+		  size_t count,
+		  int little_endian)
+{
+    size_t ucs2len = 0;
+    size_t utflen, i;
+    krb5_ucs2 ch;
+
+    /* If input ptr is NULL or empty... */
+    if (utf8str == NULL || *utf8str == '\0') {
+	*ucs2str = 0;
+
+	return 0;
+    }
+
+    /* Examine next UTF-8 character.  */
+    while (*utf8str && ucs2len < count) {
+	/* Get UTF-8 sequence length from 1st byte */
+	utflen = KRB5_UTF8_CHARLEN2(utf8str, utflen);
+		
+	if (utflen == 0 || utflen > KRB5_MAX_UTF8_LEN)
+	    return -1;
+
+	/* First byte minus length tag */
+	ch = (krb5_ucs2)(utf8str[0] & mask[utflen]);
+		
+	for (i = 1; i < utflen; i++) {
+	    /* Subsequent bytes must start with 10 */
+	    if ((utf8str[i] & 0xc0) != 0x80)
+		return -1;
+		
+	    ch <<= 6;			/* 6 bits of data in each subsequent byte */
+	    ch |= (krb5_ucs2)(utf8str[i] & 0x3f);
+	}
+		
+	if (ucs2str != NULL) {
+#ifdef K5_BE
+#ifndef SWAP16
+#define SWAP16(X)	((((X) << 8) | ((X) >> 8)) & 0xFFFF)
+#endif
+	    if (little_endian)
+		ucs2str[ucs2len] = SWAP16(ch);
+	    else
+#endif
+		ucs2str[ucs2len] = ch;
+	}
+
+	utf8str += utflen;	/* Move to next UTF-8 character */
+	ucs2len++;		/* Count number of wide chars stored/required */
+    }
+
+    assert(ucs2len < count);
+    
+    if (ucs2str != NULL) {
+	/* Add null terminator if there's room in the buffer. */
+	ucs2str[ucs2len] = 0;
+    }
+
+    return ucs2len;
+}
+
+int
+krb5int_utf8s_to_ucs2s(const char *utf8s,
+		       krb5_ucs2 **ucs2s,
+		       size_t *ucs2chars)
+{
+    ssize_t len;
+    size_t chars;
+
+    chars = krb5int_utf8_chars(utf8s);
+    *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
+    if (*ucs2s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0);
+    if (len < 0) {
+	free(*ucs2s);
+	*ucs2s = NULL;
+	return EINVAL;
+    }
+
+    if (ucs2chars != NULL) {
+	*ucs2chars = chars;
+    }
+
+    return 0;
+}
+
+int
+krb5int_utf8cs_to_ucs2s(const char *utf8s,
+			size_t utf8slen,
+			krb5_ucs2 **ucs2s,
+			size_t *ucs2chars)
+{
+    ssize_t len;
+    size_t chars;
+
+    chars = krb5int_utf8c_chars(utf8s, utf8slen);
+    *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
+    if (*ucs2s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0);
+    if (len < 0) {
+	free(*ucs2s);
+	*ucs2s = NULL;
+	return EINVAL;
+    }
+
+    if (ucs2chars != NULL) {
+	*ucs2chars = chars;
+    }
+
+    return 0;
+}
+
+int
+krb5int_utf8s_to_ucs2les(const char *utf8s,
+                         unsigned char **ucs2les,
+			 size_t *ucs2leslen)
+{
+    ssize_t len;
+    size_t chars;
+
+    chars = krb5int_utf8_chars(utf8s);
+
+    *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2));
+    if (*ucs2les == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1);
+    if (len < 0) {
+	free(*ucs2les);
+	*ucs2les = NULL;
+	return EINVAL;
+    }
+
+    if (ucs2leslen != NULL) {
+	*ucs2leslen = chars * sizeof(krb5_ucs2);
+    }
+
+    return 0;
+}
+
+int
+krb5int_utf8cs_to_ucs2les(const char *utf8s,
+			  size_t utf8slen,
+			  unsigned char **ucs2les,
+			  size_t *ucs2leslen)
+{
+    ssize_t len;
+    size_t chars;
+
+    chars = krb5int_utf8c_chars(utf8s, utf8slen);
+
+    *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2));
+    if (*ucs2les == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1);
+    if (len < 0) {
+	free(*ucs2les);
+	*ucs2les = NULL;
+	return EINVAL;
+    }
+
+    if (ucs2leslen != NULL) {
+	*ucs2leslen = chars * sizeof(krb5_ucs2);
+    }
+
+    return 0;
+}
+
+/*-----------------------------------------------------------------------------
+   Convert a wide char string to a UTF-8 string.
+   No more than 'count' bytes will be written to the output buffer.
+   Return the # of bytes written to the output buffer, excl null terminator.
+
+   ucs2len is -1 if the UCS-2 string is NUL terminated, otherwise it is the
+   length of the UCS-2 string in characters
+*/
+static ssize_t
+k5_ucs2s_to_utf8s(char *utf8str, const krb5_ucs2 *ucs2str,
+		  size_t count, ssize_t ucs2len, int little_endian)
+{
+    int len = 0;
+    int n;
+    char *p = utf8str;
+    krb5_ucs2 empty = 0, ch;
+
+    if (ucs2str == NULL)	/* Treat input ptr NULL as an empty string */
+	ucs2str = &empty;
+
+    if (utf8str == NULL)	/* Just compute size of output, excl null */
+    {
+	while (ucs2len == -1 ? *ucs2str : --ucs2len >= 0) {
+	    /* Get UTF-8 size of next wide char */
+	  ch = *ucs2str++;
+#ifdef K5_BE
+	    if (little_endian)
+		ch = SWAP16(ch);
+#endif
+
+	    n = krb5int_ucs2_to_utf8(ch, NULL);
+	    if (n < 1)
+		return -1;
+	    if (len + n < len)
+		return -1; /* overflow */
+	    len += n;
+	}
+
+	return len;
+    }
+	
+    /* Do the actual conversion. */
+
+    n = 1;					/* In case of empty ucs2str */
+    while (ucs2len == -1 ? *ucs2str != 0 : --ucs2len >= 0) {
+      ch = *ucs2str++;
+#ifdef K5_BE
+	if (little_endian)
+	    ch = SWAP16(ch);
+#endif
+
+	n = krb5int_ucs2_to_utf8(ch, p);
+		
+	if (n < 1)
+	    break;
+		
+	p += n;
+	count -= n;			/* Space left in output buffer */
+    }
+
+    /* If not enough room for last character, pad remainder with null
+       so that return value = original count, indicating buffer full. */
+    if (n == 0) {
+	while (count--)
+	    *p++ = 0;
+    }
+    /* Add a null terminator if there's room. */
+    else if (count)
+	*p = 0;
+
+    if (n == -1)			/* Conversion encountered invalid wide char. */
+	return -1;
+
+    /* Return the number of bytes written to output buffer, excl null. */ 
+    return (p - utf8str);
+}
+
+int
+krb5int_ucs2s_to_utf8s(const krb5_ucs2 *ucs2s,
+		       char **utf8s,
+		       size_t *utf8slen)
+{
+    ssize_t len;
+
+    len = k5_ucs2s_to_utf8s(NULL, ucs2s, 0, -1, 0);
+    if (len < 0) {
+	return EINVAL;
+    }
+
+    *utf8s = (char *)malloc((size_t)len + 1);
+    if (*utf8s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_ucs2s_to_utf8s(*utf8s, ucs2s, (size_t)len + 1, -1, 0);
+    if (len < 0) {
+	free(*utf8s);
+	*utf8s = NULL;
+	return EINVAL;
+    }
+
+    if (utf8slen != NULL) {
+	*utf8slen = len;
+    }
+
+    return 0;
+}
+
+int
+krb5int_ucs2les_to_utf8s(const unsigned char *ucs2les,
+			 char **utf8s,
+			 size_t *utf8slen)
+{
+    ssize_t len;
+
+    len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0, -1, 1);
+    if (len < 0)
+	return EINVAL;
+
+    *utf8s = (char *)malloc((size_t)len + 1);
+    if (*utf8s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len + 1, -1, 1);
+    if (len < 0) {
+	free(*utf8s);
+	*utf8s = NULL;
+	return EINVAL;
+    }
+
+    if (utf8slen != NULL) {
+	*utf8slen = len;
+    }
+
+    return 0;
+}
+
+int
+krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s,
+                        size_t ucs2slen,
+                        char **utf8s,
+                        size_t *utf8slen)
+{
+    ssize_t len;
+
+    if (ucs2slen > SSIZE_MAX)
+	return ERANGE;
+
+    len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2s, 0,
+			    (ssize_t)ucs2slen, 0);
+    if (len < 0)
+	return EINVAL;
+
+    *utf8s = (char *)malloc((size_t)len + 1);
+    if (*utf8s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s,
+			    (size_t)len + 1, (ssize_t)ucs2slen, 0);
+    if (len < 0) {
+	free(*utf8s);
+	*utf8s = NULL;
+	return EINVAL;
+    }
+
+    if (utf8slen != NULL) {
+	*utf8slen = len;
+    }
+
+    return 0;
+}
+
+int
+krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les,
+                          size_t ucs2leslen,
+                          char **utf8s,
+                          size_t *utf8slen)
+{
+    ssize_t len;
+
+    if (ucs2leslen > SSIZE_MAX)
+	return ERANGE;
+
+    len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0,
+			    (ssize_t)ucs2leslen, 1);
+    if (len < 0)
+	return EINVAL;
+
+    *utf8s = (char *)malloc((size_t)len + 1);
+    if (*utf8s == NULL) {
+	return ENOMEM;
+    }
+
+    len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les,
+			    (size_t)len + 1, (ssize_t)ucs2leslen, 1);
+    if (len < 0) {
+	free(*utf8s);
+	*utf8s = NULL;
+	return EINVAL;
+    }
+
+    if (utf8slen != NULL) {
+	*utf8slen = len;
+    }
+
+    return 0;
+}
+
--- a/usr/src/lib/gss_mechs/mech_spnego/Makefile.com	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/Makefile.com	Mon Sep 21 16:47:51 2009 -0700
@@ -19,11 +19,10 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
+
 
 #
 # This make file will build mech_spnego.so.1. This shared object
@@ -42,14 +41,13 @@
 ROOTLIBDIR =	$(ROOT)/usr/lib/gss
 ROOTLIBDIR64 = 	$(ROOT)/usr/lib/$(MACH64)/gss
 SRCDIR =	../mech
-LDLIBS += 	-lgss -lc
 
 MAPFILE_EXPORT = ../mapfile-vers-clean
 $(EXPORT_RELEASE_BUILD)MAPFILE_EXPORT = \
 		$(CLOSED)/lib/gss_mechs/mech_spnego/mapfile-vers-export
 MAPFILES =	../mapfile-vers $(MAPFILE_EXPORT)
 
-CPPFLAGS += -I$(SRC)/uts/common/gssapi/include -I$(ROOT)/usr/include/gssapi $(DEBUG)
+CPPFLAGS += -I$(SRC)/uts/common/gssapi/include $(DEBUG) -I$(SRC)/lib/gss_mechs/mech_krb5/include -I$(SRC)/uts/common/gssapi/mechs/krb5/include
 
 MAKEFILE_EXPORT = $(CLOSED)/lib/gss_mechs/mech_spnego/Makefile.export
 $(EXPORT_RELEASE_BUILD)include $(MAKEFILE_EXPORT)
@@ -62,3 +60,4 @@
 
 # include library targets
 include ../../../Makefile.targ
+
--- a/usr/src/lib/gss_mechs/mech_spnego/amd64/Makefile	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/amd64/Makefile	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,13 +19,14 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 include ../Makefile.com
 include ../../../Makefile.lib.64
+include ../../mech_krb5/Makefile.mech_krb5
+
+LDLIBS64 += 	-lgss -lc -lmech_krb5 -L$(ROOT_KLIBDIR64) $(KRUNPATH64)
 
 install: all $(ROOTLIBS64)
--- a/usr/src/lib/gss_mechs/mech_spnego/i386/Makefile	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/i386/Makefile	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,13 +19,14 @@
 # CDDL HEADER END
 #
 #
-# Copyright 1999-2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # lib/gss_mechs/mech_spnego/i386/Makefile
 
 include ../Makefile.com
+include ../../mech_krb5/Makefile.mech_krb5
+
+LDLIBS += 	-lgss -lc -lmech_krb5 -L$(ROOT_KLIBDIR) $(KRUNPATH)
 
 install: all $(ROOTLIBS)
--- a/usr/src/lib/gss_mechs/mech_spnego/mapfile-vers	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/mapfile-vers	Mon Sep 21 16:47:51 2009 -0700
@@ -41,7 +41,6 @@
     global:
 	spnego_gss_accept_sec_context;
 	spnego_gss_acquire_cred;
-	spnego_gss_context_time;
 	spnego_gss_delete_sec_context;
 	spnego_gss_display_name;
 	spnego_gss_display_status;
@@ -49,17 +48,16 @@
 	spnego_gss_import_name;
 	spnego_gss_import_sec_context;
 	spnego_gss_init_sec_context;
-	spnego_gss_inquire_context;
-	spnego_gss_inquire_cred;
+#	spnego_gss_inquire_context;
+#	spnego_gss_inquire_cred;
 	spnego_gss_inquire_names_for_mech;
 	spnego_gss_process_context_token;
 	spnego_gss_release_cred;
 	spnego_gss_release_name;
-	spnego_gss_seal;
-	spnego_gss_sign;
-	spnego_gss_unseal;
-	spnego_gss_verify;
-	spnego_gss_wrap_size_limit;
+#	spnego_gss_seal;
+#	spnego_gss_sign;
+#	spnego_gss_unseal;
+#	spnego_gss_verify;
     local:
 	*;
 };
--- a/usr/src/lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,39 +1,19 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_GSSAPIP_SPNEGO_H_
 #define	_GSSAPIP_SPNEGO_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/* #pragma ident	"@(#)gssapiP_spnego.h	1.3	03/09/18 SMI" */
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 #include <gssapi/gssapi.h>
-#include <synch.h>
+#include <gssapi/gssapi_ext.h>
 #include <syslog.h>
 
 #define	SEC_CONTEXT_TOKEN 1
@@ -42,7 +22,8 @@
 #define	ACCEPT_COMPLETE 0
 #define	ACCEPT_INCOMPLETE 1
 #define	REJECT 2
-#define	ACCEPT_DEFECTIVE_TOKEN 3
+#define REQUEST_MIC 3
+#define	ACCEPT_DEFECTIVE_TOKEN 0xffffffffUL
 
 /*
  * constants for der encoding/decoding routines.
@@ -53,9 +34,13 @@
 #define	CONTEXT			0xa0
 #define	SEQUENCE		0x30
 #define	SEQUENCE_OF		0x30
+#define	BIT_STRING		0x03
+#define	BIT_STRING_LENGTH	0x02
+#define	BIT_STRING_PADDING	0x01
 #define	ENUMERATED		0x0a
 #define	ENUMERATION_LENGTH	1
 #define	HEADER_ID		0x60
+#define GENERAL_STRING		0x1b
 
 /*
  * SPNEGO specific error codes (minor status codes)
@@ -65,7 +50,6 @@
 #define	ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR	0x20000003
 #define	ERR_SPNEGO_NEGOTIATION_FAILED		0x20000004
 #define	ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR	0x20000005
-#define	ERR_SPNEGO_BAD_INPUT_PARAMETER		0x20000006
 
 /*
  * send_token_flag is used to indicate in later steps what type
@@ -91,28 +75,44 @@
 
 typedef void *spnego_token_t;
 
+/* spnego name structure for internal representation. */
+typedef struct {
+	gss_OID type;
+	gss_buffer_t buffer;
+	gss_OID	mech_type;
+	gss_name_t	mech_name;
+} spnego_name_desc, *spnego_name_t;
+
 /* Structure for context handle */
 typedef struct {
+	OM_uint32	magic_num;
 	gss_buffer_desc DER_mechTypes;
 	gss_OID internal_mech;
 	gss_ctx_id_t ctx_handle;
 	char  *optionStr;
-	int MS_Interop;
-	int optimistic;
-	OM_uint32 last_status;
+	gss_cred_id_t default_cred;
+	int mic_reqd;
+	int mic_sent;
+	int mic_rcvd;
+	int firstpass;
+	int mech_complete;
+	int nego_done;
+	OM_uint32 ctx_flags;
+	gss_name_t internal_name;
+	gss_OID actual_mech;
 } spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t;
 
-/* SPNEGO oid structure */
-static const gss_OID_desc spnego_oids[] = {
-	{SPNEGO_OID_LENGTH, SPNEGO_OID},
-};
+/*
+ * The magic number must be less than a standard pagesize
+ * to avoid a possible collision with a real address.
+ */
+#define	SPNEGO_MAGIC_ID  0x00000fed
 
-const gss_OID_desc * const gss_mech_spnego = spnego_oids+0;
-static const gss_OID_set_desc spnego_oidsets[] = {
-	{1, (gss_OID) spnego_oids+0},
-};
-const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
+/* SPNEGO oid declarations */
+extern const gss_OID_desc * const gss_mech_spnego;
+extern const gss_OID_set_desc * const gss_mech_set_spnego;
 
+/* SUNW17PACresync */
 #define	TWRITE_STR(ptr, str, len) \
 	memcpy((ptr), (char *)(str), (len)); \
 	(ptr) += (len);
@@ -130,7 +130,19 @@
 
 OM_uint32 spnego_gss_acquire_cred
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	gss_name_t,		/* desired_name */
+	OM_uint32,		/* time_req */
+	gss_OID_set,		/* desired_mechs */
+	gss_cred_usage_t,	/* cred_usage */
+	gss_cred_id_t *,	/* output_cred_handle */
+	gss_OID_set *,		/* actual_mechs */
+	OM_uint32 *		/* time_rec */
+);
+
+OM_uint32 glue_spnego_gss_acquire_cred
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	gss_name_t,		/* desired_name */
 	OM_uint32,		/* time_req */
@@ -143,7 +155,14 @@
 
 OM_uint32 spnego_gss_release_cred
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	/* CSTYLED */
+	gss_cred_id_t	*	/* cred_handle */
+);
+
+OM_uint32 glue_spnego_gss_release_cred
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	/* CSTYLED */
 	gss_cred_id_t	*	/* cred_handle */
@@ -151,7 +170,24 @@
 
 OM_uint32 spnego_gss_init_sec_context
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	gss_cred_id_t,		/* claimant_cred_handle */
+	gss_ctx_id_t *,		/* context_handle */
+	gss_name_t,		/* target_name */
+	gss_OID,		/* mech_type */
+	OM_uint32,		/* req_flags */
+	OM_uint32,		/* time_req */
+	gss_channel_bindings_t, /* input_chan_bindings */
+	gss_buffer_t,		/* input_token */
+	gss_OID *,		/* actual_mech_type */
+	gss_buffer_t,		/* output_token */
+	OM_uint32 *,		/* ret_flags */
+	OM_uint32 *		/* time_rec */
+);
+
+OM_uint32 glue_spnego_gss_init_sec_context
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	gss_cred_id_t,		/* claimant_cred_handle */
 	gss_ctx_id_t *,		/* context_handle */
@@ -167,9 +203,25 @@
 	OM_uint32 *		/* time_rec */
 );
 
+#ifndef LEAN_CLIENT
 OM_uint32 spnego_gss_accept_sec_context
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	gss_ctx_id_t *,		/* context_handle */
+	gss_cred_id_t,		/* verifier_cred_handle */
+	gss_buffer_t,		/* input_token_buffer */
+	gss_channel_bindings_t, /* input_chan_bindings */
+	gss_name_t *,		/* src_name */
+	gss_OID *,		/* mech_type */
+	gss_buffer_t,		/* output_token */
+	OM_uint32 *,		/* ret_flags */
+	OM_uint32 *,		/* time_rec */
+	/* CSTYLED */
+	gss_cred_id_t *		/* delegated_cred_handle */
+);
+OM_uint32 glue_spnego_gss_accept_sec_context
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	gss_ctx_id_t *,		/* context_handle */
 	gss_cred_id_t,		/* verifier_cred_handle */
@@ -184,8 +236,35 @@
 	gss_cred_id_t *		/* delegated_cred_handle */
 );
 
+#endif /* LEAN_CLIENT */
+
+OM_uint32 spnego_gss_compare_name
+(
+	OM_uint32 *,		/* minor_status */
+	const gss_name_t,	/* name1 */
+	const gss_name_t,	/* name2 */
+	int *			/* name_equal */
+);
+
+OM_uint32 glue_spnego_gss_compare_name
+(
+	void *,
+	OM_uint32 *,		/* minor_status */
+	const gss_name_t,	/* name1 */
+	const gss_name_t,	/* name2 */
+	int *			/* name_equal */
+);
+
 OM_uint32 spnego_gss_display_name
 (
+	OM_uint32 *,		/* minor_status */
+	gss_name_t,		/*  input_name */
+	gss_buffer_t,		/*  output_name_buffer */
+	gss_OID *		/* output_name_type */
+);
+
+OM_uint32 glue_spnego_gss_display_name
+(
 	void *,
 	OM_uint32 *,		/* minor_status */
 	gss_name_t,		/*  input_name */
@@ -195,7 +274,17 @@
 
 OM_uint32 spnego_gss_display_status
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	OM_uint32,		/* status_value */
+	int,			/* status_type */
+	gss_OID,		/* mech_type */
+	OM_uint32 *,		/* message_context */
+	gss_buffer_t		/* status_string */
+);
+
+OM_uint32 glue_spnego_gss_display_status
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	OM_uint32,		/* status_value */
 	int,			/* status_type */
@@ -206,7 +295,6 @@
 
 OM_uint32 spnego_gss_import_name
 (
-	void *,			/* spnego context */
 	OM_uint32 *,		/* minor_status */
 	gss_buffer_t,		/* input_name_buffer */
 	gss_OID,		/* input_name_type */
@@ -214,9 +302,26 @@
 	gss_name_t *		/* output_name */
 );
 
+OM_uint32 glue_spnego_gss_import_name
+(
+	void *,
+	OM_uint32 *,		/* minor_status */
+	gss_buffer_t,		/* input_name_buffer */
+	gss_OID,		/* input_name_type */
+	/* CSTYLED */
+	gss_name_t *		/* output_name */
+);
 OM_uint32 spnego_gss_release_name
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	/* CSTYLED */
+	gss_name_t *		/* input_name */
+);
+
+OM_uint32 glue_spnego_gss_release_name
+(
+	void *,
+
 	OM_uint32 *,		/* minor_status */
 	/* CSTYLED */
 	gss_name_t *		/* input_name */
@@ -224,30 +329,35 @@
 
 OM_uint32 spnego_gss_inquire_names_for_mech
 (
-	void *,			/* spnego context */
+	OM_uint32 *,		/* minor_status */
+	gss_OID,		/* mechanism */
+	gss_OID_set *		/* name_types */
+);
+
+OM_uint32 glue_spnego_gss_inquire_names_for_mech
+(
+	void *,
 	OM_uint32 *,		/* minor_status */
 	gss_OID,		/* mechanism */
 	gss_OID_set *		/* name_types */
 );
 
-OM_uint32 spnego_gss_unseal
+OM_uint32 spnego_gss_unwrap
 (
-	void *context,
 	OM_uint32 *minor_status,
 	gss_ctx_id_t context_handle,
 	gss_buffer_t input_message_buffer,
 	gss_buffer_t output_message_buffer,
 	int *conf_state,
-	int *qop_state
+	gss_qop_t *qop_state
 );
 
-OM_uint32 spnego_gss_seal
+OM_uint32 spnego_gss_wrap
 (
-	void *context,
 	OM_uint32 *minor_status,
 	gss_ctx_id_t context_handle,
 	int conf_req_flag,
-	int qop_req,
+	gss_qop_t qop_req,
 	gss_buffer_t input_message_buffer,
 	int *conf_state,
 	gss_buffer_t output_message_buffer
@@ -255,7 +365,6 @@
 
 OM_uint32 spnego_gss_process_context_token
 (
-	void *context,
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	const gss_buffer_t token_buffer
@@ -263,7 +372,15 @@
 
 OM_uint32 spnego_gss_delete_sec_context
 (
-	void *context,
+	OM_uint32 *minor_status,
+	gss_ctx_id_t *context_handle,
+	gss_buffer_t output_token
+);
+
+OM_uint32 glue_spnego_gss_delete_sec_context
+(
+	void *,
+
 	OM_uint32 *minor_status,
 	gss_ctx_id_t *context_handle,
 	gss_buffer_t output_token
@@ -271,15 +388,29 @@
 
 OM_uint32 spnego_gss_context_time
 (
-	void *context,
+	OM_uint32	*minor_status,
+	const gss_ctx_id_t context_handle,
+	OM_uint32	*time_rec
+);
+OM_uint32 glue_spnego_gss_context_time
+(
+	void *,
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	OM_uint32	*time_rec
 );
 
+#ifndef LEAN_CLIENT
 OM_uint32 spnego_gss_export_sec_context
 (
-	void *context,
+	OM_uint32	*minor_status,
+	gss_ctx_id_t	*context_handle,
+	gss_buffer_t	interprocess_token
+);
+
+OM_uint32 glue_spnego_gss_export_sec_context
+(
+	void *,
 	OM_uint32	*minor_status,
 	gss_ctx_id_t	*context_handle,
 	gss_buffer_t	interprocess_token
@@ -287,15 +418,22 @@
 
 OM_uint32 spnego_gss_import_sec_context
 (
-	void			*context,
 	OM_uint32		*minor_status,
 	const gss_buffer_t	interprocess_token,
 	gss_ctx_id_t		*context_handle
 );
+OM_uint32 glue_spnego_gss_import_sec_context
+(
+	void *,
+	OM_uint32		*minor_status,
+	const gss_buffer_t	interprocess_token,
+	gss_ctx_id_t		*context_handle
+);
+#endif /* LEAN_CLIENT */
 
-OM_uint32 spnego_gss_inquire_context
+OM_uint32 glue_spnego_gss_inquire_context
 (
-	void		*context,
+	void *,
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	gss_name_t	*src_name,
@@ -304,12 +442,35 @@
 	gss_OID		*mech_type,
 	OM_uint32	*ctx_flags,
 	int		*locally_initiated,
-	int		*open
+	int		*opened
+);
+
+OM_uint32 spnego_gss_inquire_context
+(
+	OM_uint32	*minor_status,
+	const gss_ctx_id_t context_handle,
+	gss_name_t	*src_name,
+	gss_name_t	*targ_name,
+	OM_uint32	*lifetime_rec,
+	gss_OID		*mech_type,
+	OM_uint32	*ctx_flags,
+	int		*locally_initiated,
+	int		*opened
 );
 
 OM_uint32 spnego_gss_wrap_size_limit
 (
-	void		*context,
+	OM_uint32	*minor_status,
+	const gss_ctx_id_t context_handle,
+	int		conf_req_flag,
+	gss_qop_t	qop_req,
+	OM_uint32	req_output_size,
+	OM_uint32	*max_input_size
+);
+
+OM_uint32 glue_spnego_gss_wrap_size_limit
+(
+	void *,
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	int		conf_req_flag,
@@ -318,37 +479,105 @@
 	OM_uint32	*max_input_size
 );
 
-OM_uint32 spnego_gss_sign
+OM_uint32 spnego_gss_get_mic
 (
-	void *context,
 	OM_uint32 *minor_status,
 	const gss_ctx_id_t context_handle,
-	int  qop_req,
+	gss_qop_t qop_req,
 	const gss_buffer_t message_buffer,
 	gss_buffer_t message_token
 );
 
-OM_uint32 spnego_gss_verify
+OM_uint32 spnego_gss_verify_mic
 (
-	void *context,
 	OM_uint32 *minor_status,
 	const gss_ctx_id_t context_handle,
 	const gss_buffer_t msg_buffer,
 	const gss_buffer_t token_buffer,
-	int *qop_state
+	gss_qop_t *qop_state
+);
+
+OM_uint32
+spnego_gss_inquire_sec_context_by_oid
+(
+	OM_uint32 *minor_status,
+	const gss_ctx_id_t context_handle,
+	const gss_OID desired_object,
+	gss_buffer_set_t *data_set
+);
+
+
+#ifdef _GSS_STATIC_LINK
+int gss_spnegoint_lib_init(void);
+void gss_spnegoint_lib_fini(void);
+#else
+gss_mechanism KRB5_CALLCONV gss_mech_initialize(void);
+#endif /* _GSS_STATIC_LINK */
+
+#if 0 /* SUNW17PACresync - will be needed for full MIT 1.7 resync */
+OM_uint32 spnego_gss_wrap_aead
+(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	int conf_req_flag,
+	gss_qop_t qop_req,
+	gss_buffer_t input_assoc_buffer,
+	gss_buffer_t input_payload_buffer,
+	int *conf_state,
+	gss_buffer_t output_message_buffer
 );
 
-OM_uint32 spnego_gss_inquire_cred
+OM_uint32 spnego_gss_unwrap_aead
 (
-	void *context,
 	OM_uint32 *minor_status,
-	const gss_cred_id_t cred_handle,
-	gss_name_t  *name,
-	OM_uint32 *lifetime,
-	gss_cred_usage_t *cred_usage,
-	gss_OID_set *mechanisms
+	gss_ctx_id_t context_handle,
+	gss_buffer_t input_message_buffer,
+	gss_buffer_t input_assoc_buffer,
+	gss_buffer_t output_payload_buffer,
+	int *conf_state,
+	gss_qop_t *qop_state
+);
+
+OM_uint32 spnego_gss_wrap_iov
+(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	int conf_req_flag,
+	gss_qop_t qop_req,
+	int *conf_state,
+	gss_iov_buffer_desc *iov,
+	int iov_count
 );
 
+OM_uint32 spnego_gss_unwrap_iov
+(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	int *conf_state,
+	gss_qop_t *qop_state,
+	gss_iov_buffer_desc *iov,
+	int iov_count
+);
+
+OM_uint32 spnego_gss_wrap_iov_length
+(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	int conf_req_flag,
+	gss_qop_t qop_req,
+	int *conf_state,
+	gss_iov_buffer_desc *iov,
+	int iov_count
+);
+
+OM_uint32
+spnego_gss_complete_auth_token
+(
+	OM_uint32 *minor_status,
+	const gss_ctx_id_t context_handle,
+	gss_buffer_t input_message_buffer
+);
+#endif /* 0 */
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,23 +1,28 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
+ * Copyright (C) 2006,2008 by the Massachusetts Institute of Technology.
+ * All rights reserved.
  *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
  *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -27,131 +32,322 @@
  * peers using the GSS-API.
  *
  */
-
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* #pragma ident	"@(#)spnego_mech.c	1.7	04/09/28 SMI" */
+
+#include	<sys/param.h>
+#include	<unistd.h>
+#include	<assert.h>
 #include	<stdio.h>
 #include	<stdlib.h>
-#include	<errno.h>
+#include	<string.h>
+#include	<k5-int.h>
+#include	<krb5.h>
+
+/*
+ * SUNW17PACresync
+ * MIT Kerb has phased out the context arg (1st one) of the functions
+ * of struct gss_config, Solaris is not there yet and all mechs
+ * will need to be changed at same time to do this cleanly.
+ * Till then, we set this def to effect mechglueP.h.
+ * Revisit for full 1.7 resync.
+ */
+#define	GSSCONFIG_NO_CTXARG
+#include	<mglueP.h>
+#undef GSSCONFIG_NO_CTXARG
+
 #include	"gssapiP_spnego.h"
-#include	<mechglueP.h>
 #include	<gssapi_err_generic.h>
-#include	<rpc/types.h>
-#include	<libintl.h>
+
+
+/*
+ * SUNW17PACresync
+ * MIT has diff names for these GSS utilities.  Solaris needs to change
+ * them globally to get in sync w/MIT.
+ * Revisit for full 1.7 resync.
+ */
+#define gssint_get_modOptions __gss_get_modOptions
+#define gssint_der_length_size der_length_size
+#define gssint_get_der_length get_der_length
+#define gssint_put_der_length put_der_length
+#define gssint_get_mechanism __gss_get_mechanism
+#define gssint_copy_oid_set gss_copy_oid_set
+#define gssint_get_mech_type __gss_get_mech_type
+
+
+#undef g_token_size
+#undef g_verify_token_header
+#undef g_make_token_header
+
+#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)
+typedef const gss_OID_desc *gss_OID_const;
 
 /* der routines defined in libgss */
-extern unsigned int der_length_size(OM_uint32);
-extern int get_der_length(unsigned char **, OM_uint32, unsigned int*);
-extern int put_der_length(OM_uint32, unsigned char **, unsigned int);
+extern unsigned int gssint_der_length_size(OM_uint32);
+extern int gssint_get_der_length(unsigned char **, OM_uint32, OM_uint32*);
+extern int gssint_put_der_length(OM_uint32, unsigned char **, OM_uint32);
+
 
 /* private routines for spnego_mechanism */
 static spnego_token_t make_spnego_token(char *);
 static gss_buffer_desc make_err_msg(char *);
-static int g_token_size(gss_OID, OM_uint32);
-static int g_make_token_header(gss_OID, int, uchar_t **, int);
-static int g_verify_token_header(gss_OID, int *, uchar_t **, int, int);
-static int g_verify_neg_token_init(uchar_t **, int);
-static OM_uint32 get_negResult(unsigned char **, int);
-static gss_OID get_mech_oid(OM_uint32 *, uchar_t **, size_t);
-static gss_buffer_t get_input_token(unsigned char **, int);
-static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, int);
-static OM_uint32 get_req_flags(uchar_t **, int *, OM_uint32 *);
+static int g_token_size(gss_OID_const, unsigned int);
+static int g_make_token_header(gss_OID_const, unsigned int,
+			       unsigned char **, unsigned int);
+static int g_verify_token_header(gss_OID_const, unsigned int *,
+				 unsigned char **,
+				 int, unsigned int);
+static int g_verify_neg_token_init(unsigned char **, unsigned int);
+static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);
+static gss_buffer_t get_input_token(unsigned char **, unsigned int);
+static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);
+static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
 static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t,
 	gss_cred_usage_t, gss_cred_id_t *, gss_OID_set *);
 static void release_spnego_ctx(spnego_gss_ctx_id_t *);
 static void check_spnego_options(spnego_gss_ctx_id_t);
 static spnego_gss_ctx_id_t create_spnego_ctx(void);
-static int put_mech_set(uchar_t **, gss_OID_set, int);
-static int put_input_token(uchar_t **, gss_buffer_t, int);
-static int put_mech_oid(uchar_t **, gss_OID_desc *, int);
-static int put_negResult(uchar_t **, OM_uint32, int);
+static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);
+static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);
+static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);
+static int put_negResult(unsigned char **, OM_uint32, unsigned int);
+
+static OM_uint32
+process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
+	    gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
+	   gss_buffer_t *, OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+init_ctx_new(OM_uint32 *, gss_cred_id_t, gss_ctx_id_t *,
+	     gss_OID_set *, send_token_flag *);
+static OM_uint32
+init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
+	      gss_buffer_t *, gss_buffer_t *,
+	      OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
+	      gss_buffer_t *, gss_buffer_t *,
+	      OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
+		  gss_OID, gss_buffer_t *, gss_buffer_t *,
+		  OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+		   gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+		   gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
+		   OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+	    gss_cred_id_t, gss_buffer_t *,
+	    gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_cont(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+	     gss_buffer_t *, gss_buffer_t *,
+	     OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
+		OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+		 gss_buffer_t, gss_OID *, gss_buffer_t,
+		 OM_uint32 *, OM_uint32 *, gss_cred_id_t *,
+		 OM_uint32 *, send_token_flag *);
 
 static gss_OID
 negotiate_mech_type(OM_uint32 *, gss_OID_set, gss_OID_set,
-		OM_uint32 *, bool_t *);
+		OM_uint32 *);
 static int
 g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *);
 
 static int
-make_spnego_tokenInit_msg(spnego_gss_ctx_id_t, gss_OID_set,
-			gss_buffer_t, send_token_flag,
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t,
+			int,
+			gss_buffer_t,
+			OM_uint32, gss_buffer_t, send_token_flag,
 			gss_buffer_t);
 static int
 make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
-			gss_buffer_t, send_token_flag, int,
+			gss_buffer_t, send_token_flag,
 			gss_buffer_t);
 
+static OM_uint32
+get_negTokenInit(OM_uint32 *, gss_buffer_t, gss_buffer_t,
+		 gss_OID_set *, OM_uint32 *, gss_buffer_t *,
+		 gss_buffer_t *);
+static OM_uint32
+get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
+		 OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);
+
+static int
+is_kerb_mech(gss_OID oid);
+
+/* SPNEGO oid structure */
+static const gss_OID_desc spnego_oids[] = {
+	{SPNEGO_OID_LENGTH, SPNEGO_OID},
+};
+
+const gss_OID_desc * const gss_mech_spnego = spnego_oids+0;
+static const gss_OID_set_desc spnego_oidsets[] = {
+	{1, (gss_OID) spnego_oids+0},
+};
+const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
+
+static int make_NegHints(OM_uint32 *, gss_cred_id_t, gss_buffer_t *);
+static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
+static OM_uint32
+acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, gss_cred_id_t,
+	      gss_buffer_t *, OM_uint32 *, send_token_flag *);
+
+
 /*
  * The Mech OID for SPNEGO:
  * { iso(1) org(3) dod(6) internet(1) security(5)
  *  mechanism(5) spnego(2) }
  */
 static struct gss_config spnego_mechanism =
-{{SPNEGO_OID_LENGTH, SPNEGO_OID},
+{
+	{SPNEGO_OID_LENGTH, SPNEGO_OID},
 	NULL,
-	spnego_gss_acquire_cred,
-	spnego_gss_release_cred,
-	spnego_gss_init_sec_context,
-	spnego_gss_accept_sec_context,
-/* EXPORT DELETE START */ /* CRYPT DELETE START */
-	spnego_gss_unseal,		/* gss_unseal */
-/* EXPORT DELETE END */ /* CRYPT DELETE END */
+	glue_spnego_gss_acquire_cred,
+	glue_spnego_gss_release_cred,
+	glue_spnego_gss_init_sec_context,
+#ifndef LEAN_CLIENT
+	glue_spnego_gss_accept_sec_context,
+#else
+	NULL,				
+#endif  /* LEAN_CLIENT */
+	NULL,  /* unseal */
 	NULL,				/* gss_process_context_token */
-	spnego_gss_delete_sec_context,	/* gss_delete_sec_context */
-	spnego_gss_context_time,	/* gss_context_time */
-	spnego_gss_display_status,
+	glue_spnego_gss_delete_sec_context,	/* gss_delete_sec_context */
+	NULL,	/* gss_context_time - SUNW17PACresync make it NULL */
+	glue_spnego_gss_display_status,
 	NULL,				/* gss_indicate_mechs */
-	NULL,				/* gss_compare_name */
-	spnego_gss_display_name,
-	spnego_gss_import_name,
-	spnego_gss_release_name,
-	spnego_gss_inquire_cred,	/* gss_inquire_cred */
+	glue_spnego_gss_compare_name,
+	glue_spnego_gss_display_name,
+	glue_spnego_gss_import_name, /* glue */
+	glue_spnego_gss_release_name,
+	NULL,				/* gss_inquire_cred */
 	NULL,				/* gss_add_cred */
-/* EXPORT DELETE START */ /* CRYPT DELETE START */
-	spnego_gss_seal,		/* gss_seal */
-/* EXPORT DELETE END */ /* CRYPT DELETE END */
-	spnego_gss_export_sec_context,	/* gss_export_sec_context */
-	spnego_gss_import_sec_context,	/* gss_import_sec_context */
+	NULL, /* seal */
+#ifndef LEAN_CLIENT
+	glue_spnego_gss_export_sec_context,	/* gss_export_sec_context */
+	glue_spnego_gss_import_sec_context,	/* gss_import_sec_context */
+#else
+	NULL,				/* gss_export_sec_context */
+	NULL,				/* gss_import_sec_context */
+#endif /* LEAN_CLIENT */
 	NULL, 				/* gss_inquire_cred_by_mech */
-	spnego_gss_inquire_names_for_mech,
-	spnego_gss_inquire_context,	/* gss_inquire_context */
+	glue_spnego_gss_inquire_names_for_mech,
+	NULL,	/* gss_inquire_context - SUNW17PACresync make it NULL */
 	NULL,				/* gss_internal_release_oid */
-	spnego_gss_wrap_size_limit,	/* gss_wrap_size_limit */
-	NULL,				/* gss_pname_to_uid */
-	NULL,				/* __gss_userok */
+	NULL,	/* gss_wrap_size_limit - SUNW17PACresync make it NULL */
+	NULL, /* pname */
+	NULL, /* userok */
 	NULL,				/* gss_export_name */
-/* EXPORT DELETE START */
-/* CRYPT DELETE START */
-#if 0
-/* CRYPT DELETE END */
-	spnego_gss_seal,
-	spnego_gss_unseal,
-/* CRYPT DELETE START */
+	NULL, /* sign */
+	NULL, /* verify */
+	NULL,				/* gss_store_cred */
+        spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
+};
+
+#ifdef _GSS_STATIC_LINK
+#include "mglueP.h"
+
+static int gss_spnegomechglue_init(void)
+{
+	struct gss_mech_config mech_spnego;
+
+	memset(&mech_spnego, 0, sizeof(mech_spnego));
+	mech_spnego.mech = &spnego_mechanism;
+	mech_spnego.mechNameStr = "spnego";
+	mech_spnego.mech_type = GSS_C_NO_OID;
+
+	return gssint_register_mechinfo(&mech_spnego);
+}
+#else
+gss_mechanism KRB5_CALLCONV
+gss_mech_initialize(void)
+{
+	return (&spnego_mechanism);
+}
+
+#if 0 /* SUNW17PACresync */
+MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
+MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
+ int gss_krb5int_lib_init(void)
 #endif
-/* CRYPT DELETE END */
-/* EXPORT DELETE END */
-	spnego_gss_sign,		/* gss_sign */
-	spnego_gss_verify,		/* gss_verify */
-	NULL,				/* gss_store_cred */
-};
-
-gss_mechanism
-gss_mech_initialize(const gss_OID oid)
+
+#endif /* _GSS_STATIC_LINK */
+
+static int gss_spnegoint_lib_init(void)
 {
-	dsyslog("Entering gss_mech_initialize\n");
-
-	if (oid == NULL ||
-	    !g_OID_equal(oid, &spnego_mechanism.mech_type)) {
-		dsyslog("invalid spnego mechanism oid.\n");
-		return (NULL);
-	}
-
-	dsyslog("Leaving gss_mech_initialize\n");
-	return (&spnego_mechanism);
+#ifdef _GSS_STATIC_LINK
+	return gss_spnegomechglue_init();
+#else
+	return 0;
+#endif
+}
+
+static void gss_spnegoint_lib_fini(void)
+{
 }
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_acquire_cred(void *ctx,
-			OM_uint32 *minor_status,
+glue_spnego_gss_acquire_cred(
+	void *context,
+	OM_uint32 *minor_status,
+	gss_name_t desired_name,
+	OM_uint32 time_req,
+	gss_OID_set desired_mechs,
+	gss_cred_usage_t cred_usage,
+	gss_cred_id_t *output_cred_handle,
+	gss_OID_set *actual_mechs,
+	OM_uint32 *time_rec)
+{
+	return(spnego_gss_acquire_cred(minor_status,
+					desired_name,
+					time_req,
+					desired_mechs,
+					cred_usage,
+					output_cred_handle,
+					actual_mechs,
+					time_rec));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_acquire_cred(OM_uint32 *minor_status,
 			gss_name_t desired_name,
 			OM_uint32 time_req,
 			gss_OID_set desired_mechs,
@@ -177,8 +373,8 @@
 	 */
 	if (desired_mechs == GSS_C_NULL_OID_SET) {
 		status = get_available_mechs(minor_status,
-		    desired_name, cred_usage,
-		    output_cred_handle, &amechs);
+				desired_name, cred_usage,
+				output_cred_handle, &amechs);
 	} else {
 		/*
 		 * The caller gave a specific list of mechanisms,
@@ -187,12 +383,14 @@
 		 * which the given 'output_cred_handle' is valid.
 		 */
 		status = gss_acquire_cred(minor_status,
-		    desired_name, time_req, desired_mechs, cred_usage,
-		    output_cred_handle, &amechs, time_rec);
+				desired_name, time_req,
+				desired_mechs, cred_usage,
+				output_cred_handle, &amechs,
+				time_rec);
 	}
 
 	if (actual_mechs && amechs != GSS_C_NULL_OID_SET) {
-		(void) gss_copy_oid_set(minor_status, amechs, actual_mechs);
+		(void) gssint_copy_oid_set(minor_status, amechs, actual_mechs);
 	}
 	(void) gss_release_oid_set(minor_status, &amechs);
 
@@ -202,8 +400,16 @@
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_release_cred(void *ctx,
-			OM_uint32 *minor_status,
+glue_spnego_gss_release_cred(void *context,
+			    OM_uint32 *minor_status,
+			    gss_cred_id_t *cred_handle)
+{
+	return( spnego_gss_release_cred(minor_status, cred_handle));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_cred(OM_uint32 *minor_status,
 			gss_cred_id_t *cred_handle)
 {
 	OM_uint32 status;
@@ -227,14 +433,8 @@
 static void
 check_spnego_options(spnego_gss_ctx_id_t spnego_ctx)
 {
-	spnego_ctx->optionStr = __gss_get_modOptions(
-	    (const gss_OID)&spnego_oids[0]);
-	if (spnego_ctx->optionStr != NULL &&
-	    strstr(spnego_ctx->optionStr, "msinterop")) {
-		spnego_ctx->MS_Interop = 1;
-	} else {
-		spnego_ctx->MS_Interop = 0;
-	}
+	spnego_ctx->optionStr = gssint_get_modOptions(
+		(const gss_OID)&spnego_oids[0]);
 }
 
 static spnego_gss_ctx_id_t
@@ -242,28 +442,502 @@
 {
 	spnego_gss_ctx_id_t spnego_ctx = NULL;
 	spnego_ctx = (spnego_gss_ctx_id_t)
-	    malloc(sizeof (spnego_gss_ctx_id_rec));
+		malloc(sizeof (spnego_gss_ctx_id_rec));
 
 	if (spnego_ctx == NULL) {
 		return (NULL);
 	}
 
+	spnego_ctx->magic_num = SPNEGO_MAGIC_ID;
 	spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
 	spnego_ctx->internal_mech = NULL;
 	spnego_ctx->optionStr = NULL;
-	spnego_ctx->optimistic = 0;
-	spnego_ctx->MS_Interop = 0;
-	spnego_ctx->DER_mechTypes.length = NULL;
-	spnego_ctx->DER_mechTypes.value = GSS_C_NO_BUFFER;
+	spnego_ctx->DER_mechTypes.length = 0;
+	spnego_ctx->DER_mechTypes.value = NULL;
+	spnego_ctx->default_cred = GSS_C_NO_CREDENTIAL;
+	spnego_ctx->mic_reqd = 0;
+	spnego_ctx->mic_sent = 0;
+	spnego_ctx->mic_rcvd = 0;
+	spnego_ctx->mech_complete = 0;
+	spnego_ctx->nego_done = 0;
+	spnego_ctx->internal_name = GSS_C_NO_NAME;
+	spnego_ctx->actual_mech = GSS_C_NO_OID;
 
 	check_spnego_options(spnego_ctx);
 
 	return (spnego_ctx);
 }
 
+/*
+ * Both initiator and acceptor call here to verify and/or create
+ * mechListMIC, and to consistency-check the MIC state.
+ */
+static OM_uint32
+handle_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+	   int send_mechtok, spnego_gss_ctx_id_t sc,
+	   gss_buffer_t *mic_out,
+	   OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret;
+
+	ret = GSS_S_FAILURE;
+	*mic_out = GSS_C_NO_BUFFER;
+	if (mic_in != GSS_C_NO_BUFFER) {
+		if (sc->mic_rcvd) {
+			/* Reject MIC if we've already received a MIC. */
+			*negState = REJECT;
+			*tokflag = ERROR_TOKEN_SEND;
+			return GSS_S_DEFECTIVE_TOKEN;
+		}
+	} else if (sc->mic_reqd && !send_mechtok) {
+		/*
+		 * If the peer sends the final mechanism token, it
+		 * must send the MIC with that token if the
+		 * negotiation requires MICs.
+		 */
+		*negState = REJECT;
+		*tokflag = ERROR_TOKEN_SEND;
+		return GSS_S_DEFECTIVE_TOKEN;
+	}
+	ret = process_mic(minor_status, mic_in, sc, mic_out,
+			  negState, tokflag);
+	if (ret != GSS_S_COMPLETE) {
+		return ret;
+	}
+	if (sc->mic_reqd) {
+		assert(sc->mic_sent || sc->mic_rcvd);
+	}
+	if (sc->mic_sent && sc->mic_rcvd) {
+		ret = GSS_S_COMPLETE;
+		*negState = ACCEPT_COMPLETE;
+		if (*mic_out == GSS_C_NO_BUFFER) {
+			/*
+			 * We sent a MIC on the previous pass; we
+			 * shouldn't be sending a mechanism token.
+			 */
+			assert(!send_mechtok);
+			*tokflag = NO_TOKEN_SEND;
+		} else {
+			*tokflag = CONT_TOKEN_SEND;
+		}
+	} else if (sc->mic_reqd) {
+		*negState = ACCEPT_INCOMPLETE;
+		ret = GSS_S_CONTINUE_NEEDED;
+	} else if (*negState == ACCEPT_COMPLETE) {
+		ret = GSS_S_COMPLETE;
+	} else {
+		ret = GSS_S_CONTINUE_NEEDED;
+	}
+	return ret;
+}
+
+/*
+ * Perform the actual verification and/or generation of mechListMIC.
+ */
+static OM_uint32
+process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+	    spnego_gss_ctx_id_t sc, gss_buffer_t *mic_out,
+	    OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret, tmpmin;
+	gss_qop_t qop_state;
+	gss_buffer_desc tmpmic = GSS_C_EMPTY_BUFFER;
+
+	ret = GSS_S_FAILURE;
+	if (mic_in != GSS_C_NO_BUFFER) {
+		ret = gss_verify_mic(minor_status, sc->ctx_handle,
+				     &sc->DER_mechTypes,
+				     mic_in, &qop_state);
+		if (ret != GSS_S_COMPLETE) {
+			*negState = REJECT;
+			*tokflag = ERROR_TOKEN_SEND;
+			return ret;
+		}
+		/* If we got a MIC, we must send a MIC. */
+		sc->mic_reqd = 1;
+		sc->mic_rcvd = 1;
+	}
+	if (sc->mic_reqd && !sc->mic_sent) {
+		ret = gss_get_mic(minor_status, sc->ctx_handle,
+				  GSS_C_QOP_DEFAULT,
+				  &sc->DER_mechTypes,
+				  &tmpmic);
+		if (ret != GSS_S_COMPLETE) {
+			gss_release_buffer(&tmpmin, &tmpmic);
+			*tokflag = NO_TOKEN_SEND;
+			return ret;
+		}
+		*mic_out = malloc(sizeof(gss_buffer_desc));
+		if (*mic_out == GSS_C_NO_BUFFER) {
+			gss_release_buffer(&tmpmin, &tmpmic);
+			*tokflag = NO_TOKEN_SEND;
+			return GSS_S_FAILURE;
+		}
+		**mic_out = tmpmic;
+		sc->mic_sent = 1;
+	}
+	return GSS_S_COMPLETE;
+}
+
+/*
+ * Initial call to spnego_gss_init_sec_context().
+ */
+static OM_uint32
+init_ctx_new(OM_uint32 *minor_status,
+	     gss_cred_id_t cred,
+	     gss_ctx_id_t *ctx,
+	     gss_OID_set *mechSet,
+	     send_token_flag *tokflag)
+{
+	OM_uint32 ret, tmpmin;
+	gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+	spnego_gss_ctx_id_t sc = NULL;
+
+	/* determine negotiation mech set */
+	if (cred == GSS_C_NO_CREDENTIAL) {
+		ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+					  GSS_C_INITIATE, &creds, mechSet);
+		gss_release_cred(&tmpmin, &creds);
+	} else {
+		/*
+		 * Use the list of mechs included in the cred that we
+		 * were given.
+		 */
+		ret = gss_inquire_cred(minor_status, cred,
+				       NULL, NULL, NULL, mechSet);
+	}
+	if (ret != GSS_S_COMPLETE)
+		return ret;
+
+	sc = create_spnego_ctx();
+	if (sc == NULL)
+		return GSS_S_FAILURE;
+
+	/*
+	 * need to pull the first mech from mechSet to do first
+	 * gss_init_sec_context()
+	 */
+	ret = generic_gss_copy_oid(minor_status, (*mechSet)->elements,
+				   &sc->internal_mech);
+	if (ret != GSS_S_COMPLETE) {
+	    map_errcode(minor_status);
+	    goto cleanup;
+	}
+
+	if (put_mech_set(*mechSet, &sc->DER_mechTypes) < 0) {
+		generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+		ret = GSS_S_FAILURE;
+		goto cleanup;
+	}
+	/*
+	 * The actual context is not yet determined, set the output
+	 * context handle to refer to the spnego context itself.
+	 */
+	sc->ctx_handle = GSS_C_NO_CONTEXT;
+	*ctx = (gss_ctx_id_t)sc;
+	*tokflag = INIT_TOKEN_SEND;
+	ret = GSS_S_CONTINUE_NEEDED;
+
+cleanup:
+	gss_release_oid_set(&tmpmin, mechSet);
+	return ret;
+}
+
+/*
+ * Called by second and later calls to spnego_gss_init_sec_context()
+ * to decode reply and update state.
+ */
+static OM_uint32
+init_ctx_cont(OM_uint32 *minor_status, gss_ctx_id_t *ctx, gss_buffer_t buf,
+	      gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+	      OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret, tmpmin, acc_negState;
+	unsigned char *ptr;
+	spnego_gss_ctx_id_t sc;
+	gss_OID supportedMech = GSS_C_NO_OID;
+
+	sc = (spnego_gss_ctx_id_t)*ctx;
+	*negState = REJECT;
+	*tokflag = ERROR_TOKEN_SEND;
+
+	ptr = buf->value;
+	ret = get_negTokenResp(minor_status, ptr, buf->length,
+			       &acc_negState, &supportedMech,
+			       responseToken, mechListMIC);
+	if (ret != GSS_S_COMPLETE)
+		goto cleanup;
+	if (acc_negState == ACCEPT_DEFECTIVE_TOKEN &&
+	    supportedMech == GSS_C_NO_OID &&
+	    *responseToken == GSS_C_NO_BUFFER &&
+	    *mechListMIC == GSS_C_NO_BUFFER) {
+		/* Reject "empty" token. */
+		ret = GSS_S_DEFECTIVE_TOKEN;
+	}
+	if (acc_negState == REJECT) {
+		*minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+		map_errcode(minor_status);
+		*tokflag = NO_TOKEN_SEND;
+		ret = GSS_S_FAILURE;
+		goto cleanup;
+	}
+	/*
+	 * nego_done is false for the first call to init_ctx_cont()
+	 */
+	if (!sc->nego_done) {
+		ret = init_ctx_nego(minor_status, sc,
+				    acc_negState,
+				    supportedMech, responseToken,
+				    mechListMIC,
+				    negState, tokflag);
+	} else if (!sc->mech_complete &&
+		   *responseToken == GSS_C_NO_BUFFER) {
+		/*
+		 * mech not finished and mech token missing
+		 */
+		ret = GSS_S_DEFECTIVE_TOKEN;
+	} else if (sc->mic_reqd &&
+		   (sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+		*negState = ACCEPT_INCOMPLETE;
+		*tokflag = CONT_TOKEN_SEND;
+		ret = GSS_S_CONTINUE_NEEDED;
+	} else {
+		*negState = ACCEPT_COMPLETE;
+		*tokflag = NO_TOKEN_SEND;
+		ret = GSS_S_COMPLETE;
+	}
+cleanup:
+	if (supportedMech != GSS_C_NO_OID)
+		generic_gss_release_oid(&tmpmin, &supportedMech);
+	return ret;
+}
+
+/*
+ * Consistency checking and mechanism negotiation handling for second
+ * call of spnego_gss_init_sec_context().  Call init_ctx_reselect() to
+ * update internal state if acceptor has counter-proposed.
+ */
+static OM_uint32
+init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+	      OM_uint32 acc_negState, gss_OID supportedMech,
+	      gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+	      OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret;
+
+	*negState = REJECT;
+	*tokflag = ERROR_TOKEN_SEND;
+	ret = GSS_S_DEFECTIVE_TOKEN;
+	/*
+	 * Both supportedMech and negState must be present in first
+	 * acceptor token.
+	 */
+	if (supportedMech == GSS_C_NO_OID) {
+		*minor_status = ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR;
+		map_errcode(minor_status);
+		return GSS_S_DEFECTIVE_TOKEN;
+	}
+	if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) {
+		*minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+		map_errcode(minor_status);
+		return GSS_S_DEFECTIVE_TOKEN;
+	}
+
+	/*
+	 * If the mechanism we sent is not the mechanism returned from
+	 * the server, we need to handle the server's counter
+	 * proposal.  There is a bug in SAMBA servers that always send
+	 * the old Kerberos mech OID, even though we sent the new one.
+	 * So we will treat all the Kerberos mech OIDS as the same.
+         */
+	if (!(is_kerb_mech(supportedMech) &&
+	      is_kerb_mech(sc->internal_mech)) &&
+	    !g_OID_equal(supportedMech, sc->internal_mech)) {
+		ret = init_ctx_reselect(minor_status, sc,
+					acc_negState, supportedMech,
+					responseToken, mechListMIC,
+					negState, tokflag);
+
+	} else if (*responseToken == GSS_C_NO_BUFFER) {
+		if (sc->mech_complete) {
+			/*
+			 * Mech completed on first call to its
+			 * init_sec_context().  Acceptor sends no mech
+			 * token.
+			 */
+			*negState = ACCEPT_COMPLETE;
+			*tokflag = NO_TOKEN_SEND;
+			ret = GSS_S_COMPLETE;
+		} else {
+			/*
+			 * Reject missing mech token when optimistic
+			 * mech selected.
+			 */
+			*minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR;
+			map_errcode(minor_status);
+			ret = GSS_S_DEFECTIVE_TOKEN;
+		}
+	} else if (sc->mech_complete) {
+		/* Reject spurious mech token. */
+		ret = GSS_S_DEFECTIVE_TOKEN;
+	} else {
+		*negState = ACCEPT_INCOMPLETE;
+		*tokflag = CONT_TOKEN_SEND;
+		ret = GSS_S_CONTINUE_NEEDED;
+	}
+	sc->nego_done = 1;
+	return ret;
+}
+
+/*
+ * Handle acceptor's counter-proposal of an alternative mechanism.
+ */
+static OM_uint32
+init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+		  OM_uint32 acc_negState, gss_OID supportedMech,
+		  gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+		  OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret, tmpmin;
+
+	generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+	gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+			       GSS_C_NO_BUFFER);
+
+	ret = generic_gss_copy_oid(minor_status, supportedMech,
+				   &sc->internal_mech);
+	if (ret != GSS_S_COMPLETE) {
+		map_errcode(minor_status);
+		sc->internal_mech = GSS_C_NO_OID;
+		*tokflag = NO_TOKEN_SEND;
+		return ret;
+	}
+	if (*responseToken != GSS_C_NO_BUFFER) {
+		/* Reject spurious mech token. */
+		return GSS_S_DEFECTIVE_TOKEN;
+	}
+	/*
+	 * Windows 2003 and earlier don't correctly send a
+	 * negState of request-mic when counter-proposing a
+	 * mechanism.  They probably don't handle mechListMICs
+	 * properly either.
+	 */
+	if (acc_negState != REQUEST_MIC)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	sc->mech_complete = 0;
+	sc->mic_reqd = 1;
+	*negState = REQUEST_MIC;
+	*tokflag = CONT_TOKEN_SEND;
+	return GSS_S_CONTINUE_NEEDED;
+}
+
+/*
+ * Wrap call to mechanism gss_init_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+init_ctx_call_init(OM_uint32 *minor_status,
+		   spnego_gss_ctx_id_t sc,
+		   gss_cred_id_t claimant_cred_handle,
+		   gss_name_t target_name,
+		   OM_uint32 req_flags,
+		   OM_uint32 time_req,
+		   gss_buffer_t mechtok_in,
+		   gss_OID *actual_mech,
+		   gss_buffer_t mechtok_out,
+		   OM_uint32 *ret_flags,
+		   OM_uint32 *time_rec,
+		   OM_uint32 *negState,
+		   send_token_flag *send_token)
+{
+	OM_uint32 ret;
+
+	ret = gss_init_sec_context(minor_status,
+				   claimant_cred_handle,
+				   &sc->ctx_handle,
+				   target_name,
+				   sc->internal_mech,
+				   (req_flags | GSS_C_INTEG_FLAG),
+				   time_req,
+				   GSS_C_NO_CHANNEL_BINDINGS,
+				   mechtok_in,
+				   &sc->actual_mech,
+				   mechtok_out,
+				   &sc->ctx_flags,
+				   time_rec);
+	if (ret == GSS_S_COMPLETE) {
+		sc->mech_complete = 1;
+		if (ret_flags != NULL)
+			*ret_flags = sc->ctx_flags;
+		/*
+		 * If this isn't the first time we've been called,
+		 * we're done unless a MIC needs to be
+		 * generated/handled.
+		 */
+		if (*send_token == CONT_TOKEN_SEND &&
+		    mechtok_out->length == 0 &&
+		    (!sc->mic_reqd ||
+		     !(sc->ctx_flags & GSS_C_INTEG_FLAG))) {
+
+			*negState = ACCEPT_COMPLETE;
+			ret = GSS_S_COMPLETE;
+			if (mechtok_out->length == 0) {
+				*send_token = NO_TOKEN_SEND;
+			}
+		} else {
+			*negState = ACCEPT_INCOMPLETE;
+			ret = GSS_S_CONTINUE_NEEDED;
+		}
+	} else if (ret != GSS_S_CONTINUE_NEEDED) {
+		if (*send_token == INIT_TOKEN_SEND) {
+			/* Don't output token on error if first call. */
+			*send_token = NO_TOKEN_SEND;
+		} else {
+			*send_token = ERROR_TOKEN_SEND;
+		}
+		*negState = REJECT;
+	}
+	return ret;
+}
+
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_init_sec_context(void *ct,
+glue_spnego_gss_init_sec_context(
+	void *context,
+	OM_uint32 *minor_status,
+	gss_cred_id_t claimant_cred_handle,
+	gss_ctx_id_t *context_handle,
+	gss_name_t target_name,
+	gss_OID mech_type,
+	OM_uint32 req_flags,
+	OM_uint32 time_req,
+	gss_channel_bindings_t input_chan_bindings,
+	gss_buffer_t input_token,
+	gss_OID *actual_mech,
+	gss_buffer_t output_token,
+	OM_uint32 *ret_flags,
+	OM_uint32 *time_rec)
+{
+	return(spnego_gss_init_sec_context(
+		    minor_status,
+		    claimant_cred_handle,
+		    context_handle,
+		    target_name,
+		    mech_type,
+		    req_flags,
+		    time_req,
+		    input_chan_bindings,
+		    input_token,
+		    actual_mech,
+		    output_token,
+		    ret_flags,
+		    time_rec));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_init_sec_context(
 			OM_uint32 *minor_status,
 			gss_cred_id_t claimant_cred_handle,
 			gss_ctx_id_t *context_handle,
@@ -278,11 +952,6 @@
 			OM_uint32 *ret_flags,
 			OM_uint32 *time_rec)
 {
-	OM_uint32 ret = 0;
-	OM_uint32 status = 0;
-	OM_uint32 mstat;
-	OM_uint32 local_ret_flags = 0;
-
 	/*
 	 * send_token is used to indicate in later steps
 	 * what type of token, if any should be sent or processed.
@@ -292,394 +961,681 @@
 	 * CHECK_MIC = no token to be sent, but have a MIC to check.
 	 */
 	send_token_flag send_token = NO_TOKEN_SEND;
-
-	gss_OID_set mechSet;
+	OM_uint32 tmpmin, ret, negState;
+	gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
+	gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+	gss_OID_set mechSet = GSS_C_NO_OID_SET;
 	spnego_gss_ctx_id_t spnego_ctx = NULL;
-	gss_buffer_t i_output_token = GSS_C_NO_BUFFER;
-	gss_buffer_t i_input_token = GSS_C_NO_BUFFER;
-	gss_buffer_t mechListMIC = NULL;
-	gss_cred_id_t *credlistptr = NULL, credlist;
-	gss_qop_t *qop_state = NULL;
-	unsigned char *ptr;
-	unsigned int len;
 
 	dsyslog("Entering init_sec_context\n");
 
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	*minor_status = 0;
-	output_token->length = 0;
-	output_token->value = NULL;
-
-	if (actual_mech)
-		*actual_mech = NULL;
+	mechtok_in = mechListMIC_out = mechListMIC_in = GSS_C_NO_BUFFER;
+	negState = REJECT;
+
+	if (minor_status != NULL)
+		*minor_status = 0;
+	if (output_token != GSS_C_NO_BUFFER) {
+		output_token->length = 0;
+		output_token->value = NULL;
+	}
+	if (minor_status == NULL ||
+	    output_token == GSS_C_NO_BUFFER ||
+	    context_handle == NULL)
+		return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+	if (actual_mech != NULL)
+		*actual_mech = GSS_C_NO_OID;
 
 	if (*context_handle == GSS_C_NO_CONTEXT) {
-
-		/* determine negotiation mech set */
-		if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
-			credlistptr = &credlist;
-
-			mstat = get_available_mechs(minor_status,
-			    GSS_C_NO_NAME, GSS_C_INITIATE,
-			    credlistptr, &mechSet);
-		} else {
-			/*
-			 * Use the list of mechs included in the
-			 * cred that we were given.
-			 */
-			mstat = gss_inquire_cred(minor_status,
-			    claimant_cred_handle, NULL, NULL,
-			    NULL, &mechSet);
+		ret = init_ctx_new(minor_status, claimant_cred_handle,
+				   context_handle, &mechSet, &send_token);
+		if (ret != GSS_S_CONTINUE_NEEDED) {
+			goto cleanup;
 		}
-		if (mstat != GSS_S_COMPLETE)
-			return (mstat);
-
-		if ((spnego_ctx = create_spnego_ctx()) == NULL) {
-			ret = GSS_S_FAILURE;
+	} else {
+		ret = init_ctx_cont(minor_status, context_handle,
+				    input_token, &mechtok_in,
+				    &mechListMIC_in, &negState, &send_token);
+		if (HARD_ERROR(ret)) {
 			goto cleanup;
 		}
-
+	}
+	spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
+	if (!spnego_ctx->mech_complete) {
+		ret = init_ctx_call_init(
+			minor_status, spnego_ctx,
+			claimant_cred_handle,
+			target_name, req_flags,
+			time_req, mechtok_in,
+			actual_mech, &mechtok_out,
+			ret_flags, time_rec,
+			&negState, &send_token);
+	}
+	/* create mic/check mic */
+	if (!HARD_ERROR(ret) && spnego_ctx->mech_complete &&
+	    (spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+		ret = handle_mic(minor_status,
+				 mechListMIC_in,
+				 (mechtok_out.length != 0),
+				 spnego_ctx, &mechListMIC_out,
+				 &negState, &send_token);
+	}
+cleanup:
+	if (send_token == INIT_TOKEN_SEND) {
+		if (make_spnego_tokenInit_msg(spnego_ctx,
+					      0,
+					      mechListMIC_out,
+					      req_flags,
+					      &mechtok_out, send_token,
+					      output_token) < 0) {
+			ret = GSS_S_FAILURE;
+		}
+	} else if (send_token != NO_TOKEN_SEND) {
+		if (make_spnego_tokenTarg_msg(negState, GSS_C_NO_OID,
+					      &mechtok_out, mechListMIC_out,
+					      send_token,
+					      output_token) < 0) {
+			ret = GSS_S_FAILURE;
+		}
+	}
+	gss_release_buffer(&tmpmin, &mechtok_out);
+	if (ret == GSS_S_COMPLETE) {
 		/*
-		 * need to pull the first mech from mechSet to do first
-		 * init ctx
+		 * Now, switch the output context to refer to the
+		 * negotiated mechanism's context.
 		 */
-		status = generic_gss_copy_oid(minor_status,
-		    mechSet->elements, &spnego_ctx->internal_mech);
-
-		if (status != GSS_S_COMPLETE) {
-			ret = GSS_S_FAILURE;
-			goto cleanup;
+		*context_handle = (gss_ctx_id_t)spnego_ctx->ctx_handle;
+		if (actual_mech != NULL)
+			*actual_mech = spnego_ctx->actual_mech;
+		if (ret_flags != NULL)
+			*ret_flags = spnego_ctx->ctx_flags;
+		release_spnego_ctx(&spnego_ctx);
+	} else if (ret != GSS_S_CONTINUE_NEEDED) {
+		if (spnego_ctx != NULL) {
+			gss_delete_sec_context(&tmpmin,
+					       &spnego_ctx->ctx_handle,
+					       GSS_C_NO_BUFFER);
+			release_spnego_ctx(&spnego_ctx);
+		}
+		*context_handle = GSS_C_NO_CONTEXT;
+	}
+	if (mechtok_in != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mechtok_in);
+		free(mechtok_in);
+	}
+	if (mechListMIC_in != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mechListMIC_in);
+		free(mechListMIC_in);
+	}
+	if (mechListMIC_out != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mechListMIC_out);
+		free(mechListMIC_out);
+	}
+	if (mechSet != GSS_C_NO_OID_SET) {
+		gss_release_oid_set(&tmpmin, &mechSet);
+	}
+	return ret;
+} /* init_sec_context */
+
+/* We don't want to import KRB5 headers here */
+static const gss_OID_desc gss_mech_krb5_oid =
+	{ 9, "\052\206\110\206\367\022\001\002\002" };
+static const gss_OID_desc gss_mech_krb5_wrong_oid =
+	{ 9, "\052\206\110\202\367\022\001\002\002" };
+
+/*
+ * verify that the input token length is not 0. If it is, just return.
+ * If the token length is greater than 0, der encode as a sequence
+ * and place in buf_out, advancing buf_out.
+ */
+
+static int
+put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token,
+	      unsigned int buflen)
+{
+	int ret;
+
+	/* if token length is 0, we do not want to send */
+	if (input_token->length == 0)
+		return (0);
+
+	if (input_token->length > buflen)
+		return (-1);
+
+	*(*buf_out)++ = SEQUENCE;
+	if ((ret = gssint_put_der_length(input_token->length, buf_out,
+			    input_token->length)))
+		return (ret);
+	TWRITE_STR(*buf_out, input_token->value, input_token->length);
+	return (0);
+}
+
+/*
+ * NegHints ::= SEQUENCE {
+ *    hintName       [0]  GeneralString      OPTIONAL,
+ *    hintAddress    [1]  OCTET STRING       OPTIONAL
+ * }
+ */
+
+#define HOST_PREFIX	"host@"
+#define HOST_PREFIX_LEN	(sizeof(HOST_PREFIX) - 1)
+
+static int
+make_NegHints(OM_uint32 *minor_status,
+	      gss_cred_id_t cred, gss_buffer_t *outbuf)
+{
+	gss_buffer_desc hintNameBuf;
+	gss_name_t hintName = GSS_C_NO_NAME;
+	gss_name_t hintKerberosName;
+	gss_OID hintNameType;
+	OM_uint32 major_status;
+	OM_uint32 minor;
+	unsigned int tlen = 0;
+	unsigned int hintNameSize = 0;
+	unsigned int negHintsSize = 0;
+	unsigned char *ptr;
+	unsigned char *t;
+
+	*outbuf = GSS_C_NO_BUFFER;
+
+	if (cred != GSS_C_NO_CREDENTIAL) {
+		major_status = gss_inquire_cred(minor_status,
+						cred,
+						&hintName,
+						NULL,
+						NULL,
+						NULL);
+		if (major_status != GSS_S_COMPLETE)
+			return (major_status);
+	}
+
+	if (hintName == GSS_C_NO_NAME) {
+		krb5_error_code code;
+		krb5int_access kaccess;
+		char hostname[HOST_PREFIX_LEN + MAXHOSTNAMELEN + 1] = HOST_PREFIX;
+
+		code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION);
+		if (code != 0) {
+			*minor_status = code;
+			return (GSS_S_FAILURE);
 		}
 
-		if (input_token != NULL && input_token->value != NULL) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
+		/* this breaks mutual authentication but Samba relies on it */
+		code = (*kaccess.clean_hostname)(NULL, NULL,
+						 &hostname[HOST_PREFIX_LEN],
+						 MAXHOSTNAMELEN);
+		if (code != 0) {
+			*minor_status = code;
+			return (GSS_S_FAILURE);
+		}
+
+		major_status = gss_import_name(minor_status,
+					       &hintNameBuf,
+					       GSS_C_NT_HOSTBASED_SERVICE,
+					       &hintName);
+		if (major_status != GSS_S_COMPLETE) {
+			return (major_status);
+		}
+	}
+
+	hintNameBuf.value = NULL;
+	hintNameBuf.length = 0;
+
+	major_status = gss_canonicalize_name(minor_status,
+					     hintName,
+					     (gss_OID)&gss_mech_krb5_oid,
+					     &hintKerberosName);
+	if (major_status != GSS_S_COMPLETE) {
+		gss_release_name(&minor, &hintName);
+		return (major_status);
+	}
+	gss_release_name(&minor, &hintName);
+
+	major_status = gss_display_name(minor_status,
+					hintKerberosName,
+					&hintNameBuf,
+					&hintNameType);
+	if (major_status != GSS_S_COMPLETE) {
+		gss_release_name(&minor, &hintName);
+		return (major_status);
+	}
+	gss_release_name(&minor, &hintKerberosName);
+
+	/*
+	 * Now encode the name hint into a NegHints ASN.1 type
+	 */
+	major_status = GSS_S_FAILURE;
+
+	/* Length of DER encoded GeneralString */
+	tlen = 1 + gssint_der_length_size(hintNameBuf.length) +
+		hintNameBuf.length;
+	hintNameSize = tlen;
+
+	/* Length of DER encoded hintName */
+	tlen += 1 + gssint_der_length_size(hintNameSize);
+	negHintsSize = tlen;
+
+	t = (unsigned char *)malloc(tlen);
+	if (t == NULL) {
+		*minor_status = ENOMEM;
+		goto errout;
+	}
+
+	ptr = t;
+
+	*ptr++ = CONTEXT | 0x00; /* hintName identifier */
+	if (gssint_put_der_length(hintNameSize,
+				  &ptr, tlen - (int)(ptr-t)))
+		goto errout;
+
+	*ptr++ = GENERAL_STRING;
+	if (gssint_put_der_length(hintNameBuf.length,
+				  &ptr, tlen - (int)(ptr-t)))
+		goto errout;
+
+	memcpy(ptr, hintNameBuf.value, hintNameBuf.length);
+	ptr += hintNameBuf.length;
+
+	*outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc));
+	if (*outbuf == NULL) {
+		*minor_status = ENOMEM;
+		goto errout;
+	}
+	(*outbuf)->value = (void *)t;
+	(*outbuf)->length = ptr - t;
+
+	t = NULL; /* don't free */
+
+	*minor_status = 0;
+	major_status = GSS_S_COMPLETE;
+
+errout:
+	if (t != NULL) {
+		free(t);
+	}
+
+	gss_release_buffer(&minor, &hintNameBuf);
+	return (major_status);
+}
+
+static OM_uint32
+acc_ctx_hints(OM_uint32 *minor_status,
+	      gss_ctx_id_t *ctx,
+	      gss_cred_id_t cred,
+	      gss_buffer_t *mechListMIC,
+	      OM_uint32 *negState,
+	      send_token_flag *return_token)
+{
+	OM_uint32 tmpmin, ret;
+	gss_OID_set supported_mechSet;
+	spnego_gss_ctx_id_t sc = NULL;
+
+	*mechListMIC = GSS_C_NO_BUFFER;
+	supported_mechSet = GSS_C_NO_OID_SET;
+	*return_token = ERROR_TOKEN_SEND;
+	*negState = REJECT;
+	*minor_status = 0;
+
+	*ctx = GSS_C_NO_CONTEXT;
+	ret = GSS_S_DEFECTIVE_TOKEN;
+
+	if (cred != GSS_C_NO_CREDENTIAL) {
+		ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
+				       NULL, &supported_mechSet);
+		if (ret != GSS_S_COMPLETE) {
+			*return_token = NO_TOKEN_SEND;
 			goto cleanup;
 		}
-
-		/*
-		 * The actual context is not yet determined,
-		 * set the output context_handle to refer to
-		 * the spnego context itself.
-		 */
-		spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
-		*context_handle = (gss_ctx_id_t)spnego_ctx;
-		send_token = INIT_TOKEN_SEND;
-		ret = GSS_S_CONTINUE_NEEDED;
 	} else {
-		mechSet = NULL;
-		spnego_ctx = (spnego_gss_ctx_id_t)(*context_handle);
-
-		if (input_token == NULL || input_token->value == NULL) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
+		ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+					  GSS_C_ACCEPT, NULL,
+					  &supported_mechSet);
+		if (ret != GSS_S_COMPLETE) {
+			*return_token = NO_TOKEN_SEND;
 			goto cleanup;
 		}
-		ptr = (unsigned char *) input_token->value;
-
-		switch (get_negResult(&ptr, input_token->length)) {
-		case ACCEPT_DEFECTIVE_TOKEN:
-			*minor_status = 1;
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			break;
-		case ACCEPT_INCOMPLETE: {
-			/* pull out mech from token */
-			gss_OID internal_mech =
-			    get_mech_oid(minor_status, &ptr,
-			    input_token->length -
-			    (ptr - (uchar_t *)input_token->value));
-
-			/*
-			 * check if first mech in neg set, if it isn't,
-			 * release and copy chosen mech to context,
-			 * delete internal context from prior mech
-			 */
-			if (internal_mech != NULL &&
-			    ((internal_mech->length !=
-			    spnego_ctx->internal_mech->length) ||
-			    /* CSTYLED */
-			    memcmp(spnego_ctx->internal_mech->elements,
-			    internal_mech->elements,
-			    spnego_ctx->internal_mech->length))) {
-
-				(void) gss_delete_sec_context(&mstat,
-				    &spnego_ctx->ctx_handle, NULL);
-
-				spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
-				(void) generic_gss_release_oid(
-				    &mstat, &spnego_ctx->internal_mech);
-
-				status = generic_gss_copy_oid(
-				    minor_status, internal_mech,
-				    &spnego_ctx->internal_mech);
-
-				if (status != GSS_S_COMPLETE)
-					ret = GSS_S_DEFECTIVE_TOKEN;
-				else
-					ret = GSS_S_COMPLETE;
-
-				(void) generic_gss_release_oid(&mstat,
-				    &internal_mech);
-			} else if (internal_mech == NULL) {
-				ret = GSS_S_DEFECTIVE_TOKEN;
-				send_token = NO_TOKEN_SEND;
-			} else {
-				ret = GSS_S_COMPLETE;
-			}
-			if (ret == GSS_S_COMPLETE) {
-				/*
-				 * Check for a token, it may contain
-				 * an error message.
-				 */
-				if (*ptr ==  (CONTEXT | 0x02)) {
-					if (g_get_tag_and_length(&ptr,
-					    (CONTEXT | 0x02),
-					    input_token->length - (ptr -
-					    (uchar_t *)input_token->value),
-					    &len) < 0) {
-						ret = GSS_S_DEFECTIVE_TOKEN;
-					} else {
-						i_input_token = get_input_token(
-						    &ptr, len);
-						if (i_input_token  != NULL) {
-							/*CSTYLED*/
-							ret = GSS_S_CONTINUE_NEEDED;
-							send_token =
-							    CONT_TOKEN_SEND;
-						} else {
-							/*CSTYLED*/
-							ret = GSS_S_DEFECTIVE_TOKEN;
-							send_token =
-							    NO_TOKEN_SEND;
-						}
-					}
-				}
-			}
-			break;
+	}
+
+	ret = make_NegHints(minor_status, cred, mechListMIC);
+	if (ret != GSS_S_COMPLETE) {
+		*return_token = NO_TOKEN_SEND;
+		goto cleanup;
+	}
+
+	/*
+	 * Select the best match between the list of mechs
+	 * that the initiator requested and the list that
+	 * the acceptor will support.
+	 */
+	sc = create_spnego_ctx();
+	if (sc == NULL) {
+		ret = GSS_S_FAILURE;
+		*return_token = NO_TOKEN_SEND;
+		goto cleanup;
+	}
+	if (put_mech_set(supported_mechSet, &sc->DER_mechTypes) < 0) {
+		ret = GSS_S_FAILURE;
+		*return_token = NO_TOKEN_SEND;
+		goto cleanup;
+	}
+	sc->internal_mech = GSS_C_NO_OID;
+
+	*negState = ACCEPT_INCOMPLETE;
+	*return_token = INIT_TOKEN_SEND;
+	sc->firstpass = 1;
+	*ctx = (gss_ctx_id_t)sc;
+	ret = GSS_S_COMPLETE;
+
+cleanup:
+	gss_release_oid_set(&tmpmin, &supported_mechSet);
+	return ret;
+}
+
+/*
+ * Set negState to REJECT if the token is defective, else
+ * ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's
+ * preferred mechanism is supported.
+ */
+static OM_uint32
+acc_ctx_new(OM_uint32 *minor_status,
+	    gss_buffer_t buf,
+	    gss_ctx_id_t *ctx,
+	    gss_cred_id_t cred,
+	    gss_buffer_t *mechToken,
+	    gss_buffer_t *mechListMIC,
+	    OM_uint32 *negState,
+	    send_token_flag *return_token)
+{
+	OM_uint32 tmpmin, ret, req_flags;
+	gss_OID_set supported_mechSet, mechTypes;
+	gss_buffer_desc der_mechTypes;
+	gss_OID mech_wanted;
+	spnego_gss_ctx_id_t sc = NULL;
+
+	*ctx = GSS_C_NO_CONTEXT;
+
+	ret = GSS_S_DEFECTIVE_TOKEN;
+	der_mechTypes.length = 0;
+	der_mechTypes.value = NULL;
+	*mechToken = *mechListMIC = GSS_C_NO_BUFFER;
+	supported_mechSet = mechTypes = GSS_C_NO_OID_SET;
+	*return_token = ERROR_TOKEN_SEND;
+	*negState = REJECT;
+	*minor_status = 0;
+
+	ret = get_negTokenInit(minor_status, buf, &der_mechTypes,
+			       &mechTypes, &req_flags,
+			       mechToken, mechListMIC);
+	if (ret != GSS_S_COMPLETE) {
+		goto cleanup;
+	}
+	if (cred != GSS_C_NO_CREDENTIAL) {
+		ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
+				       NULL, &supported_mechSet);
+		if (ret != GSS_S_COMPLETE) {
+			*return_token = NO_TOKEN_SEND;
+			goto cleanup;
 		}
-		case ACCEPT_COMPLETE:
-			/* pull out mech from token */
-			if (spnego_ctx->internal_mech != NULL)
-				(void) generic_gss_release_oid(&mstat,
-				    &spnego_ctx->internal_mech);
-
-			spnego_ctx->internal_mech =
-			    get_mech_oid(minor_status, &ptr,
-			    input_token->length -
-			    (ptr - (uchar_t *)input_token->value));
-
-			if (spnego_ctx->internal_mech == NULL) {
-				/* CSTYLED */
-				*minor_status = ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR;
-				ret = GSS_S_FAILURE;
-			}
-
-			if (ret != GSS_S_FAILURE && *ptr == (CONTEXT | 0x02)) {
-				if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
-				    input_token->length - (ptr -
-				    (uchar_t *)input_token->value), &len) < 0) {
-					ret = GSS_S_DEFECTIVE_TOKEN;
-				} else {
-					i_input_token = get_input_token(&ptr,
-					    len);
-					if (i_input_token  != NULL) {
-						ret = GSS_S_COMPLETE;
-						send_token = CHECK_MIC;
-					} else {
-						ret = GSS_S_DEFECTIVE_TOKEN;
-						send_token = NO_TOKEN_SEND;
-					}
-				}
-			} else if (ret == GSS_S_CONTINUE_NEEDED ||
-			    ret == GSS_S_COMPLETE) {
-				send_token = CHECK_MIC;
-			}
-
-			/*
-			 * If we sent "optimistic" initial token,
-			 * but the acceptor did not send a response token,
-			 * this is an error.
-			 */
-			if (ret == GSS_S_COMPLETE &&
-			    i_input_token == GSS_C_NO_BUFFER &&
-			    spnego_ctx->last_status == GSS_S_CONTINUE_NEEDED &&
-			    spnego_ctx->optimistic) {
-				/* CSTYLED */
-				*minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR;
-				ret = GSS_S_DEFECTIVE_TOKEN;
-				send_token = NO_TOKEN_SEND;
-			}
-
-			if (send_token != NO_TOKEN_SEND) {
-				if (i_input_token == NULL)
-					ret = GSS_S_COMPLETE;
-				else
-					ret = GSS_S_CONTINUE_NEEDED;
-				send_token = CHECK_MIC;
-			}
-			break;
-
-		case REJECT:
-			ret = GSS_S_BAD_MECH;
-			*minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
-			send_token = NO_TOKEN_SEND;
-			break;
-
-		default:
-			ret = GSS_S_FAILURE;
-			send_token = NO_TOKEN_SEND;
-			break;
+	} else {
+		ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+					  GSS_C_ACCEPT, NULL,
+					  &supported_mechSet);
+		if (ret != GSS_S_COMPLETE) {
+			*return_token = NO_TOKEN_SEND;
+			goto cleanup;
 		}
 	}
-
-
-	if (send_token == NO_TOKEN_SEND) {
-		output_token->length = 0;
-		output_token->value = NULL;
+	/*
+	 * Select the best match between the list of mechs
+	 * that the initiator requested and the list that
+	 * the acceptor will support.
+	 */
+	mech_wanted = negotiate_mech_type(minor_status,
+					  supported_mechSet,
+					  mechTypes,
+					  negState);
+	if (*negState == REJECT) {
+		ret = GSS_S_BAD_MECH;
+		goto cleanup;
+	}
+	sc = (spnego_gss_ctx_id_t)*ctx;
+	if (sc != NULL) {
+		gss_release_buffer(&tmpmin, &sc->DER_mechTypes);
+		assert(mech_wanted != GSS_C_NO_OID);
+	} else
+		sc = create_spnego_ctx();
+	if (sc == NULL) {
+		ret = GSS_S_FAILURE;
+		*return_token = NO_TOKEN_SEND;
+		generic_gss_release_oid(&tmpmin, &mech_wanted);
 		goto cleanup;
 	}
-
-	i_output_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
-
-	if (i_output_token == NULL) {
-		ret = status = GSS_S_FAILURE;
+	sc->internal_mech = mech_wanted;
+	sc->DER_mechTypes = der_mechTypes;
+	der_mechTypes.length = 0;
+	der_mechTypes.value = NULL;
+
+	if (*negState == REQUEST_MIC)
+		sc->mic_reqd = 1;
+
+	*return_token = INIT_TOKEN_SEND;
+	sc->firstpass = 1;
+	*ctx = (gss_ctx_id_t)sc;
+	ret = GSS_S_COMPLETE;
+cleanup:
+	gss_release_oid_set(&tmpmin, &mechTypes);
+	gss_release_oid_set(&tmpmin, &supported_mechSet);
+	if (der_mechTypes.length != 0)
+		gss_release_buffer(&tmpmin, &der_mechTypes);
+	return ret;
+}
+
+static OM_uint32
+acc_ctx_cont(OM_uint32 *minstat,
+	     gss_buffer_t buf,
+	     gss_ctx_id_t *ctx,
+	     gss_buffer_t *responseToken,
+	     gss_buffer_t *mechListMIC,
+	     OM_uint32 *negState,
+	     send_token_flag *return_token)
+{
+	OM_uint32 ret, tmpmin;
+	gss_OID supportedMech;
+	spnego_gss_ctx_id_t sc;
+	unsigned int len;
+	unsigned char *ptr, *bufstart;
+
+	sc = (spnego_gss_ctx_id_t)*ctx;
+	ret = GSS_S_DEFECTIVE_TOKEN;
+	*negState = REJECT;
+	*minstat = 0;
+	supportedMech = GSS_C_NO_OID;
+	*return_token = ERROR_TOKEN_SEND;
+	*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+
+	ptr = bufstart = buf->value;
+#define REMAIN (buf->length - (ptr - bufstart))
+	if (REMAIN > INT_MAX)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	/*
+	 * Attempt to work with old Sun SPNEGO.
+	 */
+	if (*ptr == HEADER_ID) {
+		ret = g_verify_token_header(gss_mech_spnego,
+					    &len, &ptr, 0, REMAIN);
+		if (ret) {
+			*minstat = ret;
+			return GSS_S_DEFECTIVE_TOKEN;
+		}
+	}
+	if (*ptr != (CONTEXT | 0x01)) {
+		return GSS_S_DEFECTIVE_TOKEN;
+	}
+	ret = get_negTokenResp(minstat, ptr, REMAIN,
+			       negState, &supportedMech,
+			       responseToken, mechListMIC);
+	if (ret != GSS_S_COMPLETE)
+		goto cleanup;
+
+	if (*responseToken == GSS_C_NO_BUFFER &&
+	    *mechListMIC == GSS_C_NO_BUFFER) {
+
+		ret = GSS_S_DEFECTIVE_TOKEN;
+		goto cleanup;
+	}
+	if (supportedMech != GSS_C_NO_OID) {
+		ret = GSS_S_DEFECTIVE_TOKEN;
 		goto cleanup;
 	}
-
-	i_output_token->length = 0;
-	i_output_token->value = NULL;
-
-	if (ret == GSS_S_CONTINUE_NEEDED) {
-		gss_OID inner_mech_type = GSS_C_NO_OID;
-
-		status = gss_init_sec_context(minor_status,
-		    claimant_cred_handle,
-		    &spnego_ctx->ctx_handle,
-		    target_name,
-		    spnego_ctx->internal_mech,
-		    req_flags,
-		    time_req,
-		    NULL,
-		    i_input_token,
-		    &inner_mech_type,
-		    i_output_token,
-		    &local_ret_flags,
-		    time_rec);
-
-		if (ret_flags)
-			*ret_flags = local_ret_flags;
-
-		spnego_ctx->last_status = status;
-
-		if (i_input_token != GSS_C_NO_BUFFER) {
-			(void) gss_release_buffer(&mstat, i_input_token);
-			free(i_input_token);
-		}
-
-		if ((status != GSS_S_COMPLETE) &&
-		    (status != GSS_S_CONTINUE_NEEDED)) {
-			ret = status;
+	sc->firstpass = 0;
+	*negState = ACCEPT_INCOMPLETE;
+	*return_token = CONT_TOKEN_SEND;
+cleanup:
+	if (supportedMech != GSS_C_NO_OID) {
+		generic_gss_release_oid(&tmpmin, &supportedMech);
+	}
+	return ret;
+#undef REMAIN
+}
+
+/*
+ * Verify that mech OID is either exactly the same as the negotiated
+ * mech OID, or is a mech OID supported by the negotiated mech.  MS
+ * implementations can list a most preferred mech using an incorrect
+ * krb5 OID while emitting a krb5 initiator mech token having the
+ * correct krb5 mech OID.
+ */
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *minor_status,
+		spnego_gss_ctx_id_t sc, gss_OID mechoid,
+		OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret, tmpmin;
+	gss_mechanism mech = NULL;
+	gss_OID_set mech_set = GSS_C_NO_OID_SET;
+	int present = 0;
+
+	if (g_OID_equal(sc->internal_mech, mechoid))
+		return GSS_S_COMPLETE;
+
+	/*
+	 * SUNW17PACresync
+	 * If both mechs are kerb, we are done.
+	 */
+	if (is_kerb_mech(mechoid) && is_kerb_mech(sc->internal_mech)) {
+		return GSS_S_COMPLETE;
+	}
+
+	mech = gssint_get_mechanism(mechoid);
+	if (mech == NULL || mech->gss_indicate_mechs == NULL) {
+		*minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+		map_errcode(minor_status);
+		*negState = REJECT;
+		*tokflag = ERROR_TOKEN_SEND;
+		return GSS_S_BAD_MECH;
+	}
+	ret = mech->gss_indicate_mechs(mech->context, minor_status, &mech_set);
+	if (ret != GSS_S_COMPLETE) {
+		*tokflag = NO_TOKEN_SEND;
+		map_error(minor_status, mech);
+		goto cleanup;
+	}
+	ret = gss_test_oid_set_member(minor_status, sc->internal_mech,
+				      mech_set, &present);
+	if (ret != GSS_S_COMPLETE)
+		goto cleanup;
+	if (!present) {
+		*minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+		map_errcode(minor_status);
+		*negState = REJECT;
+		*tokflag = ERROR_TOKEN_SEND;
+		ret = GSS_S_BAD_MECH;
+	}
+cleanup:
+	gss_release_oid_set(&tmpmin, &mech_set);
+	return ret;
+}
+#ifndef LEAN_CLIENT
+/*
+ * Wrap call to gss_accept_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+		 gss_cred_id_t cred, gss_buffer_t mechtok_in,
+		 gss_OID *mech_type, gss_buffer_t mechtok_out,
+		 OM_uint32 *ret_flags, OM_uint32 *time_rec,
+		 gss_cred_id_t *delegated_cred_handle,
+		 OM_uint32 *negState, send_token_flag *tokflag)
+{
+	OM_uint32 ret;
+	gss_OID_desc mechoid;
+
+	if (sc->ctx_handle == GSS_C_NO_CONTEXT) {
+		/*
+		 * mechoid is an alias; don't free it.
+		 */
+		ret = gssint_get_mech_type(&mechoid, mechtok_in);
+		if (ret != GSS_S_COMPLETE) {
+			*tokflag = NO_TOKEN_SEND;
+			return ret;
 		}
-
-		/* create mic/check mic */
-		if ((i_output_token->length == 0) &&
-		    (status == GSS_S_COMPLETE) &&
-		    (local_ret_flags & GSS_C_INTEG_FLAG)) {
-			if (*ptr == (CONTEXT | 0x03)) {
-				if (g_get_tag_and_length(&ptr,
-				    (CONTEXT | 0x03), input_token->length -
-				    (ptr - (uchar_t *)input_token->value),
-				    &len) < 0) {
-					ret = GSS_S_DEFECTIVE_TOKEN;
-				} else {
-					ret = GSS_S_COMPLETE;
-					mechListMIC = get_input_token(&ptr,
-					    len);
-					if (mechListMIC == NULL)
-						ret = GSS_S_DEFECTIVE_TOKEN;
-					else if (!spnego_ctx->MS_Interop &&
-					    spnego_ctx->DER_mechTypes.length >
-					    0) {
-						status = gss_verify_mic(
-						    minor_status,
-						    spnego_ctx->ctx_handle,
-						    &spnego_ctx->DER_mechTypes,
-						    mechListMIC, qop_state);
-					}
-				}
-			} else if (!spnego_ctx->MS_Interop) {
-			/*
-			 * If no MIC was sent and we are in
-			 * "standard" mode (i.e. NOT MS_Interop),
-			 * the MIC must be present.
-			 */
-				ret = GSS_S_DEFECTIVE_TOKEN;
-			} else {
-				/* In "MS_Interop" mode, MIC is ignored. */
-				ret = GSS_S_COMPLETE;
-			}
-		}
+		ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid,
+				      negState, tokflag);
+		if (ret != GSS_S_COMPLETE)
+			return ret;
 	}
 
-	if ((status == GSS_S_COMPLETE) &&
-	    (ret == GSS_S_COMPLETE)) {
-		if (actual_mech) {
-			(void) generic_gss_release_oid(&mstat, actual_mech);
-			ret = generic_gss_copy_oid(&mstat,
-			    spnego_ctx->internal_mech, actual_mech);
-			if (ret != GSS_S_COMPLETE)
-				goto cleanup;
+	ret = gss_accept_sec_context(minor_status,
+				     &sc->ctx_handle,
+				     cred,
+				     mechtok_in,
+				     GSS_C_NO_CHANNEL_BINDINGS,
+				     &sc->internal_name,
+				     mech_type,
+				     mechtok_out,
+				     &sc->ctx_flags,
+				     time_rec,
+				     delegated_cred_handle);
+
+	if (ret == GSS_S_COMPLETE) {
+#ifdef MS_BUG_TEST
+		/*
+		 * Force MIC to be not required even if we previously
+		 * requested a MIC.
+		 */
+		char *envstr = getenv("MS_FORCE_NO_MIC");
+
+		if (envstr != NULL && strcmp(envstr, "1") == 0 &&
+		    !(sc->ctx_flags & GSS_C_MUTUAL_FLAG) &&
+		    sc->mic_reqd) {
+
+			sc->mic_reqd = 0;
 		}
-
-	} else if (ret == GSS_S_CONTINUE_NEEDED) {
-		if (make_spnego_tokenInit_msg(spnego_ctx,
-		    mechSet, i_output_token, send_token,
-		    output_token) < 0) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
+#endif
+		sc->mech_complete = 1;
+		if (ret_flags != NULL)
+			*ret_flags = sc->ctx_flags;
+
+		if (!sc->mic_reqd) {
+			*negState = ACCEPT_COMPLETE;
+			ret = GSS_S_COMPLETE;
+		} else {
+			ret = GSS_S_CONTINUE_NEEDED;
 		}
+	} else if (ret != GSS_S_CONTINUE_NEEDED) {
+		*negState = REJECT;
+		*tokflag = ERROR_TOKEN_SEND;
 	}
-
-cleanup:
-	if (status != GSS_S_COMPLETE)
-		ret = status;
-	if (ret != GSS_S_COMPLETE &&
-	    ret != GSS_S_CONTINUE_NEEDED) {
-		if (spnego_ctx != NULL &&
-		    spnego_ctx->ctx_handle != NULL)
-			gss_delete_sec_context(&mstat, &spnego_ctx->ctx_handle,
-			    GSS_C_NO_BUFFER);
-
-		if (spnego_ctx != NULL)
-			release_spnego_ctx(&spnego_ctx);
-
-		*context_handle = GSS_C_NO_CONTEXT;
-
-		if (output_token)
-			(void) gss_release_buffer(&mstat, output_token);
-	}
-
-	if (i_output_token != GSS_C_NO_BUFFER) {
-		(void) gss_release_buffer(&mstat, i_output_token);
-		free(i_output_token);
-	}
-
-	if (mechListMIC != GSS_C_NO_BUFFER) {
-		(void) gss_release_buffer(&mstat, mechListMIC);
-		free(mechListMIC);
-	}
-
-	if (mechSet != NULL)
-		(void) gss_release_oid_set(&mstat, &mechSet);
-
-	if (credlistptr != NULL)
-		(void) gss_release_cred(&mstat, credlistptr);
-
-	return (ret);
-} /* init_sec_context */
+	return ret;
+}
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_accept_sec_context(void *ct,
+glue_spnego_gss_accept_sec_context(
+			    void *context,
 			    OM_uint32 *minor_status,
 			    gss_ctx_id_t *context_handle,
 			    gss_cred_id_t verifier_cred_handle,
@@ -692,403 +1648,188 @@
 			    OM_uint32 *time_rec,
 			    gss_cred_id_t *delegated_cred_handle)
 {
-	spnego_gss_ctx_id_t spnego_ctx = NULL;
-	gss_OID mech_wanted = NULL;
-	gss_OID_set mechSet = GSS_C_NO_OID_SET;
-	gss_OID_set supported_mechSet = GSS_C_NO_OID_SET;
-	gss_buffer_t i_output_token = GSS_C_NO_BUFFER;
-	gss_buffer_t i_input_token = GSS_C_NO_BUFFER;
-	gss_buffer_t mechListMIC = GSS_C_NO_BUFFER;
-	gss_cred_id_t acquired_cred = NULL;
-	gss_name_t internal_name = GSS_C_NO_NAME;
-	OM_uint32 status = GSS_S_COMPLETE;
-	OM_uint32 ret = GSS_S_COMPLETE;
-	unsigned char *ptr;
-	unsigned char *bufstart;
-	int bodysize;
-	int err;
-	unsigned int len;
-	OM_uint32 negResult;
-	OM_uint32 minor_stat;
-	OM_uint32 mstat;
-	OM_uint32 req_flags;
-	OM_uint32 mechsetlen;
-	gss_qop_t qop_state;
-	send_token_flag return_token =  NO_TOKEN_SEND;
-	bool_t firstMech;
-	bool_t Need_Cred = FALSE;
-	OM_uint32 local_ret_flags = 0;
-	uchar_t *buf, *tmp;
-
-	dsyslog("Entering accept_sec_context\n");
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	if (src_name)
-		*src_name = (gss_name_t)NULL;
-
-	output_token->length = 0;
-	output_token->value = NULL;
-	*minor_status = 0;
-
-	if (mech_type)
-		*mech_type = GSS_C_NULL_OID;
-
-	/* return a bogus cred handle */
-	if (delegated_cred_handle)
-		*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
-
-	if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
-		Need_Cred = TRUE;
-	}
-
-	/* Check for defective input token. */
-	ptr = bufstart = (unsigned char *) input_token->value;
-	if (err = g_verify_token_header((gss_OID)gss_mech_spnego, &bodysize,
-	    &ptr, 0, input_token->length)) {
-		*minor_status = err;
-		ret = GSS_S_DEFECTIVE_TOKEN;
-		negResult = REJECT;
-		return_token = ERROR_TOKEN_SEND;
-		goto senderror;
-	}
-
-	/*
-	 * set up of context, determine mech to be used, save mechset
-	 * for use later in integrety check.
-	 */
-	if (*context_handle == GSS_C_NO_CONTEXT) {
-		if ((spnego_ctx = create_spnego_ctx()) == NULL)
-			return (GSS_S_FAILURE);
-
-		/*
-		 * Until the accept operation is complete, the
-		 * context_handle returned should refer to
-		 * the spnego context.
-		 */
-		*context_handle = (gss_ctx_id_t)spnego_ctx;
-		minor_stat = get_available_mechs(minor_status,
-		    GSS_C_NO_NAME, GSS_C_ACCEPT,
-		    NULL, &supported_mechSet);
-
-		if (minor_stat != GSS_S_COMPLETE) {
-			release_spnego_ctx(&spnego_ctx);
-			*context_handle = GSS_C_NO_CONTEXT;
-			return (minor_stat);
-		}
-
-		if (Need_Cred) {
-			minor_stat = gss_acquire_cred(minor_status,
-			    GSS_C_NO_NAME, NULL, supported_mechSet,
-			    GSS_C_ACCEPT, &acquired_cred, NULL,
-			    NULL);
-
-			if (minor_stat != GSS_S_COMPLETE) {
-				(void) gss_release_oid_set(minor_status,
-				    &supported_mechSet);
-				release_spnego_ctx(&spnego_ctx);
-				*context_handle = GSS_C_NO_CONTEXT;
-				return (minor_stat);
-			} else {
-				verifier_cred_handle = acquired_cred;
-			}
-		}
-
-		if (err = g_verify_neg_token_init(&ptr, input_token->length)) {
-			*minor_status = err;
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			negResult = REJECT;
-			return_token = ERROR_TOKEN_SEND;
-			goto senderror;
-		}
-
-		/*
-		 * Allocate space to hold the mechTypes
-		 * because we need it later.
-		 */
-		mechsetlen = input_token->length - (ptr - bufstart);
-		buf = (uchar_t *)malloc(mechsetlen);
-		if (buf == NULL) {
-			ret = GSS_S_FAILURE;
-			goto cleanup;
-		}
-		(void) memcpy(buf, ptr, mechsetlen);
-		ptr = bufstart = buf;
-
-		/*
-		 * Get pointers to the DER encoded MechSet so we
-		 * can properly check and calculate a MIC later.
-		 */
-		spnego_ctx->DER_mechTypes.value = ptr;
-		mechSet = get_mech_set(minor_status, &ptr, mechsetlen);
-		if (mechSet == NULL) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			negResult = REJECT;
-			return_token = ERROR_TOKEN_SEND;
-			goto senderror;
-		}
-		spnego_ctx->DER_mechTypes.length = ptr - bufstart;
-		mechsetlen -= (ptr - bufstart);
-
-		/*
-		 * Select the best match between the list of mechs
-		 * that the initiator requested and the list that
-		 * the acceptor will support.
-		 */
-		mech_wanted = negotiate_mech_type(minor_status,
-		    supported_mechSet, mechSet, &negResult,
-		    &firstMech);
-
-		(void) gss_release_oid_set(&minor_stat, &supported_mechSet);
-		(void) gss_release_oid_set(&minor_stat, &mechSet);
-		supported_mechSet = NULL;
-		mechSet = NULL;
-
-		if (get_req_flags(&ptr, (int *)&mechsetlen, &req_flags) ==
-		    ACCEPT_DEFECTIVE_TOKEN) {
-			negResult = REJECT;
-		}
-
-		tmp = ptr;
-		if (negResult == ACCEPT_COMPLETE) {
-			if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
-			    mechsetlen, &len) < 0) {
-				negResult = REJECT;
-			} else {
-				i_input_token = get_input_token(&ptr, len);
-				if (i_input_token == NULL) {
-					negResult = REJECT;
-				}
-			}
-			return_token = INIT_TOKEN_SEND;
-		}
-		if (negResult == REJECT) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			return_token = ERROR_TOKEN_SEND;
-		} else {
-			ret = GSS_S_CONTINUE_NEEDED;
-			return_token = INIT_TOKEN_SEND;
-		}
-
-		mechsetlen -= ptr - tmp;
-		/*
-		 * Check to see if there is a MechListMIC field
-		 */
-		if (negResult == ACCEPT_COMPLETE && mechsetlen > 0) {
-			tmp = ptr;
-			if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
-			    mechsetlen, &len) >= 0) {
-				mechListMIC = get_input_token(&ptr, len);
-				if (mechListMIC == GSS_C_NO_BUFFER) {
-					negResult = REJECT;
-					return_token = ERROR_TOKEN_SEND;
-					ret = GSS_S_DEFECTIVE_TOKEN;
-				}
-				mechsetlen -= (ptr - tmp);
-			}
-		}
-	} else {
-		/*
-		 * get internal input token and context for continued
-		 * calls of spnego_gss_init_sec_context.
-		 */
-		i_input_token = get_input_token(&ptr,
-		    input_token->length - (ptr -
-		    (uchar_t *)input_token->value));
-		if (i_input_token == NULL) {
-			negResult = REJECT;
-			return_token = ERROR_TOKEN_SEND;
-			ret = GSS_S_DEFECTIVE_TOKEN;
-		} else {
-			spnego_ctx = (spnego_gss_ctx_id_t)(*context_handle);
-			return_token = CONT_TOKEN_SEND;
-		}
-	}
-
-	/*
-	 * If we still don't have a cred, we have an error.
-	 */
-	if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
-		ret = GSS_S_FAILURE;
-		goto cleanup;
-	}
-
-	/* If we have an error already, bail out */
-	if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED)
-		goto senderror;
-
-	if (i_input_token != GSS_C_NO_BUFFER) {
-		i_output_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
-
-		if (i_output_token == NULL) {
-			ret = GSS_S_FAILURE;
-			goto cleanup;
-		}
-
-		i_output_token->length = 0;
-		i_output_token->value = NULL;
-
-		status = gss_accept_sec_context(&minor_stat,
-		    &spnego_ctx->ctx_handle, verifier_cred_handle,
-		    i_input_token, GSS_C_NO_CHANNEL_BINDINGS,
-		    &internal_name, mech_type, i_output_token,
-		    &local_ret_flags, time_rec, delegated_cred_handle);
-
-		if ((status != GSS_S_COMPLETE) &&
-		    (status != GSS_S_CONTINUE_NEEDED)) {
-			*minor_status = minor_stat;
-			(void) gss_release_buffer(&mstat, i_input_token);
-
-			if (i_input_token != GSS_C_NO_BUFFER) {
-				free(i_input_token);
-				i_input_token = GSS_C_NO_BUFFER;
-			}
-
-			ret = status;
-
-			/*
-			 * Reject the request with an error token.
-			 */
-			negResult = REJECT;
-			return_token = ERROR_TOKEN_SEND;
-
-			goto senderror;
-		}
-
-		if (ret_flags)
-			*ret_flags = local_ret_flags;
-
-		if (i_input_token != GSS_C_NO_BUFFER) {
-			(void) gss_release_buffer(&mstat, i_input_token);
-			free(i_input_token);
-			i_input_token = GSS_C_NO_BUFFER;
-		}
-
-		/* If we got a MIC, verify it if possible */
-		if ((status == GSS_S_COMPLETE) &&
-		    (local_ret_flags & GSS_C_INTEG_FLAG) &&
-		    mechListMIC != GSS_C_NO_BUFFER &&
-		    !spnego_ctx->MS_Interop) {
-
-			ret = gss_verify_mic(minor_status,
-			    spnego_ctx->ctx_handle,
-			    &spnego_ctx->DER_mechTypes,
-			    mechListMIC, &qop_state);
-
-			(void) gss_release_buffer(&mstat, mechListMIC);
-			free(mechListMIC);
-			mechListMIC = GSS_C_NO_BUFFER;
-
-			if (ret != GSS_S_COMPLETE) {
-				negResult = REJECT;
-				return_token = ERROR_TOKEN_SEND;
-				goto senderror;
-			}
-		}
-
-		/*
-		 * If the MIC was verified OK, create a new MIC
-		 * for the response message.
-		 */
-		if (status == GSS_S_COMPLETE &&
-		    (local_ret_flags & GSS_C_INTEG_FLAG) &&
-		    !spnego_ctx->MS_Interop) {
-			mechListMIC = (gss_buffer_t)
-			    malloc(sizeof (gss_buffer_desc));
-
-			if (mechListMIC == NULL ||
-			    spnego_ctx->DER_mechTypes.length == 0) {
-				ret = GSS_S_FAILURE;
-				goto cleanup;
-			}
-
-			ret = gss_get_mic(minor_status,
-			    spnego_ctx->ctx_handle,
-			    GSS_C_QOP_DEFAULT,
-			    &spnego_ctx->DER_mechTypes,
-			    mechListMIC);
-
-			if (ret != GSS_S_COMPLETE) {
-				negResult = REJECT;
-				return_token = ERROR_TOKEN_SEND;
-				goto senderror;
-			}
-		}
-		ret = status;
-
-		if (status == GSS_S_COMPLETE) {
-			if (internal_name != NULL && src_name != NULL)
-				*src_name = internal_name;
-		}
-
-
-		if (status == GSS_S_CONTINUE_NEEDED) {
-			if (return_token == INIT_TOKEN_SEND)
-				negResult = ACCEPT_INCOMPLETE;
-		}
-	}
-
-senderror:
-	if ((return_token == INIT_TOKEN_SEND) ||
-	    (return_token == CONT_TOKEN_SEND) ||
-	    (return_token == ERROR_TOKEN_SEND)) {
-		int MS_Interop = 0;
-
-		if (spnego_ctx)
-			MS_Interop = spnego_ctx->MS_Interop;
-
-		/*
-		 * create response for the initiator.
-		 */
-		err = make_spnego_tokenTarg_msg(negResult,
-		    mech_wanted, i_output_token,
-		    mechListMIC, return_token,
-		    MS_Interop, output_token);
-
-		(void) gss_release_buffer(&mstat, mechListMIC);
-		free(mechListMIC);
-
-		/*
-		 * If we could not make the response token,
-		 * we will have to fail without sending a response.
-		 */
-		if (err) {
-			(void) gss_release_buffer(&mstat, output_token);
-		}
-	} else {
-		(void) gss_release_buffer(&mstat, output_token);
-	}
-
-cleanup:
-	if (ret != GSS_S_COMPLETE &&
-	    ret != GSS_S_CONTINUE_NEEDED) {
-		if (spnego_ctx != NULL) {
-			(void) gss_delete_sec_context(&mstat,
-			    &spnego_ctx->ctx_handle, NULL);
-
-			spnego_ctx->ctx_handle = NULL;
-
-			release_spnego_ctx(&spnego_ctx);
-		}
-		*context_handle = GSS_C_NO_CONTEXT;
-	}
-	if (mech_wanted != NULL) {
-		generic_gss_release_oid(&mstat, &mech_wanted);
-	}
-
-	(void) gss_release_cred(minor_status, &acquired_cred);
-	(void) gss_release_oid_set(minor_status, &supported_mechSet);
-
-	(void) gss_release_buffer(&mstat, i_output_token);
-	free(i_output_token);
-
-	return (ret);
+	return(spnego_gss_accept_sec_context(
+		    minor_status,
+		    context_handle,
+		    verifier_cred_handle,
+		    input_token,
+		    input_chan_bindings,
+		    src_name,
+		    mech_type,
+		    output_token,
+		    ret_flags,
+		    time_rec,
+		    delegated_cred_handle));
 }
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_display_status(void *ctx,
+spnego_gss_accept_sec_context(
+			    OM_uint32 *minor_status,
+			    gss_ctx_id_t *context_handle,
+			    gss_cred_id_t verifier_cred_handle,
+			    gss_buffer_t input_token,
+			    gss_channel_bindings_t input_chan_bindings,
+			    gss_name_t *src_name,
+			    gss_OID *mech_type,
+			    gss_buffer_t output_token,
+			    OM_uint32 *ret_flags,
+			    OM_uint32 *time_rec,
+			    gss_cred_id_t *delegated_cred_handle)
+{
+	OM_uint32 ret, tmpmin, negState;
+	send_token_flag return_token;
+	gss_buffer_t mechtok_in, mic_in, mic_out;
+	gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+	spnego_gss_ctx_id_t sc = NULL;
+	OM_uint32 mechstat = GSS_S_FAILURE;
+	int sendTokenInit = 0;
+
+	mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER;
+
+	if (minor_status != NULL)
+		*minor_status = 0;
+	if (output_token != GSS_C_NO_BUFFER) {
+		output_token->length = 0;
+		output_token->value = NULL;
+	}
+
+
+	if (minor_status == NULL ||
+	    output_token == GSS_C_NO_BUFFER ||
+	    context_handle == NULL) {
+		return GSS_S_CALL_INACCESSIBLE_WRITE;
+	}
+
+	if (input_token == GSS_C_NO_BUFFER) {
+		return GSS_S_CALL_INACCESSIBLE_READ;
+	}
+
+	sc = (spnego_gss_ctx_id_t)*context_handle;
+	if (sc == NULL || sc->internal_mech == GSS_C_NO_OID) {
+		if (src_name != NULL)
+			*src_name = GSS_C_NO_NAME;
+		if (mech_type != NULL)
+			*mech_type = GSS_C_NO_OID;
+		if (time_rec != NULL)
+			*time_rec = 0;
+		if (ret_flags != NULL)
+			*ret_flags = 0;
+		if (delegated_cred_handle != NULL)
+			*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+		if (input_token->length == 0) {
+			sendTokenInit = 1;
+			ret = acc_ctx_hints(minor_status,
+					    context_handle,
+					    verifier_cred_handle,
+					    &mic_out,
+					    &negState,
+					    &return_token);
+			if (ret != GSS_S_COMPLETE)
+				goto cleanup;
+			ret = GSS_S_CONTINUE_NEEDED;
+		} else {
+			/* Can set negState to REQUEST_MIC */
+			ret = acc_ctx_new(minor_status, input_token,
+					  context_handle, verifier_cred_handle,
+					  &mechtok_in, &mic_in,
+					  &negState, &return_token);
+			if (ret != GSS_S_COMPLETE)
+				goto cleanup;
+			ret = GSS_S_CONTINUE_NEEDED;
+		}
+	} else {
+		/* Can set negState to ACCEPT_INCOMPLETE */
+		ret = acc_ctx_cont(minor_status, input_token,
+				   context_handle, &mechtok_in,
+				   &mic_in, &negState, &return_token);
+		if (ret != GSS_S_COMPLETE)
+			goto cleanup;
+		ret = GSS_S_CONTINUE_NEEDED;
+	}
+
+	sc = (spnego_gss_ctx_id_t)*context_handle;
+	/*
+	 * Handle mechtok_in and mic_in only if they are
+	 * present in input_token.  If neither is present, whether
+	 * this is an error depends on whether this is the first
+	 * round-trip.  RET is set to a default value according to
+	 * whether it is the first round-trip.
+	 */
+	mechstat = GSS_S_FAILURE;
+	if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
+		ret = acc_ctx_call_acc(minor_status, sc,
+				       verifier_cred_handle, mechtok_in,
+				       mech_type, &mechtok_out,
+				       ret_flags, time_rec,
+				       delegated_cred_handle,
+				       &negState, &return_token);
+	} else if (negState == REQUEST_MIC) {
+		mechstat = GSS_S_CONTINUE_NEEDED;
+	}
+
+	if (!HARD_ERROR(ret) && sc->mech_complete &&
+	    (sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+		ret = handle_mic(minor_status, mic_in,
+				 (mechtok_out.length != 0),
+				 sc, &mic_out,
+				 &negState, &return_token);
+	}
+
+cleanup:
+	if (return_token != NO_TOKEN_SEND && return_token != CHECK_MIC) {
+		/* For acceptor-sends-first send a tokenInit */
+		int tmpret;
+
+		assert(sc != NULL);
+
+		if (sendTokenInit) {
+			tmpret = make_spnego_tokenInit_msg(sc,
+							   1,
+							   mic_out,
+							   0,
+							   GSS_C_NO_BUFFER,
+							   return_token,
+							   output_token);
+		} else {
+			tmpret = make_spnego_tokenTarg_msg(negState, sc->internal_mech,
+							   &mechtok_out, mic_out,
+							   return_token,
+							   output_token);
+		}
+		if (tmpret < 0)
+			ret = GSS_S_FAILURE;
+	}
+	if (ret == GSS_S_COMPLETE) {
+		*context_handle = (gss_ctx_id_t)sc->ctx_handle;
+		if (sc->internal_name != GSS_C_NO_NAME &&
+		    src_name != NULL) {
+			*src_name = sc->internal_name;
+		}
+		release_spnego_ctx(&sc);
+	}
+	gss_release_buffer(&tmpmin, &mechtok_out);
+	if (mechtok_in != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mechtok_in);
+		free(mechtok_in);
+	}
+	if (mic_in != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mic_in);
+		free(mic_in);
+	}
+	if (mic_out != GSS_C_NO_BUFFER) {
+		gss_release_buffer(&tmpmin, mic_out);
+		free(mic_out);
+	}
+	return ret;
+}
+#endif /*  LEAN_CLIENT */
+
+/*ARGSUSED*/
+OM_uint32
+glue_spnego_gss_display_status(
+	void *context,
 		OM_uint32 *minor_status,
 		OM_uint32 status_value,
 		int status_type,
@@ -1096,50 +1837,76 @@
 		OM_uint32 *message_context,
 		gss_buffer_t status_string)
 {
-	OM_uint32 ret = GSS_S_COMPLETE;
+	return (spnego_gss_display_status(minor_status,
+					status_value,
+					status_type,
+					mech_type,
+					message_context,
+					status_string));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_status(
+		OM_uint32 *minor_status,
+		OM_uint32 status_value,
+		int status_type,
+		gss_OID mech_type,
+		OM_uint32 *message_context,
+		gss_buffer_t status_string)
+{
 	dsyslog("Entering display_status\n");
 
 	*message_context = 0;
 	switch (status_value) {
-		case ERR_SPNEGO_NO_MECHS_AVAILABLE:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO cannot find mechanisms to negotiate"));
-			break;
-		case ERR_SPNEGO_NO_CREDS_ACQUIRED:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO failed to acquire creds"));
-			break;
-		case ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO acceptor did not select a mechanism"));
-			break;
-		case ERR_SPNEGO_NEGOTIATION_FAILED:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO failed to negotiate a mechanism"));
-			break;
-		case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO acceptor did not return a valid token"));
-			break;
-		case ERR_SPNEGO_BAD_INPUT_PARAMETER:
-			*status_string = make_err_msg(gettext(
-			    "SPNEGO function received an incorrect input "
-			    "parameter"));
-			break;
-		default:
-			status_string->length = 0;
-			status_string->value = "";
-			ret = GSS_S_BAD_STATUS;
-			break;
+	    case ERR_SPNEGO_NO_MECHS_AVAILABLE:
+		/* CSTYLED */
+		*status_string = make_err_msg("SPNEGO cannot find mechanisms to negotiate");
+		break;
+	    case ERR_SPNEGO_NO_CREDS_ACQUIRED:
+		/* CSTYLED */
+		*status_string = make_err_msg("SPNEGO failed to acquire creds");
+		break;
+	    case ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR:
+		/* CSTYLED */
+		*status_string = make_err_msg("SPNEGO acceptor did not select a mechanism");
+		break;
+	    case ERR_SPNEGO_NEGOTIATION_FAILED:
+		/* CSTYLED */
+		*status_string = make_err_msg("SPNEGO failed to negotiate a mechanism");
+		break;
+	    case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR:
+		/* CSTYLED */
+		*status_string = make_err_msg("SPNEGO acceptor did not return a valid token");
+		break;
+	    default:
+		status_string->length = 0;
+		status_string->value = "";
+		break;
 	}
 
 	dsyslog("Leaving display_status\n");
-	return (ret);
+	return (GSS_S_COMPLETE);
 }
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_import_name(void *ctx,
+glue_spnego_gss_import_name(
+	void *context,
+		    OM_uint32 *minor_status,
+		    gss_buffer_t input_name_buffer,
+		    gss_OID input_name_type,
+		    gss_name_t *output_name)
+{
+	return(spnego_gss_import_name(minor_status,
+				    input_name_buffer,
+				    input_name_type,
+				    output_name));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_import_name(
 		    OM_uint32 *minor_status,
 		    gss_buffer_t input_name_buffer,
 		    gss_OID input_name_type,
@@ -1150,7 +1917,7 @@
 	dsyslog("Entering import_name\n");
 
 	status = gss_import_name(minor_status, input_name_buffer,
-	    input_name_type, output_name);
+			input_name_type, output_name);
 
 	dsyslog("Leaving import_name\n");
 	return (status);
@@ -1158,7 +1925,17 @@
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_release_name(void *ctx,
+glue_spnego_gss_release_name(
+	void *context,
+			OM_uint32 *minor_status,
+			gss_name_t *input_name)
+{
+	return(spnego_gss_release_name(minor_status, input_name));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_name(
 			OM_uint32 *minor_status,
 			gss_name_t *input_name)
 {
@@ -1174,7 +1951,54 @@
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_display_name(void *ctx,
+glue_spnego_gss_compare_name(
+	void *context,
+	OM_uint32 *minor_status,
+	const gss_name_t name1,
+	const gss_name_t name2,
+	int *name_equal)
+{
+	return(spnego_gss_compare_name(minor_status,
+				name1,
+				name2,
+				name_equal));
+}
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_compare_name(
+			OM_uint32 *minor_status,
+			const gss_name_t name1,
+			const gss_name_t name2,
+			int *name_equal)
+{
+	OM_uint32 status = GSS_S_COMPLETE;
+	dsyslog("Entering compare_name\n");
+
+	status = gss_compare_name(minor_status, name1, name2, name_equal);
+
+	dsyslog("Leaving compare_name\n");
+	return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+glue_spnego_gss_display_name(
+ 	void *context,
+			OM_uint32 *minor_status,
+			gss_name_t input_name,
+			gss_buffer_t output_name_buffer,
+			gss_OID *output_name_type)
+{
+	return(spnego_gss_display_name(
+		    minor_status,
+		    input_name,
+		    output_name_buffer,
+		    output_name_type));
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_name(
 			OM_uint32 *minor_status,
 			gss_name_t input_name,
 			gss_buffer_t output_name_buffer,
@@ -1184,82 +2008,28 @@
 	dsyslog("Entering display_name\n");
 
 	status = gss_display_name(minor_status, input_name,
-	    output_name_buffer, output_name_type);
+			output_name_buffer, output_name_type);
 
 	dsyslog("Leaving display_name\n");
 	return (status);
 }
 
-/*ARGSUSED*/
-OM_uint32
-spnego_gss_inquire_cred(void *ctx,
-	OM_uint32 *minor_status,
-	const gss_cred_id_t cred_handle,
-	gss_name_t *name,
-	OM_uint32 *lifetime,
-	gss_cred_usage_t *cred_usage,
-	gss_OID_set *mechanisms)
-{
-	OM_uint32 stat = GSS_S_COMPLETE;
-	gss_cred_id_t *credlistptr = NULL, credlist = NULL;
-	OM_uint32 init_lt, accept_lt;
-	int i;
-
-	if (cred_handle == GSS_C_NO_CREDENTIAL) {
-		OM_uint32 tstat;
-		credlistptr = &credlist;
-
-		/*
-		 * Get a list of all non-SPNEGO
-		 * mechanisms that are available and
-		 * acquire a default cred.
-		 */
-		stat = get_available_mechs(minor_status,
-		    NULL, GSS_C_BOTH, credlistptr, mechanisms);
-
-		/*
-		 * inquire about the default cred from the
-		 * first non-SPNEGO mechanism that was found.
-		 */
-		if (stat == GSS_S_COMPLETE && mechanisms &&
-		    (*mechanisms)->count > 0) {
-			i = 0;
-			do {
-				stat = gss_inquire_cred_by_mech(
-				    minor_status, credlist,
-				    &((*mechanisms)->elements[i]),
-				    name, &init_lt, &accept_lt,
-				    cred_usage);
-
-				/*
-				 * Set the lifetime to the correct value.
-				 */
-				if (stat == GSS_S_COMPLETE) {
-					if (*cred_usage == GSS_C_INITIATE)
-						*lifetime = init_lt;
-					else
-						*lifetime = accept_lt;
-				}
-				if (credlist != GSS_C_NO_CREDENTIAL)
-					(void) gss_release_cred(&tstat,
-					    &credlist);
-			} while (stat != GSS_S_COMPLETE &&
-			    (i < (*mechanisms)->count));
-		}
-	} else {
-		/*
-		 * This should not happen, it cannot be processed.
-		 */
-		stat = GSS_S_FAILURE;
-		if (minor_status != NULL)
-			*minor_status = ERR_SPNEGO_BAD_INPUT_PARAMETER;
-	}
-	return (stat);
-}
 
 /*ARGSUSED*/
 OM_uint32
-spnego_gss_inquire_names_for_mech(void *ctx,
+glue_spnego_gss_inquire_names_for_mech(
+	void		*context,
+	OM_uint32	*minor_status,
+	gss_OID		mechanism,
+	gss_OID_set	*name_types)
+{
+	return(spnego_gss_inquire_names_for_mech(minor_status,
+						mechanism,
+						name_types));
+}
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_inquire_names_for_mech(
 				OM_uint32	*minor_status,
 				gss_OID		mechanism,
 				gss_OID_set	*name_types)
@@ -1280,17 +2050,17 @@
 	if (major == GSS_S_COMPLETE) {
 		/* Now add our members. */
 		if (((major = gss_add_oid_set_member(minor_status,
-		    (gss_OID) GSS_C_NT_USER_NAME,
-		    name_types)) == GSS_S_COMPLETE) &&
+				(gss_OID) GSS_C_NT_USER_NAME,
+				name_types)) == GSS_S_COMPLETE) &&
 		    ((major = gss_add_oid_set_member(minor_status,
-		    (gss_OID) GSS_C_NT_MACHINE_UID_NAME,
-		    name_types)) == GSS_S_COMPLETE) &&
+				(gss_OID) GSS_C_NT_MACHINE_UID_NAME,
+				name_types)) == GSS_S_COMPLETE) &&
 		    ((major = gss_add_oid_set_member(minor_status,
-		    (gss_OID) GSS_C_NT_STRING_UID_NAME,
-		    name_types)) == GSS_S_COMPLETE)) {
+				(gss_OID) GSS_C_NT_STRING_UID_NAME,
+				name_types)) == GSS_S_COMPLETE)) {
 			major = gss_add_oid_set_member(minor_status,
-			    (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
-			    name_types);
+				(gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
+				name_types);
 		}
 
 		if (major != GSS_S_COMPLETE)
@@ -1302,193 +2072,256 @@
 }
 
 OM_uint32
-spnego_gss_unseal(void *context,
+spnego_gss_unwrap(
 		OM_uint32 *minor_status,
 		gss_ctx_id_t context_handle,
 		gss_buffer_t input_message_buffer,
 		gss_buffer_t output_message_buffer,
 		int *conf_state,
-		int *qop_state)
+		gss_qop_t *qop_state)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx = (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	ret = gss_unseal(minor_status,
-	    ctx->ctx_handle, input_message_buffer,
-	    output_message_buffer, conf_state, qop_state);
+	ret = gss_unwrap(minor_status,
+			context_handle,
+			input_message_buffer,
+			output_message_buffer,
+			conf_state,
+			qop_state);
 
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_seal(void *context,
+spnego_gss_wrap(
 		OM_uint32 *minor_status,
 		gss_ctx_id_t context_handle,
 		int conf_req_flag,
-		int qop_req,
+		gss_qop_t qop_req,
 		gss_buffer_t input_message_buffer,
 		int *conf_state,
 		gss_buffer_t output_message_buffer)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	ret = gss_seal(minor_status,
-	    ctx->ctx_handle, conf_req_flag,
-	    qop_req, input_message_buffer,
-	    conf_state, output_message_buffer);
+	ret = gss_wrap(minor_status,
+		    context_handle,
+		    conf_req_flag,
+		    qop_req,
+		    input_message_buffer,
+		    conf_state,
+		    output_message_buffer);
 
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_process_context_token(void *context,
-	OM_uint32	*minor_status,
-	const gss_ctx_id_t context_handle,
-	const gss_buffer_t token_buffer)
+spnego_gss_process_context_token(
+				OM_uint32	*minor_status,
+				const gss_ctx_id_t context_handle,
+				const gss_buffer_t token_buffer)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
 	ret = gss_process_context_token(minor_status,
-	    ctx->ctx_handle, token_buffer);
+					context_handle,
+					token_buffer);
 
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_delete_sec_context(void *context,
+glue_spnego_gss_delete_sec_context(
+	void *context,
+			    OM_uint32 *minor_status,
+			    gss_ctx_id_t *context_handle,
+			    gss_buffer_t output_token)
+{
+	return(spnego_gss_delete_sec_context(minor_status,
+					    context_handle, output_token));
+}
+
+OM_uint32
+spnego_gss_delete_sec_context(
 			    OM_uint32 *minor_status,
 			    gss_ctx_id_t *context_handle,
 			    gss_buffer_t output_token)
 {
 	OM_uint32 ret = GSS_S_COMPLETE;
 	spnego_gss_ctx_id_t *ctx =
-	    (spnego_gss_ctx_id_t *)context_handle;
-
-	if (context_handle == NULL || *ctx == NULL)
-		return (GSS_S_NO_CONTEXT);
+		    (spnego_gss_ctx_id_t *)context_handle;
+
+	if (context_handle == NULL)
+		return (GSS_S_FAILURE);
 
 	/*
-	 * If this is still a SPNEGO mech, release it locally.
+	 * If this is still an SPNEGO mech, release it locally.
 	 */
-	if ((*ctx)->ctx_handle == GSS_C_NO_CONTEXT) {
+	if (*ctx != NULL &&
+	    (*ctx)->magic_num == SPNEGO_MAGIC_ID) {
 		(void) release_spnego_ctx(ctx);
+                /* SUNW17PACresync - MIT 1.7 bug (and our fix) */
+		if (output_token) {
+			output_token->length = 0; 
+			output_token->value = NULL;
+		}
 	} else {
 		ret = gss_delete_sec_context(minor_status,
-		    &(*ctx)->ctx_handle, output_token);
+				    context_handle,
+				    output_token);
 	}
 
 	return (ret);
 }
 
+#if 0 /* SUNW17PACresync */
 OM_uint32
-spnego_gss_context_time(void *context,
+glue_spnego_gss_context_time(
+	void *context,
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	OM_uint32	*time_rec)
 {
+	return(spnego_gss_context_time(minor_status,
+				    context_handle,
+				    time_rec));
+}
+
+OM_uint32
+spnego_gss_context_time(
+			OM_uint32	*minor_status,
+			const gss_ctx_id_t context_handle,
+			OM_uint32	*time_rec)
+{
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
 	ret = gss_context_time(minor_status,
-	    ctx->ctx_handle, time_rec);
-
+			    context_handle,
+			    time_rec);
+	return (ret);
+}
+#endif
+
+#ifndef LEAN_CLIENT
+OM_uint32
+glue_spnego_gss_export_sec_context(
+	void *context,
+	OM_uint32	  *minor_status,
+	gss_ctx_id_t *context_handle,
+	gss_buffer_t interprocess_token)
+{
+	return(spnego_gss_export_sec_context(minor_status,
+				    context_handle,
+				    interprocess_token));
+}
+OM_uint32
+spnego_gss_export_sec_context(
+			    OM_uint32	  *minor_status,
+			    gss_ctx_id_t *context_handle,
+			    gss_buffer_t interprocess_token)
+{
+	OM_uint32 ret;
+	ret = gss_export_sec_context(minor_status,
+				    context_handle,
+				    interprocess_token);
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_export_sec_context(void *context,
-	OM_uint32	  *minor_status,
-	gss_ctx_id_t *context_handle,
-	gss_buffer_t interprocess_token)
+glue_spnego_gss_import_sec_context(
+	void *context,
+	OM_uint32		*minor_status,
+	const gss_buffer_t	interprocess_token,
+	gss_ctx_id_t		*context_handle)
 {
-	OM_uint32 ret;
-	spnego_gss_ctx_id_t *ctx =
-	    (spnego_gss_ctx_id_t *)context_handle;
-
-	if (context_handle == NULL || *ctx == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	ret = gss_export_sec_context(minor_status,
-	    &(*ctx)->ctx_handle, interprocess_token);
-	return (ret);
+	return(spnego_gss_import_sec_context(minor_status,
+				    interprocess_token,
+				    context_handle));
 }
-
 OM_uint32
-spnego_gss_import_sec_context(void *context,
+spnego_gss_import_sec_context(
 	OM_uint32		*minor_status,
 	const gss_buffer_t	interprocess_token,
 	gss_ctx_id_t		*context_handle)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	if ((ctx = create_spnego_ctx()) == NULL) {
-		*minor_status = ENOMEM;
-		return (GSS_S_FAILURE);
-	}
-
 	ret = gss_import_sec_context(minor_status,
-	    interprocess_token, &(ctx->ctx_handle));
-	if (GSS_ERROR(ret)) {
-		(void) release_spnego_ctx(&ctx);
-		return (ret);
-	}
-
-	*context_handle = (gss_ctx_id_t)ctx;
-
+				    interprocess_token,
+				    context_handle);
 	return (ret);
 }
+#endif /* LEAN_CLIENT */
+
+#if 0 /* SUNW17PACresync */
+OM_uint32
+glue_spnego_gss_inquire_context(
+	void *context,
+			OM_uint32	*minor_status,
+			const gss_ctx_id_t context_handle,
+			gss_name_t	*src_name,
+			gss_name_t	*targ_name,
+			OM_uint32	*lifetime_rec,
+			gss_OID		*mech_type,
+			OM_uint32	*ctx_flags,
+			int		*locally_initiated,
+			int		*opened)
+{
+	return(spnego_gss_inquire_context(
+		    minor_status,
+		    context_handle,
+		    src_name,
+		    targ_name,
+		    lifetime_rec,
+		    mech_type,
+		    ctx_flags,
+		    locally_initiated,
+		    opened));
+}
 
 OM_uint32
-spnego_gss_inquire_context(void *context,
-	OM_uint32	*minor_status,
-	const gss_ctx_id_t context_handle,
-	gss_name_t	*src_name,
-	gss_name_t	*targ_name,
-	OM_uint32	*lifetime_rec,
-	gss_OID		*mech_type,
-	OM_uint32	*ctx_flags,
-	int		*locally_initiated,
-	int		*open)
+spnego_gss_inquire_context(
+			OM_uint32	*minor_status,
+			const gss_ctx_id_t context_handle,
+			gss_name_t	*src_name,
+			gss_name_t	*targ_name,
+			OM_uint32	*lifetime_rec,
+			gss_OID		*mech_type,
+			OM_uint32	*ctx_flags,
+			int		*locally_initiated,
+			int		*opened)
 {
 	OM_uint32 ret = GSS_S_COMPLETE;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
 
 	ret = gss_inquire_context(minor_status,
-	    ctx->ctx_handle, src_name,
-	    targ_name, lifetime_rec,
-	    mech_type, ctx_flags,
-	    locally_initiated, open);
+				context_handle,
+				src_name,
+				targ_name,
+				lifetime_rec,
+				mech_type,
+				ctx_flags,
+				locally_initiated,
+				opened);
 
 	return (ret);
 }
-
+#endif
+
+#if 0 /* SUNW17PACresync */
 OM_uint32
-spnego_gss_wrap_size_limit(void *context,
+glue_spnego_gss_wrap_size_limit(
+	void *context,
+	OM_uint32	*minor_status,
+	const gss_ctx_id_t context_handle,
+	int		conf_req_flag,
+	gss_qop_t	qop_req,
+	OM_uint32	req_output_size,
+	OM_uint32	*max_input_size)
+{
+	return(spnego_gss_wrap_size_limit(minor_status,
+				context_handle,
+				conf_req_flag,
+				qop_req,
+				req_output_size,
+				max_input_size));
+}
+OM_uint32
+spnego_gss_wrap_size_limit(
 	OM_uint32	*minor_status,
 	const gss_ctx_id_t context_handle,
 	int		conf_req_flag,
@@ -1497,66 +2330,204 @@
 	OM_uint32	*max_input_size)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
 	ret = gss_wrap_size_limit(minor_status,
-	    ctx->ctx_handle, conf_req_flag,
-	    qop_req, req_output_size,
-	    max_input_size);
+				context_handle,
+				conf_req_flag,
+				qop_req,
+				req_output_size,
+				max_input_size);
+	return (ret);
+}
+#endif
+
+#if 0 /* SUNW17PACresync */
+OM_uint32
+spnego_gss_get_mic(
+		OM_uint32 *minor_status,
+		const gss_ctx_id_t context_handle,
+		gss_qop_t  qop_req,
+		const gss_buffer_t message_buffer,
+		gss_buffer_t message_token)
+{
+	OM_uint32 ret;
+	ret = gss_get_mic(minor_status,
+		    context_handle,
+		    qop_req,
+		    message_buffer,
+		    message_token);
+	return (ret);
+}
+#endif
+
+OM_uint32
+spnego_gss_verify_mic(
+		OM_uint32 *minor_status,
+		const gss_ctx_id_t context_handle,
+		const gss_buffer_t msg_buffer,
+		const gss_buffer_t token_buffer,
+		gss_qop_t *qop_state)
+{
+	OM_uint32 ret;
+	ret = gss_verify_mic(minor_status,
+			    context_handle,
+			    msg_buffer,
+			    token_buffer,
+			    qop_state);
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_sign(void *context,
+spnego_gss_inquire_sec_context_by_oid(
 		OM_uint32 *minor_status,
 		const gss_ctx_id_t context_handle,
-		int  qop_req,
-		const gss_buffer_t message_buffer,
-		gss_buffer_t message_token)
+		const gss_OID desired_object,
+		gss_buffer_set_t *data_set)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	ret = gss_sign(minor_status,
-	    ctx->ctx_handle,
-	    qop_req,
-	    message_buffer,
-	    message_token);
+	ret = gss_inquire_sec_context_by_oid(minor_status,
+			    context_handle,
+			    desired_object,
+			    data_set);
+	return (ret);
+}
+
+/*
+ * SUNW17PACresync
+ * These GSS funcs not needed yet, so disable them.
+ * Revisit for full 1.7 resync.
+ */
+#if 0
+OM_uint32
+spnego_gss_set_sec_context_option(
+		OM_uint32 *minor_status,
+		gss_ctx_id_t *context_handle,
+		const gss_OID desired_object,
+		const gss_buffer_t value)
+{
+	OM_uint32 ret;
+	ret = gss_set_sec_context_option(minor_status,
+			    context_handle,
+			    desired_object,
+			    value);
+	return (ret);
+}
+
+OM_uint32
+spnego_gss_wrap_aead(OM_uint32 *minor_status,
+		     gss_ctx_id_t context_handle,
+		     int conf_req_flag,
+		     gss_qop_t qop_req,
+		     gss_buffer_t input_assoc_buffer,
+		     gss_buffer_t input_payload_buffer,
+		     int *conf_state,
+		     gss_buffer_t output_message_buffer)
+{
+	OM_uint32 ret;
+	ret = gss_wrap_aead(minor_status,
+			    context_handle,
+			    conf_req_flag,
+			    qop_req,
+			    input_assoc_buffer,
+			    input_payload_buffer,
+			    conf_state,
+			    output_message_buffer);
 
 	return (ret);
 }
 
 OM_uint32
-spnego_gss_verify(void *context,
-	OM_uint32 *minor_status,
-	const gss_ctx_id_t context_handle,
-	const gss_buffer_t msg_buffer,
-	const gss_buffer_t token_buffer,
-	int *qop_state)
+spnego_gss_unwrap_aead(OM_uint32 *minor_status,
+		       gss_ctx_id_t context_handle,
+		       gss_buffer_t input_message_buffer,
+		       gss_buffer_t input_assoc_buffer,
+		       gss_buffer_t output_payload_buffer,
+		       int *conf_state,
+		       gss_qop_t *qop_state)
+{
+	OM_uint32 ret;
+	ret = gss_unwrap_aead(minor_status,
+			      context_handle,
+			      input_message_buffer,
+			      input_assoc_buffer,
+			      output_payload_buffer,
+			      conf_state,
+			      qop_state);
+	return (ret);
+}
+
+OM_uint32
+spnego_gss_wrap_iov(OM_uint32 *minor_status,
+		    gss_ctx_id_t context_handle,
+		    int conf_req_flag,
+		    gss_qop_t qop_req,
+		    int *conf_state,
+		    gss_iov_buffer_desc *iov,
+		    int iov_count)
 {
 	OM_uint32 ret;
-	spnego_gss_ctx_id_t ctx =
-	    (spnego_gss_ctx_id_t)context_handle;
-
-	if (context_handle == NULL)
-		return (GSS_S_NO_CONTEXT);
-
-	ret = gss_verify_mic(minor_status,
-	    ctx->ctx_handle,
-	    msg_buffer,
-	    token_buffer,
-	    (uint32_t *)qop_state);
+	ret = gss_wrap_iov(minor_status,
+			   context_handle,
+			   conf_req_flag,
+			   qop_req,
+			   conf_state,
+			   iov,
+			   iov_count);
+	return (ret);
+}
+
+OM_uint32
+spnego_gss_unwrap_iov(OM_uint32 *minor_status,
+		      gss_ctx_id_t context_handle,
+		      int *conf_state,
+		      gss_qop_t *qop_state,
+		      gss_iov_buffer_desc *iov,
+		      int iov_count)
+{
+	OM_uint32 ret;
+	ret = gss_unwrap_iov(minor_status,
+			     context_handle,
+			     conf_state,
+			     qop_state,
+			     iov,
+			     iov_count);
 	return (ret);
 }
 
+OM_uint32
+spnego_gss_wrap_iov_length(OM_uint32 *minor_status,
+			   gss_ctx_id_t context_handle,
+			   int conf_req_flag,
+			   gss_qop_t qop_req,
+			   int *conf_state,
+			   gss_iov_buffer_desc *iov,
+			   int iov_count)
+{
+	OM_uint32 ret;
+	ret = gss_wrap_iov_length(minor_status,
+				  context_handle,
+				  conf_req_flag,
+				  qop_req,
+				  conf_state,
+				  iov,
+				  iov_count);
+	return (ret);
+}
+
+
+OM_uint32
+spnego_gss_complete_auth_token(
+		OM_uint32 *minor_status,
+		const gss_ctx_id_t context_handle,
+		gss_buffer_t input_message_buffer)
+{
+	OM_uint32 ret;
+	ret = gss_complete_auth_token(minor_status,
+				      context_handle,
+				      input_message_buffer);
+	return (ret);
+}
+#endif /* 0 */
+
 /*
  * We will release everything but the ctx_handle so that it
  * can be passed back to init/accept context. This routine should
@@ -1568,27 +2539,19 @@
 {
 	spnego_gss_ctx_id_t context;
 	OM_uint32 minor_stat;
-
-	if (ctx != NULL)
-		context = *ctx;
-	else
-		return;
+	context = *ctx;
 
 	if (context != NULL) {
 		(void) gss_release_buffer(&minor_stat,
-		    &context->DER_mechTypes);
+					&context->DER_mechTypes);
 
 		(void) generic_gss_release_oid(&minor_stat,
-		    &context->internal_mech);
+				&context->internal_mech);
 
 		if (context->optionStr != NULL) {
 			free(context->optionStr);
 			context->optionStr = NULL;
 		}
-		if (context->ctx_handle != GSS_C_NO_CONTEXT)
-			gss_delete_sec_context(&minor_stat,
-			    &context->ctx_handle, GSS_C_NO_BUFFER);
-
 		free(context);
 		*ctx = NULL;
 	}
@@ -1611,34 +2574,35 @@
 	gss_name_t name, gss_cred_usage_t usage,
 	gss_cred_id_t *creds, gss_OID_set *rmechs)
 {
-	int		i;
+	unsigned int	i;
 	int		found = 0;
-	OM_uint32 stat = GSS_S_COMPLETE;
+	OM_uint32 major_status = GSS_S_COMPLETE, tmpmin;
 	gss_OID_set mechs, goodmechs;
 
-	stat = gss_indicate_mechs(minor_status, &mechs);
-
-	if (stat != GSS_S_COMPLETE) {
-		return (stat);
+	major_status = gss_indicate_mechs(minor_status, &mechs);
+
+	if (major_status != GSS_S_COMPLETE) {
+		return (major_status);
 	}
 
-	stat = gss_create_empty_oid_set(minor_status, rmechs);
-
-	if (stat != GSS_S_COMPLETE) {
+	major_status = gss_create_empty_oid_set(minor_status, rmechs);
+
+	if (major_status != GSS_S_COMPLETE) {
 		(void) gss_release_oid_set(minor_status, &mechs);
-		return (stat);
+		return (major_status);
 	}
 
-	for (i = 0; i < mechs->count && stat == GSS_S_COMPLETE; i++) {
+	for (i = 0; i < mechs->count && major_status == GSS_S_COMPLETE; i++) {
 		if ((mechs->elements[i].length
 		    != spnego_mechanism.mech_type.length) ||
 		    memcmp(mechs->elements[i].elements,
-		    spnego_mechanism.mech_type.elements,
-		    spnego_mechanism.mech_type.length)) {
-
-			stat = gss_add_oid_set_member(minor_status,
-			    &mechs->elements[i], rmechs);
-			if (stat == GSS_S_COMPLETE)
+			spnego_mechanism.mech_type.elements,
+			spnego_mechanism.mech_type.length)) {
+
+			major_status = gss_add_oid_set_member(minor_status,
+							      &mechs->elements[i],
+							      rmechs);
+			if (major_status == GSS_S_COMPLETE)
 				found++;
 		}
 	}
@@ -1648,31 +2612,33 @@
 	 * trim the list of mechanisms down to only those
 	 * for which the creds are valid.
 	 */
-	if (found > 0 && stat == GSS_S_COMPLETE && creds != NULL) {
-		stat = gss_acquire_cred(minor_status,
-		    name, NULL, *rmechs, usage, creds,
-		    &goodmechs, NULL);
+	if (found > 0 && major_status == GSS_S_COMPLETE && creds != NULL) {
+		major_status = gss_acquire_cred(minor_status,
+						name, GSS_C_INDEFINITE, 
+						*rmechs, usage, creds,
+						&goodmechs, NULL);
 
 		/*
 		 * Drop the old list in favor of the new
 		 * "trimmed" list.
 		 */
-		(void) gss_release_oid_set(minor_status, rmechs);
-		if (stat == GSS_S_COMPLETE) {
-			(void) gss_copy_oid_set(minor_status,
-			    goodmechs, rmechs);
-			(void) gss_release_oid_set(minor_status, &goodmechs);
+		(void) gss_release_oid_set(&tmpmin, rmechs);
+		if (major_status == GSS_S_COMPLETE) {
+			(void) gssint_copy_oid_set(&tmpmin,
+					goodmechs, rmechs);
+			(void) gss_release_oid_set(&tmpmin, &goodmechs);
 		}
 	}
 
-	(void) gss_release_oid_set(minor_status, &mechs);
-	if (found == 0 || stat != GSS_S_COMPLETE) {
+	(void) gss_release_oid_set(&tmpmin, &mechs);
+	if (found == 0 || major_status != GSS_S_COMPLETE) {
 		*minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
-		if (stat == GSS_S_COMPLETE)
-			stat = GSS_S_FAILURE;
+		map_errcode(minor_status);
+		if (major_status == GSS_S_COMPLETE)
+			major_status = GSS_S_FAILURE;
 	}
 
-	return (stat);
+	return (major_status);
 }
 
 /* following are token creation and reading routines */
@@ -1688,7 +2654,7 @@
 	OM_uint32	status;
 	gss_OID_desc 	toid;
 	gss_OID		mech_out = NULL;
-	uchar_t		*start, *end;
+	unsigned char		*start, *end;
 
 	if (length < 1 || **buff_in != MECH_OID)
 		return (NULL);
@@ -1707,8 +2673,10 @@
 
 	status = generic_gss_copy_oid(minor_status, &toid, &mech_out);
 
-	if (status != GSS_S_COMPLETE)
+	if (status != GSS_S_COMPLETE) {
+		map_errcode(minor_status);
 		mech_out = NULL;
+	}
 
 	return (mech_out);
 }
@@ -1719,7 +2687,7 @@
  */
 
 static int
-put_mech_oid(unsigned char **buf_out, gss_OID_desc *mech, int buflen)
+put_mech_oid(unsigned char **buf_out, gss_OID_const mech, unsigned int buflen)
 {
 	if (buflen < mech->length + 2)
 		return (-1);
@@ -1737,19 +2705,25 @@
  * buffer pointer.
  */
 static gss_buffer_t
-get_input_token(unsigned char **buff_in, int buff_length)
+get_input_token(unsigned char **buff_in, unsigned int buff_length)
 {
 	gss_buffer_t input_token;
-	unsigned int len;
-
-	if (g_get_tag_and_length(buff_in, OCTET_STRING, buff_length, &len) < 0)
+	unsigned int bytes;
+
+	if (**buff_in != OCTET_STRING)
 		return (NULL);
 
+	(*buff_in)++;
 	input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+
 	if (input_token == NULL)
 		return (NULL);
 
-	input_token->length = len;
+	input_token->length = gssint_get_der_length(buff_in, buff_length, &bytes);
+	if ((int)input_token->length == -1) {
+		free(input_token);
+		return (NULL);
+	}
 	input_token->value = malloc(input_token->length);
 
 	if (input_token->value == NULL) {
@@ -1770,7 +2744,7 @@
 
 static int
 put_input_token(unsigned char **buf_out, gss_buffer_t input_token,
-		int buflen)
+		unsigned int buflen)
 {
 	int ret;
 
@@ -1782,10 +2756,10 @@
 		return (-1);
 
 	*(*buf_out)++ = OCTET_STRING;
-	if ((ret = put_der_length(input_token->length, buf_out,
-	    input_token->length)))
+	if ((ret = gssint_put_der_length(input_token->length, buf_out,
+			    input_token->length)))
 		return (ret);
-	TWRITE_STR(*buf_out, input_token->value, ((int)input_token->length));
+	TWRITE_STR(*buf_out, input_token->value, input_token->length);
 	return (0);
 }
 
@@ -1796,14 +2770,15 @@
  * return it, advancing the buffer pointer.
  */
 static gss_OID_set
-get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, int buff_length)
+get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
+	     unsigned int buff_length)
 {
 	gss_OID_set returned_mechSet;
 	OM_uint32 major_status;
-	int length;
-	unsigned int bytes;
+	int length; /* SUNW17PACresync */
+	OM_uint32 bytes;
 	OM_uint32 set_length;
-	uchar_t		*start;
+	unsigned char		*start;
 	int i;
 
 	if (**buff_in != SEQUENCE_OF)
@@ -1812,27 +2787,26 @@
 	start = *buff_in;
 	(*buff_in)++;
 
-	length = get_der_length(buff_in, buff_length, &bytes);
-	if (length < 0 || buff_length - bytes < (unsigned int)length)
-		return NULL;
+	length = gssint_get_der_length(buff_in, buff_length, &bytes);
+	if (length < 0) /* SUNW17PACresync - MIT17 lacks this check */
+		return (NULL);
 
 	major_status = gss_create_empty_oid_set(minor_status,
-	    &returned_mechSet);
+						&returned_mechSet);
 	if (major_status != GSS_S_COMPLETE)
 		return (NULL);
 
-	for (set_length = 0, i = 0; set_length < (unsigned int)length; i++) {
+	for (set_length = 0, i = 0; set_length < length; i++) {
 		gss_OID_desc *temp = get_mech_oid(minor_status, buff_in,
-		    buff_length - (*buff_in - start));
-		if (temp == NULL)
-			break;
-
-		major_status = gss_add_oid_set_member(minor_status,
-		    temp, &returned_mechSet);
-		if (major_status == GSS_S_COMPLETE) {
-				set_length +=
-				    returned_mechSet->elements[i].length +2;
-				generic_gss_release_oid(minor_status, &temp);
+			buff_length - (*buff_in - start));
+		if (temp != NULL) {
+		    major_status = gss_add_oid_set_member(minor_status,
+					temp, &returned_mechSet);
+		    if (major_status == GSS_S_COMPLETE) {
+			set_length += returned_mechSet->elements[i].length +2;
+			if (generic_gss_release_oid(minor_status, &temp))
+			    map_errcode(minor_status);
+		    }
 		}
 	}
 
@@ -1840,44 +2814,46 @@
 }
 
 /*
- * der encode the passed mechSet and place it into buf_out,
- * advancing the buffer pointer.
+ * Encode mechSet into buf.
  */
 static int
-put_mech_set(uchar_t **buf_out, gss_OID_set mechSet, int buflen)
+put_mech_set(gss_OID_set mechSet, gss_buffer_t buf)
 {
-	int i, ret;
-	OM_uint32 length = 0;
-	uchar_t *start;
-
-	if (buf_out == NULL || *buf_out == NULL)
-		return (-1);
-
-	start = *buf_out;
-
-	*(*buf_out)++ = SEQUENCE_OF;
-
+	unsigned char *ptr;
+	unsigned int i;
+	unsigned int tlen, ilen;
+
+	tlen = ilen = 0;
 	for (i = 0; i < mechSet->count; i++) {
 		/*
-		 * Mech OID ASN.1 size = 2 + length.
-		 * 1 = 0x06, 1 for length of OID
-		 * typically, less than 128, so only 1 byte needed.
+		 * 0x06 [DER LEN] [OID]
 		 */
-		length += 1 + der_length_size(mechSet->elements[i].length) +
-		    mechSet->elements[i].length;
+		ilen += 1 +
+			gssint_der_length_size(mechSet->elements[i].length) +
+			mechSet->elements[i].length;
 	}
-	if (length > (buflen-1))
-		return (-1);
-
-	if (put_der_length(length, buf_out, buflen-1) < 0)
-		return (-1);
-
+	/*
+	 * 0x30 [DER LEN]
+	 */
+	tlen = 1 + gssint_der_length_size(ilen) + ilen;
+	ptr = malloc(tlen);
+	if (ptr == NULL)
+		return -1;
+
+	buf->value = ptr;
+	buf->length = tlen;
+#define REMAIN (buf->length - ((unsigned char *)buf->value - ptr))
+
+	*ptr++ = SEQUENCE_OF;
+	if (gssint_put_der_length(ilen, &ptr, REMAIN) < 0)
+		return -1;
 	for (i = 0; i < mechSet->count; i++) {
-		if ((ret = put_mech_oid(buf_out, &mechSet->elements[i],
-		    buflen - (int)(*buf_out	 - start))))
-			return (ret);
+		if (put_mech_oid(&ptr, &mechSet->elements[i], REMAIN) < 0) {
+			return -1;
+		}
 	}
-	return (0);
+	return 0;
+#undef REMAIN
 }
 
 /*
@@ -1886,89 +2862,197 @@
  * and return them, otherwise, return NULL.
  */
 static OM_uint32
-get_req_flags(unsigned char **buff_in, int *bodysize, OM_uint32 *req_flags)
+get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
+	      OM_uint32 *req_flags)
 {
 	unsigned int len;
-	uchar_t *start = *buff_in;
-
-	/* It is OK if no ReqFlags data is sent. */
+
 	if (**buff_in != (CONTEXT | 0x01))
 		return (0);
 
-	/* If they are sent, make sure the fields are correct. */
 	if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
-	    *bodysize, &len) < 0)
-		return (ACCEPT_DEFECTIVE_TOKEN);
-
-	/* We don't care what the flags are. */
-	(*buff_in) += len;
-
-	/* Don't return any flags, this field is useless */
-	*req_flags = 0;
-
-	*bodysize -= *buff_in - start;
+				bodysize, &len) < 0)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	if (*(*buff_in)++ != BIT_STRING)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	if (*(*buff_in)++ != BIT_STRING_LENGTH)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	if (*(*buff_in)++ != BIT_STRING_PADDING)
+		return GSS_S_DEFECTIVE_TOKEN;
+
+	*req_flags = (OM_uint32) (*(*buff_in)++ >> 1);
 	return (0);
 }
 
-/*
- * get the negotiation results, decoding the ENUMERATED type result
- * from the buffer, advancing the buffer pointer.
- */
 static OM_uint32
-get_negResult(unsigned char **buff_in, int bodysize)
+get_negTokenInit(OM_uint32 *minor_status,
+		 gss_buffer_t buf,
+		 gss_buffer_t der_mechSet,
+		 gss_OID_set *mechSet,
+		 OM_uint32 *req_flags,
+		 gss_buffer_t *mechtok,
+		 gss_buffer_t *mechListMIC)
 {
-	unsigned char *iptr = *buff_in;
+	OM_uint32 err;
+	unsigned char *ptr, *bufstart;
 	unsigned int len;
-	unsigned int bytes;
-	OM_uint32 result;
-	/*
-	 * Verify that the data is ASN.1 encoded correctly
-	 */
-	if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
-	    bodysize, &len) < 0)
-		return (ACCEPT_DEFECTIVE_TOKEN);
-
-	if (*(*buff_in)++ == SEQUENCE) {
-		if ((len = get_der_length(buff_in,
-		    bodysize - (*buff_in - iptr), &bytes)) < 0)
-			return (ACCEPT_DEFECTIVE_TOKEN);
-	} else {
-		return (ACCEPT_INCOMPLETE);
+	gss_buffer_desc tmpbuf;
+
+	*minor_status = 0;
+	der_mechSet->length = 0;
+	der_mechSet->value = NULL;
+	*mechSet = GSS_C_NO_OID_SET;
+	*req_flags = 0;
+	*mechtok = *mechListMIC = GSS_C_NO_BUFFER;
+
+	ptr = bufstart = buf->value;
+	if ((buf->length - (ptr - bufstart)) > INT_MAX)
+		return GSS_S_FAILURE;
+#define REMAIN (buf->length - (ptr - bufstart))
+
+	err = g_verify_token_header(gss_mech_spnego,
+				    &len, &ptr, 0, REMAIN);
+	if (err) {
+		*minor_status = err;
+		map_errcode(minor_status);
+		return GSS_S_FAILURE;
+	}
+	*minor_status = g_verify_neg_token_init(&ptr, REMAIN);
+	if (*minor_status) {
+		map_errcode(minor_status);
+		return GSS_S_FAILURE;
+	}
+
+	/* alias into input_token */
+	tmpbuf.value = ptr;
+	tmpbuf.length = REMAIN;
+	*mechSet = get_mech_set(minor_status, &ptr, REMAIN);
+	if (*mechSet == NULL)
+		return GSS_S_FAILURE;
+
+	tmpbuf.length = ptr - (unsigned char *)tmpbuf.value;
+	der_mechSet->value = malloc(tmpbuf.length);
+	if (der_mechSet->value == NULL)
+		return GSS_S_FAILURE;
+	memcpy(der_mechSet->value, tmpbuf.value, tmpbuf.length);
+	der_mechSet->length = tmpbuf.length;
+
+	err = get_req_flags(&ptr, REMAIN, req_flags);
+	if (err != GSS_S_COMPLETE) {
+		return err;
+	}
+	if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
+				 REMAIN, &len) >= 0) {
+		*mechtok = get_input_token(&ptr, len);
+		if (*mechtok == GSS_C_NO_BUFFER) {
+			return GSS_S_FAILURE;
+		}
+	}
+	if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
+				 REMAIN, &len) >= 0) {
+		*mechListMIC = get_input_token(&ptr, len);
+		if (*mechListMIC == GSS_C_NO_BUFFER) {
+			return GSS_S_FAILURE;
+		}
 	}
-
-	/*
-	 * if we find an octet string, we need to return
-	 * incomplete so that we process the token correctly.
-	 * Anything else unexpected, we reject.
-	 */
-	if (*(*buff_in)++ == CONTEXT) {
-		if ((len = get_der_length(buff_in, bodysize -
-		    (*buff_in - iptr), &bytes)) < 0)
-			return (ACCEPT_DEFECTIVE_TOKEN);
-	} else {
-		return (ACCEPT_INCOMPLETE);
+	return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+static OM_uint32
+get_negTokenResp(OM_uint32 *minor_status,
+		 unsigned char *buf, unsigned int buflen,
+		 OM_uint32 *negState,
+		 gss_OID *supportedMech,
+		 gss_buffer_t *responseToken,
+		 gss_buffer_t *mechListMIC)
+{
+	unsigned char *ptr, *bufstart;
+	unsigned int len;
+	int tmplen;
+	unsigned int tag, bytes;
+
+	*negState = ACCEPT_DEFECTIVE_TOKEN;
+	*supportedMech = GSS_C_NO_OID;
+	*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+	ptr = bufstart = buf;
+#define REMAIN (buflen - (ptr - bufstart))
+
+	if (g_get_tag_and_length(&ptr, (CONTEXT | 0x01), REMAIN, &len) < 0)
+		return GSS_S_DEFECTIVE_TOKEN;
+	if (*ptr++ == SEQUENCE) {
+		tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+		if (tmplen < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
 	}
-
-	if (*(*buff_in) == OCTET_STRING)
-		return (ACCEPT_INCOMPLETE);
-
-	if (*(*buff_in)++ != ENUMERATED)
-		return (ACCEPT_DEFECTIVE_TOKEN);
-
-	if (*(*buff_in)++ != ENUMERATION_LENGTH)
-		return (ACCEPT_DEFECTIVE_TOKEN);
-
-	/*
-	 * Save the result byte to return later.
-	 * This is the result
-	 */
-	result = (OM_uint32)*(*buff_in)++;
-
-	if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
-	    bodysize - (*buff_in - iptr), &len) < 0)
-		result = ACCEPT_DEFECTIVE_TOKEN;
-
-	return (result);
+	if (REMAIN < 1)
+		tag = 0;
+	else
+		tag = *ptr++;
+
+	if (tag == CONTEXT) {
+		tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+		if (tmplen < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		if (g_get_tag_and_length(&ptr, ENUMERATED,
+					 REMAIN, &len) < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		if (len != ENUMERATION_LENGTH)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		if (REMAIN < 1)
+			return GSS_S_DEFECTIVE_TOKEN;
+		*negState = *ptr++;
+
+		if (REMAIN < 1)
+			tag = 0;
+		else
+			tag = *ptr++;
+	}
+	if (tag == (CONTEXT | 0x01)) {
+		tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+		if (tmplen < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		*supportedMech = get_mech_oid(minor_status, &ptr, REMAIN);
+		if (*supportedMech == GSS_C_NO_OID)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		if (REMAIN < 1)
+			tag = 0;
+		else
+			tag = *ptr++;
+	}
+	if (tag == (CONTEXT | 0x02)) {
+		tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+		if (tmplen < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		*responseToken = get_input_token(&ptr, REMAIN);
+		if (*responseToken == GSS_C_NO_BUFFER)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		if (REMAIN < 1)
+			tag = 0;
+		else
+			tag = *ptr++;
+	}
+	if (tag == (CONTEXT | 0x03)) {
+		tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+		if (tmplen < 0)
+			return GSS_S_DEFECTIVE_TOKEN;
+
+		*mechListMIC = get_input_token(&ptr, REMAIN);
+		if (*mechListMIC == GSS_C_NO_BUFFER)
+			return GSS_S_DEFECTIVE_TOKEN;
+	}
+	return GSS_S_COMPLETE;
+#undef REMAIN
 }
 
 /*
@@ -1977,7 +3061,8 @@
  */
 
 static int
-put_negResult(uchar_t **buf_out, OM_uint32 negResult, int buflen)
+put_negResult(unsigned char **buf_out, OM_uint32 negResult,
+	      unsigned int buflen)
 {
 	if (buflen < 3)
 		return (-1);
@@ -1992,46 +3077,51 @@
  * this server can support. It looks sequentially through the mechset
  * and the first one that matches what the server can support is
  * chosen as the negotiated mechanism. If one is found, negResult
- * is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult
- * is set to REJECT. Also, for purposes of determining latter behavior,
- * the flag, firstMech is used to indicate if the chosen mechanism is the
- * first of the mechset or not.
+ * is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if
+ * it's not the first mech, otherwise we return NULL and negResult
+ * is set to REJECT.
+ *
+ * NOTE: There is currently no way to specify a preference order of
+ * mechanisms supported by the acceptor.
  */
 static gss_OID
 negotiate_mech_type(OM_uint32 *minor_status,
-	gss_OID_set supported_mechSet,
-	gss_OID_set mechset,
-	OM_uint32 *negResult,
-	bool_t *firstMech)
+		    gss_OID_set supported_mechSet,
+		    gss_OID_set mechset,
+		    OM_uint32 *negResult)
 {
 	gss_OID returned_mech;
 	OM_uint32 status;
 	int present;
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < mechset->count; i++) {
-		gss_test_oid_set_member(minor_status, &mechset->elements[i],
-		    supported_mechSet, &present);
-		if (present == TRUE) {
-			*negResult = ACCEPT_COMPLETE;
-
-			if (i == 0)
-				*firstMech = TRUE;
-			else
-				*firstMech = FALSE;
-
-			status = generic_gss_copy_oid(minor_status,
-			    &mechset->elements[i], &returned_mech);
-
-			if (status != GSS_S_COMPLETE) {
-				*negResult = REJECT;
-				return (NULL);
-			}
-
-			return (returned_mech);
+		gss_OID mech_oid = &mechset->elements[i];
+
+		/* Accept wrong mechanism OID from MS clients */
+		if (mech_oid->length == gss_mech_krb5_wrong_oid.length &&
+		    memcmp(mech_oid->elements, gss_mech_krb5_wrong_oid.elements, mech_oid->length) == 0)
+			mech_oid = (gss_OID)&gss_mech_krb5_oid;;
+
+		gss_test_oid_set_member(minor_status, mech_oid, supported_mechSet, &present);
+		if (!present)
+			continue;
+
+		if (i == 0)
+			*negResult = ACCEPT_INCOMPLETE;
+		else
+			*negResult = REQUEST_MIC;
+
+		status = generic_gss_copy_oid(minor_status,
+					      &mechset->elements[i],
+					      &returned_mech);
+		if (status != GSS_S_COMPLETE) {
+			*negResult = REJECT;
+			map_errcode(minor_status);
+			return (NULL);
 		}
+		return (returned_mech);
 	}
-
 	*negResult = REJECT;
 	return (NULL);
 }
@@ -2046,14 +3136,7 @@
 static spnego_token_t
 make_spnego_token(char *name)
 {
-	spnego_token_t token;
-
-	token = (spnego_token_t)malloc(strlen(name)+1);
-
-	if (token == NULL)
-		return (NULL);
-	strcpy(token, name);
-	return (token);
+	return (spnego_token_t)strdup(name);
 }
 
 static gss_buffer_desc
@@ -2080,19 +3163,21 @@
  */
 static int
 make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
-	gss_OID_set mechSet,
-	gss_buffer_t data, send_token_flag sendtoken,
-	gss_buffer_t outbuf)
+			  int negHintsCompat,
+			  gss_buffer_t mechListMIC, OM_uint32 req_flags,
+			  gss_buffer_t data, send_token_flag sendtoken,
+			  gss_buffer_t outbuf)
 {
-	OM_uint32 status, minor_stat;
-	int tlen, dataLen = 0, ret = 0;
-	int MechSetLen = 0;
-	int negTokenInitSize = 0;
-	int i;
+	int ret = 0;
+	unsigned int tlen, dataLen = 0;
+	unsigned int negTokenInitSize = 0;
+	unsigned int negTokenInitSeqSize = 0;
+	unsigned int negTokenInitContSize = 0;
+	unsigned int rspTokenSize = 0;
+	unsigned int mechListTokenSize = 0;
+	unsigned int micTokenSize = 0;
 	unsigned char *t;
 	unsigned char *ptr;
-	unsigned char *MechListPtr = NULL;
-	gss_buffer_desc MICbuff;
 
 	if (outbuf == GSS_C_NO_BUFFER)
 		return (-1);
@@ -2102,82 +3187,13 @@
 
 	/* calculate the data length */
 
-	/* no token generated if sendtoken is not init or cont */
-	if ((sendtoken < INIT_TOKEN_SEND) ||
-	    (sendtoken > CONT_TOKEN_SEND)) {
-		return (-1);
-	}
-
 	/*
-	 * if this is the init token, we will send the mechset
-	 * so include it's length.
+	 * 0xa0 [DER LEN] [mechTypes]
 	 */
-	if (sendtoken == INIT_TOKEN_SEND) {
-		/*
-		 * Count bytes for the mechSet data
-		 * Encoded in final output as:
-		 * 0xa0 [DER LEN] 0x30 [DER LEN] [DATA]
-		 */
-		for (i = 0; i < mechSet->count; i++)
-			MechSetLen += 1 +
-			    der_length_size(mechSet->elements[i].length) +
-			    mechSet->elements[i].length;
-
-		MechSetLen += 1 + der_length_size(MechSetLen);
-		dataLen += 1 + der_length_size(MechSetLen) + MechSetLen;
-
-		MechListPtr = (uchar_t *)malloc(dataLen);
-		ptr = (uchar_t *)MechListPtr;
-
-		if (MechListPtr != NULL) {
-			if ((ret = put_mech_set(&ptr, mechSet, dataLen))) {
-				free(MechListPtr);
-				goto errout;
-			}
-		} else {
-			ret = -1;
-			goto errout;
-		}
-
-		/*
-		 * The MIC is done over the DER encoded mechSet.
-		 */
-		spnego_ctx->DER_mechTypes.value = MechListPtr;
-		spnego_ctx->DER_mechTypes.length = ptr - MechListPtr;
-
-		/*
-		 * Only send the MIC if we are *NOT* interoperating
-		 * with Microsoft.
-		 */
-		if (!spnego_ctx->MS_Interop) {
-			/*
-			 * MechListMIC = DER(MIC(DER(MechSet)))
-			 * Calculate it here, stick it in the buffer later.
-			 */
-			MICbuff.length = 0;
-			MICbuff.value = NULL;
-			status = gss_get_mic(&minor_stat,
-			    spnego_ctx->ctx_handle, GSS_C_QOP_DEFAULT,
-			    &spnego_ctx->DER_mechTypes, &MICbuff);
-			/*
-			 * If the MIC operation succeeded, use it,
-			 * but don't fail if it did not succeed.
-			 * MIC is optional and is not supported by all
-			 * mechanisms all the time.
-			 */
-			if (status  == GSS_S_COMPLETE) {
-				/*
-				 * Encoded in final output as:
-				 * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
-				 *	--s--   -------tlen------------
-				 */
-				tlen = 1 + der_length_size(MICbuff.length) +
-				    MICbuff.length;
-
-				dataLen += 1 + der_length_size(tlen) + tlen;
-			}
-		}
-	}
+	mechListTokenSize = 1 +
+		gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
+		spnego_ctx->DER_mechTypes.length;
+	dataLen += mechListTokenSize;
 
 	/*
 	 * If a token from gss_init_sec_context exists,
@@ -2189,9 +3205,25 @@
 		 * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
 		 * -----s--------|--------s2----------
 		 */
-		tlen = 1 + der_length_size(data->length) + data->length;
-
-		dataLen += 1 + der_length_size(tlen) + tlen;
+		rspTokenSize = 1 +
+			gssint_der_length_size(data->length) +
+			data->length;
+		dataLen += 1 + gssint_der_length_size(rspTokenSize) +
+			rspTokenSize;
+	}
+
+	if (mechListMIC) {
+		/*
+		 * Encoded in final output as:
+		 * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
+		 *	--s--     -----tlen------------
+		 */
+		micTokenSize = 1 +
+			gssint_der_length_size(mechListMIC->length) +
+			mechListMIC->length;
+		dataLen += 1 +
+			gssint_der_length_size(micTokenSize) +
+			micTokenSize;
 	}
 
 	/*
@@ -2200,7 +3232,9 @@
 	 *   0x30 [DER_LEN] [data]
 	 *
 	 */
-	dataLen += 1 + der_length_size(dataLen);
+	negTokenInitContSize = dataLen;
+	negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
+	dataLen = negTokenInitSeqSize;
 
 	/*
 	 * negTokenInitSize indicates the bytes needed to
@@ -2209,11 +3243,11 @@
 	 * 0xa0 [DER_LEN] + data
 	 *
 	 */
-	negTokenInitSize = dataLen;
-
-	tlen = g_token_size((gss_OID)gss_mech_spnego,
-	    negTokenInitSize + 1 +
-	    der_length_size(negTokenInitSize));
+	negTokenInitSize = 1 +
+		gssint_der_length_size(negTokenInitSeqSize) +
+		negTokenInitSeqSize;
+
+	tlen = g_token_size(gss_mech_spnego, negTokenInitSize);
 
 	t = (unsigned char *) malloc(tlen);
 
@@ -2224,63 +3258,55 @@
 	ptr = t;
 
 	/* create the message */
-	if ((ret = g_make_token_header((gss_OID)gss_mech_spnego,
-	    1 + negTokenInitSize + der_length_size(negTokenInitSize),
-	    &ptr, tlen)))
+	if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
+			    &ptr, tlen)))
+		goto errout;
+
+	*ptr++ = CONTEXT; /* NegotiationToken identifier */
+	if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
+		goto errout;
+
+	*ptr++ = SEQUENCE;
+	if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
+					 tlen - (int)(ptr-t))))
 		goto errout;
 
-	if (sendtoken == INIT_TOKEN_SEND) {
-		*ptr++ = CONTEXT; /* NegotiationToken identifier */
-		if ((ret = put_der_length(negTokenInitSize, &ptr, tlen)))
-			goto errout;
-
-		*ptr++ = SEQUENCE;
-		if ((ret = put_der_length(negTokenInitSize - 4, &ptr,
-		    tlen - (int)(ptr-t))))
-			goto errout;
-
-		*ptr++ = CONTEXT; /* MechTypeList identifier */
-		if ((ret = put_der_length(spnego_ctx->DER_mechTypes.length,
-		    &ptr, tlen - (int)(ptr-t))))
-			goto errout;
-
-		/* We already encoded the MechSetList */
-		(void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
-		    spnego_ctx->DER_mechTypes.length);
-
-		ptr += spnego_ctx->DER_mechTypes.length;
-
-	}
+	*ptr++ = CONTEXT | 0x00; /* MechTypeList identifier */
+	if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
+					 &ptr, tlen - (int)(ptr-t))))
+		goto errout;
+
+	/* We already encoded the MechSetList */
+	(void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
+		      spnego_ctx->DER_mechTypes.length);
+
+	ptr += spnego_ctx->DER_mechTypes.length;
 
 	if (data != NULL) {
 		*ptr++ = CONTEXT | 0x02;
-		if ((ret = put_der_length(data->length + 4,
-		    &ptr, tlen - (int)(ptr - t))))
+		if ((ret = gssint_put_der_length(rspTokenSize,
+				&ptr, tlen - (int)(ptr - t))))
 			goto errout;
 
 		if ((ret = put_input_token(&ptr, data,
-		    tlen - (int)(ptr - t))))
+			tlen - (int)(ptr - t))))
 			goto errout;
-
-		/*
-		 * We are in "optimistic" mode if we send a token
-		 * with out initial message.
-		 */
-		spnego_ctx->optimistic = (sendtoken == INIT_TOKEN_SEND);
 	}
 
-	if (!spnego_ctx->MS_Interop && MICbuff.length > 0) {
-		/* We already calculated the MechListMIC above */
-		int len = 1 +  der_length_size(MICbuff.length) + MICbuff.length;
+	if (mechListMIC != GSS_C_NO_BUFFER) {
 		*ptr++ = CONTEXT | 0x03;
-		if ((ret = put_der_length(len, &ptr, tlen - (int)(ptr - t))))
+		if ((ret = gssint_put_der_length(micTokenSize,
+				&ptr, tlen - (int)(ptr - t))))
 			goto errout;
 
-		if ((ret = put_input_token(&ptr, &MICbuff,
-		    tlen - (int)(ptr - t))))
+		if (negHintsCompat) {
+			ret = put_neg_hints(&ptr, mechListMIC,
+					    tlen - (int)(ptr - t));
+			if (ret)
+				goto errout;
+		} else if ((ret = put_input_token(&ptr, mechListMIC,
+				tlen - (int)(ptr - t))))
 			goto errout;
-
-		(void) gss_release_buffer(&minor_stat, &MICbuff);
 	}
 
 errout:
@@ -2303,25 +3329,22 @@
  */
 static int
 make_spnego_tokenTarg_msg(OM_uint32 status, gss_OID mech_wanted,
-			gss_buffer_t data, gss_buffer_t mechListMIC,
-			send_token_flag sendtoken, int MS_Flag,
-			gss_buffer_t outbuf)
+			  gss_buffer_t data, gss_buffer_t mechListMIC,
+			  send_token_flag sendtoken,
+			  gss_buffer_t outbuf)
 {
-	int tlen;
-	int ret;
-	int NegTokenTargSize;
-	int negresultTokenSize;
-	int NegTokenSize;
-	int rspTokenSize;
-	int micTokenSize;
-	int dataLen = 0;
+	unsigned int tlen = 0;
+	unsigned int ret = 0;
+	unsigned int NegTokenTargSize = 0;
+	unsigned int NegTokenSize = 0;
+	unsigned int rspTokenSize = 0;
+	unsigned int micTokenSize = 0;
+	unsigned int dataLen = 0;
 	unsigned char *t;
 	unsigned char *ptr;
 
 	if (outbuf == GSS_C_NO_BUFFER)
 		return (GSS_S_DEFECTIVE_TOKEN);
-	if (sendtoken == INIT_TOKEN_SEND && mech_wanted == GSS_C_NO_OID)
-		return (GSS_S_DEFECTIVE_TOKEN);
 
 	outbuf->length = 0;
 	outbuf->value = NULL;
@@ -2332,7 +3355,7 @@
 	 *  ENUMERATED TAG, Length, Value,
 	 * Plus 2 bytes for the CONTEXT id and length.
 	 */
-	negresultTokenSize = 5;
+	dataLen = 5;
 
 	/*
 	 * calculate data length
@@ -2341,53 +3364,39 @@
 	 * mech_type and the negotiation result fields.
 	 */
 	if (sendtoken == INIT_TOKEN_SEND) {
-
-		if (mech_wanted != NULL) {
-			int mechlistTokenSize;
-			/*
-			 * 1 byte for the CONTEXT ID(0xa0),
-			 * 1 byte for the OID ID(0x06)
-			 * 1 byte for OID Length field
-			 * Plus the rest... (OID Length, OID value)
-			 */
-			mechlistTokenSize = 3 + mech_wanted->length +
-			    der_length_size(mech_wanted->length);
-
-			dataLen = negresultTokenSize + mechlistTokenSize;
-		}
-	} else {
+		int mechlistTokenSize;
 		/*
-		 * If this is a response from a server, count
-		 * the space needed for the negResult field.
-		 * LENGTH(2) + ENUM(2) + result
+		 * 1 byte for the CONTEXT ID(0xa0),
+		 * 1 byte for the OID ID(0x06)
+		 * 1 byte for OID Length field
+		 * Plus the rest... (OID Length, OID value)
 		 */
-		dataLen = negresultTokenSize;
+		mechlistTokenSize = 3 + mech_wanted->length +
+			gssint_der_length_size(mech_wanted->length);
+
+		dataLen += mechlistTokenSize;
 	}
 	if (data != NULL && data->length > 0) {
 		/* Length of the inner token */
-		rspTokenSize = 1 + der_length_size(data->length) +
-		    data->length;
+		rspTokenSize = 1 + gssint_der_length_size(data->length) +
+			data->length;
 
 		dataLen += rspTokenSize;
 
 		/* Length of the outer token */
-		dataLen += 1 + der_length_size(rspTokenSize);
+		dataLen += 1 + gssint_der_length_size(rspTokenSize);
 	}
 	if (mechListMIC != NULL) {
 
 		/* Length of the inner token */
-		micTokenSize = 1 + der_length_size(mechListMIC->length) +
-		    mechListMIC->length;
+		micTokenSize = 1 + gssint_der_length_size(mechListMIC->length) +
+			mechListMIC->length;
 
 		dataLen += micTokenSize;
 
 		/* Length of the outer token */
-		dataLen += 1 + der_length_size(micTokenSize);
-	} else if (data != NULL && data->length > 0 && MS_Flag) {
-		dataLen += rspTokenSize;
-		dataLen += 1 + der_length_size(rspTokenSize);
+		dataLen += 1 + gssint_der_length_size(micTokenSize);
 	}
-
 	/*
 	 * Add size of DER encoded:
 	 * NegTokenTarg [ SEQUENCE ] of
@@ -2403,7 +3412,7 @@
 	 *	Result Length + ASN.1 overhead
 	 */
 	NegTokenTargSize = dataLen;
-	dataLen += 1 + der_length_size(NegTokenTargSize);
+	dataLen += 1 + gssint_der_length_size(NegTokenTargSize);
 
 	/*
 	 * NegotiationToken [ CHOICE ]{
@@ -2411,7 +3420,7 @@
 	 *    negTokenTarg  [1]	 NegTokenTarg }
 	 */
 	NegTokenSize = dataLen;
-	dataLen += 1 + der_length_size(NegTokenSize);
+	dataLen += 1 + gssint_der_length_size(NegTokenSize);
 
 	tlen = dataLen;
 	t = (unsigned char *) malloc(tlen);
@@ -2423,98 +3432,82 @@
 
 	ptr = t;
 
-	if (sendtoken == INIT_TOKEN_SEND ||
-	    sendtoken == ERROR_TOKEN_SEND) {
+	/*
+	 * Indicate that we are sending CHOICE 1
+	 * (NegTokenTarg)
+	 */
+	*ptr++ = CONTEXT | 0x01;
+	if (gssint_put_der_length(NegTokenSize, &ptr, dataLen) < 0) {
+		ret = GSS_S_DEFECTIVE_TOKEN;
+		goto errout;
+	}
+	*ptr++ = SEQUENCE;
+	if (gssint_put_der_length(NegTokenTargSize, &ptr,
+				  tlen - (int)(ptr-t)) < 0) {
+		ret = GSS_S_DEFECTIVE_TOKEN;
+		goto errout;
+	}
+
+	/*
+	 * First field of the NegTokenTarg SEQUENCE
+	 * is the ENUMERATED NegResult.
+	 */
+	*ptr++ = CONTEXT;
+	if (gssint_put_der_length(3, &ptr,
+				  tlen - (int)(ptr-t)) < 0) {
+		ret = GSS_S_DEFECTIVE_TOKEN;
+		goto errout;
+	}
+	if (put_negResult(&ptr, status, tlen - (int)(ptr - t)) < 0) {
+		ret = GSS_S_DEFECTIVE_TOKEN;
+		goto errout;
+	}
+	if (sendtoken == INIT_TOKEN_SEND) {
 		/*
-		 * Indicate that we are sending CHOICE 1
-		 * (NegTokenTarg)
+		 * Next, is the Supported MechType
 		 */
 		*ptr++ = CONTEXT | 0x01;
-		if ((ret = put_der_length(NegTokenSize, &ptr, dataLen))) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			goto errout;
-		}
-
-		*ptr++ = SEQUENCE;
-		if ((ret = put_der_length(NegTokenTargSize, &ptr,
-		    tlen - (int)(ptr-t)))) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			goto errout;
-		}
-
-		/*
-		 * First field of the NegTokenTarg SEQUENCE
-		 * is the ENUMERATED NegResult.
-		 */
-		*ptr++ = CONTEXT;
-		if ((ret = put_der_length(3, &ptr,
-		    tlen - (int)(ptr-t)))) {
+		if (gssint_put_der_length(mech_wanted->length + 2,
+					  &ptr,
+					  tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
-		if ((ret = put_negResult(&ptr, status,
-		    tlen - (int)(ptr - t)))) {
+		if (put_mech_oid(&ptr, mech_wanted,
+				 tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
-
-		if (sendtoken != ERROR_TOKEN_SEND && mech_wanted != NULL) {
-			/*
-			 * Next, is the Supported MechType
-			 */
-			*ptr++ = CONTEXT | 0x01;
-			if ((ret = put_der_length(mech_wanted->length + 2,
-			    &ptr, tlen - (int)(ptr - t)))) {
-				ret = GSS_S_DEFECTIVE_TOKEN;
-				goto errout;
-			}
-			if ((ret = put_mech_oid(&ptr, mech_wanted,
-			    tlen - (int)(ptr - t)))) {
-				ret = GSS_S_DEFECTIVE_TOKEN;
-				goto errout;
-			}
-		}
 	}
-
 	if (data != NULL && data->length > 0) {
 		*ptr++ = CONTEXT | 0x02;
-		if ((ret = put_der_length(rspTokenSize, &ptr,
-		    tlen - (int)(ptr - t)))) {
+		if (gssint_put_der_length(rspTokenSize, &ptr,
+					  tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
-		if ((ret = put_input_token(&ptr, data,
-		    tlen - (int)(ptr - t)))) {
+		if (put_input_token(&ptr, data,
+				    tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
 	}
 	if (mechListMIC != NULL) {
 		*ptr++ = CONTEXT | 0x03;
-		if ((ret = put_der_length(micTokenSize, &ptr,
-		    tlen - (int)(ptr - t)))) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-			goto errout;
-		}
-		if ((ret = put_input_token(&ptr, mechListMIC,
-		    tlen - (int)(ptr - t)))) {
+		if (gssint_put_der_length(micTokenSize, &ptr,
+					  tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
-	} else if (data != NULL && data->length > 0 && MS_Flag) {
-		*ptr++ = CONTEXT | 0x03;
-		if ((ret = put_der_length(rspTokenSize, &ptr,
-		    tlen - (int)(ptr - t)))) {
+		if (put_input_token(&ptr, mechListMIC,
+				    tlen - (int)(ptr - t)) < 0) {
 			ret = GSS_S_DEFECTIVE_TOKEN;
 			goto errout;
 		}
-		if ((ret = put_input_token(&ptr, data,
-		    tlen - (int)(ptr - t)))) {
-			ret = GSS_S_DEFECTIVE_TOKEN;
-		}
 	}
+	ret = GSS_S_COMPLETE;
 errout:
-	if (ret != 0) {
+	if (ret != GSS_S_COMPLETE) {
 		if (t)
 			free(t);
 	} else {
@@ -2527,7 +3520,7 @@
 
 /* determine size of token */
 static int
-g_token_size(gss_OID mech, unsigned int body_size)
+g_token_size(gss_OID_const mech, unsigned int body_size)
 {
 	int hdrsize;
 
@@ -2538,14 +3531,14 @@
 	 *
 	 * 0x06 [MECHLENFIELD] MECHDATA
 	 */
-	hdrsize = 1 + der_length_size(mech->length) + mech->length;
+	hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
 
 	/*
 	 * Now add the bytes needed for the initial header
 	 * token bytes:
 	 * 0x60 + [DER_LEN] + HDRSIZE
 	 */
-	hdrsize += 1 + der_length_size(body_size + hdrsize);
+	hdrsize += 1 + gssint_der_length_size(body_size + hdrsize);
 
 	return (hdrsize + body_size);
 }
@@ -2558,55 +3551,63 @@
  * with Microsoft or others that actually follow the spec.
  */
 static int
-g_make_token_header(gss_OID mech,
-	int body_size,
-	unsigned char **buf,
-	int totallen)
+g_make_token_header(gss_OID_const mech,
+		    unsigned int body_size,
+		    unsigned char **buf,
+		    unsigned int totallen)
 {
-	int hdrsize, ret = 0;
+	int ret = 0;
+	unsigned int hdrsize;
 	unsigned char *p = *buf;
 
-	hdrsize = 1 + der_length_size(mech->length) + mech->length;
+	hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
 
 	*(*buf)++ = HEADER_ID;
-	if ((ret = put_der_length(hdrsize + body_size, buf, totallen)))
+	if ((ret = gssint_put_der_length(hdrsize + body_size, buf, totallen)))
 		return (ret);
 
 	*(*buf)++ = MECH_OID;
-	if ((ret = put_der_length(mech->length, buf,
-	    totallen - (int)(p - *buf))))
+	if ((ret = gssint_put_der_length(mech->length, buf,
+			    totallen - (int)(p - *buf))))
 		return (ret);
-	TWRITE_STR(*buf, mech->elements, ((int)mech->length));
+	TWRITE_STR(*buf, mech->elements, mech->length);
 	return (0);
 }
 
+/*
+ * NOTE: This checks that the length returned by
+ * gssint_get_der_length() is not greater than the number of octets
+ * remaining, even though gssint_get_der_length() already checks, in
+ * theory.
+ */
 static int
 g_get_tag_and_length(unsigned char **buf, int tag,
-		unsigned int buflen, unsigned int *outlen)
+		     unsigned int buflen, unsigned int *outlen)
 {
 	unsigned char *ptr = *buf;
 	int ret = -1; /* pessimists, assume failure ! */
 	unsigned int encoded_len;
-	int tmplen = 0;
+	unsigned int tmplen = 0;
 
 	*outlen = 0;
 	if (buflen > 1 && *ptr == tag) {
 		ptr++;
-		tmplen = get_der_length(&ptr, buflen - 1, &encoded_len);
+		tmplen = gssint_get_der_length(&ptr, buflen - 1,
+						&encoded_len);
 		if (tmplen < 0) {
 			ret = -1;
-		} else if ((unsigned int)tmplen > buflen - (ptr - *buf)) {
+		} else if (tmplen > buflen - (ptr - *buf)) {
 			ret = -1;
 		} else
 			ret = 0;
 	}
-	*outlen = (unsigned int)tmplen;
+	*outlen = tmplen;
 	*buf = ptr;
 	return (ret);
 }
 
 static int
-g_verify_neg_token_init(unsigned char **buf_in, int cur_size)
+g_verify_neg_token_init(unsigned char **buf_in, unsigned int cur_size)
 {
 	unsigned char *buf = *buf_in;
 	unsigned char *endptr = buf + cur_size;
@@ -2629,7 +3630,7 @@
 	 * a strucure of type NegTokenInit.
 	 */
 	if (*buf++ == SEQUENCE) {
-		if ((seqsize = get_der_length(&buf, cur_size, &bytes)) < 0)
+		if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
 			return (G_BAD_TOK_HEADER);
 		/*
 		 * Make sure we have the entire buffer as described
@@ -2646,7 +3647,7 @@
 	 * Verify that the first blob is a sequence of mechTypes
 	 */
 	if (*buf++ == CONTEXT) {
-		if ((seqsize = get_der_length(&buf, cur_size, &bytes)) < 0)
+		if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
 			return (G_BAD_TOK_HEADER);
 		/*
 		 * Make sure we have the entire buffer as described
@@ -2669,11 +3670,11 @@
 
 /* verify token header. */
 static int
-g_verify_token_header(gss_OID mech,
-	int *body_size,
-	unsigned char **buf_in,
-	int tok_type,
-	int toksize)
+g_verify_token_header(gss_OID_const mech,
+		    unsigned int *body_size,
+		    unsigned char **buf_in,
+		    int tok_type,
+		    unsigned int toksize)
 {
 	unsigned char *buf = *buf_in;
 	int seqsize;
@@ -2681,32 +3682,34 @@
 	int ret = 0;
 	unsigned int bytes;
 
-	if ((toksize -= 1) < 0)
+	if (toksize-- < 1)
 		return (G_BAD_TOK_HEADER);
 
 	if (*buf++ != HEADER_ID)
 		return (G_BAD_TOK_HEADER);
 
-	if ((seqsize = get_der_length(&buf, toksize, &bytes)) < 0)
+	if ((seqsize = gssint_get_der_length(&buf, toksize, &bytes)) < 0)
 		return (G_BAD_TOK_HEADER);
 
 	if ((seqsize + bytes) != toksize)
 		return (G_BAD_TOK_HEADER);
 
-	if ((toksize -= 1) < 0)
+	if (toksize-- < 1)
 		return (G_BAD_TOK_HEADER);
 
 
 	if (*buf++ != MECH_OID)
 		return (G_BAD_TOK_HEADER);
 
-	if ((toksize -= 1) < 0)
+	if (toksize-- < 1)
 		return (G_BAD_TOK_HEADER);
 
 	toid.length = *buf++;
 
-	if ((toksize -= toid.length) < 0)
+	if (toksize < toid.length)
 		return (G_BAD_TOK_HEADER);
+	else
+		toksize -= toid.length;
 
 	toid.elements = buf;
 	buf += toid.length;
@@ -2718,8 +3721,10 @@
 	 * G_WRONG_MECH is not returned immediately because it's more important
 	 * to return G_BAD_TOK_HEADER if the token header is in fact bad
 	 */
-	if ((toksize -= 2) < 0)
+	if (toksize < 2)
 		return (G_BAD_TOK_HEADER);
+	else
+		toksize -= 2;
 
 	if (!ret) {
 		*buf_in = buf;
@@ -2728,3 +3733,26 @@
 
 	return (ret);
 }
+
+/*
+ * Return non-zero if the oid is one of the kerberos mech oids,
+ * otherwise return zero.
+ *
+ * N.B. There are 3 oids that represent the kerberos mech:
+ * RFC-specified GSS_MECH_KRB5_OID,
+ * Old pre-RFC   GSS_MECH_KRB5_OLD_OID,
+ * Incorrect MS  GSS_MECH_KRB5_WRONG_OID
+ */
+
+static int
+is_kerb_mech(gss_OID oid)
+{
+	int answer = 0;
+	OM_uint32 minor;
+	extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
+	
+	(void) gss_test_oid_set_member(&minor,
+		oid, (gss_OID_set)gss_mech_set_krb5_both, &answer);
+	
+	return (answer);
+}
--- a/usr/src/lib/gss_mechs/mech_spnego/sparc/Makefile	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/sparc/Makefile	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,13 +19,14 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # lib/gss_mechs/mech_spnego/sparc/Makefile
 
 include ../Makefile.com
+include ../../mech_krb5/Makefile.mech_krb5
+
+LDLIBS += 	-lgss -lc -lmech_krb5 -L$(ROOT_KLIBDIR) $(KRUNPATH)
 
 install: all $(ROOTLIBS)
--- a/usr/src/lib/gss_mechs/mech_spnego/sparcv9/Makefile	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/gss_mechs/mech_spnego/sparcv9/Makefile	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,14 +19,15 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # lib/gss_mechs/mech_spnego/sparcv9/Makefile
 
 include ../Makefile.com
 include ../../../Makefile.lib.64
+include ../../mech_krb5/Makefile.mech_krb5
+
+LDLIBS64 += 	-lgss -lc -lmech_krb5 -L$(ROOT_KLIBDIR64) $(KRUNPATH64)
 
 install: all $(ROOTLIBS64)
--- a/usr/src/lib/krb5/kadm5/clnt/Makefile.com	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/krb5/kadm5/clnt/Makefile.com	Mon Sep 21 16:47:51 2009 -0700
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY= libkadm5clnt.a
 VERS= .1
@@ -70,6 +68,7 @@
 CPPFLAGS += -I.. -I../.. -I../../.. -I$(SRC)/lib/gss_mechs/mech_krb5/include \
 	-I$(SRC)/lib/krb5 \
 	-I$(SRC)/lib/gss_mechs/mech_krb5/include/krb5 \
+	-I$(SRC)/uts/common/gssapi/ \
 	-I$(SRC)/uts/common/gssapi/include/ \
 	-I$(SRC)/uts/common/gssapi/mechs/krb5/include \
 	-I$(SRC)/lib/gss_mechs/mech_krb5/krb5/os \
--- a/usr/src/lib/krb5/kadm5/srv/Makefile.com	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/krb5/kadm5/srv/Makefile.com	Mon Sep 21 16:47:51 2009 -0700
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY= libkadm5srv.a
 VERS= .1
@@ -75,6 +73,7 @@
 	-I$(SRC)/cmd/krb5/iprop \
 	-I$(SRC)/lib/gss_mechs/mech_krb5/include \
 	-I$(SRC)/lib/gss_mechs/mech_krb5/include/krb5 \
+	-I$(SRC)/uts/common/gssapi/ \
 	-I$(SRC)/uts/common/gssapi/include/ \
 	-I$(SRC)/uts/common/gssapi/mechs/krb5/include \
 	-I$(SRC)/lib/gss_mechs/mech_krb5/krb5/os \
--- a/usr/src/lib/libgss/Makefile.com	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/libgss/Makefile.com	Mon Sep 21 16:47:51 2009 -0700
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY = libgss.a
 VERS = .1
@@ -62,20 +60,29 @@
 	  g_dup_name.o \
 	  g_export_name.o \
 	  g_utils.o \
-	  g_userok.o
+	  g_userok.o \
+	  g_buffer_set.o \
+	  g_inq_context_oid.o \
 
 
 # defines the duplicate sources we share with gsscred
 GSSCRED_DIR =	$(SRC)/cmd/gss/gsscred
 GSSCREDOBJ =	gsscred_utils.o gsscred_file.o
+# defines the duplicate sources we share with krb5 mech
+KRB5DIR= $(SRC)/lib/gss_mechs/mech_krb5/mech
+KRB5OBJ= rel_buffer.o util_buffer_set.o
+# defines the duplicate sources we share with kernel module
 UTSGSSDIR =	$(SRC)/uts/common/gssapi
 UTSGSSOBJ =	gen_oids.o
+
 SRCS +=		$(GSSCREDOBJ:%.o=$(GSSCRED_DIR)/%.c) \
+		$(KRB5OBJ:%.o=$(KRB5DIR)/%.c) \
 		$(UTSGSSOBJ:%.o=$(UTSGSSDIR)/%.c)
 GSSLINTSRC =	$(GSSOBJECTS:%.o=$(SRCDIR)/%.c) \
 		$(GSSCREDOBJ:%.o=$(GSSCRED_DIR)/%.c) \
+	        $(KRB5OBJ:%.o=$(KRB5DIR)/%.c) \
 		$(UTSGSSOBJ:%.o=$(UTSGSSDIR)/%.c)
-OBJECTS =	$(GSSOBJECTS) $(GSSCREDOBJ) $(UTSGSSOBJ)
+OBJECTS =	$(GSSOBJECTS) $(GSSCREDOBJ) $(KRB5OBJ) $(UTSGSSOBJ)
 
 # include library definitions
 include ../../Makefile.lib
@@ -86,6 +93,9 @@
 LDLIBS += 	-lc
 
 CPPFLAGS += 	-I$(GSSCRED_DIR) -I$(SRC)/uts/common/gssapi/include \
+		 -I$(SRC)/uts/common/gssapi/mechs/krb5/include \
+		 -I$(SRC)/uts/common/gssapi/ \
+		 -I$(SRC)/lib/gss_mechs/mech_krb5/include/ \
 		-DHAVE_STDLIB_H
 
 $(EXPORT_RELEASE_BUILD)include $(CLOSED)/lib/libgss/Makefile.export
@@ -102,6 +112,16 @@
 	$(COMPILE.c) -o $@ $(@:pics/%.o=$(GSSCRED_DIR)/%.c)
 	$(POST_PROCESS_O)
 
+# we need this in libgss so we don't have to link against mech_krb5
+pics/rel_buffer.o: $(SRC)/lib/gss_mechs/mech_krb5/mech/rel_buffer.c
+	$(COMPILE.c) -o $@ $(SRC)/lib/gss_mechs/mech_krb5/mech/rel_buffer.c
+	$(POST_PROCESS_O)
+
+# we need this in libgss so we don't have to link against mech_krb5
+pics/util_buffer_set.o: $(SRC)/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c
+	$(COMPILE.c) -o $@ $(SRC)/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c
+	$(POST_PROCESS_O)
+
 # gen_oids.c is kept in the kernel since the OIDs declared in them are
 # used by rpcsec module
 pics/gen_oids.o: $(SRC)/uts/common/gssapi/gen_oids.c
--- a/usr/src/lib/libgss/g_accept_sec_context.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/libgss/g_accept_sec_context.c	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -140,7 +139,7 @@
 
 	if (*context_handle == GSS_C_NO_CONTEXT) {
 
-		if (GSS_EMPTY_BUFFER(input_token_buffer))
+		if (input_token_buffer == GSS_C_NO_BUFFER)
 			return (GSS_S_CALL_INACCESSIBLE_READ);
 
 		/* Get the token mech type */
@@ -365,8 +364,14 @@
 		*context_handle = GSS_C_NO_CONTEXT;
 	}
 
+#if 0
+	/*
+	 * Solaris Kerberos
+	 * Don't release, it causes a problem with error token.
+	 */
 	if (output_token->length)
 		(void) gss_release_buffer(&t_minstat, output_token);
+#endif
 
 	if (src_name)
 		*src_name = GSS_C_NO_NAME;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libgss/g_buffer_set.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32  gss_create_empty_buffer_set
+	   (OM_uint32 * minor_status,
+	    gss_buffer_set_t *buffer_set)
+{
+    return generic_gss_create_empty_buffer_set(minor_status, buffer_set);
+}
+
+OM_uint32  gss_add_buffer_set_member
+	   (OM_uint32 * minor_status,
+	    const gss_buffer_t member_buffer,
+	    gss_buffer_set_t *buffer_set)
+{
+    return generic_gss_add_buffer_set_member(minor_status,
+					     member_buffer,
+					     buffer_set);
+}
+
+OM_uint32  gss_release_buffer_set
+	   (OM_uint32 * minor_status,
+	    gss_buffer_set_t *buffer_set)
+{
+    return generic_gss_release_buffer_set(minor_status, buffer_set);
+}
+
--- a/usr/src/lib/libgss/g_glue.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/libgss/g_glue.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,38 +1,44 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#include "mglueP.h"
 
-#include <mechglueP.h>
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#include <strings.h>
+#endif
+#include <string.h>
 #include <errno.h>
 
+#include "k5-platform-store_32.h"
+#include "k5-platform-store_16.h"
+/*
+ * SUNW17PACresync
+ * MIT has diff names for these GSS utilities.  Solaris needs to change
+ * them globally to get in sync w/MIT.
+ * Revisit for full 1.7 resync.
+ */
+#define gssint_get_modOptions __gss_get_modOptions
+#define gssint_der_length_size der_length_size
+#define gssint_get_der_length get_der_length
+#define gssint_put_der_length put_der_length
+#define gssint_get_mechanism __gss_get_mechanism
+#define gssint_get_mechanism_cred __gss_get_mechanism_cred
+#define gssint_copy_oid_set gss_copy_oid_set
+#define gssint_get_mech_type __gss_get_mech_type
+#define gssint_export_internal_name __gss_export_internal_name
+#define gssint_release_internal_name __gss_release_internal_name
+#define gssint_convert_name_to_union_name __gss_convert_name_to_union_name
+#define gssint_import_internal_name __gss_import_internal_name
+#define gssint_display_internal_name __gss_display_internal_name
+
+
 #define	MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
 
+extern gss_mechanism *gssint_mechs_array;
+
 /*
  * This file contains the support routines for the glue layer.
  */
@@ -45,72 +51,72 @@
  * by the buffer. Note we return -1 on error.
  */
 int
-get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
 {
-	/* p points to the beginning of the buffer */
-	unsigned char *p = *buf;
-	int length, new_length;
-	int octets;
+    /* p points to the beginning of the buffer */
+    unsigned char *p = *buf;
+    int length, new_length;
+    unsigned int octets;
 
-	if (buf_len < 1)
-		return (-1);
+    if (buf_len < 1)
+	return (-1);
 
-	/* We should have at least one byte */
-	*bytes = 1;
+    /* We should have at least one byte */
+    *bytes = 1;
 
-	/*
-	 * If the High order bit is not set then the length is just the value
-	 * of *p.
-	 */
-	if (*p < 128) {
-		*buf = p+1;	/* Advance the buffer */
+    /*
+     * If the High order bit is not set then the length is just the value
+     * of *p.
+     */
+    if (*p < 128) {
+	*buf = p+1;	/* Advance the buffer */
 	return (*p);		/* return the length */
-	}
+    }
 
-	/*
-	 * if the High order bit is set, then the low order bits represent
-	 * the number of bytes that contain the DER encoding of the length.
-	 */
+    /*
+     * if the High order bit is set, then the low order bits represent
+     * the number of bytes that contain the DER encoding of the length.
+     */
 
-	octets = *p++ & 0x7f;
-	*bytes += octets;
+    octets = *p++ & 0x7f;
+    *bytes += octets;
 
-	/* See if the supplied buffer contains enough bytes for the length. */
-	if (octets > buf_len - 1)
-		return (-1);
+    /* See if the supplied buffer contains enough bytes for the length. */
+    if (octets > buf_len - 1)
+	return (-1);
 
-	/*
-	 * Calculate a multibyte length. The length is encoded as an
-	 * unsigned integer base 256.
-	 */
-	for (length = 0; octets; octets--) {
-		new_length = (length << 8) + *p++;
-		if (new_length < length)  /* overflow */
-			return (-1);
-		length = new_length;
-	}
+    /*
+     * Calculate a multibyte length. The length is encoded as an
+     * unsigned integer base 256.
+     */
+    for (length = 0; octets; octets--) {
+	new_length = (length << 8) + *p++;
+	if (new_length < length)  /* overflow */
+	    return (-1);
+	length = new_length;
+    }
 
-	*buf = p; /* Advance the buffer */
+    *buf = p; /* Advance the buffer */
 
-	return (length);
+    return (length);
 }
 
 /*
  * der_length_size: Return the number of bytes to encode a given length.
  */
 unsigned int
-der_length_size(unsigned int len)
+gssint_der_length_size(unsigned int len)
 {
-	int i;
+    int i;
 
-	if (len < 128)
-		return (1);
+    if (len < 128)
+	return (1);
 
-	for (i = 0; len; i++) {
-		len >>= 8;
-	}
+    for (i = 0; len; i++) {
+	len >>= 8;
+    }
 
-	return (i+1);
+    return (i+1);
 }
 
 /*
@@ -121,58 +127,60 @@
  * be encoded in max_len characters.
  */
 int
-put_der_length(unsigned length, unsigned char **buf, unsigned int max_len)
+gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
 {
-	unsigned char *s = *buf, *p;
-	unsigned int buf_len = 0;
-	int i, first;
+    unsigned char *s, *p;
+    unsigned int buf_len = 0;
+    int i, first;
 
-	/* Oops */
-	if (buf == 0 || max_len < 1)
-		return (-1);
+    /* Oops */
+    if (buf == 0 || max_len < 1)
+	return (-1);
+
+    s = *buf;
 
-	/* Single byte is the length */
-	if (length < 128) {
-		*s++ = length;
-		*buf = s;
-		return (0);
-	}
+    /* Single byte is the length */
+    if (length < 128) {
+	*s++ = length;
+	*buf = s;
+	return (0);
+    }
 
-	/* First byte contains the number of octets */
-	p = s + 1;
+    /* First byte contains the number of octets */
+    p = s + 1;
 
-	/* Running total of the DER encoding length */
-	buf_len = 0;
+    /* Running total of the DER encoding length */
+    buf_len = 0;
 
-	/*
-	 * Encode MSB first. We do the encoding by setting a shift
-	 * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
-	 * by the factor. We then encode the resulting low order byte.
-	 * We subtract 8 from the shift factor and repeat to ecnode the next
-	 * byte. We stop when the shift factor is zero or we've run out of
-	 * buffer to encode into.
-	 */
-	first = 0;
-	for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
-		unsigned int v;
-		v = (length >> i) & 0xff;
-		if ((v) || first) {
-			buf_len += 1;
-			*p++ = v;
-			first = 1;
-		}
+    /*
+     * Encode MSB first. We do the encoding by setting a shift
+     * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
+     * by the factor. We then encode the resulting low order byte.
+     * We subtract 8 from the shift factor and repeat to ecnode the next
+     * byte. We stop when the shift factor is zero or we've run out of
+     * buffer to encode into.
+     */
+    first = 0;
+    for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
+	unsigned int v;
+	v = (length >> i) & 0xff;
+	if ((v) || first) {
+	    buf_len += 1;
+	    *p++ = v;
+	    first = 1;
 	}
-	if (i >= 0)			/* buffer overflow */
-		return (-1);
+    }
+    if (i >= 0)			/* buffer overflow */
+	return (-1);
 
-	/*
-	 * We go back now and set the first byte to be the length with
-	 * the high order bit set.
-	 */
-	*s = buf_len | 0x80;
-	*buf = p;
+    /*
+     * We go back now and set the first byte to be the length with
+     * the high order bit set.
+     */
+    *s = buf_len | 0x80;
+    *buf = p;
 
-	return (0);
+    return (0);
 }
 
 
@@ -180,342 +188,433 @@
  *  glue routine for get_mech_type
  *
  */
-OM_uint32
-__gss_get_mech_type(OID, token)
-	gss_OID			OID;
-	const gss_buffer_t	token;
+
+OM_uint32 gssint_get_mech_type_oid(OID, token)
+    gss_OID		OID;
+    gss_buffer_t	token;
 {
-	unsigned char *buffer_ptr;
-	int length;
-
-	/*
-	 * This routine reads the prefix of "token" in order to determine
-	 * its mechanism type. It assumes the encoding suggested in
-	 * Appendix B of RFC 1508. This format starts out as follows :
-	 *
-	 * tag for APPLICATION 0, Sequence[constructed, definite length]
-	 * length of remainder of token
-	 * tag of OBJECT IDENTIFIER
-	 * length of mechanism OID
-	 * encoding of mechanism OID
-	 * <the rest of the token>
-	 *
-	 * Numerically, this looks like :
-	 *
-	 * 0x60
-	 * <length> - could be multiple bytes
-	 * 0x06
-	 * <length> - assume only one byte, hence OID length < 127
-	 * <mech OID bytes>
-	 *
-	 * The routine fills in the OID value and returns an error as necessary.
-	 */
-
+    unsigned char * buffer_ptr;
+    int length;
+    
+    /*
+     * This routine reads the prefix of "token" in order to determine
+     * its mechanism type. It assumes the encoding suggested in
+     * Appendix B of RFC 1508. This format starts out as follows :
+     *
+     * tag for APPLICATION 0, Sequence[constructed, definite length]
+     * length of remainder of token
+     * tag of OBJECT IDENTIFIER
+     * length of mechanism OID
+     * encoding of mechanism OID
+     * <the rest of the token>
+     *
+     * Numerically, this looks like :
+     *
+     * 0x60
+     * <length> - could be multiple bytes
+     * 0x06
+     * <length> - assume only one byte, hence OID length < 127
+     * <mech OID bytes>
+     *
+     * The routine fills in the OID value and returns an error as necessary.
+     */
+    
 	if (OID == NULL)
 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
 	if ((token == NULL) || (token->value == NULL))
-		return (GSS_S_DEFECTIVE_TOKEN);
-
-	/* Skip past the APP/Sequnce byte and the token length */
+	return (GSS_S_DEFECTIVE_TOKEN);
+    
+    /* Skip past the APP/Sequnce byte and the token length */
+    
+    buffer_ptr = (unsigned char *) token->value;
 
-	buffer_ptr = (unsigned char *) token->value;
-
-	if (*(buffer_ptr++) != 0x60)
-		return (GSS_S_DEFECTIVE_TOKEN);
-	length = *buffer_ptr++;
+    if (*(buffer_ptr++) != 0x60)
+	return (GSS_S_DEFECTIVE_TOKEN);
+    length = *buffer_ptr++;
 
 	/* check if token length is null */
 	if (length == 0)
 	    return (GSS_S_DEFECTIVE_TOKEN);
 
-	if (length & 0x80) {
-		if ((length & 0x7f) > 4)
-			return (GSS_S_DEFECTIVE_TOKEN);
-		buffer_ptr += length & 0x7f;
-	}
+    if (length & 0x80) {
+	if ((length & 0x7f) > 4)
+	    return (GSS_S_DEFECTIVE_TOKEN);
+	buffer_ptr += length & 0x7f;
+    }
+    
+    if (*(buffer_ptr++) != 0x06)
+	return (GSS_S_DEFECTIVE_TOKEN);
+    
+    OID->length = (OM_uint32) *(buffer_ptr++);
+    OID->elements = (void *) buffer_ptr;
+    return (GSS_S_COMPLETE);
+}
 
-	if (*(buffer_ptr++) != 0x06)
-		return (GSS_S_DEFECTIVE_TOKEN);
+/*
+ * The following mechanisms do not always identify themselves
+ * per the GSS-API specification, when interoperating with MS
+ * peers. We include the OIDs here so we do not have to link
+ * with the mechanism.
+ */
+static gss_OID_desc gss_ntlm_mechanism_oid_desc =
+	{10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+	{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+	{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+
+#define NTLMSSP_SIGNATURE "NTLMSSP"
 
-	OID->length = (OM_uint32) *(buffer_ptr++);
-	OID->elements = (void *) buffer_ptr;
-	return (GSS_S_COMPLETE);
+OM_uint32 gssint_get_mech_type(OID, token)
+    gss_OID		OID;
+    gss_buffer_t	token;
+{
+    /* Check for interoperability exceptions */
+    if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&
+	memcmp(token->value, NTLMSSP_SIGNATURE,
+	       sizeof(NTLMSSP_SIGNATURE)) == 0) {
+	*OID = gss_ntlm_mechanism_oid_desc;
+    } else if (token->length != 0 &&
+	       ((char *)token->value)[0] == 0x6E) {
+ 	/* Could be a raw AP-REQ (check for APPLICATION tag) */
+	*OID = gss_krb5_mechanism_oid_desc;
+    } else if (token->length == 0) {
+	*OID = gss_spnego_mechanism_oid_desc;
+    } else {
+	return gssint_get_mech_type_oid(OID, token);
+    }
+
+    return (GSS_S_COMPLETE);
 }
 
 
 /*
  *  Internal routines to get and release an internal mechanism name
  */
-OM_uint32 __gss_import_internal_name(minor_status, mech_type, union_name,
-					internal_name)
+
+#if 0 /* SUNW17PACresync */
+#include "mglueP.h"
+#endif
+
+OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name, 
+				internal_name)
 OM_uint32		*minor_status;
-const gss_OID		mech_type;
+gss_OID			mech_type;
 gss_union_name_t	union_name;
 gss_name_t		*internal_name;
 {
-	OM_uint32			status;
-	gss_mechanism		mech;
+    OM_uint32		status;
+    gss_mechanism	mech;
 
-	mech = __gss_get_mechanism(mech_type);
-	if (mech) {
-		if (mech->gss_import_name)
-			status = mech->gss_import_name(
-						mech->context,
-						minor_status,
-						union_name->external_name,
-						union_name->name_type,
-						internal_name);
-		else
-			status = GSS_S_UNAVAILABLE;
+    mech = gssint_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_import_name) {
+	    status = mech->gss_import_name (
+		    mech->context, /* SUNW17PACresync */
+					    minor_status,
+					    union_name->external_name,
+					    union_name->name_type,
+					    internal_name);
+	    if (status != GSS_S_COMPLETE)
+		map_error(minor_status, mech);
+	} else
+	    status = GSS_S_UNAVAILABLE;
 
-		return (status);
-	}
+	return (status);
+    }
 
-	return (GSS_S_BAD_MECH);
+    return (GSS_S_BAD_MECH);
 }
 
-
-OM_uint32 __gss_export_internal_name(minor_status, mech_type,
-		internal_name, name_buf)
-OM_uint32		*minor_status;
-const gss_OID		mech_type;
-const gss_name_t	internal_name;
-gss_buffer_t		name_buf;
+OM_uint32 gssint_export_internal_name(minor_status, mech_type,
+				     internal_name, name_buf)
+    OM_uint32		*minor_status;
+    const gss_OID		mech_type;
+    const gss_name_t	internal_name;
+    gss_buffer_t		name_buf;
 {
-	OM_uint32 status;
-	gss_mechanism mech;
-	gss_buffer_desc dispName;
-	gss_OID nameOid;
-	unsigned char *buf = NULL;
-	const unsigned char tokId[] = "\x04\x01";
-	const int tokIdLen = 2;
-	const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
-	int mechOidDERLen = 0;
-	int mechOidLen = 0;
+    OM_uint32 status;
+    gss_mechanism mech;
+    gss_buffer_desc dispName;
+    gss_OID nameOid;
+    unsigned char *buf = NULL;
+    const unsigned char tokId[] = "\x04\x01";
+    const unsigned int tokIdLen = 2;
+    const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
+    int mechOidDERLen = 0;
+    int mechOidLen = 0;
 
-	mech = __gss_get_mechanism(mech_type);
-	if (!mech)
-		return (GSS_S_BAD_MECH);
+    mech = gssint_get_mechanism(mech_type);
+    if (!mech)
+	return (GSS_S_BAD_MECH);
 
-	if (mech->gss_export_name)
-		return (mech->gss_export_name(mech->context,
-						minor_status,
-						internal_name,
-						name_buf));
+    if (mech->gss_export_name) {
+	status = mech->gss_export_name(
+		mech->context,  /* SUNW17PACresync */
+		minor_status,
+		internal_name,
+		name_buf);
+	if (status != GSS_S_COMPLETE)
+	    map_error(minor_status, mech);
+	return status;
+    }
 
-	/*
-	 * if we are here it is because the mechanism does not provide
-	 * a gss_export_name so we will use our implementation.  We
-	 * do required that the mechanism define a gss_display_name.
-	 */
-	if (!mech->gss_display_name)
-		return (GSS_S_UNAVAILABLE);
+    /*
+     * if we are here it is because the mechanism does not provide
+     * a gss_export_name so we will use our implementation.  We
+     * do required that the mechanism define a gss_display_name.
+     */
+    if (!mech->gss_display_name)
+	return (GSS_S_UNAVAILABLE);
 
-	/*
-	 * NOTE: RFC2743 (section 3.2) governs the format of the outer
-	 *	 wrapper of exported names; the mechanisms' specs govern
-	 *	 the format of the inner portion of the exported name
-	 *	 and, for some (e.g., RFC1964, the Kerberos V mech), a
-	 *	 generic default as implemented here will do.
-	 *
-	 * The outer wrapper of an exported MN is: 2-octet tok Id
-	 * (0x0401) + 2-octet network-byte order mech OID length + mech
-	 * oid (in DER format, including DER tag and DER length) +
-	 * 4-octet network-byte order length of inner portion + inner
-	 * portion.
-	 *
-	 * For the Kerberos V mechanism the inner portion of an exported
-	 * MN is the display name string and ignores the name type OID
-	 * altogether.  And we hope this will be so for any future
-	 * mechanisms also, so that factoring name export/import out of
-	 * the mech and into libgss pays off.
-	 */
-	if ((status = mech->gss_display_name(mech->context,
-						minor_status,
-						internal_name,
-						&dispName,
-						&nameOid))
-						!= GSS_S_COMPLETE)
-		return (status);
+    /*
+     * NOTE: RFC2743 (section 3.2) governs the format of the outer
+     *	 wrapper of exported names; the mechanisms' specs govern
+     *	 the format of the inner portion of the exported name
+     *	 and, for some (e.g., RFC1964, the Kerberos V mech), a
+     *	 generic default as implemented here will do.
+     *
+     * The outer wrapper of an exported MN is: 2-octet tok Id
+     * (0x0401) + 2-octet network-byte order mech OID length + mech
+     * oid (in DER format, including DER tag and DER length) +
+     * 4-octet network-byte order length of inner portion + inner
+     * portion.
+     *
+     * For the Kerberos V mechanism the inner portion of an exported
+     * MN is the display name string and ignores the name type OID
+     * altogether.  And we hope this will be so for any future
+     * mechanisms also, so that factoring name export/import out of
+     * the mech and into libgss pays off.
+     */
+    if ((status = mech->gss_display_name(
+		mech->context,
+		minor_status,
+					 internal_name,
+					 &dispName,
+					 &nameOid))
+	!= GSS_S_COMPLETE) {
+	map_error(minor_status, mech);
+	return (status);
+    }
 
-	/* determine the size of the buffer needed */
-	mechOidDERLen = der_length_size(mech_type->length);
-	name_buf->length = tokIdLen + mechOidLenLen +
-				mechOidTagLen + mechOidDERLen +
-				mech_type->length +
-				nameLenLen + dispName.length;
-	if ((name_buf->value = (void*)malloc(name_buf->length)) ==
-		(void*)NULL) {
-			name_buf->length = 0;
-			(void) gss_release_buffer(&status, &dispName);
-			return (GSS_S_FAILURE);
-	}
+    /* determine the size of the buffer needed */
+    mechOidDERLen = gssint_der_length_size(mech_type->length);
+    name_buf->length = tokIdLen + mechOidLenLen +
+	mechOidTagLen + mechOidDERLen +
+	mech_type->length +
+	nameLenLen + dispName.length;
+    if ((name_buf->value = (void*)malloc(name_buf->length)) ==
+	(void*)NULL) {
+	name_buf->length = 0;
+	(void) gss_release_buffer(&status, &dispName);
+	return (GSS_S_FAILURE);
+    }
 
-	/* now create the name ..... */
-	buf = (unsigned char *)name_buf->value;
-	(void) memset(name_buf->value, 0, name_buf->length);
-	(void) memcpy(buf, tokId, tokIdLen);
-	buf += tokIdLen;
+    /* now create the name ..... */
+    buf = (unsigned char *)name_buf->value;
+    (void) memset(name_buf->value, 0, name_buf->length);
+    (void) memcpy(buf, tokId, tokIdLen);
+    buf += tokIdLen;
 
-	/* spec allows only 2 bytes for the mech oid length */
-	mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
-	*buf++ = (mechOidLen & 0xFF00) >> 8;
-	*buf++ = (mechOidLen & 0x00FF);
+    /* spec allows only 2 bytes for the mech oid length */
+    mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
+    store_16_be(mechOidLen, buf);
+    buf += 2;
 
-	/*
-	 * DER Encoding of mech OID contains OID Tag (0x06), length and
-	 * mech OID value
-	 */
-	*buf++ = 0x06;
-	if (put_der_length(mech_type->length, &buf,
-		(name_buf->length - tokIdLen -2)) != 0) {
-		name_buf->length = 0;
-		free(name_buf->value);
-		(void) gss_release_buffer(&status, &dispName);
-		return (GSS_S_FAILURE);
-	}
+    /*
+     * DER Encoding of mech OID contains OID Tag (0x06), length and
+     * mech OID value
+     */
+    *buf++ = 0x06;
+    if (gssint_put_der_length(mech_type->length, &buf,
+		       (name_buf->length - tokIdLen -2)) != 0) {
+	name_buf->length = 0;
+	free(name_buf->value);
+	(void) gss_release_buffer(&status, &dispName);
+	return (GSS_S_FAILURE);
+    }
 
-	(void) memcpy(buf, mech_type->elements, mech_type->length);
-	buf += mech_type->length;
+    (void) memcpy(buf, mech_type->elements, mech_type->length);
+    buf += mech_type->length;
 
-	/* spec designates the next 4 bytes for the name length */
-	*buf++ = (dispName.length & 0xFF000000) >> 24;
-	*buf++ = (dispName.length & 0x00FF0000) >> 16;
-	*buf++ = (dispName.length & 0x0000FF00) >> 8;
-	*buf++ = (dispName.length & 0X000000FF);
+    /* spec designates the next 4 bytes for the name length */
+    store_32_be(dispName.length, buf);
+    buf += 4;
 
-	/* for the final ingredient - add the name from gss_display_name */
-	(void) memcpy(buf, dispName.value, dispName.length);
+    /* for the final ingredient - add the name from gss_display_name */
+    (void) memcpy(buf, dispName.value, dispName.length);
 
-	/* release the buffer obtained from gss_display_name */
-	(void) gss_release_buffer(minor_status, &dispName);
-	return (GSS_S_COMPLETE);
-} /*  __gss_export_internal_name */
-
+    /* release the buffer obtained from gss_display_name */
+    (void) gss_release_buffer(minor_status, &dispName);
+    return (GSS_S_COMPLETE);
+} /*  gssint_export_internal_name */
 
-OM_uint32 __gss_display_internal_name(minor_status, mech_type, internal_name,
-						external_name, name_type)
-OM_uint32		*minor_status;
-const gss_OID		mech_type;
-const gss_name_t	internal_name;
-gss_buffer_t		external_name;
-gss_OID			*name_type;
+OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name, 
+				 external_name, name_type)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_name_t	internal_name;
+gss_buffer_t	external_name;
+gss_OID		*name_type;
 {
-	OM_uint32			status;
-	gss_mechanism		mech;
+    OM_uint32		status;
+    gss_mechanism	mech;
 
-	mech = __gss_get_mechanism(mech_type);
-	if (mech) {
-		if (mech->gss_display_name)
-			status = mech->gss_display_name(
-							mech->context,
-							minor_status,
-							internal_name,
-							external_name,
-							name_type);
-		else
-			status = GSS_S_UNAVAILABLE;
+    mech = gssint_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_display_name) {
+	    status = mech->gss_display_name (
+		    mech->context,
+					     minor_status,
+					     internal_name,
+					     external_name,
+					     name_type);
+	    if (status != GSS_S_COMPLETE)
+		map_error(minor_status, mech);
+	} else
+	    status = GSS_S_UNAVAILABLE;
 
-		return (status);
-	}
+	return (status);
+    }
 
-	return (GSS_S_BAD_MECH);
+    return (GSS_S_BAD_MECH);
 }
 
-OM_uint32
-__gss_release_internal_name(minor_status, mech_type, internal_name)
-OM_uint32		*minor_status;
-const gss_OID		mech_type;
-gss_name_t		*internal_name;
+OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_name_t	*internal_name;
 {
-	OM_uint32			status;
-	gss_mechanism		mech;
+    OM_uint32		status;
+    gss_mechanism	mech;
 
-	mech = __gss_get_mechanism(mech_type);
-	if (mech) {
-		if (mech->gss_release_name)
-			status = mech->gss_release_name(
-							mech->context,
-							minor_status,
-							internal_name);
-		else
-			status = GSS_S_UNAVAILABLE;
+    mech = gssint_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_release_name) {
+	    status = mech->gss_release_name (
+		    mech->context,
+					     minor_status,
+					     internal_name);
+	    if (status != GSS_S_COMPLETE)
+		map_error(minor_status, mech);
+	} else
+	    status = GSS_S_UNAVAILABLE;
 
-		return (status);
-	}
+	return (status);
+    }
 
-	return (GSS_S_BAD_MECH);
+    return (GSS_S_BAD_MECH);
 }
 
+OM_uint32 gssint_delete_internal_sec_context (minor_status,
+					      mech_type,
+					      internal_ctx,
+					      output_token)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_ctx_id_t	*internal_ctx;
+gss_buffer_t	output_token;
+{
+    OM_uint32		status;
+    gss_mechanism	mech;
+
+    mech = gssint_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_delete_sec_context)
+	    status = mech->gss_delete_sec_context (
+		    mech->context,  /* SUNW17PACresync */
+		    minor_status,
+		    internal_ctx,
+		    output_token);
+	else
+	    /* SUNW17PACresync - map error here? */
+	    status = GSS_S_UNAVAILABLE;
+
+	return (status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
 
 /*
  * This function converts an internal gssapi name to a union gssapi
  * name.  Note that internal_name should be considered "consumed" by
  * this call, whether or not we return an error.
  */
-OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
-						internal_name, external_name)
-	OM_uint32 *minor_status;
-	gss_mechanism		mech;
-	gss_name_t		internal_name;
-	gss_name_t		*external_name;
+OM_uint32 gssint_convert_name_to_union_name(minor_status, mech,
+					   internal_name, external_name)
+    OM_uint32 *minor_status;
+    gss_mechanism	mech;
+    gss_name_t	internal_name;
+    gss_name_t	*external_name;
 {
-	OM_uint32 major_status, tmp;
-	gss_union_name_t union_name;
+    OM_uint32 major_status,tmp;
+    gss_union_name_t union_name;
 
-	union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
-	if (!union_name) {
-			goto allocation_failure;
-	}
-	union_name->mech_type = 0;
-	union_name->mech_name = internal_name;
-	union_name->name_type = 0;
-	union_name->external_name = 0;
+    union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
+    if (!union_name) {
+	major_status = GSS_S_FAILURE;
+	*minor_status = ENOMEM;
+	map_errcode(minor_status);
+	goto allocation_failure;
+    }
+    union_name->mech_type = 0;
+    union_name->mech_name = internal_name;
+    union_name->name_type = 0;
+    union_name->external_name = 0;
 
-	major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
-						&union_name->mech_type);
-	if (major_status != GSS_S_COMPLETE)
-		goto allocation_failure;
+    major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
+					&union_name->mech_type);
+    if (major_status != GSS_S_COMPLETE) {
+	map_errcode(minor_status);
+	goto allocation_failure;
+    }
 
-	union_name->external_name =
-		(gss_buffer_t)malloc(sizeof (gss_buffer_desc));
-	if (!union_name->external_name) {
-			goto allocation_failure;
-	}
+    union_name->external_name =
+	(gss_buffer_t) malloc(sizeof(gss_buffer_desc));
+    if (!union_name->external_name) {
+	    major_status = GSS_S_FAILURE;
+	    *minor_status = ENOMEM;
+	    goto allocation_failure;
+    }
+	
+    major_status = mech->gss_display_name(
+	    mech->context,  /* SUNW17PACresync */
+	    minor_status,
+	    internal_name,
+	    union_name->external_name,
+	    &union_name->name_type);
+    if (major_status != GSS_S_COMPLETE) {
+	map_error(minor_status, mech);
+	goto allocation_failure;
+    }
 
-	major_status = mech->gss_display_name(mech->context, minor_status,
-						internal_name,
-						union_name->external_name,
-						&union_name->name_type);
-	if (major_status != GSS_S_COMPLETE)
-		goto allocation_failure;
-
-	*external_name =  (gss_name_t)union_name;
-	return (GSS_S_COMPLETE);
+    union_name->loopback = union_name;
+    *external_name = (gss_name_t) union_name;
+    return (GSS_S_COMPLETE);
 
 allocation_failure:
-	if (union_name) {
-		if (union_name->external_name) {
-			if (union_name->external_name->value)
-				free(union_name->external_name->value);
-			free(union_name->external_name);
-		}
-		if (union_name->name_type)
-			(void) gss_release_oid(&tmp, &union_name->name_type);
-		if (union_name->mech_type)
-			(void) gss_release_oid(&tmp, &union_name->mech_type);
-		free(union_name);
+    if (union_name) {
+	if (union_name->external_name) {
+	    if (union_name->external_name->value)
+		free(union_name->external_name->value);
+	    free(union_name->external_name);
 	}
-	/*
-	 * do as the top comment says - since we are now owners of
-	 * internal_name, we must clean it up
-	 */
-	if (internal_name)
-		(void) __gss_release_internal_name(&tmp, &mech->mech_type,
-						&internal_name);
-
-	return (major_status);
+	if (union_name->name_type)
+		(void) gss_release_oid(&tmp, &union_name->name_type);
+	if (union_name->mech_type)
+		(void) gss_release_oid(&tmp, &union_name->mech_type);
+	free(union_name);
+    }
+    /*
+     * do as the top comment says - since we are now owners of
+     * internal_name, we must clean it up
+     */
+    if (internal_name)
+	(void) gssint_release_internal_name(&tmp, &mech->mech_type,
+					   &internal_name);
+    return (major_status);
 }
 
 /*
@@ -523,63 +622,87 @@
  * external union credential.
  */
 gss_cred_id_t
-__gss_get_mechanism_cred(union_cred, mech_type)
-	const gss_union_cred_t	union_cred;
-	const gss_OID		mech_type;
+gssint_get_mechanism_cred(union_cred, mech_type)
+    gss_union_cred_t	union_cred;
+    gss_OID		mech_type;
 {
-	int			i;
+    int		i;
+
+    if (union_cred == (gss_union_cred_t) GSS_C_NO_CREDENTIAL)
+	return GSS_C_NO_CREDENTIAL;
+
+    /*
+     * SUNW17PACresync
+     * Disable this block as it causes problems for gss_add_cred
+     * for HTTP SSO (and also probably causes STC gss.13 to fail too).
+     */
+#if 0
+    /* SPNEGO mechanism will again call into GSSAPI */
+    if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type))
+	return (gss_cred_id_t)union_cred;
+#endif
 
-	if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
-		return (GSS_C_NO_CREDENTIAL);
+    for (i=0; i < union_cred->count; i++) {
+	if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
+	    return union_cred->cred_array[i];
+
+	/* for SPNEGO, check the next-lower set of creds */
+	if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) {
+	    gss_union_cred_t candidate_cred;
+	    gss_cred_id_t    sub_cred;
 
-	for (i = 0; i < union_cred->count; i++) {
-		if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
-			return (union_cred->cred_array[i]);
+	    candidate_cred = (gss_union_cred_t)union_cred->cred_array[i];
+	    sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type);
+
+	    if(sub_cred != GSS_C_NO_CREDENTIAL)
+		return sub_cred;
 	}
-	return (GSS_C_NO_CREDENTIAL);
+    }
+
+    return GSS_C_NO_CREDENTIAL;
 }
 
-
 /*
  * Routine to create and copy the gss_buffer_desc structure.
  * Both space for the structure and the data is allocated.
  */
 OM_uint32
 gssint_create_copy_buffer(srcBuf, destBuf, addNullChar)
-	const gss_buffer_t	srcBuf;
-	gss_buffer_t 		*destBuf;
-	int			addNullChar;
+    const gss_buffer_t	srcBuf;
+    gss_buffer_t 		*destBuf;
+    int			addNullChar;
 {
-	gss_buffer_t aBuf;
-	int len;
+    gss_buffer_t aBuf;
+    unsigned int len;
 
-	if (destBuf == NULL)
-		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    if (destBuf == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-	*destBuf = 0;
+    *destBuf = 0;
 
-	aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
-	if (!aBuf)
-		return (GSS_S_FAILURE);
+    aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+    if (!aBuf)
+	return (GSS_S_FAILURE);
 
-	if (addNullChar)
-		len = srcBuf->length + 1;
-	else
-		len = srcBuf->length;
+    if (addNullChar)
+	len = srcBuf->length + 1;
+    else
+	len = srcBuf->length;
 
-	if (!(aBuf->value = (void*)malloc(len))) {
-		free(aBuf);
-		return (GSS_S_FAILURE);
-	}
+    if (!(aBuf->value = (void*)malloc(len))) {
+	free(aBuf);
+	return (GSS_S_FAILURE);
+    }
 
 
-	(void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
-	aBuf->length = srcBuf->length;
-	*destBuf = aBuf;
+    (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
+    aBuf->length = srcBuf->length;
+    *destBuf = aBuf;
 
-	/* optionally add a NULL character */
-	if (addNullChar)
-		((char *)aBuf->value)[aBuf->length] = '\0';
+    /* optionally add a NULL character */
+    if (addNullChar)
+	((char *)aBuf->value)[aBuf->length] = '\0';
 
-	return (GSS_S_COMPLETE);
-} /* ****** __gss_create_copy_buffer  ****** */
+    return (GSS_S_COMPLETE);
+} /* ****** gssint_create_copy_buffer  ****** */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libgss/g_inq_context_oid.c	Mon Sep 21 16:47:51 2009 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ *  glue routine for gss_inquire_sec_context_by_oid
+ */
+
+#include "mglueP.h"
+#define gssint_get_mechanism __gss_get_mechanism /* SUNW17PACresync */
+
+OM_uint32
+gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
+	                        const gss_ctx_id_t context_handle,
+	                        const gss_OID desired_object,
+	                        gss_buffer_set_t *data_set)
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = gssint_get_mechanism (ctx->mech_type);
+
+    if (mech != NULL) {
+	if (mech->gss_inquire_sec_context_by_oid != NULL) {
+	    status = mech->gss_inquire_sec_context_by_oid(minor_status,
+							  ctx->internal_ctx_id,
+							  desired_object,
+							  data_set);
+	    if (status != GSS_S_COMPLETE)
+		map_error(minor_status, mech);
+	} else
+	    status = GSS_S_BAD_MECH;
+
+	return status;
+    }
+
+    return GSS_S_NO_CONTEXT;
+}
+
--- a/usr/src/lib/libgss/mapfile-vers	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/libgss/mapfile-vers	Mon Sep 21 16:47:51 2009 -0700
@@ -52,6 +52,7 @@
 	GSS_C_NT_MACHINE_UID_NAME;
 	GSS_C_NT_STRING_UID_NAME;
 	GSS_C_NT_USER_NAME;
+	GSS_C_INQ_SSPI_SESSION_KEY;
 	gss_compare_name;
 	gss_context_time;
 	gss_create_empty_oid_set;
@@ -87,6 +88,10 @@
 	gss_verify_mic;
 	gss_wrap;
 	gss_wrap_size_limit;
+	gss_add_buffer_set_member;
+	gss_create_empty_buffer_set;
+	gss_release_buffer_set;
+	gss_inquire_sec_context_by_oid;
 } SUNW_1.1;
 
 # Due to mistakes made early in the history of this library, there are
@@ -112,6 +117,7 @@
 	gsscred_set_options;
 	gss_get_group_info;
 	__gss_get_kmodName;
+	__gss_get_mechanism;
 	__gss_get_mechanisms;
 	__gss_get_mech_info;
 	__gss_get_mech_type;
--- a/usr/src/lib/libkrb5/common/mapfile-vers	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/lib/libkrb5/common/mapfile-vers	Mon Sep 21 16:47:51 2009 -0700
@@ -260,6 +260,15 @@
         krb5_set_key_enctype =	FUNCTION FILTER mech_krb5.so.1;
         krb5_set_key_data =	FUNCTION FILTER mech_krb5.so.1;
         krb5_set_key_length =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_add_buffer =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_free =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_get_buffer =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_get_types =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_init =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_parse =	FUNCTION FILTER mech_krb5.so.1;
+        krb5_pac_verify =	FUNCTION FILTER mech_krb5.so.1;
+	krb5_decode_authdata_container  =	FUNCTION FILTER mech_krb5.so.1;
+	krb5_encode_authdata_container  =	FUNCTION FILTER mech_krb5.so.1;
 
 # krb5.h - priv/deprecated
         krb5_string_to_key =	FUNCTION FILTER mech_krb5.so.1;
@@ -274,6 +283,9 @@
 	krb5_free_ap_rep =	FUNCTION FILTER mech_krb5.so.1;
 	krb5_free_cred =	FUNCTION FILTER mech_krb5.so.1;
 	krb5_decrypt_tkt_part =	FUNCTION FILTER mech_krb5.so.1;
+	krb5_get_error_message = 	FUNCTION FILTER mech_krb5.so.1;
+	krb5_free_error_message = FUNCTION FILTER mech_krb5.so.1;
+	krb5_clear_error_message =  FUNCTION FILTER mech_krb5.so.1;
 	valid_cksumtype =	FUNCTION FILTER mech_krb5.so.1;
 
 # k5-int.h (needed by Samba, openssl, etc)
@@ -283,5 +295,4 @@
 	krb5_rc_initialize =	FUNCTION FILTER mech_krb5.so.1;
 	krb5_rc_default	=	FUNCTION FILTER mech_krb5.so.1;
 	krb5_rc_destroy =	FUNCTION FILTER mech_krb5.so.1;
-
 };
--- a/usr/src/uts/common/gssapi/gen_oids.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/gen_oids.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,10 +1,8 @@
 /*
- * Copyright 1996-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
  *
@@ -66,6 +64,8 @@
 	{6, "\053\006\001\005\006\002"},
 	{6, "\053\006\001\005\006\003"},
 	{6, "\053\006\001\005\006\004"},
+	{11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"},
+
 };
 
 const gss_OID_desc * const gss_nt_user_name = oids+0;
@@ -93,3 +93,4 @@
 const gss_OID GSS_C_NT_HOSTBASED_SERVICE = (gss_OID)oids+4;
 const gss_OID GSS_C_NT_ANONYMOUS = (gss_OID)oids+5;
 const gss_OID GSS_C_NT_EXPORT_NAME = (gss_OID)oids+6;
+const gss_OID GSS_C_INQ_SSPI_SESSION_KEY   = (gss_OID)oids+7;
--- a/usr/src/uts/common/gssapi/gssapi_ext.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/gssapi_ext.h	Mon Sep 21 16:47:51 2009 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Private extensions and utilities to the GSS-API.
@@ -31,8 +30,6 @@
 #ifndef _GSSAPI_EXT_H
 #define	_GSSAPI_EXT_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <gssapi/gssapi.h>
 #ifdef	_KERNEL
 #include <sys/systm.h>
@@ -200,6 +197,13 @@
 	OM_uint32		*initiator_time_rec,
 	OM_uint32		*acceptor_time_rec);
 
+/*
+ * Returns a buffer set with the first member containing the
+ * session key for SSPI compatibility. The optional second
+ * member contains an OID identifying the session key type.
+ */
+extern const gss_OID GSS_C_INQ_SSPI_SESSION_KEY;
+
 #else	/*	_KERNEL	*/
 
 OM_uint32
@@ -228,9 +232,36 @@
 	gid_t *gids[],
 	int *gidsLen,
 	uid_t uid);
-
 #endif
 
+/*
+ * GGF extensions
+ */
+typedef struct gss_buffer_set_desc_struct {
+    size_t count;
+    gss_buffer_desc *elements;
+} gss_buffer_set_desc, *gss_buffer_set_t;
+
+#define	GSS_C_NO_BUFFER_SET ((gss_buffer_set_t)0)
+
+OM_uint32 gss_create_empty_buffer_set
+	(OM_uint32 *, /* minor_status */
+	gss_buffer_set_t *); /* buffer_set */
+
+OM_uint32 gss_add_buffer_set_member
+	(OM_uint32 *, /* minor_status */
+	const gss_buffer_t, /* member_buffer */
+	gss_buffer_set_t *); /* buffer_set */
+
+OM_uint32  gss_release_buffer_set
+	(OM_uint32 *, /* minor_status */
+	gss_buffer_set_t *); /* buffer_set */
+
+OM_uint32 gss_inquire_sec_context_by_oid
+	(OM_uint32 *, /* minor_status */
+	const gss_ctx_id_t, /* context_handle */
+	const gss_OID, /* desired_object */
+	gss_buffer_set_t *); /* data_set */
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/gssapi/gssd_clnt_stubs.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/gssd_clnt_stubs.c	Mon Sep 21 16:47:51 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  *  GSSAPI library stub module for gssd.
  */
@@ -766,6 +764,16 @@
 	if (minor_status != NULL)
 		*minor_status = res.minor_status;
 
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
+		output_token->length =
+			(size_t)res.output_token.GSS_BUFFER_T_len;
+		output_token->value =
+			(void *)MALLOC(output_token->length);
+		(void) memcpy(output_token->value,
+			    res.output_token.GSS_BUFFER_T_val,
+			    output_token->length);
+	}
+
 	/* if the call was successful, copy out the results */
 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
 		res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
@@ -779,16 +787,6 @@
 			res.context_handle.GSS_CTX_ID_T_val);
 		*gssd_context_verifier = res.gssd_context_verifier;
 
-		if (output_token != NULL) {
-			output_token->length =
-				(size_t)res.output_token.GSS_BUFFER_T_len;
-			output_token->value =
-				(void *)MALLOC(output_token->length);
-			(void) memcpy(output_token->value,
-				res.output_token.GSS_BUFFER_T_val,
-				output_token->length);
-		}
-
 		if (res.status == GSS_S_COMPLETE) {
 			if (actual_mech_type != NULL) {
 				*actual_mech_type =
@@ -1055,6 +1053,19 @@
 		return (GSS_S_FAILURE);
 	}
 
+	if (minor_status != NULL)
+		*minor_status = res.minor_status;
+
+	if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
+		output_token->length =
+			res.output_token.GSS_BUFFER_T_len;
+		output_token->value =
+			(void *)  MALLOC(output_token->length);
+		(void) memcpy(output_token->value,
+			    res.output_token.GSS_BUFFER_T_val,
+			    output_token->length);
+	}
+
 	/* if the call was successful, copy out the results */
 
 	if (res.status == (OM_uint32) GSS_S_COMPLETE ||
@@ -1070,19 +1081,6 @@
 			res.context_handle.GSS_CTX_ID_T_val);
 			*gssd_context_verifier = res.gssd_context_verifier;
 
-		if (output_token != NULL) {
-			output_token->length =
-					res.output_token.GSS_BUFFER_T_len;
-			output_token->value =
-				(void *)  MALLOC(output_token->length);
-			(void) memcpy(output_token->value,
-				res.output_token.GSS_BUFFER_T_val,
-				output_token->length);
-		}
-
-		if (minor_status != NULL)
-			*minor_status = res.minor_status;
-
 		/* these other parameters are only ready upon GSS_S_COMPLETE */
 		if (res.status == (OM_uint32) GSS_S_COMPLETE) {
 
--- a/usr/src/uts/common/gssapi/include/mechglueP.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/include/mechglueP.h	Mon Sep 21 16:47:51 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This header contains the private mechglue definitions.
  *
@@ -72,7 +70,8 @@
  * Generic GSSAPI names.  A name can either be a generic name, or a
  * mechanism specific name....
  */
-typedef struct gss_union_name_t {
+typedef struct gss_name_struct {
+	struct gss_name_struct *loopback;
 	gss_OID			name_type;
 	gss_buffer_t		external_name;
 	/*
@@ -161,6 +160,7 @@
 	OM_uint32	    (*gss_acquire_cred)
 	(
 		    void *,		/* context */
+
 		    OM_uint32 *,	/* minor_status */
 		    const gss_name_t,	/* desired_name */
 		    OM_uint32,		/* time_req */
@@ -172,6 +172,7 @@
 	/* */);
 	OM_uint32	    (*gss_release_cred)
 	(
+
 		    void *,		/* context */
 		    OM_uint32 *,	/* minor_status */
 		    gss_cred_id_t *	/* cred_handle */
@@ -516,6 +517,17 @@
 		gss_OID_set *,		/* elements_stored */
 		gss_cred_usage_t *	/* cred_usage_stored */
 	/* */);
+
+	/* GGF extensions */
+
+        OM_uint32       (*gss_inquire_sec_context_by_oid)
+        (
+		OM_uint32 *,        /* minor_status */
+		const gss_ctx_id_t, /* context_handle */
+		const gss_OID,      /* OID */
+		gss_buffer_set_t *  /* data_set */
+	/* */);
+
 #endif
 } *gss_mechanism;
 
@@ -873,5 +885,59 @@
 	    gss_OID *		/* oid */
 	   );
 
+OM_uint32
+generic_gss_oid_compose(
+    OM_uint32 *,        /* minor_status */
+    const char *,       /* prefix */
+    size_t,             /* prefix_len */
+    int,                /* suffix */
+    gss_OID_desc *);    /* oid */
+
+OM_uint32
+generic_gss_oid_decompose(
+    OM_uint32 *,        /* minor_status */
+    const char *,       /*prefix */
+    size_t,             /* prefix_len */
+    gss_OID_desc *,     /* oid */
+    int *);             /* suffix */
+
+OM_uint32 generic_gss_create_empty_buffer_set
+(OM_uint32 * /*minor_status*/,
+            gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 generic_gss_add_buffer_set_member
+(OM_uint32 * /*minor_status*/,
+            const gss_buffer_t /*member_buffer*/,
+            gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 generic_gss_release_buffer_set
+(OM_uint32 * /*minor_status*/,
+            gss_buffer_set_t * /*buffer_set*/);
+
+/*
+ * SUNW17PACresync
+ * New map error API in MIT 1.7, at build time generates code for errors.
+ * Solaris does not gen the errors at build time so we just stub these
+ * for now, need to revisit.
+ * See mglueP.h and util_errmap.c in MIT 1.7.
+*/
+#ifdef _KERNEL
+
+#define map_error(MINORP, MECH)
+#define map_errcode(MINORP)
+
+#else  /* _KERNEL */
+
+#include <syslog.h>
+
+#define map_error(MINORP, MECH)				\
+	(void) syslog(LOG_AUTH|LOG_DEBUG,		\
+		    "map_error: minor status=%x",	\
+		    (MINORP) ? *(MINORP) : 0xffffffff)
+#define map_errcode(MINORP) \
+	(void) syslog(LOG_AUTH|LOG_DEBUG,		\
+		    "map_errcode: minor status=%x",	\
+		    (MINORP) ? *(MINORP) : 0xffffffff)
+#endif /* _KERNEL */
 
 #endif /* _GSS_MECHGLUEP_H */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_generic.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_generic.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -282,6 +282,23 @@
 	    gss_buffer_t,	/* oid_str */
 	    gss_OID *		/* oid */
 	   );
+
+OM_uint32
+generic_gss_oid_compose(
+    OM_uint32 *,        /* minor_status */
+    const char *,       /* prefix */
+    size_t,             /* prefix_len */
+    int,                /* suffix */
+    gss_OID_desc *);    /* oid */
+
+OM_uint32
+generic_gss_oid_decompose(
+    OM_uint32 *,        /* minor_status */
+    const char *,       /*prefix */
+    size_t,             /* prefix_len */
+    gss_OID_desc *,     /* oid */
+    int *);             /* suffix */
+
 #endif /* 0 */
 
 #endif /* _GSSAPIP_GENERIC_H_ */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_krb5.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_krb5.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -74,6 +74,7 @@
  */
 #include "gssapi_krb5.h"
 #include "gssapi_err_krb5.h"
+#include "gssapi_ext.h"
 
 /* for debugging */
 #undef CFX_EXERCISE
@@ -194,6 +195,7 @@
    krb5_keyblock *enc;
    krb5_keyblock *seq;
    krb5_timestamp endtime;
+   krb5_ticket_times krb_times;
    krb5_flags krb_flags;
    /* XXX these used to be signed.  the old spec is inspecific, and
       the new spec specifies unsigned.  I don't believe that the change
@@ -213,6 +215,7 @@
    krb5_keyblock *acceptor_subkey; /* CFX only */
    krb5_cksumtype acceptor_subkey_cksumtype;
    int cred_rcache;		/* did we get rcache from creds? */
+   krb5_authdata **authdata;
 } krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
 
 extern g_set kg_vdb;
@@ -716,32 +719,159 @@
  * These take unglued krb5-mech-specific contexts.
  */
 
-OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags 
-	(OM_uint32 *minor_status,
-		   gss_ctx_id_t context_handle,
-		   krb5_flags *ticket_flags);
+#define GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH 11
+#define GSS_KRB5_GET_TKT_FLAGS_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x01"
+
+#ifndef _KERNEL
+OM_uint32  gss_krb5int_get_tkt_flags
+(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
 
 OM_uint32 KRB5_CALLCONV gss_krb5int_copy_ccache
 	(OM_uint32 *minor_status,
 		   gss_cred_id_t cred_handle,
 		   krb5_ccache out_ccache);
 
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH 11
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x04"
+
+struct krb5_gss_set_allowable_enctypes_req {
+    OM_uint32 num_ktypes;
+    krb5_enctype *ktypes;
+};
+
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
+
+OM_uint32
+gss_krb5int_inq_session_key(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+
 OM_uint32 KRB5_CALLCONV
 gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, 
 				   gss_cred_id_t cred,
 				   OM_uint32 num_ktypes,
 				   krb5_enctype *ktypes);
 
+#endif /* _KERNEL */
+
+#if 0
+/*
+ * SUNW17PACresync
+ * These two functions not needed yet, revisit for full 1.7 resync.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+                                   gss_cred_id_t cred,
+                                   const gss_OID desired_oid,
+                                   const gss_buffer_t value);
+
 OM_uint32 KRB5_CALLCONV
 gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
 				     gss_ctx_id_t *context_handle,
 				     OM_uint32 version,
 				     void **kctx);
+#endif
+
+#ifndef _KERNEL
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06"
+
+OM_uint32
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+                                     const gss_ctx_id_t context_handle,
+                                     const gss_OID desired_object,
+                                     gss_buffer_set_t *data_set);
+
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07"
+
+OM_uint32
+gss_krb5int_free_lucid_sec_context(OM_uint32 *, const gss_OID,
+                                   const gss_OID, gss_buffer_t);
 
 
 extern k5_mutex_t kg_kdc_flag_mutex;
 krb5_error_code krb5_gss_init_context (krb5_context *ctxp);
 
+
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
+
+OM_uint32
+gss_krb5int_inq_session_key(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+
+
+#define GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_USE_KDC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x08"
+
+OM_uint32 krb5int_gss_use_kdc_context(OM_uint32 *, const gss_OID,
+                                      const gss_OID, gss_buffer_t);
+
 krb5_error_code krb5_gss_use_kdc_context(void);
 
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH 11
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x09"
+
+OM_uint32
+gss_krb5int_register_acceptor_identity(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a"
+
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+                                                const gss_ctx_id_t context_handle,
+                                                const gss_OID desired_object,
+                                                gss_buffer_set_t *ad_data);
+
+#define GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH 11
+#define GSS_KRB5_SET_CRED_RCACHE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0b"
+
+OM_uint32
+gss_krb5int_set_cred_rcache(OM_uint32 *, gss_cred_id_t, const gss_OID, const gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
+
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
+                                              const gss_ctx_id_t,
+                                              const gss_OID,
+                                              gss_buffer_set_t *);
+#endif /* _KERNEL */
+
+/* For error message handling.  */
+/* Returns a shared string, not a private copy!  */
+extern char *
+krb5_gss_get_error_message(OM_uint32 minor_code);
+extern void
+krb5_gss_save_error_string(OM_uint32 minor_code, char *msg);
+extern void
+krb5_gss_save_error_message(OM_uint32 minor_code, const char *format, ...)
+#if !defined(__cplusplus) && (__GNUC__ > 2)
+    __attribute__((__format__(__printf__, 2, 3)))
+#endif
+    ;
+    extern void
+    krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx);
+#define get_error_message krb5_gss_get_error_message
+#define save_error_string krb5_gss_save_error_string
+#define save_error_message krb5_gss_save_error_message
+
+
+#if 0 /* SUNW17PACresync - revisit for full MIT 1.7 resync */
+#define save_error_info krb5_gss_save_error_info
+#endif
+#define save_error_info(m, ctx)
+
+
+extern void krb5_gss_delete_error_info(void *p);
+
+/* Prefix concatenated with Kerberos encryption type */
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
+
 #endif /* _GSSAPIP_KRB5_H_ */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/gssapi_krb5.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/gssapi_krb5.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,10 +1,7 @@
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
  * 
@@ -178,17 +175,6 @@
 
 OM_uint32 KRB5_CALLCONV krb5_gss_register_acceptor_identity(const char *);
 
-  /*
-   * SUNW15resync
-   * The name has changed (_krb5_ to _krb5int_) in MIT's
-   * get_tkt_flags.c but did not change here
-   * ...a bug I assume so we change it here.
-   */
-OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags 
-	(OM_uint32 *minor_status,
-		   gss_ctx_id_t context_handle,
-		   krb5_flags *ticket_flags);
-
 OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache
 	(OM_uint32 *minor_status,
 		   gss_cred_id_t cred_handle,
@@ -290,6 +276,21 @@
 				void *kctx);
 
 
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+                                            const gss_ctx_id_t context_handle,
+                                            int ad_type,
+                                            gss_buffer_t ad_data);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
+                         gss_cred_id_t cred,
+                         krb5_rcache rcache);
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *, gss_ctx_id_t, krb5_timestamp *);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -412,6 +412,12 @@
 
 typedef krb5_etype_info_entry ** krb5_etype_info;
 
+/* RFC 4537 */
+typedef struct _krb5_etype_list {
+        int             length;
+        krb5_enctype    *etypes;
+} krb5_etype_list;
+
 /*
  * a sam_challenge is returned for alternate preauth 
  */
@@ -689,6 +695,14 @@
 		void *msg_handler_data);
 
 krb5_error_code krb5int_get_fq_local_hostname (char *, size_t);
+
+krb5_error_code krb5_set_debugging_time
+        (krb5_context, krb5_timestamp, krb5_int32);
+krb5_error_code krb5_use_natural_time
+        (krb5_context);
+krb5_error_code krb5_set_time_offsets
+        (krb5_context, krb5_timestamp, krb5_int32);
+krb5_error_code krb5int_check_clockskew(krb5_context, krb5_timestamp);
 #endif
 
 /*
@@ -1140,6 +1154,54 @@
     krb5_int32		pausec;
 } krb5_pa_enc_ts;
 
+typedef struct _krb5_pa_for_user {
+    krb5_principal      user;
+    krb5_checksum       cksum;
+    krb5_data           auth_package;
+} krb5_pa_for_user;
+
+enum {
+  KRB5_FAST_ARMOR_AP_REQUEST = 0x1
+};
+
+typedef struct _krb5_fast_armor {
+    krb5_int32 armor_type;
+    krb5_data armor_value;
+} krb5_fast_armor;
+typedef struct _krb5_fast_armored_req {
+    krb5_magic magic;
+    krb5_fast_armor *armor;
+    krb5_checksum req_checksum;
+    krb5_enc_data enc_part;
+} krb5_fast_armored_req;
+
+typedef struct _krb5_fast_req {
+    krb5_magic magic;
+    krb5_flags fast_options;
+    /* padata from req_body is used*/
+   krb5_kdc_req *req_body;
+} krb5_fast_req;
+
+
+/* Bits 0-15 are critical in fast options.*/
+#define UNSUPPORTED_CRITICAL_FAST_OPTIONS 0x00ff
+#define KRB5_FAST_OPTION_HIDE_CLIENT_NAMES 0x01
+
+typedef struct _krb5_fast_finished {
+    krb5_timestamp timestamp;
+    krb5_int32 usec;
+    krb5_principal client;
+    krb5_checksum ticket_checksum;
+} krb5_fast_finished;
+
+typedef struct _krb5_fast_response {
+    krb5_magic magic;
+    krb5_pa_data **padata;
+    krb5_keyblock *strengthen_key;
+    krb5_fast_finished *finished;
+    krb5_int32 nonce;
+} krb5_fast_response;
+
 typedef krb5_error_code (*krb5_preauth_obtain_proc)
     (krb5_context,
 		    krb5_pa_data *,
@@ -1809,8 +1871,13 @@
 krb5_error_code encode_krb5_safe
 	(const krb5_safe *rep, krb5_data **code);
 
+struct krb5_safe_with_body {
+	krb5_safe *safe;
+	krb5_data *body;
+};
+
 krb5_error_code encode_krb5_safe_with_body
-	(const krb5_safe *rep, const krb5_data *body, krb5_data **code);
+	(const struct krb5_safe_with_body *rep, krb5_data **code);
 
 krb5_error_code encode_krb5_priv
 	(const krb5_priv *rep, krb5_data **code);
@@ -1828,7 +1895,7 @@
 	(const krb5_error *rep, krb5_data **code);
 
 krb5_error_code encode_krb5_authdata
-	(const krb5_authdata **rep, krb5_data **code);
+	(krb5_authdata *const *rep, krb5_data **code);
 
 krb5_error_code encode_krb5_authdata_elt
 	(const krb5_authdata *rep, krb5_data **code);
@@ -1840,15 +1907,15 @@
 	(const krb5_pwd_data *rep, krb5_data **code);
 
 krb5_error_code encode_krb5_padata_sequence
-	(const krb5_pa_data ** rep, krb5_data **code);
+        (krb5_pa_data *const *rep, krb5_data **code);
 
 krb5_error_code encode_krb5_alt_method
 	(const krb5_alt_method *, krb5_data **code);
 
 krb5_error_code encode_krb5_etype_info
-	(const krb5_etype_info_entry **, krb5_data **code);
+        (krb5_etype_info_entry *const *, krb5_data **code);
 krb5_error_code encode_krb5_etype_info2
-	(const krb5_etype_info_entry **, krb5_data **code);
+        (krb5_etype_info_entry *const *, krb5_data **code);
 
 krb5_error_code encode_krb5_enc_data
     	(const krb5_enc_data *, krb5_data **);
@@ -1883,8 +1950,12 @@
 krb5_error_code encode_krb5_predicted_sam_response
 	(const krb5_predicted_sam_response * , krb5_data **);
 
+struct krb5_setpw_req {
+    krb5_principal target;
+    krb5_data password;
+};
 krb5_error_code encode_krb5_setpw_req
-(const krb5_principal target, char *password, krb5_data **code);
+        (const struct krb5_setpw_req *rep, krb5_data **code);
 
 /*************************************************************************
  * End of prototypes for krb5_encode.c
@@ -2291,6 +2362,7 @@
 					    struct srv_dns_entry **answers);
     void (*free_srv_dns_data)(struct srv_dns_entry *);
     int (*use_dns_kdc)(krb5_context);
+    krb5_error_code (*clean_hostname)(krb5_context, const char *, char *, size_t);
 
     /* krb4 compatibility stuff -- may be null if not enabled */
     krb5_int32 (*krb_life_to_time)(krb5_int32, int);
@@ -2505,6 +2577,7 @@
     krb5_ui_4 hash;
     char *server;			/* null-terminated */
     char *client;			/* null-terminated */
+    char *msghash;                      /* null-terminated */
     krb5_int32 cusec;
     krb5_timestamp ctime;
 } krb5_donot_replay;
@@ -2647,4 +2720,12 @@
 		char *,
 		size_t);
 
+/*
+ * Solaris Kerberos
+ * Kernel & user space realloc.
+ */
+void *krb5int_realloc
+	(void *oldp,
+	 size_t new_size,
+	 size_t old_size);
 #endif /* _KRB5_INT_H */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/k5-platform.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/k5-platform.h	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -527,6 +527,20 @@
 #define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)  \
         (*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
 
+/* Return true if the snprintf return value RESULT reflects a buffer
+   overflow for the buffer size SIZE.
+
+   We cast the result to unsigned int for two reasons.  First, old
+   implementations of snprintf (such as the one in Solaris 9 and
+   prior) return -1 on a buffer overflow.  Casting the result to -1
+   will convert that value to UINT_MAX, which should compare larger
+   than any reasonable buffer size.  Second, comparing signed and
+   unsigned integers will generate warnings with some compilers, and
+   can have unpredictable results, particularly when the relative
+   widths of the types is not known (size_t may be the same width as
+   int or larger).
+*/
+#define SNPRINTF_OVERFLOW(result, size) \
+    ((unsigned int)(result) >= (size_t)(size))
 
 #endif /* K5_PLATFORM_H */
-
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/krb5.h	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/include/krb5.h	Mon Sep 21 16:47:51 2009 -0700
@@ -315,6 +315,18 @@
 #define KRB5_NT_SRV_XHST	4
 /* Unique ID */
 #define KRB5_NT_UID		5
+/* PKINIT */
+#define KRB5_NT_X500_PRINCIPAL          6
+/* Name in form of SMTP email name */
+#define KRB5_NT_SMTP_NAME               7
+/* Windows 2000 UPN */
+#define KRB5_NT_ENTERPRISE_PRINCIPAL    10
+/* Windows 2000 UPN and SID */
+#define KRB5_NT_MS_PRINCIPAL            -128
+/* NT 4 style name */
+#define KRB5_NT_MS_PRINCIPAL_AND_ID     -129
+/* NT 4 style name and SID */
+#define KRB5_NT_ENT_PRINCIPAL_AND_ID    -130
 
 /* constant version thereof: */
 typedef const krb5_principal_data *krb5_const_principal;
@@ -1010,6 +1022,9 @@
 #define KRB5_AUTHDATA_INITIAL_VERIFIED_CAS      9
 #define	KRB5_AUTHDATA_OSF_DCE	64
 #define KRB5_AUTHDATA_SESAME	65
+#define KRB5_AUTHDATA_WIN2K_PAC 128
+#define KRB5_AUTHDATA_ETYPE_NEGOTIATION 129     /* RFC 4537 */
+#define KRB5_AUTHDATA_FX_ARMOR 71
 
 /* password change constants */
 
@@ -1162,6 +1177,7 @@
     krb5_principal server;		/* server's principal identifier */
     krb5_address **caddrs;	/* array of ptrs to addresses,
 					   optional */
+    krb5_pa_data **enc_padata;          /* Windows 2000 compat */
 } krb5_enc_kdc_rep_part;
 
 typedef struct _krb5_kdc_rep {
@@ -1264,6 +1280,24 @@
 
 /* these need to be here so the typedefs are available for the prototypes */
 
+typedef struct _krb5_pa_svr_referral_data {
+    /* Referred name, only realm is required */
+    krb5_principal     principal;
+} krb5_pa_svr_referral_data;
+
+typedef struct _krb5_pa_server_referral_data {
+    krb5_data          *referred_realm;
+    krb5_principal     true_principal_name;
+    krb5_principal     requested_principal_name;
+    krb5_timestamp     referral_valid_until;
+    krb5_checksum      rep_cksum;
+} krb5_pa_server_referral_data;
+
+typedef struct _krb5_pa_pac_req {
+    /* TRUE if a PAC should be included in TGS-REP */
+    krb5_boolean       include_pac;
+} krb5_pa_pac_req;
+
 /*
  * begin "safepriv.h"
  */
@@ -1646,6 +1680,14 @@
 	(krb5_context,
 		const char *,
 		krb5_principal * );
+#define KRB5_PRINCIPAL_PARSE_NO_REALM           0x1
+#define KRB5_PRINCIPAL_PARSE_REQUIRE_REALM      0x2
+#define KRB5_PRINCIPAL_PARSE_ENTERPRISE         0x4
+krb5_error_code KRB5_CALLCONV krb5_parse_name_flags
+	(krb5_context,
+	const char *,
+	int,
+	krb5_principal * );
 krb5_error_code KRB5_CALLCONV krb5_unparse_name
 	(krb5_context,
 		krb5_const_principal,
@@ -1655,6 +1697,20 @@
 		krb5_const_principal,
 		char **,
 		unsigned int *);
+#define KRB5_PRINCIPAL_UNPARSE_SHORT            0x1
+#define KRB5_PRINCIPAL_UNPARSE_NO_REALM         0x2
+#define KRB5_PRINCIPAL_UNPARSE_DISPLAY          0x4
+krb5_error_code KRB5_CALLCONV krb5_unparse_name_flags
+        (krb5_context,
+                krb5_const_principal,
+                int,
+                char **);
+krb5_error_code KRB5_CALLCONV krb5_unparse_name_flags_ext
+        (krb5_context,
+                krb5_const_principal,
+                int,
+                char **,
+                unsigned int *);
 
 krb5_error_code KRB5_CALLCONV krb5_set_principal_realm
 	(krb5_context, krb5_principal, const char *);
@@ -1766,6 +1822,14 @@
 	(krb5_context,
 		krb5_authdata * const *,
 		krb5_authdata ***);
+krb5_error_code KRB5_CALLCONV krb5_merge_authdata
+	(krb5_context,
+	krb5_authdata * const *,
+	krb5_authdata *const *,
+	krb5_authdata ***);
+/* Merge two authdata arrays, such as the array from a ticket
+ * and authenticator */
+
 krb5_error_code KRB5_CALLCONV krb5_copy_authenticator
 	(krb5_context,
 		const krb5_authenticator *,
@@ -2824,6 +2888,70 @@
 void KRB5_CALLCONV
 krb5_clear_error_message (krb5_context);
 
+krb5_error_code KRB5_CALLCONV
+krb5_decode_authdata_container(krb5_context context,
+    krb5_authdatatype type,
+    const krb5_authdata *container,
+    krb5_authdata ***authdata);
+krb5_error_code KRB5_CALLCONV
+krb5_encode_authdata_container(krb5_context context,
+    krb5_authdatatype type,
+    krb5_authdata * const*authdata,
+    krb5_authdata ***container);
+
+/*
+ * Windows PAC
+ */
+struct krb5_pac_data;
+typedef struct krb5_pac_data *krb5_pac;
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_add_buffer
+(krb5_context context,
+                krb5_pac pac,
+                krb5_ui_4 type,
+                const krb5_data *data);
+
+void KRB5_CALLCONV
+krb5_pac_free
+(krb5_context context,
+                krb5_pac pac);
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_get_buffer
+(krb5_context context,
+                krb5_pac pac,
+                krb5_ui_4 type,
+                krb5_data *data);
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_get_types
+(krb5_context context,
+                krb5_pac pac,
+                size_t *len,
+                krb5_ui_4 **types);
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_init
+(krb5_context context,
+                krb5_pac *pac);
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_parse
+(krb5_context context,
+                const void *ptr,
+                size_t len,
+                krb5_pac *pac);
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_verify
+(krb5_context context,
+                const krb5_pac pac,
+                krb5_timestamp authtime,
+                krb5_const_principal principal,
+                const krb5_keyblock *server,
+                const krb5_keyblock *privsvr);
+
 
 #if TARGET_OS_MAC
 #    pragma pack(pop)
@@ -3112,6 +3240,13 @@
 #define KRB5_PLUGIN_NO_HANDLE			(-1765328132L)
 #define KRB5_PLUGIN_OP_NOTSUPP			(-1765328131L)
 
+/* SUNW17PACresync */
+#define KRB5_ERR_INVALID_UTF8			(-1765328130L)
+#define KRB5_ERR_FAST_REQUIRED			(-1765328129L)
+#define KRB5_LOCAL_ADDR_REQUIRED		(-1765328128L)
+#define KRB5_REMOTE_ADDR_REQUIRED		(-1765328127L)
+
+
 #define ERROR_TABLE_BASE_krb5 (-1765328384L)
 
 /* for compatibility with older versions... */
--- a/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/copy_auth.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/copy_auth.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,8 +1,3 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
 /*
  * lib/krb5/krb/copy_auth.c
  *
@@ -31,20 +26,46 @@
  *
  * krb5_copy_authdata()
  */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 #include "k5-int.h"
 
-/*ARGSUSED*/
 static krb5_error_code
 krb5_copy_authdatum(krb5_context context, const krb5_authdata *inad, krb5_authdata **outad)
 {
     krb5_authdata *tmpad;
 
-    if (!(tmpad = (krb5_authdata *)MALLOC(sizeof(*tmpad))))
+    if (!(tmpad = (krb5_authdata *)malloc(sizeof(*tmpad))))
 	return ENOMEM;
     *tmpad = *inad;
-    if (!(tmpad->contents = (krb5_octet *)MALLOC(inad->length))) {
-	krb5_xfree_wrap(tmpad, inad->length);
+    if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
+	free(tmpad);
 	return ENOMEM;
     }
     (void) memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
@@ -56,33 +77,202 @@
  * Copy an authdata array, with fresh allocation.
  */
 krb5_error_code KRB5_CALLCONV
-krb5_copy_authdata(krb5_context context, krb5_authdata *const *inauthdat, krb5_authdata ***outauthdat)
+krb5_merge_authdata(krb5_context context, krb5_authdata *const *inauthdat1, krb5_authdata * const *inauthdat2,
+		    krb5_authdata ***outauthdat)
 {
     krb5_error_code retval;
     krb5_authdata ** tempauthdat;
-    register unsigned int nelems = 0;
+    register unsigned int nelems = 0, nelems2 = 0;
 
-    if (!inauthdat) {
+    *outauthdat = NULL;
+    if (!inauthdat1 && !inauthdat2) {
 	    *outauthdat = 0;
 	    return 0;
     }
 
-    while (inauthdat[nelems]) nelems++;
+    if (inauthdat1) 
+	while (inauthdat1[nelems]) nelems++;
+    if (inauthdat2) 
+	while (inauthdat2[nelems2]) nelems2++;
 
     /* one more for a null terminated list */
-    if (!(tempauthdat = (krb5_authdata **) CALLOC(nelems+1,
+    if (!(tempauthdat = (krb5_authdata **) calloc(nelems+nelems2+1,
 						  sizeof(*tempauthdat))))
 	return ENOMEM;
 
-    for (nelems = 0; inauthdat[nelems]; nelems++) {
-	retval = krb5_copy_authdatum(context, inauthdat[nelems],
-				     &tempauthdat[nelems]);
-	if (retval) {
-	    krb5_free_authdata(context, tempauthdat);
-	    return retval;
+    if (inauthdat1) {
+	for (nelems = 0; inauthdat1[nelems]; nelems++) {
+	    retval = krb5_copy_authdatum(context, inauthdat1[nelems],
+					 &tempauthdat[nelems]);
+	    if (retval) {
+		krb5_free_authdata(context, tempauthdat);
+		return retval;
+	    }
+	}
+    }
+
+    if (inauthdat2) {
+	for (nelems2 = 0; inauthdat2[nelems2]; nelems2++) {
+	    retval = krb5_copy_authdatum(context, inauthdat2[nelems2],
+					 &tempauthdat[nelems++]);
+	    if (retval) {
+		krb5_free_authdata(context, tempauthdat);
+		return retval;
+	    }
 	}
     }
 
     *outauthdat = tempauthdat;
     return 0;
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_authdata(krb5_context context,
+		   krb5_authdata *const *in_authdat, krb5_authdata ***out)
+{
+    return krb5_merge_authdata(context, in_authdat, NULL, out);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_decode_authdata_container(krb5_context context,
+			       krb5_authdatatype type,
+			       const krb5_authdata *container,
+			       krb5_authdata ***authdata)
+{
+    krb5_error_code code;
+    krb5_data data;
+
+    *authdata = NULL;
+
+    if ((container->ad_type & AD_TYPE_FIELD_TYPE_MASK) != type)
+	return EINVAL;
+
+    data.length = container->length;
+    data.data = (char *)container->contents;
+
+    code = decode_krb5_authdata(&data, authdata);
+    if (code)
+	return code;
+
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_encode_authdata_container(krb5_context context,
+			       krb5_authdatatype type,
+			       krb5_authdata *const*authdata,
+			       krb5_authdata ***container)
+{
+    krb5_error_code code;
+    krb5_data *data;
+    krb5_authdata ad_datum;
+    krb5_authdata *ad_data[2];
+
+    *container = NULL;
+
+    code = encode_krb5_authdata((krb5_authdata * const *)authdata, &data);
+    if (code)
+	return code;
+
+    ad_datum.ad_type = type & AD_TYPE_FIELD_TYPE_MASK;
+    ad_datum.length = data->length;
+    ad_datum.contents = (unsigned char *)data->data;
+
+    ad_data[0] = &ad_datum;
+    ad_data[1] = NULL;
+
+    code = krb5_copy_authdata(context, ad_data, container);
+
+    krb5_free_data(context, data);
+
+    return code;
+}
+
+struct find_authdata_context {
+  krb5_authdata **out;
+  size_t space;
+  size_t length;
+};
+
+static krb5_error_code grow_find_authdata
+(krb5_context context, struct find_authdata_context *fctx,
+ krb5_authdata *elem)
+{
+  krb5_error_code retval = 0;
+  if (fctx->length == fctx->space) {
+    krb5_authdata **new;
+    if (fctx->space >= 256) {
+      krb5_set_error_message(context, ERANGE, "More than 256 authdata matched a query");
+      return ERANGE;
+    }
+    new       = realloc(fctx->out,
+			sizeof (krb5_authdata *)*(2*fctx->space+1));
+    if (new == NULL)
+      return ENOMEM;
+    fctx->out = new;
+    fctx->space *=2;
+  }
+  fctx->out[fctx->length+1] = NULL;
+  retval = krb5_copy_authdatum(context, elem,
+			       &fctx->out[fctx->length]);
+  if (retval == 0)
+    fctx->length++;
+  return retval;
+}
+
+  
+  
+
+static krb5_error_code find_authdata_1
+(krb5_context context, krb5_authdata *const *in_authdat, krb5_authdatatype ad_type,
+ struct find_authdata_context *fctx)
+{
+  int i = 0;
+  krb5_error_code retval=0;
+  
+  for (i = 0; in_authdat[i]; i++) {
+    krb5_authdata *ad = in_authdat[i];
+    if (ad->ad_type == ad_type && retval ==0)
+      retval = grow_find_authdata(context, fctx, ad);
+    else switch (ad->ad_type) {
+      krb5_authdata **decoded_container;
+    case KRB5_AUTHDATA_IF_RELEVANT:
+      if (retval == 0)
+	retval = krb5_decode_authdata_container( context, ad->ad_type, ad, &decoded_container);
+      if (retval == 0) {
+	retval = find_authdata_1(context,
+				 decoded_container, ad_type, fctx);
+	krb5_free_authdata(context, decoded_container);
+      }
+      break;
+    default:
+      break;
+    }
+  }
+  return retval;
+}
+
+
+krb5_error_code krb5int_find_authdata
+(krb5_context context, krb5_authdata *const * ticket_authdata,
+ krb5_authdata * const *ap_req_authdata,
+ krb5_authdatatype ad_type,
+ krb5_authdata ***results)
+{
+  krb5_error_code retval = 0;
+  struct find_authdata_context fctx;
+  fctx.length = 0;
+  fctx.space = 2;
+  fctx.out = calloc(fctx.space+1, sizeof (krb5_authdata *));
+  *results = NULL;
+  if (fctx.out == NULL)
+    return ENOMEM;
+  if (ticket_authdata)
+      retval = find_authdata_1( context, ticket_authdata, ad_type, &fctx);
+  if ((retval==0) && ap_req_authdata)
+    retval = find_authdata_1( context, ap_req_authdata, ad_type, &fctx);
+  if ((retval== 0) && fctx.length)
+    *results = fctx.out;
+  else krb5_free_authdata(context, fctx.out);
+  return retval;
+}
--- a/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/parse.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/parse.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,12 +1,12 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
  * lib/krb5/krb/parse.c
  *
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -38,12 +38,6 @@
 
 #include "k5-int.h"
 
-#ifndef _KERNEL
-#include <assert.h>
-#include <stdarg.h> 
-#define ASSERT assert 
-#endif
-
 /*
  * converts a single-string representation of the name to the
  * multi-part principal format used in the protocols.
@@ -70,18 +64,18 @@
 
 #define FCOMPNUM	10
 
-
 /*
  * May the fleas of a thousand camels infest the ISO, they who think
  * that arbitrarily large multi-component names are a Good Thing.....
  */
-/*ARGSUSED*/
-krb5_error_code KRB5_CALLCONV
-krb5_parse_name(krb5_context context, const char *name, krb5_principal *nprincipal)
+static krb5_error_code
+/*LINTED*/
+k5_parse_name(krb5_context context, const char *name,
+	      int flags, krb5_principal *nprincipal)
 {
 	register const char	*cp;
 	register char	*q;
-	register int    i,c,size;
+	register int	i,c,size;
 	int		components = 0;
 	const char	*parsed_realm = NULL;
 	int		fcompsize[FCOMPNUM];
@@ -93,26 +87,32 @@
 #endif
 	char		*tmpdata;
 	krb5_principal	principal;
+	unsigned int	enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
+	int		first_at;
+
+	*nprincipal = NULL;
 
 	/*
 	 * Pass 1.  Find out how many components there are to the name,
-	 * and get string sizes for the first FCOMPNUM components.
+	 * and get string sizes for the first FCOMPNUM components. For
+	 * enterprise principal names (UPNs), there is only a single
+	 * component.
 	 */
 	size = 0;
 	/*LINTED*/
-	for (i = 0, cp = name; (c = *cp); cp++) {
+	for (i=0,cp = name, first_at = 1; (c = *cp); cp++) {
 		if (c == QUOTECHAR) {
 			cp++;
 			/*LINTED*/
 			if (!(c = *cp))
 				/*
-				 * QUOTECHAR can't be at the last
-				 * character of the name!
-				 */
+			 	 * QUOTECHAR can't be at the last
+			 	 * character of the name!
+			 	 */
 				return(KRB5_PARSE_MALFORMED);
 			size++;
 			continue;
-		} else if (c == COMPONENT_SEP) {
+		} else if (c == COMPONENT_SEP && !enterprise) {
 			if (parsed_realm)
 				/*
 				 * Shouldn't see a component separator
@@ -124,22 +124,26 @@
 			}
 			size = 0;
 			i++;
-		} else if (c == REALM_SEP) {
+		} else if (c == REALM_SEP && (!enterprise || !first_at)) {
 			if (parsed_realm)
 				/*
 				 * Multiple realm separaters
 				 * not allowed; zero-length realms are.
 				 */
 				return(KRB5_PARSE_MALFORMED);
-			parsed_realm = cp+1;
+			parsed_realm = cp + 1;
 			if (i < FCOMPNUM) {
 				fcompsize[i] = size;
 			}
 			size = 0;
-		} else
+		} else {
+			if (c == REALM_SEP && enterprise && first_at)
+				first_at = 0;
+
 			size++;
+		}
 	}
-	if (parsed_realm)
+	if (parsed_realm != NULL)
 		realmsize = size;
 	else if (i < FCOMPNUM) 
 		fcompsize[i] = size;
@@ -149,39 +153,49 @@
 	 * component pieces
 	 */
 	principal = (krb5_principal)MALLOC(sizeof(krb5_principal_data));
-	if (!principal) {
-		return(ENOMEM);
+	if (principal == NULL) {
+	    return(ENOMEM);
 	}
 	principal->data = (krb5_data *)MALLOC(sizeof(krb5_data) * components);
-	if (!principal->data) {
-	    krb5_xfree_wrap((char *)principal, sizeof(krb5_principal_data));
+	if (principal->data == NULL) {
+	    krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
 	    return ENOMEM;
 	}
 	principal->length = components;
-	/*
-	 * If a realm was not found, then use the defualt realm....
-	 */
+
 	/*
-	 * In the kernel we import the ctx and it always contains the
-	 * default realm
+	 * If a realm was not found, then use the default realm, unless
+	 * KRB5_PRINCIPAL_PARSE_NO_REALM was specified in which case the
+	 * realm will be empty.
 	 */
-
 #ifndef _KERNEL
 	if (!parsed_realm) {
-	    if (!default_realm) {
+	    if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) {
+		krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
+				       "Principal %s is missing required realm", name);
+		krb5_xfree_wrap(principal->data, principal->length);
+		krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
+		return KRB5_PARSE_MALFORMED;
+	    }
+	    if (!default_realm && (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) == 0) {
 		retval = krb5_get_default_realm(context, &default_realm);
 		if (retval) {
-		    krb5_xfree_wrap(principal->data,
-			sizeof (krb5_data) * components);
-		    krb5_xfree_wrap((char *)principal,
-			sizeof (krb5_principal_data));
+		    krb5_xfree_wrap(principal->data, principal->length);
+		    krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
 		    return(retval);
 		}
 		default_realm_size = strlen(default_realm);
 	    }
 	    realmsize = default_realm_size;
+	} else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
+	    krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
+				  "Principal %s has realm present", name);
+	    krb5_xfree_wrap(principal->data, principal->length);
+	    krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
+	    return KRB5_PARSE_MALFORMED;
 	}
 #endif
+
 	/*
 	 * Pass 2.  Happens only if there were more than FCOMPNUM
 	 * component; if this happens, someone should be shot
@@ -217,14 +231,15 @@
 		if (i + 1 != components) {
 #ifndef _KERNEL
 #if !defined(_WIN32)
-		    fprintf(stderr,
+ 		    fprintf(stderr,
 			    "Programming error in krb5_parse_name!");
 #endif
-		    ASSERT(i + 1 == components);
-		    abort();
+ 		    ASSERT(i + 1 == components);
+ 		    abort();
 #else
-		    ASSERT(i + 1 == components);
+ 		    ASSERT(i + 1 == components);
 #endif /* !_KERNEL */
+
 		}
 	} else {
 		/*
@@ -238,47 +253,37 @@
 	/*	
 	 * Now, we need to allocate the space for the strings themselves.....
 	 */
-	tmpdata = MALLOC(realmsize+1);
+	tmpdata = MALLOC(realmsize + 1);
 	if (tmpdata == 0) {
-		krb5_xfree_wrap(principal->data,
-		    sizeof (krb5_data) * components);
-		krb5_xfree_wrap((char *)principal,
-		    sizeof (krb5_principal_data));
+		krb5_xfree_wrap(principal->data, principal->length);
+		krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
 #ifndef _KERNEL
-		if (default_realm)
-			krb5_xfree_wrap(default_realm, strlen(default_realm));
+		krb5_xfree_wrap(default_realm, strlen(default_realm));
 #endif
-		return (ENOMEM);
+		return ENOMEM;
 	}
 	krb5_princ_set_realm_length(context, principal, realmsize);
 	krb5_princ_set_realm_data(context, principal, tmpdata);
 	for (i=0; i < components; i++) {
 		char *tmpdata2 =
 		  MALLOC(krb5_princ_component(context, principal, i)->length + 1);
-		if (!tmpdata2) {
-                        /*
-                         * Release the principle and realm strings remembering
-                         * that we allocated one additional byte beyond the
-                         * 'length' to hold the string terminating zero byte.
-                         * It's critical that the free size match the malloc
-			 * size.
-                         */
+		if (tmpdata2 == NULL) {
 			for (i--; i >= 0; i--)
-				krb5_xfree_wrap(krb5_princ_component(context,
+ 				krb5_xfree_wrap(krb5_princ_component(context,
 				    principal, i)->data,
-				    krb5_princ_component(context,
-				    principal, i)->length + 1);
-			krb5_xfree_wrap(krb5_princ_realm(context,
-			    principal)->data, krb5_princ_realm(context,
-			    principal)->length + 1);
+                                    krb5_princ_component(context,
+                                    principal, i)->length + 1);
+
+ 			krb5_xfree_wrap(krb5_princ_realm(context,
+ 			    principal)->data, krb5_princ_realm(context,
+ 			    principal)->length + 1);
+
 			krb5_xfree_wrap(principal->data, principal->length);
 			krb5_xfree_wrap(principal, sizeof(krb5_principal_data));
 #ifndef _KERNEL
-			if (default_realm)
-				krb5_xfree_wrap(default_realm,
-						strlen(default_realm));
+			krb5_xfree_wrap(default_realm, strlen(default_realm));
 #endif
-			return (ENOMEM);
+			return(ENOMEM);
 		}
 		krb5_princ_component(context, principal, i)->data = tmpdata2;
 		krb5_princ_component(context, principal, i)->magic = KV5M_DATA;
@@ -291,7 +296,7 @@
 	 */
 	q = krb5_princ_component(context, principal, 0)->data;
 	/*LINTED*/
-	for (i=0,cp = name; (c = *cp); cp++) {
+	for (i=0,cp = name, first_at = 1; (c = *cp); cp++) {
 		if (c == QUOTECHAR) {
 			cp++;
 			switch (c = *cp) {
@@ -308,35 +313,64 @@
 				*q++ = '\0';
 				break;
 			default:
-				*q++ = (char) c;
+				*q++ = c;
+				break;
 			}
-		} else if ((c == COMPONENT_SEP) || (c == REALM_SEP)) {
+		} else if (c == COMPONENT_SEP && !enterprise) {
+			i++;
+			*q++ = '\0';
+			q = krb5_princ_component(context, principal, i)->data;
+		} else if (c == REALM_SEP && (!enterprise || !first_at)) {
 			i++;
 			*q++ = '\0';
-			if (c == COMPONENT_SEP) 
-				q = krb5_princ_component(context, principal, i)->data;
-			else
-				q = krb5_princ_realm(context, principal)->data;
-		} else
-			*q++ = (char) c;
+			q = krb5_princ_realm(context, principal)->data;
+		} else {
+			if (c == REALM_SEP && enterprise && first_at)
+				first_at = 0;
+
+			*q++ = c;
+		}
 	}
 	*q++ = '\0';
-	if (!parsed_realm)
+	/*LINTED*/
+	if (!parsed_realm) {
 #ifndef _KERNEL
-		(void) strcpy(krb5_princ_realm(context, principal)->data,
-			default_realm);
+
+		if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM)
+			(krb5_princ_realm(context, principal)->data)[0] = '\0';
+		else
+			strlcpy(krb5_princ_realm(context, principal)->data, default_realm, realmsize+1);
 #endif
+	}
 	/*
 	 * Alright, we're done.  Now stuff a pointer to this monstrosity
 	 * into the return variable, and let's get out of here.
 	 */
-	krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL;
+	if (enterprise)
+		krb5_princ_type(context, principal) = KRB5_NT_ENTERPRISE_PRINCIPAL;
+	else
+		krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL;
 	principal->magic = KV5M_PRINCIPAL;
 	principal->realm.magic = KV5M_DATA;
 	*nprincipal = principal;
+
 #ifndef _KERNEL
-	if (default_realm)
-		krb5_xfree_wrap(default_realm, strlen(default_realm));
+	if (default_realm != NULL)
+ 	    krb5_xfree_wrap(default_realm, strlen(default_realm));
 #endif
+
 	return(0);
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_parse_name(krb5_context context, const char *name, krb5_principal *nprincipal)
+{
+	 return k5_parse_name(context, name, 0, nprincipal);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_parse_name_flags(krb5_context context, const char *name,
+		      int flags, krb5_principal *nprincipal)
+{
+	 return k5_parse_name(context, name, flags, nprincipal);
+}
--- a/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/unparse.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/unparse.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,12 +1,12 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
  * lib/krb5/krb/unparse.c
  *
- * Copyright 1990 by the Massachusetts Institute of Technology.
+ * Copyright 1990, 2008 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -21,7 +21,10 @@
  * this permission notice appear in supporting documentation, and that
  * the name of M.I.T. not be used in advertising or publicity pertaining
  * to distribution of the software without specific, written prior
- * permission.  M.I.T. makes no representations about the suitability of
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
  * this software for any purpose.  It is provided "as is" without express
  * or implied warranty.
  * 
@@ -35,11 +38,33 @@
 
 
 #include "k5-int.h"
-#ifndef	_KERNEL
+#ifndef _KERNEL
 #include <stdio.h>
 #endif
 
 /*
+ * SUNW17PACresync / Solaris Kerberos
+ * This realloc works for both Solaris kernel and user space.
+ */
+void *
+krb5int_realloc(
+		void *oldp,
+		size_t new_size,
+		size_t old_size)
+{
+#ifdef _KERNEL
+    char *newp = MALLOC(new_size);
+
+    bcopy(oldp, newp, old_size < new_size ? old_size : new_size);
+    FREE(oldp, old_size);
+
+    return (newp);
+#else
+    return (realloc(oldp, new_size));
+#endif
+}
+
+/*
  * converts the multi-part principal format used in the protocols to a
  * single-string representation of the name. 
  *  
@@ -61,39 +86,142 @@
 #define REALM_SEP	'@'
 #define	COMPONENT_SEP	'/'
 
-/*ARGSUSED*/
-krb5_error_code KRB5_CALLCONV
-krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal, register char **name, unsigned int *size)
+static int
+component_length_quoted(const krb5_data *src, int flags)
+{
+    const char *cp = src->data;
+    int length = src->length;
+    int j;
+    int size = length;
+
+    if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) {
+	int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
+		       !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
+
+	for (j = 0; j < length; j++,cp++)
+	    if ((!no_realm && *cp == REALM_SEP) ||
+		*cp == COMPONENT_SEP ||
+		*cp == '\0' || *cp == '\\' || *cp == '\t' ||
+		*cp == '\n' || *cp == '\b')
+		size++;
+    }
+
+    return size;
+}
+
+static int
+copy_component_quoting(char *dest, const krb5_data *src, int flags)
 {
-	register char *cp, *q;
-	register int i,j;
-	int	length;
+    int j;
+    const char *cp = src->data;
+    char *q = dest;
+    int length = src->length;
+
+    if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) {
+        (void) memcpy(dest, src->data, src->length);
+	return src->length;
+    }
+
+    for (j=0; j < length; j++,cp++) {
+	int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
+		       !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
+
+	switch (*cp) {
+	case REALM_SEP:
+	    if (no_realm) {
+		*q++ = *cp;
+		break;
+	    }
+	/*LINTED*/
+	case COMPONENT_SEP:
+	case '\\':
+	    *q++ = '\\';
+	    *q++ = *cp;
+	    break;
+	case '\t':
+	    *q++ = '\\';
+	    *q++ = 't';
+	    break;
+	case '\n':
+	    *q++ = '\\';
+	    *q++ = 'n';
+	    break;
+	case '\b':
+	    *q++ = '\\';
+	    *q++ = 'b';
+	    break;
+#if 0
+	/* Heimdal escapes spaces in principal names upon unparsing */
+	case ' ':
+	    *q++ = '\\';
+	    *q++ = ' ';
+	    break;
+#endif
+	case '\0':
+	    *q++ = '\\';
+	    *q++ = '0';
+	    break;
+	default:
+	    *q++ = *cp;
+	}
+    }
+    /*LINTED*/
+    return q - dest;
+}
+
+static krb5_error_code
+/*LINTED*/
+k5_unparse_name(krb5_context context, krb5_const_principal principal,
+		int flags, char **name, unsigned int *size)
+{
+#if 0
+	/* SUNW17PACresync - lint - cp/length not used */
+        char *cp;
+        int	length;
+#endif
+	char *q;
+	int i;
 	krb5_int32 nelem;
-	register unsigned int totalsize = 0;
+	unsigned int totalsize = 0;
+#ifndef _KERNEL
+	/* SUNW17PACresync - princ in kernel will always have realm */
+	char *default_realm = NULL;
+#endif
+	krb5_error_code ret = 0;
 
 	if (!principal || !name)
 		return KRB5_PARSE_MALFORMED;
 
-	cp = krb5_princ_realm(context, principal)->data;
-	length = krb5_princ_realm(context, principal)->length;
-	totalsize += length;
-	for (j = 0; j < length; j++,cp++)
-		if (*cp == REALM_SEP  || *cp == COMPONENT_SEP ||
-		    *cp == '\0' || *cp == '\\' || *cp == '\t' ||
-		    *cp == '\n' || *cp == '\b')
-			totalsize++;
-	totalsize++;		/* This is for the separator */
+#ifndef _KERNEL
+	if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) {
+		/* omit realm if local realm */
+		krb5_principal_data p;
+
+		ret = krb5_get_default_realm(context, &default_realm);
+		if (ret != 0)
+			goto cleanup;
+
+		krb5_princ_realm(context, &p)->length = strlen(default_realm);
+		krb5_princ_realm(context, &p)->data = default_realm;
+
+		if (krb5_realm_compare(context, &p, principal))
+			flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
+	}
+#endif
+	if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
+		totalsize += component_length_quoted(krb5_princ_realm(context,
+								      principal),
+						     flags);
+		totalsize++;		/* This is for the separator */
+	}
 
 	nelem = krb5_princ_size(context, principal);
 	for (i = 0; i < (int) nelem; i++) {
+#if 0
+		/* SUNW17PACresync - lint - cp not used */
 		cp = krb5_princ_component(context, principal, i)->data;
-		length = krb5_princ_component(context, principal, i)->length;
-		totalsize += length;
-		for (j=0; j < length; j++,cp++)
-			if (*cp == REALM_SEP || *cp == COMPONENT_SEP ||
-			    *cp == '\0' || *cp == '\\' || *cp == '\t' ||
-			    *cp == '\n' || *cp == '\b')
-				totalsize++;
+#endif
+		totalsize += component_length_quoted(krb5_princ_component(context, principal, i), flags);
 		totalsize++;	/* This is for the separator */
 	}
 	if (nelem == 0)
@@ -104,107 +232,87 @@
 	 * provided, use it, realloc'ing it if necessary.
 	 * 
 	 * We need only n-1 seperators for n components, but we need
-	 * an extra byte for the NULL at the end.
+	 * an extra byte for the NUL at the end.
 	 */
-	/*The realloc case seems to be bogus 
-	* We never pass non-null name 
-	*/
 
-	/* if (*name) {
-		if (*size < (totalsize)) {
-			*size = totalsize;
-			*name = realloc(*name, totalsize);
-		}
-	   } else { 
-	*/
+        if (size) {
+            if (*name && (*size < totalsize)) {
+	        /* SUNW17PACresync - works for both kernel&user */
+	        *name = krb5int_realloc(*name, totalsize, *size);
+            } else {
+                *name = MALLOC(totalsize);
+            }
+            *size = totalsize;
+        } else {
+            *name = MALLOC(totalsize);
+        }
 
-	*name = MALLOC(totalsize);
-	if (size)
-		*size = totalsize;
-	
-	if (!*name)
-		return ENOMEM;
+	if (!*name) {
+		ret = ENOMEM;
+		goto cleanup;
+	}
 
 	q = *name;
 	
 	for (i = 0; i < (int) nelem; i++) {
+#if 0
+		/* SUNW17PACresync - lint - cp/length not used */
 		cp = krb5_princ_component(context, principal, i)->data;
 		length = krb5_princ_component(context, principal, i)->length;
-		for (j=0; j < length; j++,cp++) {
-		    switch (*cp) {
-		    case COMPONENT_SEP:
-		    case REALM_SEP:
-		    case '\\':
-			*q++ = '\\';
-			*q++ = *cp;
-			break;
-		    case '\t':
-			*q++ = '\\';
-			*q++ = 't';
-			break;
-		    case '\n':
-			*q++ = '\\';
-			*q++ = 'n';
-			break;
-		    case '\b':
-			*q++ = '\\';
-			*q++ = 'b';
-			break;
-		    case '\0':
-			*q++ = '\\';
-			*q++ = '0';
-			break;
-		    default:
-			*q++ = *cp;
-		    }
-		}
+#endif
+		q += copy_component_quoting(q,
+					    krb5_princ_component(context,
+								 principal,
+								 i),
+					    flags);
 		*q++ = COMPONENT_SEP;
 	}
 
 	if (i > 0)
 	    q--;		/* Back up last component separator */
-	*q++ = REALM_SEP;
-	
-	cp = krb5_princ_realm(context, principal)->data;
-	length = krb5_princ_realm(context, principal)->length;
-	for (j=0; j < length; j++,cp++) {
-		switch (*cp) {
-		case COMPONENT_SEP:
-		case REALM_SEP:
-		case '\\':
-			*q++ = '\\';
-			*q++ = *cp;
-			break;
-		case '\t':
-			*q++ = '\\';
-			*q++ = 't';
-			break;
-		case '\n':
-			*q++ = '\\';
-			*q++ = 'n';
-			break;
-		case '\b':
-			*q++ = '\\';
-			*q++ = 'b';
-			break;
-		case '\0':
-			*q++ = '\\';
-			*q++ = '0';
-			break;
-		default:
-			*q++ = *cp;
-		}
+	if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
+		*q++ = REALM_SEP;
+		q += copy_component_quoting(q, krb5_princ_realm(context, principal), flags);
 	}
 	*q++ = '\0';
-	
-    return 0;
+
+cleanup:
+#ifndef _KERNEL
+	if (default_realm != NULL)
+		krb5_free_default_realm(context, default_realm);
+#endif
+	return ret;
 }
 
 krb5_error_code KRB5_CALLCONV
 krb5_unparse_name(krb5_context context, krb5_const_principal principal, register char **name)
 {
-        if (name)                       /* name == NULL will return error from _ext */
-            *name = NULL;
-	return(krb5_unparse_name_ext(context, principal, name, NULL));
+    if (name != NULL)                      /* name == NULL will return error from _ext */
+	*name = NULL;
+
+    return k5_unparse_name(context, principal, 0, name, NULL);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal,
+		      char **name, unsigned int *size)
+{
+    return k5_unparse_name(context, principal, 0, name, size);
 }
 
+krb5_error_code KRB5_CALLCONV
+krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal,
+			int flags, char **name)
+{
+    if (name != NULL)
+	*name = NULL;
+    return k5_unparse_name(context, principal, flags, name, NULL);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_unparse_name_flags_ext(krb5_context context, krb5_const_principal principal,
+			    int flags, char **name, unsigned int *size)
+{
+    return k5_unparse_name(context, principal, flags, name, size);
+}
+
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/delete_sec_context.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/delete_sec_context.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,9 +1,7 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-
 /*
  * Copyright 1993 by OpenVision Technologies, Inc.
  * 
@@ -196,6 +194,9 @@
    if (ctx->mech_used)
        (void) KGSS_RELEASE_OID(minor_status, &ctx->mech_used);
    
+   if (ctx->authdata)
+	krb5_free_authdata(context, ctx->authdata);
+
    if (ctx->k5_context)
        krb5_free_context(ctx->k5_context);
 
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/gssapi_krb5.c	Mon Sep 21 16:32:48 2009 -0700
+++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/gssapi_krb5.c	Mon Sep 21 16:47:51 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -296,4 +296,83 @@
     *minor_status = 0;
     return GSS_S_COMPLETE;
 }
+
+#define g_OID_prefix_equal(o1, o2) \
+        (((o1)->length >= (o2)->length) && \
+        (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
+/*
+ * gss_inquire_sec_context_by_oid() methods
+ */
+static struct {
+    gss_OID_desc oid;
+    OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+} krb5_gss_inquire_sec_context_by_oid_ops[] = {
+    {
+        {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
+        gss_krb5int_get_tkt_flags
+    },
+    {
+        {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
+        gss_krb5int_extract_authz_data_from_sec_context
+    },
+    {
+        {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
+        gss_krb5int_inq_session_key
+    },
+    {
+        {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
+        gss_krb5int_export_lucid_sec_context
+    },
+    {
+        {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
+        gss_krb5int_extract_authtime_from_sec_context
+    }
+};
+
+OM_uint32
+krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
+                                     const gss_ctx_id_t context_handle,
+                                     const gss_OID desired_object,
+                                     gss_buffer_set_t *data_set)
+{
+    krb5_gss_ctx_id_rec *ctx;
+    size_t i;
+
+    if (minor_status == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *minor_status = 0;
+
+    if (desired_object == GSS_C_NO_OID)
+        return GSS_S_CALL_INACCESSIBLE_READ;
+
+    if (data_set == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *data_set = GSS_C_NO_BUFFER_SET;
+
+    if (!kg_validate_ctx_id(context_handle))
+        return GSS_S_NO_CONTEXT;
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+    if (!ctx->established)
+        return GSS_S_NO_CONTEXT;
+
+    for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
+                    sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
+        if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
+            return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
+                                                                      context_handle,
+                                                                      desired_object,
+                                                                      data_set);
+        }
+    }
+
+    *minor_status = EINVAL;
+
+    return GSS_S_UNAVAILABLE;
+}
+
 #endif