The branch main has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=554651ebf1c1798fa8fb2560cab761ac3d219555

commit 554651ebf1c1798fa8fb2560cab761ac3d219555
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2025-08-06 22:36:21 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2025-08-06 22:37:20 +0000

    kgssapi: Fix the kgssapi so that it can use MIT Kerberos
    
    Without this patch, the kgssapi uses detailed knowledge
    of the internal context structure for Heimdal (up to vers 1.5).
    It also does four upcalls to the gssd daemon to establish
    a server side RPCSEC_GSS context.
    
    This patch adds support for three new upcalls:
    gss_init_sec_context_lucid_v1()
    gss_accept_sec_context_lucid_v1()
    gss_supports_lucid()
    
    These are used to determine if the gssd can do the upcalls
    and uses them to avoid needing detailed Heimdal knowledge
    if they are supported.
    
    gss_init_sec_context_lucid_v1() and
    gss_accept_sec_context_lucid_v1() return the information
    needed to complete the RPCSEC_GSS context.
    They use gss_krb5_export_lucid_sec_context() to acquire
    the information from the libraries. (MIT Kerberos supports
    this and I believe newer versions of Heimdal does, as well).
    
    This avoids the need for detailed knowledge about MIT's
    internals and replaces the 2 or 4 (initiator or acceptor) upcalls
    with a single upcall to create the RPCSEC_GSS context.
    
    The old Heimdal (up to 1.5) support is left intact, but should
    be removed whenever Heimdal 1.5 is removed from /usr/src.
    
    It also modifies the Makefile so that the gssd is only built
    when MK_KERBEROS_SUPPORT != "no", since it is useless without
    Kerberos.
    
    Reviewed by:    cy
    Differential Revision:  https://reviews.freebsd.org/D51731
    Differential Revision:  https://reviews.freebsd.org/D51733
---
 sys/kgssapi/gss_accept_sec_context.c | 145 +++++++++-
 sys/kgssapi/gss_impl.c               |   8 +-
 sys/kgssapi/gss_init_sec_context.c   | 145 +++++++++-
 sys/kgssapi/gssapi.h                 |  42 +++
 sys/kgssapi/gssapi_impl.h            |   2 +-
 sys/kgssapi/gssd.x                   |  79 +++++-
 sys/kgssapi/krb5/krb5_mech.c         |  80 ++++++
 sys/rpc/rpcsec_gss/rpcsec_gss.c      |  50 +++-
 sys/rpc/rpcsec_gss/rpcsec_gss_int.h  |   6 +
 sys/rpc/rpcsec_gss/svc_rpcsec_gss.c  | 122 +++++++--
 usr.sbin/Makefile                    |   2 +
 usr.sbin/gssd/Makefile               |   9 +-
 usr.sbin/gssd/gssd.c                 | 506 ++++++++++++++++++++++++++++++++---
 13 files changed, 1110 insertions(+), 86 deletions(-)

diff --git a/sys/kgssapi/gss_accept_sec_context.c 
b/sys/kgssapi/gss_accept_sec_context.c
index 723ed9db9072..8a49b85be852 100644
--- a/sys/kgssapi/gss_accept_sec_context.c
+++ b/sys/kgssapi/gss_accept_sec_context.c
@@ -41,6 +41,11 @@
 #include "gssd.h"
 #include "kgss_if.h"
 
+/*
+ * This function should only be called when the gssd
+ * daemon running on the system is an old one that
+ * does not use gss_krb5_export_lucid_sec_context().
+ */
 OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
     gss_ctx_id_t *context_handle,
     const gss_cred_id_t acceptor_cred_handle,
@@ -138,7 +143,145 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
         * 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);
