diff --git a/sys/kgssapi/gss_accept_sec_context.c.sav b/sys/kgssapi/gss_accept_sec_context.c --- a/sys/kgssapi/gss_accept_sec_context.c.sav +++ 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,147 @@ * 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_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); + } + + xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res); + + return (res.major_status); +} diff --git a/sys/kgssapi/gss_impl.c.sav b/sys/kgssapi/gss_impl.c --- a/sys/kgssapi/gss_impl.c.sav +++ b/sys/kgssapi/gss_impl.c @@ -192,12 +192,18 @@ } 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)) { diff --git a/sys/kgssapi/gss_init_sec_context.c.sav b/sys/kgssapi/gss_init_sec_context.c --- a/sys/kgssapi/gss_init_sec_context.c.sav +++ 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,168 @@ * 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_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) { + 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); + } + + xdr_free((xdrproc_t) xdr_init_sec_context_plus_res, &res); + + return (res.major_status); +} diff --git a/sys/kgssapi/gssapi.h.sav b/sys/kgssapi/gssapi.h --- a/sys/kgssapi/gssapi.h.sav +++ b/sys/kgssapi/gssapi.h @@ -25,6 +25,27 @@ * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ #ifndef _KGSSAPI_GSSAPI_H_ #define _KGSSAPI_GSSAPI_H_ @@ -75,6 +96,54 @@ typedef OM_uint32 gss_qop_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. @@ -406,6 +475,23 @@ ); 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 +508,11 @@ 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 +528,21 @@ 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 */ diff --git a/sys/kgssapi/gssapi_impl.h.sav b/sys/kgssapi/gssapi_impl.h --- a/sys/kgssapi/gssapi_impl.h.sav +++ b/sys/kgssapi/gssapi_impl.h @@ -78,5 +78,5 @@ 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.sav b/sys/kgssapi/gssd.x --- a/sys/kgssapi/gssd.x.sav +++ b/sys/kgssapi/gssd.x @@ -70,6 +70,40 @@ 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 { + 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 { KGSS_HEIMDAL_0_6, - KGSS_HEIMDAL_1_1 + KGSS_HEIMDAL_1_1, + MIT_V1 }; struct export_sec_context_res { @@ -229,6 +295,11 @@ char ip_addr; }; +struct supports_lucid_res { + uint32_t major_status; + uint32_t vers; +}; + program GSSD { version GSSDVERS { void GSSD_NULL(void) = 0; @@ -274,5 +345,14 @@ 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; diff --git a/sys/kgssapi/krb5/krb5_mech.c.sav b/sys/kgssapi/krb5/krb5_mech.c --- a/sys/kgssapi/krb5/krb5_mech.c.sav +++ b/sys/kgssapi/krb5/krb5_mech.c @@ -217,6 +217,18 @@ *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); + } +} + /* * Return non-zero if we are initiator. */ @@ -402,6 +414,67 @@ } 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; + + 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) { + 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); + } + 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) @@ -412,6 +485,10 @@ 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 diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss.c.sav b/sys/rpc/rpcsec_gss/rpcsec_gss.c --- a/sys/rpc/rpcsec_gss/rpcsec_gss.c.sav +++ b/sys/rpc/rpcsec_gss/rpcsec_gss.c @@ -746,6 +746,7 @@ 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()"); @@ -850,6 +851,14 @@ options_ret->major_status = maj_stat; options_ret->minor_status = min_stat; 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. */ @@ -862,19 +871,34 @@ 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_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; /* diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss_int.h.sav b/sys/rpc/rpcsec_gss/rpcsec_gss_int.h --- a/sys/rpc/rpcsec_gss/rpcsec_gss_int.h.sav +++ b/sys/rpc/rpcsec_gss/rpcsec_gss_int.h @@ -73,6 +73,12 @@ /* 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.sav b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c --- a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c.sav +++ b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c @@ -925,9 +925,19 @@ 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 @@ 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) { /*