s3-winbindd: let winbind try to use samlogon validation level 6. (bug #7945)
authorGünther Deschner <gd@samba.org>
Fri, 7 Jan 2011 16:28:29 +0000 (17:28 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 4 Feb 2011 17:11:04 +0000 (18:11 +0100)
The benefit of this that it makes us more robust to secure channel resets
triggered from tools outside the winbind process. Long term we need to have a
shared tdb secure channel store though as well.

Guenther

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User: Stefan Metzmacher <metze@samba.org>
Autobuild-Date: Fri Feb  4 18:11:04 CET 2011 on sn-devel-104

source3/auth/auth_domain.c
source3/auth/auth_netlogond.c
source3/rpc_client/cli_netlogon.c
source3/rpc_client/cli_netlogon.h
source3/winbindd/winbindd.h
source3/winbindd/winbindd_cm.c
source3/winbindd/winbindd_pam.c

index 0f541cd1e72acab536ee6ddff57530c25f448192..05421debbb95e17c872d5056770dc6b2d4a81b25 100644 (file)
@@ -309,6 +309,7 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
                                                      user_info->client.domain_name,       /* domain name */
                                                      user_info->workstation_name,         /* workstation name */
                                                      chal,                                /* 8 byte challenge. */
+                                                     3,                                   /* validation level */
                                                      user_info->password.response.lanman, /* lanman 24 byte response */
                                                      user_info->password.response.nt,     /* nt 24 byte response */
                                                      &info3);                             /* info3 out */
index 889371c7229dc3d6fa94fdafbe22383f500f0565..1e3ccb1189d2120f59d34bfe852040293229ea34 100644 (file)
@@ -88,6 +88,7 @@ static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx,
                user_info->client.domain_name,         /* domain name */
                user_info->workstation_name,           /* workstation name */
                (uchar *)auth_context->challenge.data, /* 8 byte challenge. */
+               3,                                     /* validation level */
                user_info->password.response.lanman,   /* lanman 24 byte response */
                user_info->password.response.nt,       /* nt 24 byte response */
                &info3);                               /* info3 out */
index 914bfd3df698a48d81f7ec92b1176a5c32e64423..f34d794ea445597fae3d512fa5477a27a158336b 100644 (file)
@@ -25,6 +25,8 @@
 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
 #include "rpc_client/cli_netlogon.h"
 #include "rpc_client/init_netlogon.h"
+#include "rpc_client/util_netlogon.h"
+#include "../libcli/security/security.h"
 
 /****************************************************************************
  Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
@@ -298,6 +300,52 @@ NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
        return result;
 }
 
+static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
+                                       uint16_t validation_level,
+                                       union netr_Validation *validation,
+                                       struct netr_SamInfo3 **info3_p)
+{
+       struct netr_SamInfo3 *info3;
+       NTSTATUS status;
+
+       if (validation == NULL) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       switch (validation_level) {
+       case 3:
+               if (validation->sam3 == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               info3 = talloc_move(mem_ctx, &validation->sam3);
+               break;
+       case 6:
+               if (validation->sam6 == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
+               if (info3 == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(info3);
+                       return status;
+               }
+
+               info3->sidcount = validation->sam6->sidcount;
+               info3->sids = talloc_move(info3, &validation->sam6->sids);
+               break;
+       default:
+               return NT_STATUS_BAD_VALIDATION_CLASS;
+       }
+
+       *info3_p = info3;
+
+       return NT_STATUS_OK;
+}
 
 /**
  * Logon domain user with an 'network' SAM logon
@@ -313,13 +361,13 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
                                           const char *domain,
                                           const char *workstation,
                                           const uint8 chal[8],
+                                          uint16_t validation_level,
                                           DATA_BLOB lm_response,
                                           DATA_BLOB nt_response,
                                           struct netr_SamInfo3 **info3)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        NTSTATUS status;
-       int validation_level = 3;
        const char *workstation_name_slash;
        const char *server_name_slash;
        struct netr_Authenticator clnt_creds;
@@ -417,7 +465,10 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
 
        netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
 
-       *info3 = validation.sam3;
+       result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
+       if (!NT_STATUS_IS_OK(result)) {
+               return result;
+       }
 
        return result;
 }
@@ -430,13 +481,13 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
                                              const char *domain,
                                              const char *workstation,
                                              const uint8 chal[8],
+                                             uint16_t validation_level,
                                              DATA_BLOB lm_response,
                                              DATA_BLOB nt_response,
                                              struct netr_SamInfo3 **info3)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        NTSTATUS status;
-       int validation_level = 3;
        const char *workstation_name_slash;
        const char *server_name_slash;
        union netr_LogonLevel *logon = NULL;
@@ -522,7 +573,10 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
 
        netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
 
-       *info3 = validation.sam3;
+       result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
+       if (!NT_STATUS_IS_OK(result)) {
+               return result;
+       }
 
        return result;
 }
index bb38b75b95c3e873fe3e8403d5db691970a8c911..808a4283ce74a9f39b534ccc9f52db8ed2f713c3 100644 (file)
@@ -25,6 +25,7 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
                                           const char *domain,
                                           const char *workstation,
                                           const uint8 chal[8],
+                                          uint16_t validation_level,
                                           DATA_BLOB lm_response,
                                           DATA_BLOB nt_response,
                                           struct netr_SamInfo3 **info3);
@@ -36,6 +37,7 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
                                              const char *domain,
                                              const char *workstation,
                                              const uint8 chal[8],
+                                             uint16_t validation_level,
                                              DATA_BLOB lm_response,
                                              DATA_BLOB nt_response,
                                              struct netr_SamInfo3 **info3);
index 3217acc8ea260be1f42377a461eef25667c395c8..a32c78f4e4d9005b42f36eb92d68722f8a52e145 100644 (file)
@@ -169,6 +169,7 @@ struct winbindd_domain {
                                  * we don't have to try _ex every time. */
 
        bool can_do_ncacn_ip_tcp;
