--- usr.sbin/gssd/Makefile.sav	2025-07-28 16:49:35.386386000 -0700
+++ usr.sbin/gssd/Makefile	2025-07-31 19:56:16.666434000 -0700
@@ -9,15 +9,14 @@ WARNS?= 1
 CFLAGS+= -I.
 WARNS?= 1
 
-LIBADD=	gssapi
 .if ${MK_KERBEROS_SUPPORT} != "no"
 .if ${MK_MITKRB5} != "no"
 # MIT KRB5
-LIBADD+=	krb5 k5crypto krb5profile krb5support
+LIBADD=	krb5 k5crypto krb5profile krb5support gssapi_krb5
 CFLAGS+= -DMK_MITKRB5=yes
 .else
 # Heimdal
-LIBADD+=	krb5 roken
+LIBADD=	gssapi krb5 roken
 .endif
 .else
 CFLAGS+= -DWITHOUT_KERBEROS
--- usr.sbin/gssd/gssd.c.sav	2025-07-26 19:21:27.204328000 -0700
+++ usr.sbin/gssd/gssd.c	2025-08-01 08:32:54.958122000 -0700
@@ -53,6 +53,9 @@
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <gssapi/gssapi.h>
+#ifdef MK_MITKRB5
+#include <gssapi/gssapi_krb5.h>
+#endif
 #include <rpc/rpc.h>
 #include <rpc/rpc_com.h>
 
@@ -335,6 +338,7 @@ gssd_null_1_svc(void *argp, void *result, struct svc_r
 	return (TRUE);
 }
 
+#ifndef MK_MITKRB5
 bool_t
 gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *result, struct svc_req *rqstp)
 {
@@ -454,11 +458,40 @@ gssd_init_sec_context_1_svc(init_sec_context_args *arg
 		else
 			result->ctx = gssd_make_resource(ctx);
 	}
+
+	return (TRUE);
+}
+
+bool_t
+gssd_supports_lucid_1_svc(void *argp, supports_lucid_res *result, struct svc_req *rqstp)
+{
 
+	gssd_verbose_out("gssd_lucid: done\n");
+	result->major_status = GSS_S_UNAVAILABLE;
 	return (TRUE);
 }
 
 bool_t