+}
+
+/*
+ * This function should be called when the gssd daemon is
+ * one that uses gss_krb5_export_lucid_sec_context().
+ * There is a lot of code common with
+ * gss_accept_sec_context().  However, the structures used
+ * are not the same and future changes may be needed for
+ * this one.  As such, I have not factored out the common
+ * code.
+ * gss_supports_lucid() may be used to check to see if the
+ * gssd daemon uses gss_krb5_export_lucid_sec_context().
+ */
+OM_uint32 gss_accept_sec_context_lucid_v1(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,
+    gss_buffer_t exported_name,
+    uid_t *uidp,
+    gid_t *gidp,
+    int *numgroups,
+    gid_t *groups)
+{
+       struct accept_sec_context_lucid_v1_res res;
+       struct accept_sec_context_lucid_v1_args args;
+       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_lucid_v1_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) {
+               int i, n;
+
+               /* First, get the unix credentials. */
+               *uidp = res.uid;
+               *gidp = res.gid;
+               n = res.gidlist.gidlist_len;
+               if (n > *numgroups)
+                       n = *numgroups;
+               for (i = 0; i < n; i++)
+                       groups[i] = res.gidlist.gidlist_val[i];
+               *numgroups = n;
+
+               /* Next, get the exported_name. */
+               kgss_copy_buffer(&res.exported_name, exported_name);
+
+               /* Now, handle the lucid credential setup. */
+               res.major_status = kgss_transfer_context(ctx, &res.lucid);
+               if (res.major_status != GSS_S_COMPLETE)
+                       printf("gss_accept_sec_context_lucid_v1: "
+                           "transfer failed\n");
+       }
+
+       xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
 
        return (res.major_status);
 }
diff --git a/sys/kgssapi/gss_impl.c b/sys/kgssapi/gss_impl.c
index e2569bea61f9..c9cd4d880695 100644
--- a/sys/kgssapi/gss_impl.c
+++ b/sys/kgssapi/gss_impl.c
@@ -192,13 +192,19 @@ kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t 
output_token)
 }
 
 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)) {
                KGSS_CURVNET_RESTORE();
diff --git a/sys/kgssapi/gss_init_sec_context.c 
b/sys/kgssapi/gss_init_sec_context.c
index fa0d3fb2ae19..a0f48fda8b29 100644
--- a/sys/kgssapi/gss_init_sec_context.c
+++ b/sys/kgssapi/gss_init_sec_context.c
@@ -42,6 +42,11 @@
 #include "gssd.h"
 #include "kgss_if.h"
 
+/*
+ * This function should only be called when the gssd
+ * daemon running on the system is an old one that
+ * does not use gss_krb5_export_lucid_sec_context().
+ */
 OM_uint32
 gss_init_sec_context(OM_uint32 * minor_status,
     const gss_cred_id_t initiator_cred_handle,
@@ -133,7 +138,145 @@ gss_init_sec_context(OM_uint32 * minor_status,
         * 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_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);
+}
+
+/*
+ * This function should be called when the gssd daemon is
+ * one that uses gss_krb5_export_lucid_sec_context().
+ * There is a lot of code common with
+ * gss_init_sec_context().  However, the structures used
+ * are not the same and future changes may be needed for
+ * this one.  As such, I have not factored out the common
+ * code.
+ * gss_supports_lucid() may be used to check to see if the
+ * gssd daemon uses gss_krb5_export_lucid_sec_context().
+ */
+OM_uint32
+gss_init_sec_context_lucid_v1(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_lucid_v1_res res;
+       struct init_sec_context_lucid_v1_args args;
+       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_lucid_v1_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_lucid_v1_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_lucid_v1_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, &res.lucid);
+               if (res.major_status != GSS_S_COMPLETE)
+                       printf("gss_init_sec_context_lucid_v1: "
+                           "transfer failed\n");
+       }
+
+       xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res);
 
        return (res.major_status);
 }
diff --git a/sys/kgssapi/gssapi.h b/sys/kgssapi/gssapi.h
index 37cc8a1a5a09..cd4a4b508cc5 100644
--- a/sys/kgssapi/gssapi.h
+++ b/sys/kgssapi/gssapi.h
@@ -422,6 +422,28 @@ OM_uint32 gss_init_sec_context
               OM_uint32 *             /* time_rec */
              );
 
