idl: Merge NETR_TRUST and LSA_TRUST definitions into one set only in lsa.idl
[samba.git] / source3 / winbindd / winbindd_cm.c
index 0f3e418b3219ad1f7d99145c3201ea1221923d44..1e639b7cfa67a5aacaa8ce708e30fb564e4a954a 100644 (file)
@@ -79,6 +79,9 @@
 #include "auth/gensec/gensec.h"
 #include "../libcli/smb/smbXcli_base.h"
 #include "lib/param/loadparm.h"
+#include "libcli/auth/netlogon_creds_cli.h"
+#include "auth.h"
+#include "rpc_server/rpc_ncacn_np.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -91,7 +94,7 @@ struct dc_name_ip {
 extern struct winbindd_methods reconnect_methods;
 extern bool override_logfile;
 
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc);
 static void set_dc_type_and_flags( struct winbindd_domain *domain );
 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                    struct dc_name_ip **dcs, int *num_dcs);
@@ -173,7 +176,7 @@ static void msg_try_to_go_online(struct messaging_context *msg,
                           the offline handler if false. Bypasses online
                           check so always does network calls. */
 
-                       init_dc_connection_network(domain);
+                       init_dc_connection_network(domain, true);
                        break;
                }
        }
@@ -833,6 +836,10 @@ static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
                        return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;                       
                }
 
+               if (our_domain->alt_name == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
                if (asprintf(machine_krb5_principal, "%s$@%s",
                             account_name, our_domain->alt_name) == -1)
                {
@@ -904,8 +911,8 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
        cli_set_timeout(*cli, 10000); /* 10 seconds */
 
        result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
-                                lp_cli_minprotocol(),
-                                lp_cli_maxprotocol());
+                                lp_client_min_protocol(),
+                                lp_client_max_protocol());
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
@@ -1199,7 +1206,7 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
        /* For active directory servers, try to get the ldap server name.
           None of these failures should be considered critical for now */
 
-       if (lp_security() == SEC_ADS) {
+       if ((lp_security() == SEC_ADS) && (domain->alt_name != NULL)) {
                ADS_STRUCT *ads;
                ADS_STATUS ads_status;
                char addr[INET6_ADDRSTRLEN];
@@ -1232,8 +1239,7 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
                                        create_local_private_krb5_conf_for_domain(domain->alt_name,
                                                                        domain->name,
                                                                        sitename,
-                                                                       pss,
-                                                                       *name);
+                                                                       pss);
 
                                        TALLOC_FREE(sitename);
                                } else {
@@ -1241,8 +1247,7 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
                                        create_local_private_krb5_conf_for_domain(domain->alt_name,
                                                                        domain->name,
                                                                        NULL,
-                                                                       pss,
-                                                                       *name);
+                                                                       pss);
                                }
                                winbindd_set_locator_kdc_envs(domain);
 
@@ -1327,7 +1332,7 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                return True;
        }
 
