s4-librpc: Fix NETLOGON credential chain with Windows 2008.
authorAndreas Schneider <asn@samba.org>
Mon, 12 Dec 2011 18:28:49 +0000 (19:28 +0100)
committerAndreas Schneider <asn@samba.org>
Wed, 14 Dec 2011 12:41:28 +0000 (13:41 +0100)
Windows Server 2008 returns NT_STATUS_DOWNGRADE_DETECTED if you call
netrServerAuthenticate2 during a domain join without setting the strong
keys flag (128bit crypto).

Only for NT4 we need to do a downgrade to the returned negotiate flags.

See also 0970369ca0cb9ae465cff40e5c75739824daf1d0.

librpc/rpc/rpc_common.h
source4/librpc/rpc/dcerpc_schannel.c
source4/winbind/wb_init_domain.c

index 44c3cfd39b58a652e6c3bbe51fdf89281f6352c3..a28835fa6347f216896eb04802f53530ac28d039 100644 (file)
@@ -107,6 +107,9 @@ struct dcerpc_binding {
 /* specify binding interface */
 #define        DCERPC_LOCALADDRESS            (1<<22)
 
 /* specify binding interface */
 #define        DCERPC_LOCALADDRESS            (1<<22)
 
+/* handle upgrades or downgrades automatically */
+#define DCERPC_SCHANNEL_AUTO           (1<<23)
+
 /* The following definitions come from ../librpc/rpc/dcerpc_error.c  */
 
 const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
 /* The following definitions come from ../librpc/rpc/dcerpc_error.c  */
 
 const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
index fc56eccf7c534f05d8aee69f5dfecc435aeecafa..9501e3e047ef0f1aff3b260a68c8e42ad29ab1eb 100644 (file)
@@ -36,9 +36,11 @@ struct schannel_key_state {
        struct dcerpc_pipe *pipe;
        struct dcerpc_pipe *pipe2;
        struct dcerpc_binding *binding;
        struct dcerpc_pipe *pipe;
        struct dcerpc_pipe *pipe2;
        struct dcerpc_binding *binding;
+       bool dcerpc_schannel_auto;
        struct cli_credentials *credentials;
        struct netlogon_creds_CredentialState *creds;
        struct cli_credentials *credentials;
        struct netlogon_creds_CredentialState *creds;
-       uint32_t negotiate_flags;
+       uint32_t local_negotiate_flags;
+       uint32_t remote_negotiate_flags;
        struct netr_Credential credentials1;
        struct netr_Credential credentials2;
        struct netr_Credential credentials3;
        struct netr_Credential credentials1;
        struct netr_Credential credentials2;
        struct netr_Credential credentials3;
@@ -176,16 +178,17 @@ static void continue_srv_challenge(struct tevent_req *subreq)
        s->a.in.secure_channel_type =
                cli_credentials_get_secure_channel_type(s->credentials);
        s->a.in.computer_name    = cli_credentials_get_workstation(s->credentials);
        s->a.in.secure_channel_type =
                cli_credentials_get_secure_channel_type(s->credentials);
        s->a.in.computer_name    = cli_credentials_get_workstation(s->credentials);
-       s->a.in.negotiate_flags  = &s->negotiate_flags;
+       s->a.in.negotiate_flags  = &s->local_negotiate_flags;
        s->a.in.credentials      = &s->credentials3;
        s->a.in.credentials      = &s->credentials3;
-       s->a.out.negotiate_flags = &s->negotiate_flags;
+       s->a.out.negotiate_flags = &s->remote_negotiate_flags;
        s->a.out.return_credentials     = &s->credentials3;
 
        s->creds = netlogon_creds_client_init(s, 
                                              s->a.in.account_name, 
                                              s->a.in.computer_name,
                                              &s->credentials1, &s->credentials2,
        s->a.out.return_credentials     = &s->credentials3;
 
        s->creds = netlogon_creds_client_init(s, 
                                              s->a.in.account_name, 
                                              s->a.in.computer_name,
                                              &s->credentials1, &s->credentials2,
-                                             s->mach_pwd, &s->credentials3, s->negotiate_flags);
+                                             s->mach_pwd, &s->credentials3,
+                                             s->local_negotiate_flags);
        if (composite_nomem(s->creds, c)) {
                return;
        }
        if (composite_nomem(s->creds, c)) {
                return;
        }
@@ -218,6 +221,30 @@ static void continue_srv_auth2(struct tevent_req *subreq)
        TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
+       /*
+        * Strong keys could be unsupported (NT4) or disables. So retry with the
+        * flags returned by the server. - asn
+        */
+       if (NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED) &&
+           s->dcerpc_schannel_auto &&
+           (s->local_negotiate_flags & NETLOGON_NEG_STRONG_KEYS)) {
+               DEBUG(3, ("Server doesn't support strong keys, "
+                         "downgrade and retry!\n"));
+               s->local_negotiate_flags = s->remote_negotiate_flags;
+
+               generate_random_buffer(s->credentials1.data,
+                                      sizeof(s->credentials1.data));
+
+               subreq = dcerpc_netr_ServerReqChallenge_r_send(s,
+                                                              c->event_ctx,
+                                                              s->pipe2->binding_handle,
+                                                              &s->r);
+               if (composite_nomem(subreq, c)) return;
+
+               tevent_req_set_callback(subreq, continue_srv_challenge, c);
+               return;
+       }
+
        /* verify credentials */
        if (!netlogon_creds_client_check(s->creds, s->a.out.return_credentials)) {
                composite_error(c, NT_STATUS_UNSUCCESSFUL);
        /* verify credentials */
        if (!netlogon_creds_client_check(s->creds, s->a.out.return_credentials)) {
                composite_error(c, NT_STATUS_UNSUCCESSFUL);
@@ -256,15 +283,19 @@ struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
        /* store parameters in the state structure */
        s->pipe        = p;
        s->credentials = credentials;
        /* store parameters in the state structure */
        s->pipe        = p;
        s->credentials = credentials;
+       s->local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
 
        /* allocate credentials */
        /* type of authentication depends on schannel type */
        if (schannel_type == SEC_CHAN_RODC) {
 
        /* allocate credentials */
        /* type of authentication depends on schannel type */
        if (schannel_type == SEC_CHAN_RODC) {
-               s->negotiate_flags = NETLOGON_NEG_AUTH2_RODC_FLAGS;
-       } else if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
-               s->negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
-       } else {
-               s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
+               s->local_negotiate_flags = NETLOGON_NEG_AUTH2_RODC_FLAGS;
+       }
+       if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
+               s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+       }
+       if (s->pipe->conn->flags & DCERPC_SCHANNEL_AUTO) {
+               s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+               s->dcerpc_schannel_auto = true;
        }
 
        /* allocate binding structure */
        }
 
        /* allocate binding structure */
index 9847afbba052ca4545822253ee4cc932e17e01bf..9d807d87764d98bcbb50c3b2342bcccf5ef56e5f 100644 (file)
@@ -154,7 +154,7 @@ struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
             (lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) &&
            (dom_sid_equal(state->domain->info->sid,
                           state->service->primary_sid))) {
             (lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) &&
            (dom_sid_equal(state->domain->info->sid,
                           state->service->primary_sid))) {
-               state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_128;
+               state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO;
 
                /* For debugging, it can be a real pain if all the traffic is encrypted */
                if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) {
 
                /* For debugging, it can be a real pain if all the traffic is encrypted */
                if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) {
@@ -236,7 +236,7 @@ static bool retry_with_schannel(struct init_domain_state *state,
                 * NTLMSSP binds */
 
                /* Try again with schannel */
                 * NTLMSSP binds */
 
                /* Try again with schannel */
-               binding->flags |= DCERPC_SCHANNEL;
+               binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO;
 
                /* Try again, likewise on the same IPC$ share, 
                   secured with SCHANNEL */
 
                /* Try again, likewise on the same IPC$ share, 
                   secured with SCHANNEL */