+OM_uint32 gss_init_sec_context_lucid_v1
+             (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_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 +459,26 @@ OM_uint32 gss_accept_sec_context
               gss_cred_id_t *         /* delegated_cred_handle */
              );
 
+OM_uint32 gss_accept_sec_context_lucid_v1
+             (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 */
+              gss_buffer_t,           /* exported_name */
+              uid_t *,                /* Unix cred */
+              gid_t *,
+              int *,                  /* Number of groups */
+              gid_t *                 /* groups list */
+             );
+
 OM_uint32 gss_delete_sec_context
              (OM_uint32 *,            /* minor_status */
               gss_ctx_id_t *,         /* context_handle */
diff --git a/sys/kgssapi/gssapi_impl.h b/sys/kgssapi/gssapi_impl.h
index 3279dc8da122..d8a85f20a602 100644
--- a/sys/kgssapi/gssapi_impl.h
+++ b/sys/kgssapi/gssapi_impl.h
@@ -78,5 +78,5 @@ extern gss_OID kgss_find_mech_by_name(const char *name);
 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);
diff --git a/sys/kgssapi/gssd.x b/sys/kgssapi/gssd.x
index b50f39b33554..bf63ba95f8df 100644
--- a/sys/kgssapi/gssd.x
+++ b/sys/kgssapi/gssd.x
@@ -48,6 +48,21 @@ typedef uint64_t gssd_ctx_id_t;
 typedef uint64_t gssd_cred_id_t;
 typedef uint64_t gssd_name_t;
 
+struct kgss_lucid_desc {
+       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_res {
        uint32_t        major_status;
        uint32_t        minor_status;
@@ -70,6 +85,29 @@ struct init_sec_context_args {
        gss_buffer_desc input_token;
 };
 
+struct init_sec_context_lucid_v1_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;
+       kgss_lucid_desc lucid;
+};
+
+struct init_sec_context_lucid_v1_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;
@@ -89,6 +127,30 @@ struct accept_sec_context_args {
        gss_channel_bindings_t input_chan_bindings;
 };
 
+struct accept_sec_context_lucid_v1_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;
+       kgss_lucid_desc lucid;
+       gss_buffer_desc exported_name;
+       uint32_t        uid;
+       uint32_t        gid;
+       uint32_t        gidlist<>;
+};
+
+struct accept_sec_context_lucid_v1_args {
+       gssd_ctx_id_t   ctx;
+       gssd_cred_id_t  cred;
+       gss_buffer_desc input_token;
+       gss_channel_bindings_t input_chan_bindings;
+};
+
 struct delete_sec_context_res {
        uint32_t        major_status;
        uint32_t        minor_status;
@@ -101,7 +163,8 @@ struct delete_sec_context_args {
 
 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 +292,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 +342,14 @@ program GSSD {
 
                ip_to_dns_res
                GSSD_IP_TO_DNS(ip_to_dns_args) = 14;
+
+               init_sec_context_lucid_v1_res
+               GSSD_INIT_SEC_CONTEXT_LUCID_V1(init_sec_context_lucid_v1_args) 
= 15;
+
+               accept_sec_context_lucid_v1_res
+               
GSSD_ACCEPT_SEC_CONTEXT_LUCID_V1(accept_sec_context_lucid_v1_args) = 16;
+
+               supports_lucid_res
+               GSSD_SUPPORTS_LUCID(void) = 17;
        } = 1;
 } = 0x40677373;
diff --git a/sys/kgssapi/krb5/krb5_mech.c b/sys/kgssapi/krb5/krb5_mech.c
index 0b8fbc90fcd1..59d5b120e4fb 100644
--- a/sys/kgssapi/krb5/krb5_mech.c
+++ b/sys/kgssapi/krb5/krb5_mech.c
@@ -217,6 +217,18 @@ copy_key(struct krb5_keyblock *from, struct krb5_keyblock 
**to)
                *to = NULL;
 }
 
