lib/crypto: move gnutls error wrapper to own subsystem
[samba.git] / auth / ntlmssp / ntlmssp_client.c
index b4196157c81c40f97dbcd2eb4fd5c42420c02174..df891f8d93306a10878bf2ce0cf78d106a2dfaae 100644 (file)
@@ -25,7 +25,6 @@ struct auth_session_info;
 
 #include "includes.h"
 #include "auth/ntlmssp/ntlmssp.h"
-#include "../lib/crypto/crypto.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "auth/credentials/credentials.h"
 #include "auth/gensec/gensec.h"
@@ -36,6 +35,13 @@ struct auth_session_info;
 #include "../auth/ntlmssp/ntlmssp_ndr.h"
 #include "../nsswitch/libwbclient/wbclient.h"
 
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
 /*********************************************************************
  Client side NTLMSSP
 *********************************************************************/
@@ -172,19 +178,14 @@ NTSTATUS gensec_ntlmssp_resume_ccache(struct gensec_security *gensec_security,
 
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
                gensec_security->want_features |= GENSEC_FEATURE_SIGN;
-
-               ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
        }
 
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
                gensec_security->want_features |= GENSEC_FEATURE_SEAL;
-
-               ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
-               ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
        }
 
-       ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
        ntlmssp_state->conf_flags = ntlmssp_state->neg_flags;
+       ntlmssp_state->required_flags = 0;
 
        if (DEBUGLEVEL >= 10) {
                struct NEGOTIATE_MESSAGE *negotiate = talloc(
@@ -250,7 +251,8 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
        const NTTIME *server_timestamp = NULL;
        uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, };
        DATA_BLOB mic_blob = data_blob_const(mic_buffer, sizeof(mic_buffer));
-       HMACMD5Context ctx;
+       gnutls_hmac_hd_t hmac_hnd = NULL;
+       int rc;
 
        TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
        if (!mem_ctx) {
@@ -344,6 +346,22 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
                }
        }
 
+       if (DEBUGLEVEL >= 10) {
+               struct CHALLENGE_MESSAGE *challenge =
+                       talloc(ntlmssp_state, struct CHALLENGE_MESSAGE);
+               if (challenge != NULL) {
+                       NTSTATUS status;
+                       challenge->NegotiateFlags = chal_flags;
+                       status = ntlmssp_pull_CHALLENGE_MESSAGE(
+                                       &in, challenge, challenge);
+                       if (NT_STATUS_IS_OK(status)) {
+                               NDR_PRINT_DEBUG(CHALLENGE_MESSAGE,
+                                               challenge);
+                       }
+                       TALLOC_FREE(challenge);
+               }
+       }
+
        if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
                ntlmssp_state->server.is_standalone = true;
        } else {
@@ -704,6 +722,22 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
                return nt_status;
        }
 
+       if (DEBUGLEVEL >= 10) {
+               struct AUTHENTICATE_MESSAGE *authenticate =
+                       talloc(ntlmssp_state, struct AUTHENTICATE_MESSAGE);
+               if (authenticate != NULL) {
+                       NTSTATUS status;
+                       authenticate->NegotiateFlags = ntlmssp_state->neg_flags;
+                       status = ntlmssp_pull_AUTHENTICATE_MESSAGE(
+                               out, authenticate, authenticate);
+                       if (NT_STATUS_IS_OK(status)) {
+                               NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE,
+                                               authenticate);
+                       }
+                       TALLOC_FREE(authenticate);
+               }
+       }
+
        /*
         * We always include the MIC, even without:
         * av_flags->Value.AvFlags |= NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE;
@@ -711,18 +745,45 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
         *
         * This matches a Windows client.
         */
