diff options
-rw-r--r-- | source3/librpc/crypto/gse.c | 136 |
1 files changed, 69 insertions, 67 deletions
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c index ec37073014..9f06dc3d8c 100644 --- a/source3/librpc/crypto/gse.c +++ b/source3/librpc/crypto/gse.c @@ -28,6 +28,7 @@ #include "auth/gensec/gensec.h" #include "auth/credentials/credentials.h" #include "../librpc/gen_ndr/dcerpc.h" +#include "lib/util/asn1.h" #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV) @@ -77,8 +78,6 @@ struct gse_context { gss_cred_id_t delegated_cred_handle; - gss_krb5_lucid_context_v1_t *lucid; - /* gensec_gse only */ krb5_context k5ctx; krb5_ccache ccache; @@ -149,11 +148,6 @@ static int gse_context_destructor(void *ptr) &gse_ctx->delegated_cred_handle); } - if (gse_ctx->lucid) { - gss_krb5_free_lucid_sec_context(&gss_min, gse_ctx->lucid); - gse_ctx->lucid = NULL; - } - /* MIT and Heimdal differ as to if you can call * gss_release_oid() on this OID, generated by * gss_{accept,init}_sec_context(). However, as long as the @@ -628,42 +622,13 @@ done: return errstr; } -static NTSTATUS gse_init_lucid(struct gse_context *gse_ctx) -{ - OM_uint32 maj_stat, min_stat; - void *ptr = NULL; - - if (gse_ctx->lucid) { - return NT_STATUS_OK; - } - - maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, - &gse_ctx->gssapi_context, - 1, &ptr); - if (maj_stat != GSS_S_COMPLETE) { - DEBUG(0,("gse_init_lucid: %s\n", - gse_errstr(talloc_tos(), maj_stat, min_stat))); - return NT_STATUS_INTERNAL_ERROR; - } - gse_ctx->lucid = (gss_krb5_lucid_context_v1_t *)ptr; - - if (gse_ctx->lucid->version != 1) { - DEBUG(0,("gse_init_lucid: lucid version[%d] != 1\n", - gse_ctx->lucid->version)); - gss_krb5_free_lucid_sec_context(&min_stat, gse_ctx->lucid); - gse_ctx->lucid = NULL; - return NT_STATUS_INTERNAL_ERROR; - } - - return NT_STATUS_OK; -} - -static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx, - struct gse_context *gse_ctx) +static NTSTATUS gse_get_session_key(TALLOC_CTX *mem_ctx, + struct gse_context *gse_ctx, + DATA_BLOB *session_key, + uint32_t *keytype) { OM_uint32 gss_min, gss_maj; gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; - DATA_BLOB ret; gss_maj = gss_inquire_sec_context_by_oid( &gss_min, gse_ctx->gssapi_context, @@ -671,7 +636,7 @@ static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx, if (gss_maj) { DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n", gse_errstr(talloc_tos(), gss_maj, gss_min))); - return data_blob_null; + return NT_STATUS_NO_USER_SESSION_KEY; } if ((set == GSS_C_NO_BUFFER_SET) || @@ -686,26 +651,58 @@ static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx, &subkey); if (gss_maj != 0) { DEBUG(1, ("NO session key for this mech\n")); - return data_blob_null; + return NT_STATUS_NO_USER_SESSION_KEY; + } + if (session_key) { + *session_key = data_blob_talloc(mem_ctx, + KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey)); + } + if (keytype) { + *keytype = KRB5_KEY_TYPE(subkey); } - ret = data_blob_talloc(mem_ctx, - KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey)); krb5_free_keyblock(NULL /* should be krb5_context */, subkey); - return ret; + return NT_STATUS_OK; #else DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown " "OID for data in results:\n")); dump_data(1, (uint8_t *)set->elements[1].value, set->elements[1].length); - return data_blob_null; + return NT_STATUS_NO_USER_SESSION_KEY; #endif } - ret = data_blob_talloc(mem_ctx, set->elements[0].value, - set->elements[0].length); + if (session_key) { + *session_key = data_blob_talloc(mem_ctx, set->elements[0].value, + set->elements[0].length); + } + if (keytype) { + char *oid; + char *p, *q = NULL; + if (!ber_read_OID_String(talloc_tos(), + data_blob_const(set->elements[0].value, + set->elements[0].length), &oid)) { + TALLOC_FREE(oid); + gss_maj = gss_release_buffer_set(&gss_min, &set); + return NT_STATUS_INVALID_PARAMETER; + } + p = strrchr(oid, '.'); + if (!p) { + TALLOC_FREE(oid); + gss_maj = gss_release_buffer_set(&gss_min, &set); + return NT_STATUS_INVALID_PARAMETER; + } else { + p++; + *keytype = strtoul(p, &q, 10); + if (q == NULL || *q != '\0') { + return NT_STATUS_INVALID_PARAMETER; + } + } + TALLOC_FREE(oid); + } + gss_maj = gss_release_buffer_set(&gss_min, &set); - return ret; + return NT_STATUS_OK; } static size_t gse_get_signature_length(struct gse_context *gse_ctx, @@ -1178,21 +1175,33 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security, } if (feature & GENSEC_FEATURE_NEW_SPNEGO) { NTSTATUS status; + uint32_t keytype; if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) { return false; } - status = gse_init_lucid(gse_ctx); - if (!NT_STATUS_IS_OK(status)) { - return false; - } - - if (gse_ctx->lucid->protocol == 1) { - return true; + status = gse_get_session_key(talloc_tos(), + gse_ctx, NULL, &keytype); + /* + * We should do a proper sig on the mechListMic unless + * we know we have to be backwards compatible with + * earlier windows versions. + * + * Negotiating a non-krb5 + * mech for example should be regarded as having + * NEW_SPNEGO + */ + if (NT_STATUS_IS_OK(status)) { + switch (keytype) { + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_ARCFOUR_HMAC: + case ENCTYPE_DES3_CBC_SHA1: + return false; + } } - - return false; + return true; } /* We can always do async (rather than strict request/reply) packets. */ if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { @@ -1209,20 +1218,13 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security, */ static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, - DATA_BLOB *session_key_out) + DATA_BLOB *session_key) { struct gse_context *gse_ctx = talloc_get_type_abort(gensec_security->private_data, struct gse_context); - DATA_BLOB session_key = gse_get_session_key(mem_ctx, gse_ctx); - if (session_key.data == NULL) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - - *session_key_out = session_key; - - return NT_STATUS_OK; + return gse_get_session_key(mem_ctx, gse_ctx, session_key, NULL); } /* Get some basic (and authorization) information about the user on |