+static void
+copy_lucid_key(gss_buffer_desc *from, uint32_t type, struct krb5_keyblock *to)
+{
+
+       to->kk_type = 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->value, from->length);
+       }
+}
+
 /*
  * Return non-zero if we are initiator.
  */
@@ -401,6 +413,70 @@ krb5_init(gss_ctx_id_t ctx)
        mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF);
 }
 
+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;
+       kgss_lucid_desc *lctx = (kgss_lucid_desc *)context_token;
+       OM_uint32 res;
+
+       kc->kc_more_flags = 0;
+       if (lctx->protocol == 0) {
+               kc->kc_cksumtype = lctx->rfc_sign;
+               kc->kc_keytype = lctx->rfc_seal;
+               copy_lucid_key(&lctx->ctx_key, lctx->ctx_type,
+                   &kc->kc_keyblock);
+       } else if (lctx->protocol == 1) {
+               if (lctx->have_subkey != 0) {
+                       if (lctx->initiate != 0)
+                               copy_lucid_key(&lctx->subkey_key,
+                                   lctx->subkey_type,
+                                   &kc->kc_remote_subkey);
+                       else
+                               copy_lucid_key(&lctx->subkey_key,
+                                   lctx->subkey_type,
+                                   &kc->kc_local_subkey);
+                       kc->kc_cksumtype = lctx->subkey_type;
+                       kc->kc_keytype = lctx->subkey_type;
+                       kc->kc_more_flags |= ACCEPTOR_SUBKEY;
+               } else {
+                       if (lctx->initiate != 0)
+                               copy_lucid_key(&lctx->ctx_key,
+                                   lctx->ctx_type,
+                                   &kc->kc_remote_subkey);
+                       else
+                               copy_lucid_key(&lctx->ctx_key,
+                                   lctx->ctx_type,
+                                   &kc->kc_local_subkey);
+                       kc->kc_cksumtype = lctx->ctx_type;
+                       kc->kc_keytype = lctx->ctx_type;
+               }
+       } else {
+               return (GSS_S_DEFECTIVE_TOKEN);
+       }
+       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_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,
@@ -413,6 +489,10 @@ krb5_import(gss_ctx_id_t ctx,
        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
         */
diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss.c b/sys/rpc/rpcsec_gss/rpcsec_gss.c
index 983dd251f81f..53770d139c61 100644
--- a/sys/rpc/rpcsec_gss/rpcsec_gss.c
+++ b/sys/rpc/rpcsec_gss/rpcsec_gss.c
@@ -746,6 +746,7 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
        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 
*options_ret)
                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,19 +871,34 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t 
*options_ret)
        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);
