aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2025-08-07 21:02:32 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2025-08-07 21:02:32 +0000
commite3ac01e18eb3db571572d819d6b40966d00f80fe (patch)
tree08c69789fe13754ba4cd02d3c34db00947d3e528 /sys
parent42cacae4eb186258c1f65cf5d0f9821d5a396049 (diff)
Diffstat (limited to 'sys')
-rw-r--r--sys/kgssapi/gss_accept_sec_context.c145
-rw-r--r--sys/kgssapi/gss_impl.c8
-rw-r--r--sys/kgssapi/gss_init_sec_context.c145
-rw-r--r--sys/kgssapi/gssapi.h42
-rw-r--r--sys/kgssapi/gssapi_impl.h2
-rw-r--r--sys/kgssapi/gssd.x79
-rw-r--r--sys/kgssapi/krb5/krb5_mech.c80
-rw-r--r--sys/rpc/rpcsec_gss/rpcsec_gss.c50
-rw-r--r--sys/rpc/rpcsec_gss/rpcsec_gss_int.h6
-rw-r--r--sys/rpc/rpcsec_gss/svc_rpcsec_gss.c122
10 files changed, 632 insertions, 47 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.
*/
@@ -402,6 +414,70 @@ krb5_init(gss_ctx_id_t ctx)
}
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,
const gss_buffer_t context_token)
@@ -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);