-       if (sec == SEC_ADS) {
+       if ((sec == SEC_ADS) && (domain->alt_name != NULL)) {
                char *sitename = NULL;
 
                /* We need to make sure we know the local site before
@@ -1565,7 +1570,8 @@ bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx,
                                    const char *domain_name,
                                    char **p_dc_name, char **p_dc_ip)
 {
-       char *key, *value, *p;
+       char *key, *p;
+       char *value = NULL;
        bool ret = false;
        char *dc_name = NULL;
        char *dc_ip = NULL;
@@ -1607,6 +1613,47 @@ done:
        return ret;
 }
 
+NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
+                              const struct ndr_interface_table *table,
+                              struct rpc_pipe_client **ret_pipe)
+{
+       struct rpc_pipe_client *cli = NULL;
+       const struct auth_session_info *session_info;
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+
+       session_info = get_session_info_system();
+       SMB_ASSERT(session_info != NULL);
+
+       /* create a connection to the specified pipe */
+       if (lp_parm_bool(-1, "winbindd", "use external pipes", false)) {
+               status = rpc_pipe_open_interface(mem_ctx,
+                                                table,
+                                                session_info,
+                                                NULL,
+                                                winbind_messaging_context(),
+                                                &cli);
+       } else {
+               status = rpc_pipe_open_internal(mem_ctx,
+                                               &table->syntax_id,
+                                               session_info,
+                                               NULL,
+                                               winbind_messaging_context(),
+                                               &cli);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("open_internal_pipe: Could not connect to %s pipe: %s\n",
+                         table->name, nt_errstr(status)));
+               return status;
+       }
+
+       if (ret_pipe) {
+               *ret_pipe = cli;
+       }
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                                   struct winbindd_cm_conn *new_conn)
 {
@@ -1723,6 +1770,7 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
        }
 
        if (NT_STATUS_IS_OK(result)) {
+               bool seal_pipes = true;
 
                winbindd_set_locator_kdc_envs(domain);
 
@@ -1742,6 +1790,17 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                 */
                store_current_dc_in_gencache(domain->name, domain->dcname,
                                             new_conn->cli);
+
+               seal_pipes = lp_winbind_sealed_pipes();
+               seal_pipes = lp_parm_bool(-1, "winbind sealed pipes",
+                                         domain->name,
+                                         seal_pipes);
+
+               if (seal_pipes) {
+                       new_conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+               } else {
+                       new_conn->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+               }
        } else {
                /* Ensure we setup the retry handler. */
                set_domain_offline(domain);
@@ -1814,6 +1873,11 @@ void invalidate_cm_connection(struct winbindd_cm_conn *conn)
                }
        }
 
+       conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+       conn->netlogon_force_reauth = false;
+       conn->netlogon_flags = 0;
+       TALLOC_FREE(conn->netlogon_creds);
+
        if (conn->cli) {
                cli_shutdown(conn->cli);
        }
@@ -1871,17 +1935,21 @@ static bool connection_ok(struct winbindd_domain *domain)
 /* Initialize a new connection up to the RPC BIND.
    Bypass online status check so always does network calls. */
 
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc)
 {
        NTSTATUS result;
+       bool skip_connection = domain->internal;
+       if (need_rw_dc && domain->rodc) {
+               skip_connection = false;
+       }
 
        /* Internal connections never use the network. */
-       if (domain->internal) {
-               domain->initialized = True;
-               return NT_STATUS_OK;
+       if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       if (connection_ok(domain)) {
+       /* Still ask the internal LSA and SAMR server about the local domain */
+       if (skip_connection || connection_ok(domain)) {
                if (!domain->initialized) {
                        set_dc_type_and_flags(domain);
                }
@@ -1899,9 +1967,9 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
        return result;
 }
 
-NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc)
 {
-       if (domain->internal) {
+       if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
@@ -1910,14 +1978,14 @@ NTSTATUS init_dc_connection(struct winbindd_domain *domain)
                return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
        }
 
-       return init_dc_connection_network(domain);
+       return init_dc_connection_network(domain, need_rw_dc);
 }
 
-static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain, bool need_rw_dc)
 {
        NTSTATUS status;
 
-       status = init_dc_connection(domain);
+       status = init_dc_connection(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1956,38 +2024,46 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
                return False;           
        }
 
+       mem_ctx = talloc_stackframe();
        our_domain = find_our_domain();
-
-       if ( !connection_ok(our_domain) ) {
-               DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));           
-               return False;
+       if (our_domain->internal) {
+               result = init_dc_connection(our_domain, false);
+               if (!NT_STATUS_IS_OK(result)) {
+                       DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+                                "Not able to make a connection to our domain: %s\n",
+                                 nt_errstr(result)));
+                       TALLOC_FREE(mem_ctx);
+                       return false;
+               }
        }
 
        /* This won't work unless our domain is AD */