+               if (my_krb_imp == KRBIMP_MIT)
+                       maj_stat = gss_init_sec_context_lucid_v1(&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;
                
                /*
diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss_int.h 
b/sys/rpc/rpcsec_gss/rpcsec_gss_int.h
index 3d643af8c498..02a7767220de 100644
--- a/sys/rpc/rpcsec_gss/rpcsec_gss_int.h
+++ b/sys/rpc/rpcsec_gss/rpcsec_gss_int.h
@@ -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
 
diff --git a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c 
b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
index 51077c71822c..e047c557c712 100644
--- a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
+++ b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
@@ -925,9 +925,29 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
        OM_uint32               maj_stat = 0, min_stat = 0, ret_flags;
        OM_uint32               cred_lifetime;
        struct svc_rpc_gss_svc_name *sname;
+       gss_buffer_desc         export_name;
+       rpc_gss_ucred_t         *uc = &client->cl_ucred;
+       int                     numgroups;
+       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;
+       }
+
+       if (my_krb_imp == KRBIMP_MIT) {
+               uc->uid = 65534;
+               uc->gid = 65534;
+               uc->gidlist = client->cl_gid_storage;
+               numgroups = NGROUPS;
+       }
+
        /* Deserialize arguments. */
        memset(&recv_tok, 0, sizeof(recv_tok));
        
@@ -949,18 +969,38 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
                        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_lucid_v1(
+                                               &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,
+                                               &export_name,
+                                               &uc->uid,
+                                               &uc->gid,
+                                               &numgroups,
+                                               &uc->gidlist[0]);
+                               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) {
                                        /*
@@ -982,18 +1022,37 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
                        return (FALSE);
                }
        } else {
-               gr->gr_major = gss_accept_sec_context(
-                       &gr->gr_minor,
-                       &client->cl_ctx,
-                       client->cl_sname->sn_cred,
-                       &recv_tok,
-                       GSS_C_NO_CHANNEL_BINDINGS,
-                       &client->cl_cname,
-                       &mech,
-                       &gr->gr_token,
-                       &ret_flags,
-                       &cred_lifetime,
-                       NULL);
+               if (my_krb_imp == KRBIMP_MIT)
+                       gr->gr_major = gss_accept_sec_context_lucid_v1(
+                               &gr->gr_minor,
+                               &client->cl_ctx,
+                               client->cl_sname->sn_cred,
+                               &recv_tok,
+                               GSS_C_NO_CHANNEL_BINDINGS,
+                               &client->cl_cname,
+                               &mech,
+                               &gr->gr_token,
+                               &ret_flags,
+                               &cred_lifetime,
+                               NULL,
+                               &export_name,
+                               &uc->uid,
+                               &uc->gid,
+                               &numgroups,
+                               &uc->gidlist[0]);
+               else
+                       gr->gr_major = gss_accept_sec_context(
+                               &gr->gr_minor,
+                               &client->cl_ctx,
+                               client->cl_sname->sn_cred,
+                               &recv_tok,
+                               GSS_C_NO_CHANNEL_BINDINGS,
+                               &client->cl_cname,
+                               &mech,
+                               &gr->gr_token,
+                               &ret_flags,
+                               &cred_lifetime,
+                               NULL);
        }
        sx_xunlock(&svc_rpc_gss_lock);
        
@@ -1009,8 +1068,12 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
                rpc_gss_log_status("accept_sec_context", client->cl_mech,
                    gr->gr_major, gr->gr_minor);
                client->cl_state = CLIENT_STALE;
+               if (my_krb_imp == KRBIMP_MIT)
+                       uc->gidlen = 0;
                return (TRUE);
        }
+       if (my_krb_imp == KRBIMP_MIT)
+               uc->gidlen = numgroups;
 
        gr->gr_handle.value = &client->cl_id;
        gr->gr_handle.length = sizeof(client->cl_id);
@@ -1022,8 +1085,6 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
        client->cl_done_callback = FALSE;
 
        if (gr->gr_major == GSS_S_COMPLETE) {
-               gss_buffer_desc export_name;
-
                /*
                 * Change client expiration time to be near when the
                 * client creds expire (or 24 hours if we can't figure
@@ -1046,8 +1107,10 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
                 */
                client->cl_rawcred.version = RPCSEC_GSS_VERSION;
                rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism);
-               maj_stat = gss_export_name(&min_stat, client->cl_cname,
-                   &export_name);
+               maj_stat = GSS_S_COMPLETE;
+               if (my_krb_imp != KRBIMP_MIT)
+                       maj_stat = gss_export_name(&min_stat, client->cl_cname,
+                           &export_name);
                if (maj_stat != GSS_S_COMPLETE) {
                        rpc_gss_log_status("gss_export_name", client->cl_mech,
                            maj_stat, min_stat);
@@ -1068,7 +1131,8 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client 
*client,
                 * Use gss_pname_to_uid to map to unix creds. For
                 * kerberos5, this uses krb5_aname_to_localname.
                 */
-               svc_rpc_gss_build_ucred(client, client->cl_cname);
+               if (my_krb_imp != KRBIMP_MIT)
+                       svc_rpc_gss_build_ucred(client, client->cl_cname);
                svc_rpc_gss_set_flavor(client);
                gss_release_name(&min_stat, &client->cl_cname);
 
*** 693 LINES SKIPPED ***

Reply via email to