--- sys/kgssapi/krb5/krb5_mech.c.sav	2025-07-27 19:20:29.886309000 -0700
+++ sys/kgssapi/krb5/krb5_mech.c	2025-08-01 14:00:25.394711000 -0700
@@ -215,6 +215,18 @@ copy_key(struct krb5_keyblock *from, struct krb5_keybl
 		*to = from;
 	else
 		*to = NULL;
+}
+
+static void
+copy_lucid_key(gss_krb5_lucid_key_t *from, struct krb5_keyblock *to)
+{
+
+	to->kk_type = from->type;
+	to->kk_key.kd_length = from->length;
+	if (from->length > 0) {
+		to->kk_key.kd_data = malloc(from->length, M_GSSAPI, M_WAITOK);
+		memcpy(to->kk_key.kd_data, from->data, from->length);
+	}
 }
 
 /*
@@ -258,6 +270,98 @@ static OM_uint32
 }
 
 static OM_uint32
+get_lucid_keys(struct krb5_context *kc)
+{
+	struct krb5_keyblock *keydata;
+	struct krb5_encryption_class *ec;
+	struct krb5_key_state *key;
+	int etype;
+
+	keydata = NULL;
+	get_acceptor_subkey(kc, &keydata);
+	if (!keydata)
+		if ((kc->kc_more_flags & ACCEPTOR_SUBKEY) == 0)
+			get_initiator_subkey(kc, &keydata);
+	if (!keydata)
+		return (GSS_S_FAILURE);
+
+	/*
+	 * GSS-API treats all DES etypes the same and all DES3 etypes
+	 * the same.
+	 */
+	switch (keydata->kk_type) {
+	case ETYPE_DES_CBC_CRC:
+	case ETYPE_DES_CBC_MD4:
+	case ETYPE_DES_CBC_MD5:
+	case ETYPE_DES3_CBC_MD5:
+	case ETYPE_DES3_CBC_SHA1:
+	case ETYPE_OLD_DES3_CBC_SHA1:
+		return (GSS_S_FAILURE);
+
+	default:
+		etype = keydata->kk_type;
+	}
+
+	ec = krb5_find_encryption_class(etype);
+	if (!ec)
+		return (GSS_S_FAILURE);
+
+	key = krb5_create_key(ec);
+	krb5_set_key(key, keydata->kk_key.kd_data);
+	kc->kc_tokenkey = key;
+
+	/*
+	 * We need eight derived keys four for sending and
+	 * four for receiving.
+	 */
+	if (is_initiator(kc)) {
+		/*
+		 * We are initiator.
+		 */
+		kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_INITIATOR_SIGN);
+
+		kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_ACCEPTOR_SIGN);
+	} else {
+		/*
+		 * We are acceptor.
+		 */
+		kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_ACCEPTOR_SEAL);
+		kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_ACCEPTOR_SIGN);
+
+		kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_INITIATOR_SEAL);
+		kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
+		    KG_USAGE_INITIATOR_SIGN);
+	}
+
+	return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
 get_keys(struct krb5_context *kc)
 {
 	struct krb5_keyblock *keydata;
@@ -402,6 +506,77 @@ static OM_uint32
 }
 
 static OM_uint32