-       hmac_md5_init_limK_to_64(session_key.data,
-                                session_key.length,
-                                &ctx);
-       hmac_md5_update(ntlmssp_state->negotiate_blob.data,
-                       ntlmssp_state->negotiate_blob.length,
-                       &ctx);
-       hmac_md5_update(in.data, in.length, &ctx);
-       hmac_md5_update(out->data, out->length, &ctx);
-       hmac_md5_final(mic_buffer, &ctx);
+       rc = gnutls_hmac_init(&hmac_hnd,
+                             GNUTLS_MAC_MD5,
+                        session_key.data,
+                        MIN(session_key.length, 64));
+       if (rc < 0) {
+               nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
+               goto done;
+       }
+
+       rc = gnutls_hmac(hmac_hnd,
+                        ntlmssp_state->negotiate_blob.data,
+                        ntlmssp_state->negotiate_blob.length);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
+               goto done;
+       }
+       rc = gnutls_hmac(hmac_hnd, in.data, in.length);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
+               goto done;
+       }
+       rc = gnutls_hmac(hmac_hnd, out->data, out->length);
+       if (rc < 0) {
+               gnutls_hmac_deinit(hmac_hnd, NULL);
+               nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
+               goto done;
+       }
+
+       gnutls_hmac_deinit(hmac_hnd, mic_buffer);
+
        memcpy(out->data + NTLMSSP_MIC_OFFSET, mic_buffer, NTLMSSP_MIC_SIZE);
+       ZERO_ARRAY(mic_buffer);
 
+       nt_status = NT_STATUS_OK;
 done:
+       ZERO_ARRAY_LEN(ntlmssp_state->negotiate_blob.data,
+                      ntlmssp_state->negotiate_blob.length);
        data_blob_free(&ntlmssp_state->negotiate_blob);
 
        ntlmssp_state->session_key = session_key;
@@ -746,7 +807,7 @@ done:
        }
 
        talloc_free(mem_ctx);
-       return NT_STATUS_OK;
+       return nt_status;
 }
 
 NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
@@ -779,7 +840,11 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
 
        ntlmssp_state->unicode = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "unicode", true);
 
-       ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true);
+       ntlmssp_state->use_nt_response = \
+               gensec_setting_bool(gensec_security->settings,
+                                   "ntlmssp_client",
+                                   "send_nt_response",
+                                   true);
 
        ntlmssp_state->allow_lm_response = lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx);
 
@@ -789,6 +854,9 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
 
        ntlmssp_state->use_ntlmv2 = lpcfg_client_ntlmv2_auth(gensec_security->settings->lp_ctx);
 
+       ntlmssp_state->force_old_spnego = gensec_setting_bool(gensec_security->settings,
+                                               "ntlmssp_client", "force_old_spnego", false);
+
        ntlmssp_state->expected_state = NTLMSSP_INITIAL;
 
        ntlmssp_state->neg_flags =
@@ -848,8 +916,11 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
                 * Without this, Windows will not create the master key
                 * that it thinks is only used for NTLMSSP signing and
                 * sealing.  (It is actually pulled out and used directly)
+                *
+                * We don't require this here as some servers (e.g. NetAPP)
+                * doesn't support this.
                 */
-               ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
        }
        if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
                ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -861,13 +932,23 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
                         * is requested.
                         */
                        ntlmssp_state->force_wrap_seal = true;
-                       /*
-                        * We want also work against old Samba servers
-                        * which didn't had GENSEC_FEATURE_LDAP_STYLE
-                        * we negotiate SEAL too. We may remove this
-                        * in a few years. As all servers should have
-                        * GENSEC_FEATURE_LDAP_STYLE by then.
-                        */
+               }
+       }
+       if (ntlmssp_state->force_wrap_seal) {
+               bool ret;
+
+               /*
+                * We want also work against old Samba servers
+                * which didn't had GENSEC_FEATURE_LDAP_STYLE
+                * we negotiate SEAL too. We may remove this
+                * in a few years. As all servers should have
+                * GENSEC_FEATURE_LDAP_STYLE by then.
+                */
+               ret = gensec_setting_bool(gensec_security->settings,
+                                         "ntlmssp_client",
+                                         "ldap_style_send_seal",
+                                         true);
+               if (ret) {
                        ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
                }
        }