-
        if ( !our_domain->active_directory ) {
+               TALLOC_FREE(mem_ctx);
                return False;
        }
 
-       /* Use DsEnumerateDomainTrusts to get us the trust direction
-          and type */
-
-       result = cm_connect_netlogon(our_domain, &cli);
+       if (our_domain->internal) {
+               result = wb_open_internal_pipe(mem_ctx, &ndr_table_netlogon, &cli);
+       } else if (!connection_ok(our_domain)) {
+               DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+                        "No connection to our domain!\n"));
+               TALLOC_FREE(mem_ctx);
+               return False;
+       } else {
+               result = cm_connect_netlogon(our_domain, &cli);
+       }
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
                          "a connection to %s for PIPE_NETLOGON (%s)\n", 
                          domain->name, nt_errstr(result)));
+               TALLOC_FREE(mem_ctx);
                return False;
        }
-
        b = cli->binding_handle;
 
-       if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
-               DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
-               return False;
-       }       
-
+       /* Use DsEnumerateDomainTrusts to get us the trust direction and type. */
        result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
                                                      cli->desthost,
                                                      flags,
@@ -1997,14 +2073,14 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
                DEBUG(0,("set_dc_type_and_flags_trustinfo: "
                        "failed to query trusted domain list: %s\n",
                        nt_errstr(result)));
-               talloc_destroy(mem_ctx);
+               TALLOC_FREE(mem_ctx);
                return false;
        }
        if (!W_ERROR_IS_OK(werr)) {
                DEBUG(0,("set_dc_type_and_flags_trustinfo: "
                        "failed to query trusted domain list: %s\n",
                        win_errstr(werr)));
-               talloc_destroy(mem_ctx);
+               TALLOC_FREE(mem_ctx);
                return false;
        }
 
@@ -2016,7 +2092,7 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
                        domain->domain_type           = trusts.array[i].trust_type;
                        domain->domain_trust_attribs  = trusts.array[i].trust_attributes;
 
-                       if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
+                       if ( domain->domain_type == LSA_TRUST_TYPE_UPLEVEL )
                                domain->active_directory = True;
 
                        /* This flag is only set if the domain is *our* 
@@ -2034,7 +2110,6 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
                                 domain->active_directory ? "" : "NOT "));
 
                        domain->can_do_ncacn_ip_tcp = domain->active_directory;
-                       domain->can_do_validation6 = domain->active_directory;
 
                        domain->initialized = True;
 
@@ -2042,7 +2117,7 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
                }               
        }
 
-       talloc_destroy( mem_ctx );
+       TALLOC_FREE(mem_ctx);
 
        return domain->initialized;     
 }
@@ -2065,7 +2140,7 @@ static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
        union dssetup_DsRoleInfo info;
        union lsa_PolicyInformation *lsa_info = NULL;
 
-       if (!connection_ok(domain)) {
+       if (!domain->internal && !connection_ok(domain)) {
                return;
        }
 
@@ -2078,9 +2153,15 @@ static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
 
        DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
 
-       status = cli_rpc_pipe_open_noauth(domain->conn.cli,
-                                         &ndr_table_dssetup,
-                                         &cli);
+       if (domain->internal) {
+               status = wb_open_internal_pipe(mem_ctx,
+                                              &ndr_table_dssetup,
+                                              &cli);
+       } else {
+               status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+                                                 &ndr_table_dssetup,
+                                                 &cli);
+       }
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
@@ -2129,9 +2210,14 @@ static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
        }
 
 no_dssetup:
-       status = cli_rpc_pipe_open_noauth(domain->conn.cli,
-                                         &ndr_table_lsarpc, &cli);
-
+       if (domain->internal) {
+               status = wb_open_internal_pipe(mem_ctx,
+                                              &ndr_table_lsarpc,
+                                              &cli);
+       } else {
+               status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+                                                 &ndr_table_lsarpc, &cli);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
                          "PI_LSARPC on domain %s: (%s)\n",
@@ -2235,7 +2321,6 @@ 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);
 
@@ -2252,9 +2337,9 @@ static void set_dc_type_and_flags( struct winbindd_domain *domain )
 {
        /* we always have to contact our primary domain */
 
