/* * Extract the 'sesssion key' needed by SMB signing and ncacn_np * (for encrypting some passwords). * * This breaks all the abstractions, but what do you expect... */ static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, DATA_BLOB *session_key) { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); return gssapi_get_session_key(mem_ctx, gensec_gssapi_state->gssapi_context, session_key, NULL); }
size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context, const gss_OID mech, uint32_t gss_want_flags, size_t data_size) { TALLOC_CTX *frame = talloc_stackframe(); size_t sig_size = 0; if (gss_want_flags & GSS_C_CONF_FLAG) { OM_uint32 min_stat, maj_stat; bool want_sealing = true; int sealed = 0; gss_iov_buffer_desc iov[2]; if (!(gss_want_flags & GSS_C_DCE_STYLE)) { TALLOC_FREE(frame); return 0; } /* * gss_wrap_iov_length() only needs the type and length */ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; iov[0].buffer.value = NULL; iov[0].buffer.length = 0; iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; iov[1].buffer.value = NULL; iov[1].buffer.length = data_size; maj_stat = gss_wrap_iov_length(&min_stat, gssapi_context, want_sealing, GSS_C_QOP_DEFAULT, &sealed, iov, ARRAY_SIZE(iov)); if (maj_stat) { DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n", gssapi_error_string(frame, maj_stat, min_stat, mech))); TALLOC_FREE(frame); return 0; } sig_size = iov[0].buffer.length; } else if (gss_want_flags & GSS_C_INTEG_FLAG) { NTSTATUS status; uint32_t keytype; status = gssapi_get_session_key(frame, gssapi_context, NULL, &keytype); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return 0; } switch (keytype) { case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_CRC: case ENCTYPE_ARCFOUR_HMAC: case ENCTYPE_ARCFOUR_HMAC_EXP: sig_size = 37; break; default: sig_size = 28; break; } } TALLOC_FREE(frame); return sig_size; }
/* Try to figure out what features we actually got on the connection */ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, uint32_t feature) { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); if (feature & GENSEC_FEATURE_SIGN) { /* If we are going GSSAPI SASL, then we honour the second negotiation */ if (gensec_gssapi_state->sasl && gensec_gssapi_state->sasl_state == STAGE_DONE) { return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) && (gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)); } return gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG; } if (feature & GENSEC_FEATURE_SEAL) { /* If we are going GSSAPI SASL, then we honour the second negotiation */ if (gensec_gssapi_state->sasl && gensec_gssapi_state->sasl_state == STAGE_DONE) { return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) && (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG)); } return gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG; } if (feature & GENSEC_FEATURE_SESSION_KEY) { /* Only for GSSAPI/Krb5 */ if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) { return true; } } if (feature & GENSEC_FEATURE_DCE_STYLE) { return gensec_gssapi_state->gss_got_flags & GSS_C_DCE_STYLE; } if (feature & GENSEC_FEATURE_NEW_SPNEGO) { NTSTATUS status; uint32_t keytype; if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) { return false; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "force_new_spnego", false)) { return true; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "disable_new_spnego", false)) { return false; } status = gssapi_get_session_key(gensec_gssapi_state, gensec_gssapi_state->gssapi_context, 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 true; } /* We can always do async (rather than strict request/reply) packets. */ if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { return true; } if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { return true; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { return true; } return false; } return false; }