+       bool can_do_validation6;
 
        /* Lookup methods for this domain (LDAP or RPC) */
        struct winbindd_methods *methods;
index c692ffe75c84ebc2c412e632f66f6fd4bbdbf6e5..c53a553af888aa93da61994d87c014ae729f3a6c 100644 (file)
@@ -2086,6 +2086,7 @@ done:
                  domain->name, domain->active_directory ? "" : "NOT "));
 
        domain->can_do_ncacn_ip_tcp = domain->active_directory;
+       domain->can_do_validation6 = domain->active_directory;
 
        TALLOC_FREE(cli);
 
index 760fa3bc6020fabcbaa5d82629a49845b48d9b18..68fa01f6d70c3a610b7c63f276a48fec234e1924 100644 (file)
@@ -1148,6 +1148,8 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
 
        do {
                struct rpc_pipe_client *netlogon_pipe;
+               const struct pipe_auth_data *auth;
+               uint32_t neg_flags = 0;
 
                ZERO_STRUCTP(info3);
                retry = false;
@@ -1159,6 +1161,10 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
                                  nt_errstr(result)));
                        return result;
                }
+               auth = netlogon_pipe->auth;
+               if (netlogon_pipe->dc) {
+                       neg_flags = netlogon_pipe->dc->negotiate_flags;
+               }
 
                /* It is really important to try SamLogonEx here,
                 * because in a clustered environment, we want to use
@@ -1179,8 +1185,35 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
                 * wrapping SamLogon context.
                 *
                 *  -- abartlet 21 April 2008
+                *
+                * It's also important to use NetlogonValidationSamInfo4 (6),
+                * because it relies on the rpc transport encryption
+                * and avoids using the global netlogon schannel
+                * session key to en/decrypt secret information
+                * like the user_session_key for network logons.
+                *
+                * [MS-APDS] 3.1.5.2 NTLM Network Logon
+                * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
+                * NETLOGON_NEG_AUTHENTICATED_RPC set together
+                * are the indication that the server supports
+                * NetlogonValidationSamInfo4 (6). And it must only
+                * be used if "SealSecureChannel" is used.
+                *
+                * -- metze 4 February 2011
                 */
 
+               if (auth == NULL) {
+                       domain->can_do_validation6 = false;
+               } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+                       domain->can_do_validation6 = false;
+               } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+                       domain->can_do_validation6 = false;
+               } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
+                       domain->can_do_validation6 = false;
+               } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+                       domain->can_do_validation6 = false;
+               }
+
                if (domain->can_do_samlogon_ex) {
                        result = rpccli_netlogon_sam_network_logon_ex(
                                        netlogon_pipe,
@@ -1191,6 +1224,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
                                        domainname,     /* target domain */
                                        workstation,    /* workstation */
                                        chal,
+                                       domain->can_do_validation6 ? 6 : 3,
                                        lm_response,
                                        nt_response,
                                        info3);
@@ -1204,22 +1238,43 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
                                        domainname,     /* target domain */
                                        workstation,    /* workstation */
                                        chal,
+                                       domain->can_do_validation6 ? 6 : 3,
                                        lm_response,
                                        nt_response,
                                        info3);
                }
 
-               attempts += 1;
-
                if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
                    && domain->can_do_samlogon_ex) {
                        DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
                                  "retrying with NetSamLogon\n"));
                        domain->can_do_samlogon_ex = false;
+                       /*
+                        * It's likely that the server also does not support
+                        * validation level 6
+                        */
+                       domain->can_do_validation6 = false;
                        retry = true;
                        continue;
                }
 
+               if (domain->can_do_validation6 &&
+                   (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
+                    NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
+                    NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
+                       DEBUG(3,("Got a DC that can not do validation level 6, "
+                                 "retrying with level 3\n"));
+                       domain->can_do_validation6 = false;
+                       retry = true;
+                       continue;
+               }
+
+               /*
+                * we increment this after the "feature negotiation"
+                * for can_do_samlogon_ex and can_do_validation6
+                */
+               attempts += 1;
+
                /* We have to try a second time as cm_connect_netlogon
                   might not yet have noticed that the DC has killed
                   our connection. */