-       if ( domain->primary ) {
+       if ( domain->primary || domain->internal) {
                DEBUG(10,("set_dc_type_and_flags: setting up flags for "
-                         "primary domain\n"));
+                         "primary or internal domain\n"));
                set_dc_type_and_flags_connect( domain );
                return;         
        }
@@ -2276,13 +2361,23 @@ static void set_dc_type_and_flags( struct winbindd_domain *domain )
 ***********************************************************************/
 
 static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
-                                  struct netlogon_creds_CredentialState **ppdc)
+                                  struct netlogon_creds_cli_context **ppdc)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        struct rpc_pipe_client *netlogon_pipe;
 
-       if (lp_client_schannel() == False) {
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       *ppdc = NULL;
+
+       if ((!IS_DC) && (!domain->primary)) {
+               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;
+               return NT_STATUS_OK;
        }
 
        result = cm_connect_netlogon(domain, &netlogon_pipe);
@@ -2290,32 +2385,36 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
                return result;
        }
 
-       /* Return a pointer to the struct netlogon_creds_CredentialState from the
-          netlogon pipe. */
+       if (domain->conn.netlogon_creds == NULL) {
+               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+       }
 
-       if (!domain->conn.netlogon_pipe->dc) {
-               return NT_STATUS_INTERNAL_ERROR; /* This shouldn't happen. */
+       if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
        }
 
-       *ppdc = domain->conn.netlogon_pipe->dc;
+       *ppdc = domain->conn.netlogon_creds;
        return NT_STATUS_OK;
 }
 
 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+                       bool need_rw_dc,
                        struct rpc_pipe_client **cli, struct policy_handle *sam_handle)
 {
        struct winbindd_cm_conn *conn;
        NTSTATUS status, result;
-       struct netlogon_creds_CredentialState *p_creds;
+       struct netlogon_creds_cli_context *p_creds;
        char *machine_password = NULL;
        char *machine_account = NULL;
        const char *domain_name = NULL;
 
        if (sid_check_is_our_sam(&domain->sid)) {
-               return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+               if (domain->rodc == false || need_rw_dc == false) {
+                       return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+               }
        }
 
-       status = init_dc_connection_rpc(domain);
+       status = init_dc_connection_rpc(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2364,7 +2463,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                          &ndr_table_samr,
                                          NCACN_NP,
                                          GENSEC_OID_NTLMSSP,
-                                         DCERPC_AUTH_LEVEL_PRIVACY,
+                                         conn->auth_level,
                                          smbXcli_conn_remote_name(conn->cli->conn),
                                          domain_name,
                                          machine_account,
@@ -2417,8 +2516,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        }
        status = cli_rpc_pipe_open_schannel_with_key
                (conn->cli, &ndr_table_samr, NCACN_NP,
-                DCERPC_AUTH_LEVEL_PRIVACY,
-                domain->name, &p_creds, &conn->samr_pipe);
+                domain->name, p_creds, &conn->samr_pipe);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
@@ -2521,12 +2619,12 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
                            struct rpc_pipe_client **cli)
 {
        struct winbindd_cm_conn *conn;
-       struct netlogon_creds_CredentialState *creds;
+       struct netlogon_creds_cli_context *creds;
        NTSTATUS status;
 
        DEBUG(10,("cm_connect_lsa_tcp\n"));
 
-       status = init_dc_connection_rpc(domain);
+       status = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2535,7 +2633,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
        if (conn->lsa_pipe_tcp &&
            conn->lsa_pipe_tcp->transport->transport == NCACN_IP_TCP &&
-           conn->lsa_pipe_tcp->auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY &&
+           conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY &&
            rpccli_is_connected(conn->lsa_pipe_tcp)) {
                goto done;
        }
@@ -2550,9 +2648,8 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
        status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
                                                     &ndr_table_lsarpc,
                                                     NCACN_IP_TCP,
-                                                    DCERPC_AUTH_LEVEL_PRIVACY,
                                                     domain->name,
-                                                    &creds,
+                                                    creds,
                                                     &conn->lsa_pipe_tcp);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