+gssd_init_sec_context_plus_1_svc(init_sec_context_plus_args *argp,
+    init_sec_context_plus_res *result, struct svc_req *rqstp)
+{
+
+	gssd_verbose_out("gssd_init_sec_context_plus: Heimdal\n");
+	result->major_status = GSS_S_UNAVAILABLE;
+	return (TRUE);
+}
+
+bool_t
+gssd_accept_sec_context_plus_1_svc(accept_sec_context_plus_args *argp,
+    accept_sec_context_plus_res *result, struct svc_req *rqstp)
+{
+
+	gssd_verbose_out("gssd_accept_sec_context_plus: Heimdal\n");
+	result->major_status = GSS_S_UNAVAILABLE;
+	return (TRUE);
+}
+
+bool_t
 gssd_accept_sec_context_1_svc(accept_sec_context_args *argp, accept_sec_context_res *result, struct svc_req *rqstp)
 {
 	gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
@@ -508,8 +541,342 @@ gssd_accept_sec_context_1_svc(accept_sec_context_args 
 
 	return (TRUE);
 }
+#else	/* MK_MITKRB5 */
+bool_t
+gssd_supports_lucid_1_svc(void *argp, supports_lucid_res *result, struct svc_req *rqstp)
+{
 
+	gssd_verbose_out("gssd_lucid: done\n");
+	result->vers = 1;
+	result->major_status = GSS_S_COMPLETE;
+	return (TRUE);
+}
+
 bool_t
+gssd_init_sec_context_1_svc(init_sec_context_args *argp,
+    init_sec_context_res *result, struct svc_req *rqstp)
+{
+
+	gssd_verbose_out("gssd_init_sec_context_plus: MIT\n");
+	result->major_status = GSS_S_UNAVAILABLE;
+	return (TRUE);
+}
+
+bool_t
+gssd_accept_sec_context_1_svc(accept_sec_context_args *argp,
+    accept_sec_context_res *result, struct svc_req *rqstp)
+{
+
+	gssd_verbose_out("gssd_accept_sec_context_plus: MIT\n");
+	result->major_status = GSS_S_UNAVAILABLE;
+	return (TRUE);
+}
+
+bool_t
+gssd_init_sec_context_plus_1_svc(init_sec_context_plus_args *argp,
+    init_sec_context_plus_res *result, struct svc_req *rqstp)
+{
+	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+	gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+	gss_name_t name = GSS_C_NO_NAME;
+	char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
+	int gotone, gotcred;
+	OM_uint32 min_stat;
+#ifndef WITHOUT_KERBEROS
+	gss_buffer_desc principal_desc;
+	char enctype[sizeof(uint32_t)];
+	int key_enctype;
+	OM_uint32 maj_stat;
+#endif
+
+	memset(result, 0, sizeof(*result));
+	if (hostbased_initiator_cred != 0 && argp->cred != 0 &&
+	    argp->uid == 0) {
+		/*
+		 * These credentials are for a host based initiator name
+		 * in a keytab file, which should now have credentials
+		 * in /tmp/krb5cc_gssd, because gss_acquire_cred() did
+		 * the equivalent of "kinit -k".
+		 */
+		snprintf(ccname, sizeof(ccname), "FILE:%s",
+		    GSSD_CREDENTIAL_CACHE_FILE);
+	} else if (ccfile_dirlist[0] != '\0' && argp->cred == 0) {
+		/*
+		 * For the "-s" case and no credentials provided as an
+		 * argument, search the directory list for an appropriate
+		 * credential cache file. If the search fails, return failure.
+		 */
+		gotone = 0;
+		cp = ccfile_dirlist;
+		do {
+			cp2 = strchr(cp, ':');
+			if (cp2 != NULL)
+				*cp2 = '\0';
+			gotone = find_ccache_file(cp, argp->uid, ccname);
+			if (gotone != 0)
+				break;
+			if (cp2 != NULL)
+				*cp2++ = ':';
+			cp = cp2;
+		} while (cp != NULL && *cp != '\0');
+		if (gotone == 0) {
+			result->major_status = GSS_S_CREDENTIALS_EXPIRED;
+			gssd_verbose_out("gssd_init_sec_context_plus: -s no"
+			    " credential cache file found for uid=%d\n",
+			    (int)argp->uid);
+			return (TRUE);
+		}
+	} else {
+		/*
+		 * If there wasn't a "-s" option or the credentials have
+		 * been provided as an argument, do it the old way.
+		 * When credentials are provided, the uid should be root.
+		 */
+		if (argp->cred != 0 && argp->uid != 0) {
+			if (debug_level == 0)
+				syslog(LOG_ERR, "gss_init_sec_context_plus:"
+				    " cred for non-root");
+			else
+				fprintf(stderr, "gss_init_sec_context_plus:"
+				    " cred for non-root\n");
+		}
+		snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
+		    (int) argp->uid);
+	}
+	setenv("KRB5CCNAME", ccname, TRUE);
+
+	if (argp->cred) {
+		cred = gssd_find_resource(argp->cred);
+		if (!cred) {
+			result->major_status = GSS_S_CREDENTIALS_EXPIRED;
+			gssd_verbose_out("gssd_init_sec_context_plus: cred"
+			    " resource not found\n");
+			return (TRUE);
+		}
+	}
+	if (argp->ctx) {
+		ctx = gssd_find_resource(argp->ctx);
+		if (!ctx) {
+			result->major_status = GSS_S_CONTEXT_EXPIRED;
+			gssd_verbose_out("gssd_init_sec_context_plus: context"
+			    " resource not found\n");
+			return (TRUE);
+		}
+	}
+	if (argp->name) {
+		name = gssd_find_resource(argp->name);
+		if (!name) {
+			result->major_status = GSS_S_BAD_NAME;
+			gssd_verbose_out("gssd_init_sec_context_plus: name"
+			    " resource not found\n");
+			return (TRUE);
+		}
+	}
+	gotcred = 0;
+
+	result->major_status = gss_init_sec_context(&result->minor_status,
+	    cred, &ctx, name, argp->mech_type,
+	    argp->req_flags, argp->time_req, argp->input_chan_bindings,
+	    &argp->input_token, &result->actual_mech_type,
+	    &result->output_token, &result->ret_flags, &result->time_rec);
+	gssd_verbose_out("gssd_init_sec_context_plus: done major=0x%x minor=%d"
+	    " uid=%d\n", (unsigned int)result->major_status,
+	    (int)result->minor_status, (int)argp->uid);
+	if (gotcred != 0)
+		gss_release_cred(&min_stat, &cred);
+
+	if (result->actual_mech_type) {
+gssd_verbose_out("gssd mech len=%d elem=%p\n", result->actual_mech_type->length, result->actual_mech_type->elements);
+		/*
+		 * Just to keep the bogus "elements" pointer
+		 * from core dumping the daemon.
+		 */
+		result->actual_mech_type = GSS_KRB5_MECH_OID_X;
+gssd_verbose_out("gssd aft mech\n");
+	}
+
+	if (result->major_status == GSS_S_COMPLETE
+	    || result->major_status == GSS_S_CONTINUE_NEEDED) {
+		if (argp->ctx)
+			result->ctx = argp->ctx;
+		else
+			result->ctx = gssd_make_resource(ctx);
+		gssd_verbose_out("gssd_init_ctx=%p arg=%ld res=%ld", ctx, argp->ctx, result->ctx);
+	}
+
+	if (result->major_status == GSS_S_COMPLETE) {
+		gss_krb5_lucid_context_v1_t *lctx;
+
+		result->major_status = gss_krb5_export_lucid_sec_context(
+		    &result->minor_status, &ctx, 1, (void *)&lctx);
+		gssd_verbose_out("gss_lucid: maj=0x%x min=0x%x lctx=%p\n", result->major_status, result->minor_status, lctx);
+		if (result->major_status == GSS_S_COMPLETE &&
+		    lctx != NULL) {
+			gssd_verbose_out("Got the sucker!!");
+			result->initiate = lctx->initiate;
+			result->endtime = lctx->endtime;
+			result->send_seq = lctx->send_seq;
+			result->recv_seq = lctx->recv_seq;
+			result->protocol = lctx->protocol;
+			if (lctx->protocol == 0) {
+				result->rfc_sign = lctx->rfc1964_kd.sign_alg;
+				result->rfc_seal = lctx->rfc1964_kd.seal_alg;
+				result->ctx_type =
+				    lctx->rfc1964_kd.ctx_key.type;
+				result->ctx_key.length =
+				    lctx->rfc1964_kd.ctx_key.length;
+				result->ctx_key.value =
+				    mem_alloc(result->ctx_key.length);
+				memcpy(result->ctx_key.value,
+				    lctx->rfc1964_kd.ctx_key.data,
+				    result->ctx_key.length);
+			} else if (lctx->protocol == 1) {
+				gssd_verbose_out("accsub=%d\n", lctx->cfx_kd.have_acceptor_subkey);
+				gssd_verbose_out("ctx ty=%d len=%d k=%p\n", lctx->cfx_kd.ctx_key.type, lctx->cfx_kd.ctx_key.length, lctx->cfx_kd.ctx_key.data);
+				gssd_verbose_out("sub ty=%d len=%d k=%p\n", lctx->cfx_kd.acceptor_subkey.type, lctx->cfx_kd.acceptor_subkey.length, lctx->cfx_kd.acceptor_subkey.data);
+				result->have_subkey =
+				    lctx->cfx_kd.have_acceptor_subkey;
+				result->ctx_type = lctx->cfx_kd.ctx_key.type;
+				result->ctx_key.length =
+				    lctx->cfx_kd.ctx_key.length;
+				result->ctx_key.value =
+				    mem_alloc(result->ctx_key.length);
+				memcpy(result->ctx_key.value,
+				    lctx->cfx_kd.ctx_key.data,
+				    result->ctx_key.length);
+				if (result->have_subkey != 0) {
+					result->subkey_type =
+					    lctx->cfx_kd.acceptor_subkey.type;
+					result->subkey_key.length =
+					    lctx->cfx_kd.acceptor_subkey.length;
+					result->subkey_key.value = mem_alloc(
+					    result->subkey_key.length);
+					memcpy(result->subkey_key.value,
+					    lctx->cfx_kd.acceptor_subkey.data,
+					    result->subkey_key.length);
+				} else {
+					result->subkey_type = 0;
+					result->subkey_key.length = 0;
+					result->subkey_key.value = NULL;
+				}
+			}
+		}
+	}
+
+	return (TRUE);
+}
+
+bool_t
+gssd_accept_sec_context_plus_1_svc(accept_sec_context_plus_args *argp, accept_sec_context_plus_res *result, struct svc_req *rqstp)
+{
+	gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+	gss_name_t src_name;
+	gss_cred_id_t delegated_cred_handle;
+
+	memset(result, 0, sizeof(*result));
+	if (argp->ctx) {
+		ctx = gssd_find_resource(argp->ctx);
+		if (!ctx) {
+			result->major_status = GSS_S_CONTEXT_EXPIRED;
+			gssd_verbose_out("gssd_accept_sec_context: ctx"
+			    " resource not found\n");
+			return (TRUE);
+		}
+	}
+	if (argp->cred) {
+		cred = gssd_find_resource(argp->cred);
+		if (!cred) {
+			result->major_status = GSS_S_CREDENTIALS_EXPIRED;
+			gssd_verbose_out("gssd_accept_sec_context: cred"
+			    " resource not found\n");
+			return (TRUE);
+		}
+	}
+
+	memset(result, 0, sizeof(*result));
+	result->major_status = gss_accept_sec_context(&result->minor_status,
+	    &ctx, cred, &argp->input_token, argp->input_chan_bindings,
+	    &src_name, &result->mech_type, &result->output_token,
+	    &result->ret_flags, &result->time_rec,
+	    &delegated_cred_handle);
+	gssd_verbose_out("gssd_accept_sec_context: done major=0x%x minor=%d\n",
+	    (unsigned int)result->major_status, (int)result->minor_status);
+
+	if (result->major_status == GSS_S_COMPLETE
+	    || result->major_status == GSS_S_CONTINUE_NEEDED) {
+		if (argp->ctx)
+			result->ctx = argp->ctx;
+		else
+			result->ctx = gssd_make_resource(ctx);
+		result->src_name = gssd_make_resource(src_name);
+		result->delegated_cred_handle =
+			gssd_make_resource(delegated_cred_handle);
+	}
+
+	if (result->major_status == GSS_S_COMPLETE) {
+		gss_krb5_lucid_context_v1_t *lctx;
+
+		result->major_status = gss_krb5_export_lucid_sec_context(
+		    &result->minor_status, &ctx, 1, (void *)&lctx);
+		gssd_verbose_out("gss_lucid: maj=0x%x min=0x%x lctx=%p\n", result->major_status, result->minor_status, lctx);
+		if (result->major_status == GSS_S_COMPLETE &&
+		    lctx != NULL) {
+			gssd_verbose_out("Got the sucker!!");
+			result->initiate = lctx->initiate;
+			result->endtime = lctx->endtime;
+			result->send_seq = lctx->send_seq;
+			result->recv_seq = lctx->recv_seq;
+			result->protocol = lctx->protocol;
+			if (lctx->protocol == 0) {
+				result->rfc_sign = lctx->rfc1964_kd.sign_alg;
+				result->rfc_seal = lctx->rfc1964_kd.seal_alg;
+				result->ctx_type =
+				    lctx->rfc1964_kd.ctx_key.type;
+				result->ctx_key.length =
+				    lctx->rfc1964_kd.ctx_key.length;
+				result->ctx_key.value =
+				    mem_alloc(result->ctx_key.length);
+				memcpy(result->ctx_key.value,
+				    lctx->rfc1964_kd.ctx_key.data,
+				    result->ctx_key.length);
+			} else if (lctx->protocol == 1) {
+				gssd_verbose_out("accsub=%d\n", lctx->cfx_kd.have_acceptor_subkey);
+				gssd_verbose_out("ctx ty=%d len=%d k=%p\n", lctx->cfx_kd.ctx_key.type, lctx->cfx_kd.ctx_key.length, lctx->cfx_kd.ctx_key.data);
+				gssd_verbose_out("sub ty=%d len=%d k=%p\n", lctx->cfx_kd.acceptor_subkey.type, lctx->cfx_kd.acceptor_subkey.length, lctx->cfx_kd.acceptor_subkey.data);
+				result->have_subkey =
+				    lctx->cfx_kd.have_acceptor_subkey;
+				result->ctx_type = lctx->cfx_kd.ctx_key.type;
+				result->ctx_key.length =
+				    lctx->cfx_kd.ctx_key.length;
+				result->ctx_key.value =
+				    mem_alloc(result->ctx_key.length);
+				memcpy(result->ctx_key.value,
+				    lctx->cfx_kd.ctx_key.data,
+				    result->ctx_key.length);
+				if (result->have_subkey != 0) {
+					result->subkey_type =
+					    lctx->cfx_kd.acceptor_subkey.type;
+					result->subkey_key.length =
+					    lctx->cfx_kd.acceptor_subkey.length;
+					result->subkey_key.value = mem_alloc(
+					    result->subkey_key.length);
+					memcpy(result->subkey_key.value,
+					    lctx->cfx_kd.acceptor_subkey.data,
+					    result->subkey_key.length);
+				} else {
+					result->subkey_type = 0;
+					result->subkey_key.length = 0;
+					result->subkey_key.value = NULL;
+				}
+			}
+		}
+	}
+	return (TRUE);
+}
+#endif	/* !MK_MITKRB5 */
+
+bool_t
 gssd_delete_sec_context_1_svc(delete_sec_context_args *argp, delete_sec_context_res *result, struct svc_req *rqstp)
 {
 	gss_ctx_id_t ctx = gssd_find_resource(argp->ctx);
