]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libcli/auth: add infrastructure for netr_ServerAuthenticateKerberos()
authorStefan Metzmacher <metze@samba.org>
Tue, 29 Oct 2024 17:02:19 +0000 (18:02 +0100)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 12 Dec 2024 13:59:29 +0000 (13:59 +0000)
This shows that STRONG_KEY without ARCFOUR means no encryption
for ServerPasswordSet2.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
auth/gensec/schannel.c
libcli/auth/credentials.c
libcli/auth/proto.h
librpc/idl/schannel.idl
selftest/knownfail.d/samba4.rpc.netlogon.netlogon.SetPassword2 [new file with mode: 0644]

index 86527fe46858cc09059f5efb47a6f5ca0348992f..6e88e11990deea0bd742994d5b7fbce1bd3246f2 100644 (file)
@@ -145,6 +145,13 @@ static NTSTATUS netsec_do_seq_num(struct schannel_state *state,
                                  uint32_t checksum_length,
                                  uint8_t seq_num[8])
 {
+       if (state->creds->authenticate_kerberos) {
+               DBG_WARNING("Called with authenticate_kerberos from %s %s\n",
+                           state->creds->account_name,
+                           state->creds->computer_name);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                gnutls_cipher_hd_t cipher_hnd = NULL;
                gnutls_datum_t key = {
@@ -243,6 +250,13 @@ static NTSTATUS netsec_do_seal(struct schannel_state *state,
                               uint8_t *data, uint32_t length,
                               bool forward)
 {
+       if (state->creds->authenticate_kerberos) {
+               DBG_WARNING("Called with authenticate_kerberos from %s %s\n",
+                           state->creds->account_name,
+                           state->creds->computer_name);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                gnutls_cipher_hd_t cipher_hnd = NULL;
                uint8_t sess_kf0[16] = {0};
@@ -423,6 +437,13 @@ static NTSTATUS netsec_do_sign(struct schannel_state *state,
                               uint8_t header[8],
                               uint8_t *checksum)
 {
+       if (state->creds->authenticate_kerberos) {
+               DBG_WARNING("Called with authenticate_kerberos from %s %s\n",
+                           state->creds->account_name,
+                           state->creds->computer_name);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                gnutls_hmac_hd_t hmac_hnd = NULL;
                int rc;
@@ -833,6 +854,16 @@ static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security
                        return NT_STATUS_INVALID_PARAMETER_MIX;
                }
 
+               if (creds->authenticate_kerberos) {
+                       DBG_ERR("attempted schannel connection with "
+                               "authenticate_kerberos from %s %s\n",
+                               creds->account_name,
+                               creds->computer_name);
+                       NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+                       log_stack_trace();
+                       return NT_STATUS_INVALID_PARAMETER_MIX;
+               }
+
                state = netsec_create_state(gensec_security,
                                            creds, true /* initiator */);
                if (state == NULL) {
index 86bb8c338191372dfaab567b71fa60e3de014e6b..8470815b82eb1be0630e026e7d2a54595a2479f6 100644 (file)
@@ -56,6 +56,78 @@ bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
        return true;
 }
 
+static NTSTATUS netlogon_creds_no_step_check(struct netlogon_creds_CredentialState *creds,
+                                            enum dcerpc_AuthType auth_type,
+                                            enum dcerpc_AuthLevel auth_level,
+                                            bool *skip)
+{
+       *skip = false;
+
+       if (creds == NULL) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /*
+        * Only if ServerAuthenticateKerberos() was
+        * used the content of the netr_Authenticator
+        * values are not checked.
+        *
+        * It is independent from the
+        * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH flag.
+        */
+       if (creds->authenticate_kerberos) {
+               if (auth_type != DCERPC_AUTH_TYPE_KRB5) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+               if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+               *skip = true;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS netlogon_creds_no_buffer_crypt(struct netlogon_creds_CredentialState *creds,
+                                              enum dcerpc_AuthType auth_type,
+                                              enum dcerpc_AuthLevel auth_level,
+                                              bool *skip)
+{
+       *skip = false;
+
+       if (creds == NULL) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (creds->authenticate_kerberos) {
+               if (auth_type != DCERPC_AUTH_TYPE_KRB5) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+               if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+       }
+
+       /*
+        * Even if NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH is
+        * negotiated within ServerAuthenticate3()
+        * encryption on application buffers is skipped.
+        *
+        * Also ServerAuthenticateKerberos() without
+        * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH uses
+        * encryption with a random session key.
+        */
+       if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
+               if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
+               *skip = true;
+       }
+
+       return NT_STATUS_OK;
+}
+
 void netlogon_creds_random_challenge(struct netr_Credential *challenge)
 {
        ZERO_STRUCTP(challenge);
@@ -71,6 +143,13 @@ static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState
        NTSTATUS status;
        int rc;
 
+       if (creds->authenticate_kerberos) {
+               /*
+                * The caller should have checked this already...
+                */
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
        if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                memcpy(out->data, in->data, sizeof(out->data));
 
@@ -257,6 +336,17 @@ static NTSTATUS netlogon_creds_step(struct netlogon_creds_CredentialState *creds
        struct netr_Credential time_cred;
        NTSTATUS status;
 
+       if (creds->authenticate_kerberos) {
+               /* This is only called on the client side */
+               generate_nonce_buffer(creds->seed.data,
+                                     ARRAY_SIZE(creds->seed.data));
+               generate_nonce_buffer(creds->client.data,
+                                     ARRAY_SIZE(creds->client.data));
+               generate_nonce_buffer(creds->server.data,
+                                     ARRAY_SIZE(creds->server.data));
+               return NT_STATUS_OK;
+       }
+
        DEBUG(5,("\tseed        %08x:%08x\n",
                 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
 
@@ -529,6 +619,64 @@ netlogon_creds_alloc(TALLOC_CTX *mem_ctx,
        return creds;
 }
 
+struct netlogon_creds_CredentialState *netlogon_creds_kerberos_init(TALLOC_CTX *mem_ctx,
+                                                                   const char *client_account,
+                                                                   const char *client_computer_name,
+                                                                   uint16_t secure_channel_type,
+                                                                   uint32_t client_requested_flags,
+                                                                   const struct dom_sid *client_sid,
+                                                                   uint32_t negotiate_flags)
+{
+       struct netlogon_creds_CredentialState *creds = NULL;
+
+       creds = netlogon_creds_alloc(mem_ctx,
+                                    client_account,
+                                    client_computer_name,
+                                    secure_channel_type,
+                                    client_requested_flags,
+                                    client_sid,
+                                    negotiate_flags);
+       if (creds == NULL) {
+               return NULL;
+       }
+
+       /*
+        * Some Windows versions used
+        * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+        * as a dummy flag in ServerAuthenticate3,
+        * so we should not use
+        * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+        * for any logic decisions.
+        *
+        * So we use a dedicated bool that
+        * is only set if ServerAuthenticateKerberos
+        * was really used. And for that we assert
+        * that NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+        * is set too.
+        */
+       creds->authenticate_kerberos = true;
+
+       /*
+        * This should not be required, but we better
+        * make sure we would not use a zero session key...
+        *
+        * It seems that's what Windows is also doing...
+        * as the values in netr_ServerPasswordGet() are
+        * encrypted in random ways if NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+        * is missing in netr_ServerAuthenticateKerberos().
+        */
+       generate_nonce_buffer(creds->session_key,
+                             ARRAY_SIZE(creds->session_key));
+       generate_nonce_buffer(creds->seed.data,
+                             ARRAY_SIZE(creds->seed.data));
+       generate_nonce_buffer(creds->client.data,
+                             ARRAY_SIZE(creds->client.data));
+       generate_nonce_buffer(creds->server.data,
+                             ARRAY_SIZE(creds->server.data));
+
+       return creds;
+}
+
 /*****************************************************************
 The above functions are common to the client and server interface
 next comes the client specific functions
@@ -666,6 +814,21 @@ NTSTATUS netlogon_creds_client_verify(struct netlogon_creds_CredentialState *cre
                        enum dcerpc_AuthType auth_type,
                        enum dcerpc_AuthLevel auth_level)
 {
+       NTSTATUS status;
+       bool skip_crypto = false;
+
+       status = netlogon_creds_no_step_check(creds,
+                                             auth_type,
+                                             auth_level,
+                                             &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (skip_crypto) {
+               return NT_STATUS_OK;
+       }
+
        if (!received_credentials ||
            !mem_equal_const_time(received_credentials->data, creds->server.data, 8)) {
                DEBUG(2,("credentials check failed\n"));
@@ -827,13 +990,23 @@ NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState
                                 enum dcerpc_AuthLevel auth_level)
 {
        NTSTATUS status;
+       bool skip_crypto = false;
 
        if (!received_authenticator || !return_authenticator) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!creds) {
-               return NT_STATUS_ACCESS_DENIED;
+       status = netlogon_creds_no_step_check(creds,
+                                             auth_type,
+                                             auth_level,
+                                             &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               ZERO_STRUCTP(return_authenticator);
+               return status;
+       }
+       if (skip_crypto) {
+               ZERO_STRUCTP(return_authenticator);
+               return NT_STATUS_OK;
        }
 
        creds->sequence = received_authenticator->timestamp;
@@ -862,6 +1035,7 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
 {
        struct netr_SamBaseInfo *base = NULL;
        NTSTATUS status;
+       bool skip_crypto = false;
 
        if (validation == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -922,12 +1096,27 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+       status = netlogon_creds_no_buffer_crypt(creds,
+                                               auth_type,
+                                               auth_level,
+                                               &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* find and decrypt the session keys, return in parameters above */
-       if (validation_level == 6) {
+       if (skip_crypto || validation_level == 6) {
                /* they aren't encrypted! */
        } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
-               /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
-               if (!all_zero(base->key.key, sizeof(base->key.key))) {
+               /*
+                * Don't crypt an all-zero key, it would give away
+                * the NETLOGON pipe session key
+                *
+                * But for ServerAuthenticateKerberos we don't care
+                * as we use a random key
+                */
+               if (creds->authenticate_kerberos ||
+                   !all_zero(base->key.key, sizeof(base->key.key))) {
                        if (do_encrypt) {
                                status = netlogon_creds_aes_encrypt(
                                        creds,
@@ -944,7 +1133,8 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
                        }
                }
 
-               if (!all_zero(base->LMSessKey.key,
+               if (creds->authenticate_kerberos ||
+                   !all_zero(base->LMSessKey.key,
                              sizeof(base->LMSessKey.key))) {
                        if (do_encrypt) {
                                status = netlogon_creds_aes_encrypt(
@@ -962,8 +1152,15 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
                        }
                }
        } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
-               /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
-               if (!all_zero(base->key.key, sizeof(base->key.key))) {
+               /*
+                * Don't crypt an all-zero key, it would give away
+                * the NETLOGON pipe session key
+                *
+                * But for ServerAuthenticateKerberos we don't care
+                * as we use a random key
+                */
+               if (creds->authenticate_kerberos ||
+                   !all_zero(base->key.key, sizeof(base->key.key))) {
                        status = netlogon_creds_arcfour_crypt(creds,
                                                              base->key.key,
                                                              sizeof(base->key.key));
@@ -972,7 +1169,8 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
                        }
                }
 
-               if (!all_zero(base->LMSessKey.key,
+               if (creds->authenticate_kerberos ||
+                   !all_zero(base->LMSessKey.key,
                              sizeof(base->LMSessKey.key))) {
                        status = netlogon_creds_arcfour_crypt(creds,
                                                              base->LMSessKey.key,
@@ -982,8 +1180,15 @@ static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_C
                        }
                }
        } else {
-               /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
-               if (!all_zero(base->LMSessKey.key,
+               /*
+                * Don't crypt an all-zero key, it would give away
+                * the NETLOGON pipe session key
+                *
+                * But for ServerAuthenticateKerberos we don't care
+                * as we use a random key
+                */
+               if (creds->authenticate_kerberos ||
+                   !all_zero(base->LMSessKey.key,
                              sizeof(base->LMSessKey.key))) {
                        if (do_encrypt) {
                                status = netlogon_creds_des_encrypt_LMKey(creds,
@@ -1037,6 +1242,15 @@ static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_Creden
                                                    bool do_encrypt)
 {
        NTSTATUS status;
+       bool skip_crypto = false;
+
+       status = netlogon_creds_no_buffer_crypt(creds,
+                                               auth_type,
+                                               auth_level,
+                                               &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        if (logon == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -1051,6 +1265,10 @@ static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_Creden
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
+               if (skip_crypto) {
+                       break;
+               }
+
                if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                        uint8_t *h;
 
@@ -1146,6 +1364,10 @@ static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_Creden
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
+               if (skip_crypto) {
+                       break;
+               }
+
                if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                        if (do_encrypt) {
                                status = netlogon_creds_aes_encrypt(
@@ -1168,8 +1390,11 @@ static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_Creden
                        if (!NT_STATUS_IS_OK(status)) {
                                return status;
                        }
-               } else {
-                       /* Using DES to verify kerberos tickets makes no sense */
+               } else if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+                       /*
+                        * Using DES to verify kerberos tickets makes no sense,
+                        * but if the connection is encrypted we don't care...
+                        */
                        return NT_STATUS_INVALID_PARAMETER;
                }
                break;
@@ -1216,6 +1441,21 @@ static NTSTATUS netlogon_creds_crypt_samr_Password(
                enum dcerpc_AuthLevel auth_level,
                bool do_encrypt)
 {
+       NTSTATUS status;
+       bool skip_crypto = false;
+
+       status = netlogon_creds_no_buffer_crypt(creds,
+                                               auth_type,
+                                               auth_level,
+                                               &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (skip_crypto) {
+               return NT_STATUS_OK;
+       }
+
        if (all_zero(pass->hash, ARRAY_SIZE(pass->hash))) {
                return NT_STATUS_OK;
        }
@@ -1263,6 +1503,21 @@ static NTSTATUS netlogon_creds_crypt_samr_CryptPassword(
                enum dcerpc_AuthLevel auth_level,
                bool do_encrypt)
 {
+       NTSTATUS status;
+       bool skip_crypto = false;
+
+       status = netlogon_creds_no_buffer_crypt(creds,
+                                               auth_type,
+                                               auth_level,
+                                               &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (skip_crypto) {
+               return NT_STATUS_OK;
+       }
+
        if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                if (do_encrypt) {
                        return netlogon_creds_aes_encrypt(creds,
@@ -1275,9 +1530,21 @@ static NTSTATUS netlogon_creds_crypt_samr_CryptPassword(
                                                  ARRAY_SIZE(pass->data));
        }
 
-       return netlogon_creds_arcfour_crypt(creds,
-                                           pass->data,
-                                           ARRAY_SIZE(pass->data));
+       if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+               return netlogon_creds_arcfour_crypt(creds,
+                                                   pass->data,
+                                                   ARRAY_SIZE(pass->data));
+       }
+
+       /*
+        * Using DES to verify to encrypt the password makes no sense,
+        * but if the connection is encrypted we don't care...
+        */
+       if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       return NT_STATUS_OK;
 }
 
 NTSTATUS netlogon_creds_decrypt_samr_CryptPassword(struct netlogon_creds_CredentialState *creds,
@@ -1312,6 +1579,21 @@ static NTSTATUS netlogon_creds_crypt_SendToSam(
                enum dcerpc_AuthLevel auth_level,
                bool do_encrypt)
 {
+       NTSTATUS status;
+       bool skip_crypto = false;
+
+       status = netlogon_creds_no_buffer_crypt(creds,
+                                               auth_type,
+                                               auth_level,
+                                               &skip_crypto);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (skip_crypto) {
+               return NT_STATUS_OK;
+       }
+
        if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
                if (do_encrypt) {
                        return netlogon_creds_aes_encrypt(creds,
@@ -1324,9 +1606,21 @@ static NTSTATUS netlogon_creds_crypt_SendToSam(
                                                  opaque_length);
        }
 
-       return netlogon_creds_arcfour_crypt(creds,
-                                           opaque_data,
-                                           opaque_length);
+       if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+               return netlogon_creds_arcfour_crypt(creds,
+                                                   opaque_data,
+                                                   opaque_length);
+       }
+
+       /*
+        * Using DES to verify to encrypt the data makes no sense,
+        * but if the connection is encrypted we don't care...
+        */
+       if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       return NT_STATUS_OK;
 }
 
 NTSTATUS netlogon_creds_decrypt_SendToSam(struct netlogon_creds_CredentialState *creds,
index d396baeebe0699fc430e245702e22bcc1e5c4787..8a9087bb647030506f14ee41bd5f0dc0b58deb2f 100644 (file)
@@ -37,6 +37,14 @@ NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds
 #define netlogon_creds_aes_encrypt __DO_NOT_USE_netlogon_creds_aes_encrypt
 #define netlogon_creds_aes_decrypt __DO_NOT_USE_netlogon_creds_aes_decrypt
 
+struct netlogon_creds_CredentialState *netlogon_creds_kerberos_init(TALLOC_CTX *mem_ctx,
+                                                                   const char *client_account,
+                                                                   const char *client_computer_name,
+                                                                   uint16_t secure_channel_type,
+                                                                   uint32_t client_requested_flags,
+                                                                   const struct dom_sid *client_sid,
+                                                                   uint32_t negotiate_flags);
+
 /*****************************************************************
 The above functions are common to the client and server interface
 next comes the client specific functions
index a891cda69611933230988ca5ce0225b0caf7a0e8..50b5bba39a035cffeeeddd71dcc5a4a6bbb8dd80 100644 (file)
@@ -58,7 +58,22 @@ interface schannel
                NTTIME auth_time;
                [value(0xFFFFFFFF)] uint32 magic3;
                dom_sid28 client_sid;
-               [value(0)] boolean8 reserved1;
+               /*
+                * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH is not
+                * enough to implement the logic
+                * for netr_ServerAuthenticateKerberos()
+                * as NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+                * was also used as dummy flag in
+                * some Windows versions.
+                *
+                * NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH
+                * also indicates no encryption for
+                * application buffers, even if it's
+                * used via netr_ServerAuthenticate3()
+                * and aes, arcfour or des are
+                * otherwise in use.
+                */
+               boolean8 authenticate_kerberos;
                /* here's some padding ... */
                [value(0)] hyper reserved2;
                [value(NULL)] netlogon_creds_CredentialState_extra_info *ex;
diff --git a/selftest/knownfail.d/samba4.rpc.netlogon.netlogon.SetPassword2 b/selftest/knownfail.d/samba4.rpc.netlogon.netlogon.SetPassword2
new file mode 100644 (file)
index 0000000..43211a6
--- /dev/null
@@ -0,0 +1,4 @@
+# The ad_dc_ntvfs allows negotiating des crypto
+# it means ServerPasswordSet2 don't use crypto at all
+# We'll adjust the server in the next commits
+^samba4.rpc.netlogon.*.netlogon.SetPassword2.*.ad_dc_ntvfs