@@ -2576,9 +2673,9 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
 {
        struct winbindd_cm_conn *conn;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       struct netlogon_creds_CredentialState *p_creds;
+       struct netlogon_creds_cli_context *p_creds;
 
-       result = init_dc_connection_rpc(domain);
+       result = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(result))
                return result;
 
@@ -2603,7 +2700,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        result = cli_rpc_pipe_open_spnego
                (conn->cli, &ndr_table_lsarpc, NCACN_NP,
                 GENSEC_OID_NTLMSSP,
-                DCERPC_AUTH_LEVEL_PRIVACY,
+                conn->auth_level,
                 smbXcli_conn_remote_name(conn->cli->conn),
                 conn->cli->domain, conn->cli->user_name, conn->cli->password,
                 &conn->lsa_pipe);
@@ -2648,8 +2745,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        }
        result = cli_rpc_pipe_open_schannel_with_key
                (conn->cli, &ndr_table_lsarpc, NCACN_NP,
-                DCERPC_AUTH_LEVEL_PRIVACY,
-                domain->name, &p_creds, &conn->lsa_pipe);
+                domain->name, p_creds, &conn->lsa_pipe);
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
@@ -2678,7 +2774,6 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                          &ndr_table_lsarpc,
                                          &conn->lsa_pipe);
        if (!NT_STATUS_IS_OK(result)) {
-               result = NT_STATUS_PIPE_NOT_AVAILABLE;
                goto done;
        }
 
@@ -2740,18 +2835,20 @@ NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                             struct rpc_pipe_client **cli)
 {
+       struct messaging_context *msg_ctx = winbind_messaging_context();
        struct winbindd_cm_conn *conn;
        NTSTATUS result;
-
-       uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
-       uint8_t  mach_pwd[16];
        enum netr_SchannelType sec_chan_type;
+       const char *_account_name;
        const char *account_name;
-       struct rpc_pipe_client *netlogon_pipe = NULL;
+       struct samr_Password current_nt_hash;
+       struct samr_Password *previous_nt_hash = NULL;
+       struct netlogon_creds_CredentialState *creds = NULL;
+       bool ok;
 
        *cli = NULL;
 
-       result = init_dc_connection_rpc(domain);
+       result = init_dc_connection_rpc(domain, true);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
        }
@@ -2764,64 +2861,80 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        }
 
        TALLOC_FREE(conn->netlogon_pipe);
-
-       result = cli_rpc_pipe_open_noauth(conn->cli,
-                                         &ndr_table_netlogon,
-                                         &netlogon_pipe);
-       if (!NT_STATUS_IS_OK(result)) {
-               return result;
-       }
+       conn->netlogon_flags = 0;
+       TALLOC_FREE(conn->netlogon_creds);
 
        if ((!IS_DC) && (!domain->primary)) {
-               /* Clear the schannel request bit and drop down */
-               neg_flags &= ~NETLOGON_NEG_SCHANNEL;            
                goto no_schannel;
        }
 