+krb5_lucid_import(gss_ctx_id_t ctx,
+    enum sec_context_format format,
+    const gss_buffer_t context_token)
+{
+	struct krb5_context *kc = (struct krb5_context *)ctx;
+	gss_krb5_lucid_context_v1_t *lctx = (gss_krb5_lucid_context_v1_t *)
+	    context_token;
+	OM_uint32 res;
+
+printf("krb5_import: initiate=%d endtime=%d send_seq=%ld recv_seq=%ld proto=%d\n", lctx->initiate, lctx->endtime, lctx->send_seq, lctx->recv_seq, lctx->protocol);
+	kc->kc_more_flags = 0;
+	if (lctx->protocol == 0) {
+		kc->kc_cksumtype = lctx->rfc1964_kd.sign_alg;
+		kc->kc_keytype = lctx->rfc1964_kd.seal_alg;
+		copy_lucid_key(&lctx->rfc1964_kd.ctx_key,
+		    &kc->kc_keyblock);
+	} else if (lctx->protocol == 1) {
+printf("acceptor=%d\n", lctx->cfx_kd.have_acceptor_subkey);
+		if (lctx->cfx_kd.have_acceptor_subkey != 0) {
+			if (lctx->initiate != 0)
+				copy_lucid_key(&lctx->cfx_kd.acceptor_subkey,
+				    &kc->kc_remote_subkey);
+			else
+				copy_lucid_key(&lctx->cfx_kd.acceptor_subkey,
+				    &kc->kc_local_subkey);
+			kc->kc_cksumtype = lctx->cfx_kd.acceptor_subkey.type;
+			kc->kc_keytype = lctx->cfx_kd.acceptor_subkey.type;
+			kc->kc_more_flags |= ACCEPTOR_SUBKEY;
+		} else {
+			if (lctx->initiate != 0)
+				copy_lucid_key(&lctx->cfx_kd.ctx_key,
+				    &kc->kc_remote_subkey);
+			else
+				copy_lucid_key(&lctx->cfx_kd.ctx_key,
+				    &kc->kc_local_subkey);
+			kc->kc_cksumtype = lctx->cfx_kd.ctx_key.type;
+			kc->kc_keytype = lctx->cfx_kd.ctx_key.type;
+		}
+	} else {
+		return (GSS_S_DEFECTIVE_TOKEN);
+	}
+#ifdef notnow
+	if (flags & SC_KEYBLOCK)
+		get_keyblock(&p, &len, &kc->kc_keyblock);
+	if (flags & SC_LOCAL_SUBKEY)
+		get_keyblock(&p, &len, &kc->kc_local_subkey);
+	if (flags & SC_REMOTE_SUBKEY)
+		get_keyblock(&p, &len, &kc->kc_remote_subkey);
+#endif
+	kc->kc_local_seqnumber = lctx->send_seq;
+	kc->kc_remote_seqnumber = lctx->recv_seq;
+	if (lctx->initiate != 0)
+		kc->kc_more_flags |= LOCAL;
+	kc->kc_lifetime = lctx->endtime;
+	kc->kc_msg_order.km_flags = 0;
+
+	res = get_lucid_keys(kc);
+	if (GSS_ERROR(res))
+		return (res);
+
+	/*
+	 * We don't need these anymore.
+	 */
+	delete_keyblock(&kc->kc_keyblock);
+	delete_keyblock(&kc->kc_local_subkey);
+	delete_keyblock(&kc->kc_remote_subkey);
+
+	return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
 krb5_import(gss_ctx_id_t ctx,
     enum sec_context_format format,
     const gss_buffer_t context_token)
@@ -412,6 +587,10 @@ krb5_import(gss_ctx_id_t ctx,
 	size_t len = context_token->length;
 	uint32_t flags;
 	int i;
+
+	/* For MIT, just call krb5_lucid_import(). */
+	if (format == MIT_V1)
+		return (krb5_lucid_import(ctx, format, context_token));
 
 	/*
 	 * We support heimdal 0.6 and heimdal 1.1
--- sys/kgssapi/gss_impl.c.sav	2025-07-31 13:18:39.391791000 -0700
+++ sys/kgssapi/gss_impl.c	2025-08-01 07:09:09.590174000 -0700
@@ -192,12 +192,18 @@ OM_uint32
 }
 
 OM_uint32
-kgss_transfer_context(gss_ctx_id_t ctx)
+kgss_transfer_context(gss_ctx_id_t ctx, void *lctx)
 {
 	struct export_sec_context_res res;
 	struct export_sec_context_args args;
 	enum clnt_stat stat;
 	OM_uint32 maj_stat;
+
+	if (lctx != NULL) {
+		maj_stat = KGSS_IMPORT(ctx, MIT_V1, lctx);
+		ctx->handle = 0;
+		return (maj_stat);
+	}
 
 	KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
 	if (!KGSS_VNET(kgss_gssd_handle)) {
--- sys/kgssapi/gssapi.h.sav	2025-07-28 14:54:59.588770000 -0700
+++ sys/kgssapi/gssapi.h	2025-08-01 08:08:35.230136000 -0700
@@ -77,6 +77,54 @@ typedef int gss_cred_usage_t;
 typedef int gss_cred_usage_t;
 
 /*
+ * The structure returned by gss_krb5_export_lucid_sec_context().
+ */
+typedef struct gss_krb5_lucid_key {
+    OM_uint32       type;           /* key encryption type */
+    OM_uint32       length;         /* length of key data */
+    void *          data;           /* actual key data */
+} gss_krb5_lucid_key_t;
+
+typedef struct gss_krb5_rfc1964_keydata {
+    OM_uint32       sign_alg;       /* signing algorithm */
+    OM_uint32       seal_alg;       /* seal/encrypt algorithm */
+    gss_krb5_lucid_key_t    ctx_key;
+    /* Context key
+       (Kerberos session key or subkey) */
+} gss_krb5_rfc1964_keydata_t;
+
+typedef struct gss_krb5_cfx_keydata {
+    OM_uint32               have_acceptor_subkey;
+    /* 1 if there is an acceptor_subkey
+       present, 0 otherwise */
+    gss_krb5_lucid_key_t    ctx_key;
+    /* Context key
+       (Kerberos session key or subkey) */
+    gss_krb5_lucid_key_t    acceptor_subkey;
+    /* acceptor-asserted subkey or
+       0's if no acceptor subkey */
+} gss_krb5_cfx_keydata_t;
+
+typedef struct gss_krb5_lucid_context_v1 {
+    OM_uint32       version;        /* Structure version number (1)
+                                       MUST be at beginning of struct! */
+    OM_uint32       initiate;       /* Are we the initiator? */
+    OM_uint32       endtime;        /* expiration time of context */
+    uint64_t        send_seq;       /* sender sequence number */
+    uint64_t        recv_seq;       /* receive sequence number */
+    OM_uint32       protocol;       /* 0: rfc1964,
+                                       1: draft-ietf-krb-wg-gssapi-cfx-07 */
+    /*
+     * if (protocol == 0) rfc1964_kd should be used
+     * and cfx_kd contents are invalid and should be zero
+     * if (protocol == 1) cfx_kd should be used
+     * and rfc1964_kd contents are invalid and should be zero
+     */
+    gss_krb5_rfc1964_keydata_t rfc1964_kd;
+    gss_krb5_cfx_keydata_t     cfx_kd;
+} gss_krb5_lucid_context_v1_t;
+
+/*
  * Flag bits for context-level services.
  */
 #define GSS_C_DELEG_FLAG      1
@@ -406,6 +454,23 @@ OM_uint32 gss_init_sec_context
 	      );
 
 OM_uint32 gss_init_sec_context
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_cred_id_t,    /* initiator_cred_handle */
+	       gss_ctx_id_t *,         /* context_handle */
+	       const gss_name_t,       /* target_name */
+	       const gss_OID,          /* mech_type */
+	       OM_uint32,              /* req_flags */
+	       OM_uint32,              /* time_req */
+	       const gss_channel_bindings_t,
+				       /* input_chan_bindings */
+	       const 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 gss_init_sec_context_plus
 	      (OM_uint32 *,            /* minor_status */
 	       const gss_cred_id_t,    /* initiator_cred_handle */
 	       gss_ctx_id_t *,         /* context_handle */
@@ -422,6 +487,11 @@ OM_uint32 gss_init_sec_context
 	       OM_uint32 *             /* time_rec */
 	      );
 
+OM_uint32 gss_supports_lucid
+	      (OM_uint32 *,            /* minor_status */
+	       OM_uint32 *              /* vers */
+	      );
+
 OM_uint32 gss_accept_sec_context
 	      (OM_uint32 *,            /* minor_status */
 	       gss_ctx_id_t *,         /* context_handle */
@@ -437,6 +507,21 @@ OM_uint32 gss_accept_sec_context
 	       gss_cred_id_t *         /* delegated_cred_handle */
 	      );
 
+OM_uint32 gss_accept_sec_context_plus
+	      (OM_uint32 *,            /* minor_status */
+	       gss_ctx_id_t *,         /* context_handle */
+	       const gss_cred_id_t,    /* acceptor_cred_handle */
+	       const gss_buffer_t,     /* input_token_buffer */
+	       const 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 gss_delete_sec_context
 	      (OM_uint32 *,            /* minor_status */
 	       gss_ctx_id_t *,         /* context_handle */
--- sys/kgssapi/gssd.x.sav	2025-07-28 14:20:10.370019000 -0700
+++ sys/kgssapi/gssd.x	2025-08-01 08:08:51.162187000 -0700
@@ -70,6 +70,40 @@ struct init_sec_context_args {
 	gss_buffer_desc input_token;
 };
 
+struct init_sec_context_plus_res {
+	uint32_t	major_status;
+	uint32_t	minor_status;
+	gssd_ctx_id_t	ctx;
+	gss_OID		actual_mech_type;
+	gss_buffer_desc output_token;
+	uint32_t	ret_flags;
+	uint32_t	time_rec;
+	uint32_t	initiate;
+	uint32_t	endtime;
+	uint64_t	send_seq;
+	uint64_t	recv_seq;
+	uint32_t	protocol;
+	uint32_t	rfc_sign;
+	uint32_t	rfc_seal;
+	uint32_t	have_subkey;
+	uint32_t	ctx_type;
+	gss_buffer_desc	ctx_key;
+	uint32_t	subkey_type;
+	gss_buffer_desc	subkey_key;
+};
+
+struct init_sec_context_plus_args {
+	uint32_t	uid;
+	gssd_cred_id_t	cred;
+	gssd_ctx_id_t	ctx;
+	gssd_name_t	name;
+	gss_OID		mech_type;
+	uint32_t	req_flags;
+	uint32_t	time_req;
+	gss_channel_bindings_t input_chan_bindings;
+	gss_buffer_desc input_token;
+};
+
 struct accept_sec_context_res {
 	uint32_t	major_status;
 	uint32_t	minor_status;
@@ -83,7 +117,38 @@ struct accept_sec_context_args {
 };
 
 struct accept_sec_context_args {
+	gssd_ctx_id_t	ctx;
+	gssd_cred_id_t	cred;
+	gss_buffer_desc	input_token;
+	gss_channel_bindings_t input_chan_bindings;
+};
+
+struct accept_sec_context_plus_res {
+	uint32_t	major_status;
+	uint32_t	minor_status;
 	gssd_ctx_id_t	ctx;
+	gssd_name_t	src_name;
+	gss_OID		mech_type;
+	gss_buffer_desc	output_token;
+	uint32_t	ret_flags;
+	uint32_t	time_rec;
+	gssd_cred_id_t	delegated_cred_handle;
+	uint32_t	initiate;
+	uint32_t	endtime;
+	uint64_t	send_seq;
+	uint64_t	recv_seq;
+	uint32_t	protocol;
+	uint32_t	rfc_sign;
+	uint32_t	rfc_seal;
+	uint32_t	have_subkey;
+	uint32_t	ctx_type;
+	gss_buffer_desc	ctx_key;
+	uint32_t	subkey_type;
+	gss_buffer_desc	subkey_key;
+};
+
+struct accept_sec_context_plus_args {
+	gssd_ctx_id_t	ctx;
 	gssd_cred_id_t	cred;
 	gss_buffer_desc	input_token;
 	gss_channel_bindings_t input_chan_bindings;
@@ -101,7 +166,8 @@ enum sec_context_format {
 
 enum sec_context_format {
 	KGSS_HEIMDAL_0_6,
-	KGSS_HEIMDAL_1_1
+	KGSS_HEIMDAL_1_1,
+	MIT_V1
 };
 
 struct export_sec_context_res {
@@ -229,6 +295,11 @@ struct ip_to_dns_args {
 	char		ip_addr<NI_MAXHOST>;
 };
 
+struct supports_lucid_res {
+	uint32_t	major_status;
+	uint32_t	vers;
+};
+
 program GSSD {
 	version GSSDVERS {
 		void GSSD_NULL(void) = 0;
@@ -274,5 +345,14 @@ program GSSD {
 
 		ip_to_dns_res
 		GSSD_IP_TO_DNS(ip_to_dns_args) = 14;
+
+		init_sec_context_plus_res
+		GSSD_INIT_SEC_CONTEXT_PLUS(init_sec_context_plus_args) = 15;
+			
+		accept_sec_context_plus_res
+		GSSD_ACCEPT_SEC_CONTEXT_PLUS(accept_sec_context_plus_args) = 16;
+
+		supports_lucid_res
+		GSSD_SUPPORTS_LUCID(void) = 17;
 	} = 1;
 } = 0x40677373;
--- sys/kgssapi/gss_init_sec_context.c.sav	2025-07-28 15:18:39.148795000 -0700
+++ sys/kgssapi/gss_init_sec_context.c	2025-08-01 08:28:02.689666000 -0700
@@ -57,8 +57,8 @@ gss_init_sec_context(OM_uint32 * minor_status,
     OM_uint32 * ret_flags,
     OM_uint32 * time_rec)
 {
-	struct init_sec_context_res res;
-	struct init_sec_context_args args;
+	struct init_sec_context_plus_res res;
+	struct init_sec_context_plus_args args;
 	enum clnt_stat stat;
 	gss_ctx_id_t ctx = *context_handle;
 	CLIENT *cl;
@@ -91,7 +91,7 @@ gss_init_sec_context(OM_uint32 * minor_status,
 	}
 
 	bzero(&res, sizeof(res));
-	stat = gssd_init_sec_context_1(&args, &res, cl);
+	stat = gssd_init_sec_context_plus_1(&args, &res, cl);
 	CLNT_RELEASE(cl);
 	if (stat != RPC_SUCCESS) {
 		*minor_status = stat;
@@ -101,7 +101,7 @@ gss_init_sec_context(OM_uint32 * minor_status,
 	if (res.major_status != GSS_S_COMPLETE
 	    && res.major_status != GSS_S_CONTINUE_NEEDED) {
 		*minor_status = res.minor_status;
-		xdr_free((xdrproc_t) xdr_init_sec_context_res, &res);
+		xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
 		return (res.major_status);
 	}
 
@@ -110,7 +110,7 @@ gss_init_sec_context(OM_uint32 * minor_status,
 	if (!ctx) {
 		ctx = kgss_create_context(res.actual_mech_type);
 		if (!ctx) {
-			xdr_free((xdrproc_t) xdr_init_sec_context_res, &res);
+			xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
 			*minor_status = 0;
 			return (GSS_S_BAD_MECH);
 		}
@@ -125,15 +125,168 @@ gss_init_sec_context(OM_uint32 * minor_status,
 	if (time_rec)
 		*time_rec = res.time_rec;
 
-	xdr_free((xdrproc_t) xdr_init_sec_context_res, &res);
+	/*
+	 * If the context establishment is complete, export it from
+	 * userland and hand the result (which includes key material
+	 * etc.) to the kernel implementation.
+	 */
+	if (res.major_status == GSS_S_COMPLETE) {
+		res.major_status = kgss_transfer_context(ctx, NULL);
+printf("krb5_import: initiate=%d endtime=%d send_seq=%ld recv_seq=%ld proto=%d\n", res.initiate, res.endtime, res.send_seq, res.recv_seq, res.protocol);
+	}
 
+	xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
+
+	return (res.major_status);
+}
+
+OM_uint32
+gss_supports_lucid(uint32_t *minor_status, uint32_t *vers)
+{
+	struct supports_lucid_res res;
+	enum clnt_stat stat;
+	CLIENT *cl;
+
+	*minor_status = 0;
+
+	cl = kgss_gssd_client();
+	if (cl == NULL)
+		return (GSS_S_FAILURE);
+
+	bzero(&res, sizeof(res));
+	stat = gssd_supports_lucid_1(NULL, &res, cl);
+	CLNT_RELEASE(cl);
+	if (stat != RPC_SUCCESS) {
+		*minor_status = stat;
+		return (GSS_S_FAILURE);
+	}
+
+	if (vers)
+		*vers = res.vers;
+
+	return (res.major_status);
+}
+
+OM_uint32
+gss_init_sec_context_plus(OM_uint32 * minor_status,
+    const gss_cred_id_t initiator_cred_handle,
+    gss_ctx_id_t * context_handle,
+    const gss_name_t target_name,
+    const gss_OID input_mech_type,
+    OM_uint32 req_flags,
+    OM_uint32 time_req,
+    const gss_channel_bindings_t input_chan_bindings,
+    const gss_buffer_t input_token,
+    gss_OID * actual_mech_type,
+    gss_buffer_t output_token,
+    OM_uint32 * ret_flags,
+    OM_uint32 * time_rec)
+{
+	struct init_sec_context_plus_res res;
+	struct init_sec_context_plus_args args;
+	gss_krb5_lucid_context_v1_t lucid;
+	enum clnt_stat stat;
+	gss_ctx_id_t ctx = *context_handle;
+	CLIENT *cl;
+
+	*minor_status = 0;
+
+	cl = kgss_gssd_client();
+	if (cl == NULL)
+		return (GSS_S_FAILURE);
+
+	args.uid = curthread->td_ucred->cr_uid;
+	if  (initiator_cred_handle)
+		args.cred = initiator_cred_handle->handle;
+	else
+		args.cred = 0;
+	if (ctx)
+		args.ctx = ctx->handle;
+	else
+		args.ctx = 0;
+	args.name = target_name->handle;
+	args.mech_type = input_mech_type;
+	args.req_flags = req_flags;
+	args.time_req = time_req;
+	args.input_chan_bindings = input_chan_bindings;
+	if (input_token)
+		args.input_token = *input_token;
+	else {
+		args.input_token.length = 0;
+		args.input_token.value = NULL;
+	}
+
+	bzero(&res, sizeof(res));
+	stat = gssd_init_sec_context_plus_1(&args, &res, cl);
+	CLNT_RELEASE(cl);
+	if (stat != RPC_SUCCESS) {
+		*minor_status = stat;
+		return (GSS_S_FAILURE);
+	}
+
+	if (res.major_status != GSS_S_COMPLETE
+	    && res.major_status != GSS_S_CONTINUE_NEEDED) {
+		*minor_status = res.minor_status;
+		xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
+		return (res.major_status);
+	}
+
+	*minor_status = res.minor_status;
+
+	if (!ctx) {
+		ctx = kgss_create_context(res.actual_mech_type);
+		if (!ctx) {
+			xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
+			*minor_status = 0;
+			return (GSS_S_BAD_MECH);
+		}
+	}
+	*context_handle = ctx;
+	ctx->handle = res.ctx;
+	if (actual_mech_type)
+		*actual_mech_type = KGSS_MECH_TYPE(ctx);
+	kgss_copy_buffer(&res.output_token, output_token);
+	if (ret_flags)
+		*ret_flags = res.ret_flags;
+	if (time_rec)
+		*time_rec = res.time_rec;
+
 	/*
 	 * If the context establishment is complete, export it from
 	 * userland and hand the result (which includes key material
 	 * etc.) to the kernel implementation.
 	 */
-	if (res.major_status == GSS_S_COMPLETE)
-		res.major_status = kgss_transfer_context(ctx);
+	if (res.major_status == GSS_S_COMPLETE) {
+		lucid.initiate = res.initiate;
+		lucid.endtime = res.endtime;
+		lucid.send_seq = res.send_seq;
+		lucid.recv_seq = res.recv_seq;
+		lucid.protocol = res.protocol;
+		if (res.protocol == 0) {
+			lucid.rfc1964_kd.sign_alg = res.rfc_sign;
+			lucid.rfc1964_kd.seal_alg = res.rfc_seal;
+			lucid.rfc1964_kd.ctx_key.type = res.ctx_type;
+			lucid.rfc1964_kd.ctx_key.length = res.ctx_key.length;
+			lucid.rfc1964_kd.ctx_key.data = res.ctx_key.value;
+		} else if (res.protocol == 1) {
+			lucid.cfx_kd.have_acceptor_subkey = res.have_subkey;
+			lucid.cfx_kd.ctx_key.type = res.ctx_type;
+			lucid.cfx_kd.ctx_key.length = res.ctx_key.length;
+			lucid.cfx_kd.ctx_key.data = res.ctx_key.value;
+			lucid.cfx_kd.acceptor_subkey.type = res.subkey_type;
+			lucid.cfx_kd.acceptor_subkey.length =
+			    res.subkey_key.length;
+			lucid.cfx_kd.acceptor_subkey.data =
+			    res.subkey_key.value;
+		} else {
+			res.major_status = GSS_S_FAILURE;
+		}
+		if (res.major_status == GSS_S_COMPLETE)
+			res.major_status = kgss_transfer_context(ctx, &lucid);
+printf("krb5_import: initiate=%d endtime=%d send_seq=%ld recv_seq=%ld proto=%d\n", res.initiate, res.endtime, res.send_seq, res.recv_seq, res.protocol);
+	}
 
+	xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res);
+
 	return (res.major_status);
 }
--- sys/kgssapi/gssapi_impl.h.sav	2025-07-31 13:34:46.411242000 -0700
+++ sys/kgssapi/gssapi_impl.h	2025-07-31 13:35:11.717676000 -0700
@@ -78,5 +78,5 @@ extern void kgss_delete_context(gss_ctx_id_t ctx, gss_
 extern const char *kgss_find_mech_by_oid(const gss_OID oid);
 extern gss_ctx_id_t kgss_create_context(gss_OID mech_type);
 extern void kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token);
-extern OM_uint32 kgss_transfer_context(gss_ctx_id_t ctx);
+extern OM_uint32 kgss_transfer_context(gss_ctx_id_t ctx, void *lctx);
 extern void kgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to);
--- sys/kgssapi/gss_accept_sec_context.c.sav	2025-07-31 13:36:34.585391000 -0700
+++ sys/kgssapi/gss_accept_sec_context.c	2025-08-01 07:23:29.409219000 -0700
@@ -138,7 +138,137 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_stat
 	 * etc.) to the kernel implementation.
 	 */
 	if (res.major_status == GSS_S_COMPLETE)
-		res.major_status = kgss_transfer_context(ctx);
+		res.major_status = kgss_transfer_context(ctx, NULL);
 
 	return (res.major_status);
 }
+
+OM_uint32 gss_accept_sec_context_plus(OM_uint32 *minor_status,
+    gss_ctx_id_t *context_handle,
+    const gss_cred_id_t acceptor_cred_handle,
+    const gss_buffer_t input_token,
+    const 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)
+{
+	struct accept_sec_context_plus_res res;
+	struct accept_sec_context_plus_args args;
+	gss_krb5_lucid_context_v1_t lucid;
+	enum clnt_stat stat;
+	gss_ctx_id_t ctx = *context_handle;
+	gss_name_t name;
+	gss_cred_id_t cred;
+	CLIENT *cl;
+
+	cl = kgss_gssd_client();
+	if (cl == NULL) {
+		*minor_status = 0;
+		return (GSS_S_FAILURE);
+	}
+
+	if (ctx)
+		args.ctx = ctx->handle;
+	else
+		args.ctx = 0;
+	if (acceptor_cred_handle)
+		args.cred = acceptor_cred_handle->handle;
+	else
+		args.cred = 0;
+	args.input_token = *input_token;
+	args.input_chan_bindings = input_chan_bindings;
+
+	bzero(&res, sizeof(res));
+	stat = gssd_accept_sec_context_plus_1(&args, &res, cl);
+	CLNT_RELEASE(cl);
+	if (stat != RPC_SUCCESS) {
+		*minor_status = stat;
+		return (GSS_S_FAILURE);
+	}
+
+	if (res.major_status != GSS_S_COMPLETE
+	    && res.major_status != GSS_S_CONTINUE_NEEDED) {
+		*minor_status = res.minor_status;
+		xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
+		return (res.major_status);
+	}
+
+	*minor_status = res.minor_status;
+
+	if (!ctx) {
+		ctx = kgss_create_context(res.mech_type);
+		if (!ctx) {
+			xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
+			*minor_status = 0;
+			return (GSS_S_BAD_MECH);
+		}
+	}
+	*context_handle = ctx;
+
+	ctx->handle = res.ctx;
+	name = malloc(sizeof(struct _gss_name_t), M_GSSAPI, M_WAITOK);
+	name->handle = res.src_name;
+	if (src_name) {
+		*src_name = name;
+	} else {
+		OM_uint32 junk;
+		gss_release_name(&junk, &name);
+	}
+	if (mech_type)
+		*mech_type = KGSS_MECH_TYPE(ctx);
+	kgss_copy_buffer(&res.output_token, output_token);
+	if (ret_flags)
+		*ret_flags = res.ret_flags;
+	if (time_rec)
+		*time_rec = res.time_rec;
+	cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK);
+	cred->handle = res.delegated_cred_handle;
+	if (delegated_cred_handle) {
+		*delegated_cred_handle = cred;
+	} else {
+		OM_uint32 junk;
+		gss_release_cred(&junk, &cred);
+	}
+
+	/*
+	 * If the context establishment is complete, export it from
+	 * userland and hand the result (which includes key material
+	 * etc.) to the kernel implementation.
+	 */
+	if (res.major_status == GSS_S_COMPLETE) {
+		lucid.initiate = res.initiate;
+		lucid.endtime = res.endtime;
+		lucid.send_seq = res.send_seq;
+		lucid.recv_seq = res.recv_seq;
+		lucid.protocol = res.protocol;
+		if (res.protocol == 0) {
+			lucid.rfc1964_kd.sign_alg = res.rfc_sign;
+			lucid.rfc1964_kd.seal_alg = res.rfc_seal;
+			lucid.rfc1964_kd.ctx_key.type = res.ctx_type;
+			lucid.rfc1964_kd.ctx_key.length = res.ctx_key.length;
+			lucid.rfc1964_kd.ctx_key.data = res.ctx_key.value;
+		} else if (res.protocol == 1) {
+			lucid.cfx_kd.have_acceptor_subkey = res.have_subkey;
+			lucid.cfx_kd.ctx_key.type = res.ctx_type;
+			lucid.cfx_kd.ctx_key.length = res.ctx_key.length;
+			lucid.cfx_kd.ctx_key.data = res.ctx_key.value;
+			lucid.cfx_kd.acceptor_subkey.type = res.subkey_type;
+			lucid.cfx_kd.acceptor_subkey.length =
+			    res.subkey_key.length;
+			lucid.cfx_kd.acceptor_subkey.data =
+			    res.subkey_key.value;
+		} else {
+			res.major_status = GSS_S_FAILURE;
+		}
+		if (res.major_status == GSS_S_COMPLETE)
+			res.major_status = kgss_transfer_context(ctx, &lucid);
+printf("krb5_import: initiate=%d endtime=%d send_seq=%ld recv_seq=%ld proto=%d\n", res.initiate, res.endtime, res.send_seq, res.recv_seq, res.protocol);
+	}
+
+	xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
+
+	return (res.major_status);
+}
--- sys/rpc/rpcsec_gss/rpcsec_gss.c.sav	2025-08-01 08:49:31.667000000 -0700
+++ sys/rpc/rpcsec_gss/rpcsec_gss.c	2025-08-01 08:48:25.095100000 -0700
@@ -746,6 +746,7 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *option
 	struct rpc_callextra	 ext;
 	gss_OID			mech_oid;
 	gss_OID_set		mechlist;
+	static enum krb_imp	my_krb_imp = KRBIMP_UNKNOWN;
 
 	rpc_gss_log_debug("in rpc_gss_refresh()");
 	
@@ -852,6 +853,14 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *option
 		goto out;
 	}
 
+	if (my_krb_imp == KRBIMP_UNKNOWN) {
+		maj_stat = gss_supports_lucid(&min_stat, NULL);
+		if (maj_stat == GSS_S_COMPLETE)
+			my_krb_imp = KRBIMP_MIT;
+		else
+			my_krb_imp = KRBIMP_HESIOD1;
+	}
+
 	/* GSS context establishment loop. */
 	memset(&recv_token, 0, sizeof(recv_token));
 	memset(&gr, 0, sizeof(gr));
@@ -862,20 +871,38 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *option
 	for (;;) {
 		crsave = td->td_ucred;
 		td->td_ucred = gd->gd_ucred;
-		maj_stat = gss_init_sec_context(&min_stat,
-		    gd->gd_options.my_cred,
-		    &gd->gd_ctx,
-		    name,
-		    gd->gd_mech,
-		    gd->gd_options.req_flags,
-		    gd->gd_options.time_req,
-		    gd->gd_options.input_channel_bindings,
-		    recv_tokenp,
-		    &gd->gd_mech,	/* used mech */
-		    &send_token,
-		    &options_ret->ret_flags,
-		    &options_ret->time_req);
+printf("gd_mech=%p\n", gd->gd_mech);
+		if (my_krb_imp == KRBIMP_MIT)
+			maj_stat = gss_init_sec_context_plus(&min_stat,
+			    gd->gd_options.my_cred,
+			    &gd->gd_ctx,
+			    name,
+			    gd->gd_mech,
+			    gd->gd_options.req_flags,
+			    gd->gd_options.time_req,
+			    gd->gd_options.input_channel_bindings,
+			    recv_tokenp,
+			    &gd->gd_mech,	/* used mech */
+			    &send_token,
+			    &options_ret->ret_flags,
+			    &options_ret->time_req);
+		else
+			maj_stat = gss_init_sec_context(&min_stat,
+			    gd->gd_options.my_cred,
+			    &gd->gd_ctx,
+			    name,
+			    gd->gd_mech,
+			    gd->gd_options.req_flags,
+			    gd->gd_options.time_req,
+			    gd->gd_options.input_channel_bindings,
+			    recv_tokenp,
+			    &gd->gd_mech,	/* used mech */
+			    &send_token,
+			    &options_ret->ret_flags,
+			    &options_ret->time_req);
 		td->td_ucred = crsave;
+printf("aft gss_init gd_mech=%p\n", gd->gd_mech);
+printf("aft gss_init maj=0x%x min=%d\n", maj_stat, min_stat);
 		
 		/*
 		 * Free the token which we got from the server (if
--- sys/rpc/rpcsec_gss/rpcsec_gss_int.h.sav	2025-08-01 08:38:06.516532000 -0700
+++ sys/rpc/rpcsec_gss/rpcsec_gss_int.h	2025-08-01 08:41:13.861239000 -0700
@@ -73,6 +73,12 @@ struct rpc_gss_init_res {
 /* Maximum sequence number value. */
 #define MAXSEQ		0x80000000
 
+enum krb_imp {
+	KRBIMP_UNKNOWN,
+	KRBIMP_HESIOD1,
+	KRBIMP_MIT
+};
+
 /* Prototypes. */
 __BEGIN_DECLS
 
--- sys/rpc/rpcsec_gss/svc_rpcsec_gss.c.sav	2025-08-01 08:50:21.724849000 -0700
+++ sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2025-08-01 08:56:44.902388000 -0700
@@ -925,9 +925,19 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_clie
 	OM_uint32		maj_stat = 0, min_stat = 0, ret_flags;
 	OM_uint32		cred_lifetime;
 	struct svc_rpc_gss_svc_name *sname;
+	static enum krb_imp	my_krb_imp = KRBIMP_UNKNOWN;
 
 	rpc_gss_log_debug("in svc_rpc_gss_accept_context()");
 	
+	if (my_krb_imp == KRBIMP_UNKNOWN) {
+		maj_stat = gss_supports_lucid(&min_stat, NULL);
+		if (maj_stat == GSS_S_COMPLETE)
+			my_krb_imp = KRBIMP_MIT;
+		else
+			my_krb_imp = KRBIMP_HESIOD1;
+		min_stat = 0;
+	}
+
 	/* Deserialize arguments. */
 	memset(&recv_tok, 0, sizeof(recv_tok));
 	
@@ -949,18 +959,33 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_clie
 			if (sname->sn_program == rqst->rq_prog
 			    && sname->sn_version == rqst->rq_vers) {
 			retry:
-				gr->gr_major = gss_accept_sec_context(
-					&gr->gr_minor,
-					&client->cl_ctx,
-					sname->sn_cred,
-					&recv_tok,
-					GSS_C_NO_CHANNEL_BINDINGS,
-					&client->cl_cname,
-					&mech,
-					&gr->gr_token,
-					&ret_flags,
-					&cred_lifetime,
-					&client->cl_creds);
+				if (my_krb_imp == KRBIMP_MIT)
+					gr->gr_major =
+					    gss_accept_sec_context_plus(
+						&gr->gr_minor,
+						&client->cl_ctx,
+						sname->sn_cred,
+						&recv_tok,
+						GSS_C_NO_CHANNEL_BINDINGS,
+						&client->cl_cname,
+						&mech,
+						&gr->gr_token,
+						&ret_flags,
+						&cred_lifetime,
+						&client->cl_creds);
+				else
+					gr->gr_major = gss_accept_sec_context(
+						&gr->gr_minor,
+						&client->cl_ctx,
+						sname->sn_cred,
+						&recv_tok,
+						GSS_C_NO_CHANNEL_BINDINGS,
+						&client->cl_cname,
+						&mech,
+						&gr->gr_token,
+						&ret_flags,
+						&cred_lifetime,
+						&client->cl_creds);
 				if (gr->gr_major == 
 				    GSS_S_CREDENTIALS_EXPIRED) {
 					/*
