winbind: Keep "force_reauth" in invalidate_cm_connection
[kai/samba-autobuild/.git] / source3 / winbindd / winbindd_cm.c
index d024d842128c9a0ce4dd5bbfe3e7310930930a7c..bf5a2b4d7b1c06b85c2af8728145451be66952e8 100644 (file)
@@ -199,6 +199,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
        pid_t parent_pid = getpid();
        char *lfile = NULL;
        NTSTATUS status;
+       bool ok;
 
        if (domain->dc_probe_pid != (pid_t)-1) {
                /*
@@ -223,10 +224,10 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
 
        if (domain->dc_probe_pid != (pid_t)0) {
                /* Parent */
-               messaging_register(winbind_messaging_context(), NULL,
+               messaging_register(server_messaging_context(), NULL,
                                   MSG_WINBIND_TRY_TO_GO_ONLINE,
                                   msg_try_to_go_online);
-               messaging_register(winbind_messaging_context(), NULL,
+               messaging_register(server_messaging_context(), NULL,
                                   MSG_WINBIND_FAILED_TO_GO_ONLINE,
                                   msg_failed_to_go_online);
                return True;
@@ -247,7 +248,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
                          nt_errstr(status)));
-               messaging_send_buf(winbind_messaging_context(),
+               messaging_send_buf(server_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_FAILED_TO_GO_ONLINE,
                                   (const uint8_t *)domain->name,
@@ -256,10 +257,12 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
        }
        SAFE_FREE(lfile);
 
+       setproctitle("dc-connect child");
+
        mem_ctx = talloc_init("fork_child_dc_connect");
        if (!mem_ctx) {
                DEBUG(0,("talloc_init failed.\n"));
-               messaging_send_buf(winbind_messaging_context(),
+               messaging_send_buf(server_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_FAILED_TO_GO_ONLINE,
                                   (const uint8_t *)domain->name,
@@ -267,9 +270,11 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
                _exit(1);
        }
 
-       if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0)) || (num_dcs == 0)) {
+       ok = get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0);
+       TALLOC_FREE(mem_ctx);
+       if (!ok || (num_dcs == 0)) {
                /* Still offline ? Can't find DC's. */
-               messaging_send_buf(winbind_messaging_context(),
+               messaging_send_buf(server_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_FAILED_TO_GO_ONLINE,
                                   (const uint8_t *)domain->name,
@@ -280,7 +285,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
        /* We got a DC. Send a message to our parent to get it to
           try and do the same. */
 
-       messaging_send_buf(winbind_messaging_context(),
+       messaging_send_buf(server_messaging_context(),
                           pid_to_procid(parent_pid),
                           MSG_WINBIND_TRY_TO_GO_ONLINE,
                           (const uint8_t *)domain->name,
@@ -428,7 +433,7 @@ void set_domain_offline(struct winbindd_domain *domain)
 
        calc_new_online_timeout_check(domain);
 
-       domain->check_online_event = tevent_add_timer(winbind_event_context(),
+       domain->check_online_event = tevent_add_timer(server_event_context(),
                                                NULL,
                                                timeval_current_ofs(domain->check_online_timeout,0),
                                                check_domain_online_handler,
@@ -444,7 +449,7 @@ void set_domain_offline(struct winbindd_domain *domain)
 
        /* Send a message to the parent that the domain is offline. */
        if (parent_pid > 1 && !domain->internal) {
-               messaging_send_buf(winbind_messaging_context(),
+               messaging_send_buf(server_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_DOMAIN_OFFLINE,
                                   (uint8_t *)domain->name,
@@ -458,7 +463,7 @@ void set_domain_offline(struct winbindd_domain *domain)
                struct winbindd_child *idmap = idmap_child();
 
                if ( idmap->pid != 0 ) {
-                       messaging_send_buf(winbind_messaging_context(),
+                       messaging_send_buf(server_messaging_context(),
                                           pid_to_procid(idmap->pid), 
                                           MSG_WINBIND_OFFLINE, 
                                           (const uint8_t *)domain->name,
@@ -521,16 +526,16 @@ static void set_domain_online(struct winbindd_domain *domain)
        TALLOC_FREE(domain->check_online_event);
 
        /* Ensure we ignore any pending child messages. */
-       messaging_deregister(winbind_messaging_context(),
+       messaging_deregister(server_messaging_context(),
                             MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
-       messaging_deregister(winbind_messaging_context(),
+       messaging_deregister(server_messaging_context(),
                             MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
 
        domain->online = True;
 
        /* Send a message to the parent that the domain is online. */
        if (parent_pid > 1 && !domain->internal) {
-               messaging_send_buf(winbind_messaging_context(),
+               messaging_send_buf(server_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_DOMAIN_ONLINE,
                                   (uint8_t *)domain->name,
@@ -544,7 +549,7 @@ static void set_domain_online(struct winbindd_domain *domain)
                struct winbindd_child *idmap = idmap_child();
 
                if ( idmap->pid != 0 ) {
-                       messaging_send_buf(winbind_messaging_context(),
+                       messaging_send_buf(server_messaging_context(),
                                           pid_to_procid(idmap->pid), 
                                           MSG_WINBIND_ONLINE, 
                                           (const uint8_t *)domain->name,
@@ -604,7 +609,7 @@ void set_domain_online_request(struct winbindd_domain *domain)
 
        TALLOC_FREE(domain->check_online_event);
 
-       domain->check_online_event = tevent_add_timer(winbind_event_context(),
+       domain->check_online_event = tevent_add_timer(server_event_context(),
                                                     NULL,
                                                     tev,
                                                     check_domain_online_handler,
@@ -994,6 +999,31 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
 
        enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
 
+       if (IS_AD_DC) {
+               if (domain->secure_channel_type == SEC_CHAN_NULL) {
+                       /*
+                        * Make sure we don't even try to
+                        * connect to a foreign domain
+                        * without a direct outbound trust.
+                        */
+                       return NT_STATUS_NO_TRUST_LSA_SECRET;
+               }
+
+               /*
+                * As AD DC we only use netlogon and lsa
+                * using schannel over an anonymous transport
+                * (ncacn_ip_tcp or ncacn_np).
+                *
+                * Currently we always establish the SMB connection,
+                * even if we don't use it, because we later use ncacn_ip_tcp.
+                *
+                * As we won't use the SMB connection there's no
+                * need to try kerberos. And NT4 domains expect
+                * an anonymous IPC$ connection anyway.
+                */
+               smb_sign_client_connections = SMB_SIGNING_OFF;
+       }
+
        if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) {
                /*
                 * If we are connecting to our own AD domain, require
@@ -1006,8 +1036,7 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                 * AD domain in our forest
                 * then require smb signing to disrupt MITM attacks
                 */
-               } else if ((lp_security() == SEC_ADS ||
-                           lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)
+               } else if ((lp_security() == SEC_ADS)
                           && domain->active_directory
                           && (domain->domain_trust_attribs
                               & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
@@ -1030,8 +1059,7 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                goto done;
        }
 
-       *cli = cli_state_create(NULL, sockfd,
-                               controller, domain->alt_name,
+       *cli = cli_state_create(NULL, sockfd, controller,
                                smb_sign_client_connections, flags);
        if (*cli == NULL) {
                close(sockfd);
@@ -1067,6 +1095,22 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                try_ipc_auth = true;
        }
 
+       if (IS_AD_DC) {
+               /*
+                * As AD DC we only use netlogon and lsa
+                * using schannel over an anonymous transport
+                * (ncacn_ip_tcp or ncacn_np).
+                *
+                * Currently we always establish the SMB connection,
+                * even if we don't use it, because we later use ncacn_ip_tcp.
+                *
+                * As we won't use the SMB connection there's no
+                * need to try kerberos. And NT4 domains expect
+                * an anonymous IPC$ connection anyway.
+                */
+               try_ipc_auth = false;
+       }
+
        if (try_ipc_auth) {
                result = get_trust_credentials(domain, talloc_tos(), false, &creds);
                if (!NT_STATUS_IS_OK(result)) {
@@ -1370,6 +1414,7 @@ static bool dcip_check_name(TALLOC_CTX *mem_ctx,
                ads = ads_init(domain->alt_name, domain->name, addr);
                ads->auth.flags |= ADS_AUTH_NO_BIND;
                ads->config.flags |= request_flags;
+               ads->server.no_fallback = true;
 
                ads_status = ads_connect(ads);
                if (ADS_ERR_OK(ads_status)) {
@@ -1420,7 +1465,7 @@ static bool dcip_check_name(TALLOC_CTX *mem_ctx,
        }
 #endif
 
-       status = nbt_getdc(winbind_messaging_context(), 10, pss, domain->name,
+       status = nbt_getdc(server_messaging_context(), 10, pss, domain->name,
                           &domain->sid, nt_version, mem_ctx, &nt_version,
                           &dc_name, NULL);
        if (NT_STATUS_IS_OK(status)) {
@@ -1789,7 +1834,7 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
                                                 session_info,
                                                 NULL,
                                                 NULL,
-                                                winbind_messaging_context(),
+                                                server_messaging_context(),
                                                 &cli);
        } else {
                status = rpc_pipe_open_internal(mem_ctx,
@@ -1797,7 +1842,7 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
                                                session_info,
                                                NULL,
                                                NULL,
-                                               winbind_messaging_context(),
+                                               server_messaging_context(),
                                                &cli);
        }
        if (!NT_STATUS_IS_OK(status)) {
@@ -1814,13 +1859,14 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
-                                  struct winbindd_cm_conn *new_conn)
+                                  struct winbindd_cm_conn *new_conn,
+                                  bool need_rw_dc)
 {
        TALLOC_CTX *mem_ctx;
        NTSTATUS result;
        char *saf_servername;
        int retries;
-       uint32_t request_flags = 0;
+       uint32_t request_flags = need_rw_dc ? DS_WRITABLE_REQUIRED : 0;
 
        if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
                set_domain_offline(domain);
@@ -2035,9 +2081,7 @@ void invalidate_cm_connection(struct winbindd_domain *domain)
        }
 
        conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
-       conn->netlogon_force_reauth = false;
-       conn->netlogon_flags = 0;
-       TALLOC_FREE(conn->netlogon_creds);
+       TALLOC_FREE(conn->netlogon_creds_ctx);
 
        if (conn->cli) {
                cli_shutdown(conn->cli);
@@ -2127,7 +2171,7 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool
                set_dc_type_and_flags_trustinfo(domain);
        }
 
-       result = cm_open_connection(domain, &domain->conn);
+       result = cm_open_connection(domain, &domain->conn, need_rw_dc);
 
        if (NT_STATUS_IS_OK(result) && !domain->initialized) {
                set_dc_type_and_flags(domain);
@@ -2185,6 +2229,15 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
        TALLOC_CTX *mem_ctx = NULL;
        struct dcerpc_binding_handle *b;
 
+       if (IS_DC) {
+               /*
+                * On a DC we loaded all trusts
+                * from configuration and never learn
+                * new domains.
+                */
+               return true;
+       }
+
        DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
 
        /* Our primary domain doesn't need to worry about trust flags.
@@ -2579,6 +2632,15 @@ done:
 
 static void set_dc_type_and_flags( struct winbindd_domain *domain )
 {
+       if (IS_DC) {
+               /*
+                * On a DC we loaded all trusts
+                * from configuration and never learn
+                * new domains.
+                */
+               return;
+       }
+
        /* we always have to contact our primary domain */
 
        if ( domain->primary || domain->internal) {
@@ -2616,28 +2678,16 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
                return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
        }
 
-       if (domain->conn.netlogon_creds != NULL) {
-               if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
-                       return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
-               }
-               *ppdc = domain->conn.netlogon_creds;
+       if (domain->conn.netlogon_creds_ctx != NULL) {
+               *ppdc = domain->conn.netlogon_creds_ctx;
                return NT_STATUS_OK;
        }
 
-       result = cm_connect_netlogon(domain, &netlogon_pipe);
+       result = cm_connect_netlogon_secure(domain, &netlogon_pipe, ppdc);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
        }
 
-       if (domain->conn.netlogon_creds == NULL) {
-               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
-       }
-
-       if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
-               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
-       }
-
-       *ppdc = domain->conn.netlogon_creds;
        return NT_STATUS_OK;
 }
 
@@ -2657,6 +2707,20 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                }
        }
 
+       if (IS_AD_DC) {
+               /*
+                * In theory we should not use SAMR within
+                * winbindd at all, but that's a larger task to
+                * remove this and avoid breaking existing
+                * setups.
+                *
+                * At least as AD DC we have the restriction
+                * to avoid SAMR against trusted domains,
+                * as there're no existing setups.
+                */
+               return NT_STATUS_REQUEST_NOT_ACCEPTED;
+       }
+
 retry:
        status = init_dc_connection_rpc(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2763,16 +2827,9 @@ retry:
                goto anonymous;
        }
        TALLOC_FREE(creds);
-       result = get_trust_credentials(domain, talloc_tos(), true, &creds);
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(10, ("cm_connect_sam: No user available for "
-                          "domain %s (error %s), trying anon\n", domain->name,
-                          nt_errstr(result)));
-               goto anonymous;
-       }
-       status = cli_rpc_pipe_open_schannel_with_creds
-               (conn->cli, &ndr_table_samr, NCACN_NP,
-                creds, p_creds, &conn->samr_pipe);
+       status = cli_rpc_pipe_open_schannel_with_creds(
+               conn->cli, &ndr_table_samr, NCACN_NP, p_creds,
+               &conn->samr_pipe);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
            && !retry) {
@@ -2913,7 +2970,6 @@ static NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 {
        struct winbindd_cm_conn *conn;
        struct netlogon_creds_cli_context *p_creds = NULL;
-       struct cli_credentials *creds = NULL;
        NTSTATUS status;
 
        DEBUG(10,("cm_connect_lsa_tcp\n"));
@@ -2925,10 +2981,12 @@ static NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
        conn = &domain->conn;
 
-       if (conn->lsa_pipe_tcp &&
+       /*
+        * rpccli_is_connected handles more error cases
+        */
+       if (rpccli_is_connected(conn->lsa_pipe_tcp) &&
            conn->lsa_pipe_tcp->transport->transport == NCACN_IP_TCP &&
-           conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY &&
-           rpccli_is_connected(conn->lsa_pipe_tcp)) {
+           conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
                goto done;
        }
 
@@ -2939,15 +2997,9 @@ static NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
                goto done;
        }
 
-       status = get_trust_credentials(domain, talloc_tos(), true, &creds);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
        status = cli_rpc_pipe_open_schannel_with_creds(conn->cli,
                                                       &ndr_table_lsarpc,
                                                       NCACN_IP_TCP,
-                                                      creds,
                                                       p_creds,
                                                       &conn->lsa_pipe_tcp);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2989,6 +3041,13 @@ retry:
 
        TALLOC_FREE(conn->lsa_pipe);
 
+       if (IS_AD_DC) {
+               /*
+                * Make sure we only use schannel as AD DC.
+                */
+               goto schannel;
+       }
+
        result = get_trust_credentials(domain, talloc_tos(), false, &creds);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(10, ("cm_connect_lsa: No user available for "
@@ -3067,16 +3126,9 @@ retry:
        }
 
        TALLOC_FREE(creds);
-       result = get_trust_credentials(domain, talloc_tos(), true, &creds);
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(10, ("cm_connect_lsa: No user available for "
-                          "domain %s (error %s), trying anon\n", domain->name,
-                          nt_errstr(result)));
-               goto anonymous;
-       }
-       result = cli_rpc_pipe_open_schannel_with_creds
-               (conn->cli, &ndr_table_lsarpc, NCACN_NP,
-                creds, p_creds, &conn->lsa_pipe);
+       result = cli_rpc_pipe_open_schannel_with_creds(
+               conn->cli, &ndr_table_lsarpc, NCACN_NP, p_creds,
+               &conn->lsa_pipe);
 
        if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
            && !retry) {
@@ -3109,6 +3161,13 @@ retry:
                goto done;
        }
 
+       if (IS_AD_DC) {
+               /*
+                * Make sure we only use schannel as AD DC.
+                */
+               goto done;
+       }
+
        DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
                  "anonymous\n"));
 
@@ -3116,6 +3175,13 @@ retry:
 
  anonymous:
 
+       if (IS_AD_DC) {
+               /*
+                * Make sure we only use schannel as AD DC.
+                */
+               goto done;
+       }
+
        if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
                result = NT_STATUS_DOWNGRADE_DETECTED;
                DEBUG(1, ("Unwilling to make LSA connection to domain %s "
@@ -3202,23 +3268,32 @@ NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
 }
 
 /****************************************************************************
- Open the netlogon pipe to this DC. Use schannel if specified in client conf.
- session key stored in conn->netlogon_pipe->dc->sess_key.
+ Open the netlogon pipe to this DC.
 ****************************************************************************/
 
 static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
                                              enum dcerpc_transport_t transport,
                                              struct rpc_pipe_client **cli)
 {
-       struct messaging_context *msg_ctx = winbind_messaging_context();
+       struct messaging_context *msg_ctx = server_messaging_context();
        struct winbindd_cm_conn *conn;
        NTSTATUS result;
        enum netr_SchannelType sec_chan_type;
-       struct netlogon_creds_CredentialState *netlogon_creds = NULL;
        struct cli_credentials *creds = NULL;
 
        *cli = NULL;
 
+       if (IS_AD_DC) {
+               if (domain->secure_channel_type == SEC_CHAN_NULL) {
+                       /*
+                        * Make sure we don't even try to
+                        * connect to a foreign domain
+                        * without a direct outbound trust.
+                        */
+                       return NT_STATUS_NO_TRUST_LSA_SECRET;
+               }
+       }
+
        result = init_dc_connection_rpc(domain, domain->rodc);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
@@ -3232,8 +3307,7 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
        }
 
        TALLOC_FREE(conn->netlogon_pipe);
-       conn->netlogon_flags = 0;
-       TALLOC_FREE(conn->netlogon_creds);
+       TALLOC_FREE(conn->netlogon_creds_ctx);
 
        result = get_trust_credentials(domain, talloc_tos(), true, &creds);
        if (!NT_STATUS_IS_OK(result)) {
@@ -3243,16 +3317,18 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
        }
 
        if (cli_credentials_is_anonymous(creds)) {
-               DEBUG(1, ("get_trust_credential only gave anonymous for %s, unable to make get NETLOGON credentials\n",
-                         domain->name));
+               DBG_WARNING("get_trust_credential only gave anonymous for %s, "
+                           "unable to make get NETLOGON credentials\n",
+                           domain->name);
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
        sec_chan_type = cli_credentials_get_secure_channel_type(creds);
        if (sec_chan_type == SEC_CHAN_NULL) {
                if (transport == NCACN_IP_TCP) {
-                       DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
-                                  " deny NCACN_IP_TCP and let the caller fallback to NCACN_NP.\n",
+                       DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL "
+                                  "for %s, deny NCACN_IP_TCP and let the "
+                                  "caller fallback to NCACN_NP.\n",
                                   domain->name);
                        return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
                }
@@ -3261,10 +3337,11 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
                           "fallback to noauth on NCACN_NP.\n",
                           domain->name);
 
-               result = cli_rpc_pipe_open_noauth_transport(conn->cli,
-                                                           transport,
-                                                           &ndr_table_netlogon,
-                                                           &conn->netlogon_pipe);
+               result = cli_rpc_pipe_open_noauth_transport(
+                       conn->cli,
+                       transport,
+                       &ndr_table_netlogon,
+                       &conn->netlogon_pipe);
                if (!NT_STATUS_IS_OK(result)) {
                        invalidate_cm_connection(domain);
                        return result;
@@ -3274,11 +3351,11 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
                return NT_STATUS_OK;
        }
 
-       result = rpccli_create_netlogon_creds_with_creds(creds,
-                                                        domain->dcname,
-                                                        msg_ctx,
-                                                        domain,
-                                                        &conn->netlogon_creds);
+       result = rpccli_create_netlogon_creds_ctx(creds,
+                                                 domain->dcname,
+                                                 msg_ctx,
+                                                 domain,
+                                                 &conn->netlogon_creds_ctx);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("rpccli_create_netlogon_creds failed for %s, "
                          "unable to create NETLOGON credentials: %s\n",
@@ -3286,69 +3363,14 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
                return result;
        }
 
-       result = rpccli_setup_netlogon_creds_with_creds(conn->cli, transport,
-                                               conn->netlogon_creds,
-                                               conn->netlogon_force_reauth,
-                                               creds);
-       conn->netlogon_force_reauth = false;
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
-                         "unable to setup NETLOGON credentials: %s\n",
-                         domain->name, nt_errstr(result)));
-               return result;
-       }
-
-       result = netlogon_creds_cli_get(conn->netlogon_creds,
-                                       talloc_tos(),
-                                       &netlogon_creds);
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(1, ("netlogon_creds_cli_get failed for %s, "
-                         "unable to get NETLOGON credentials: %s\n",
-                         domain->name, nt_errstr(result)));
-               return result;
-       }
-       conn->netlogon_flags = netlogon_creds->negotiate_flags;
-       TALLOC_FREE(netlogon_creds);
-
-       if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
-               if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
-                       result = NT_STATUS_DOWNGRADE_DETECTED;
-                       DEBUG(1, ("Unwilling to make connection to domain %s"
-                                 "without connection level security, "
-                                 "must set 'winbind sealed pipes = false' and "
-                                 "'require strong key = false' to proceed: %s\n",
-                                 domain->name, nt_errstr(result)));
-                       invalidate_cm_connection(domain);
-                       return result;
-               }
-               result = cli_rpc_pipe_open_noauth_transport(conn->cli,
-                                                           transport,
-                                                           &ndr_table_netlogon,
-                                                           &conn->netlogon_pipe);
-               if (!NT_STATUS_IS_OK(result)) {
-                       invalidate_cm_connection(domain);
-                       return result;
-               }
-
-               *cli = conn->netlogon_pipe;
-               return NT_STATUS_OK;
-       }
-
-       /* Using the credentials from the first pipe, open a signed and sealed
-          second netlogon pipe. The session key is stored in the schannel
-          part of the new pipe auth struct.
-       */
-
-       result = cli_rpc_pipe_open_schannel_with_creds(
-               conn->cli, &ndr_table_netlogon, transport,
-               creds,
-               conn->netlogon_creds,
+       result = rpccli_connect_netlogon(
+               conn->cli, transport,
+               conn->netlogon_creds_ctx, conn->netlogon_force_reauth, creds,
                &conn->netlogon_pipe);
+       conn->netlogon_force_reauth = false;
        if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
-                         "was %s\n", nt_errstr(result)));
-
-               invalidate_cm_connection(domain);
+               DBG_DEBUG("rpccli_connect_netlogon failed: %s\n",
+                         nt_errstr(result));
                return result;
        }
 
@@ -3405,6 +3427,29 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        return status;
 }
 
+NTSTATUS cm_connect_netlogon_secure(struct winbindd_domain *domain,
+                                   struct rpc_pipe_client **cli,
+                                   struct netlogon_creds_cli_context **ppdc)
+{
+       NTSTATUS status;
+
+       if (domain->secure_channel_type == SEC_CHAN_NULL) {
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       status = cm_connect_netlogon(domain, cli);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (domain->conn.netlogon_creds_ctx == NULL) {
+               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+       }
+
+       *ppdc = domain->conn.netlogon_creds_ctx;
+       return NT_STATUS_OK;
+}
+
 void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
                            void *private_data,
                            uint32_t msg_type,
@@ -3464,3 +3509,19 @@ void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
        }
        TALLOC_FREE(freeit);
 }
+
+void winbind_msg_disconnect_dc(struct messaging_context *msg_ctx,
+                              void *private_data,
+                              uint32_t msg_type,
+                              struct server_id server_id,
+                              DATA_BLOB *data)
+{
+       struct winbindd_domain *domain;
+
+       for (domain = domain_list(); domain; domain = domain->next) {
+               if (domain->internal) {
+                       continue;
+               }
+               invalidate_cm_connection(domain);
+       }
+}