-       if (lp_client_schannel() != False) {
-               neg_flags |= NETLOGON_NEG_SCHANNEL;
+       ok = get_trust_pw_hash(domain->name,
+                              current_nt_hash.hash,
+                              &_account_name,
+                              &sec_chan_type);
+       if (!ok) {
+               DEBUG(1, ("get_trust_pw_hash failed for %s, "
+                         "unable to get NETLOGON credentials\n",
+                         domain->name));
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
-                              &sec_chan_type))
-       {
-               TALLOC_FREE(netlogon_pipe);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name);
+       if (account_name == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       result = rpccli_netlogon_setup_creds(
-                netlogon_pipe,
-                domain->dcname, /* server name. */
-                domain->name,   /* domain name */
-                lp_netbios_name(), /* client name */
-                account_name,   /* machine account */
-                mach_pwd,       /* machine password */
-                sec_chan_type,  /* from get_trust_pw */
-                &neg_flags);
+       result = rpccli_create_netlogon_creds(domain->dcname,
+                                             domain->name,
+                                             account_name,
+                                             sec_chan_type,
+                                             msg_ctx,
+                                             domain,
+                                             &conn->netlogon_creds);
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(1, ("rpccli_create_netlogon_creds failed for %s, "
+                         "unable to create NETLOGON credentials: %s\n",
+                         domain->name, nt_errstr(result)));
+               SAFE_FREE(previous_nt_hash);
+               return result;
+       }
 
+       result = rpccli_setup_netlogon_creds(conn->cli,
+                                            conn->netlogon_creds,
+                                            conn->netlogon_force_reauth,
+                                            current_nt_hash,
+                                            previous_nt_hash);
+       conn->netlogon_force_reauth = false;
+       SAFE_FREE(previous_nt_hash);
        if (!NT_STATUS_IS_OK(result)) {
-               TALLOC_FREE(netlogon_pipe);
+               DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
+                         "unable to setup NETLOGON credentials: %s\n",
+                         domain->name, nt_errstr(result)));
                return result;
        }
 
-       if ((lp_client_schannel() == True) &&
-                       ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
-               DEBUG(3, ("Server did not offer schannel\n"));
-               TALLOC_FREE(netlogon_pipe);
-               return NT_STATUS_ACCESS_DENIED;
+       result = netlogon_creds_cli_get(conn->netlogon_creds,
+                                       talloc_tos(),
+                                       &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 = creds->negotiate_flags;
+       TALLOC_FREE(creds);
 
  no_schannel:
-       if ((lp_client_schannel() == False) ||
-                       ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
-               /*
-                * NetSamLogonEx only works for schannel
-                */
-               domain->can_do_samlogon_ex = False;
+       if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+               result = cli_rpc_pipe_open_noauth(conn->cli,
+                                       &ndr_table_netlogon,
+                                       &conn->netlogon_pipe);
+               if (!NT_STATUS_IS_OK(result)) {
+                       invalidate_cm_connection(conn);
+                       return result;
+               }
 
-               /* We're done - just keep the existing connection to NETLOGON
-                * open */
-               conn->netlogon_pipe = netlogon_pipe;
                *cli = conn->netlogon_pipe;
                return NT_STATUS_OK;
        }
@@ -2833,12 +2946,9 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
 
        result = cli_rpc_pipe_open_schannel_with_key(
                conn->cli, &ndr_table_netlogon, NCACN_NP,
-               DCERPC_AUTH_LEVEL_PRIVACY, domain->name, &netlogon_pipe->dc,
+               domain->name,
+               conn->netlogon_creds,
                &conn->netlogon_pipe);
-
-       /* We can now close the initial netlogon pipe. */
-       TALLOC_FREE(netlogon_pipe);
-
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
                          "was %s\n", nt_errstr(result)));
@@ -2847,15 +2957,6 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                return result;
        }
 
-       /*
-        * Always try netr_LogonSamLogonEx. We will fall back for NT4
-        * which gives DCERPC_FAULT_OP_RNG_ERROR (function not
-        * supported). We used to only try SamLogonEx for AD, but
-        * Samba DCs can also do it. And because we don't distinguish
-        * between Samba and NT4, always try it once.
-        */
-       domain->can_do_samlogon_ex = true;
-
        *cli = conn->netlogon_pipe;
        return NT_STATUS_OK;
 }