s3:winbindd: fix anon fallback in cm_prepare_connection()
[obnox/samba/samba-obnox.git] / source3 / winbindd / winbindd_cm.c
index fd414b8827e79de6872cbf19340c515ef73e078a..8ce286f6b265f00b165549ff9e6779b1cb4d70da 100644 (file)
 #include "messages.h"
 #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"
+#include "auth/credentials/credentials.h"
+#include "lib/param/param.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -667,6 +668,105 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
        }
 }
 
+static NTSTATUS cm_get_ipc_credentials(TALLOC_CTX *mem_ctx,
+                                      struct cli_credentials **_creds)
+{
+
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+       struct loadparm_context *lp_ctx;
+       char *username = NULL;
+       char *netbios_domain = NULL;
+       char *password = NULL;
+       struct cli_credentials *creds = NULL;
+       bool ok;
+
+       cm_get_ipc_userpass(&username, &netbios_domain, &password);
+
+       lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
+       if (lp_ctx == NULL) {
+               DEBUG(1, ("loadparm_init_s3 failed\n"));
+               status = NT_STATUS_INTERNAL_ERROR;
+               goto fail;
+       }
+
+       creds = cli_credentials_init(mem_ctx);
+       if (creds == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       cli_credentials_set_conf(creds, lp_ctx);
+       cli_credentials_set_kerberos_state(creds, CRED_DONT_USE_KERBEROS);
+
+       ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+       if (!ok) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       ok = cli_credentials_set_username(creds, username, CRED_SPECIFIED);
+       if (!ok) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       ok = cli_credentials_set_password(creds, password, CRED_SPECIFIED);
+       if (!ok) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       *_creds = creds;
+       creds = NULL;
+       status = NT_STATUS_OK;
+ fail:
+       TALLOC_FREE(creds);
+       SAFE_FREE(username);
+       SAFE_FREE(netbios_domain);
+       SAFE_FREE(password);
+       TALLOC_FREE(frame);
+       return status;
+}
+
+static bool cm_is_ipc_credentials(struct cli_credentials *creds)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       char *ipc_account = NULL;
+       char *ipc_domain = NULL;
+       char *ipc_password = NULL;
+       const char *creds_account = NULL;
+       const char *creds_domain = NULL;
+       const char *creds_password = NULL;
+       bool ret = false;
+
+       cm_get_ipc_userpass(&ipc_account, &ipc_domain, &ipc_password);
+
+       creds_account = cli_credentials_get_username(creds);
+       creds_domain = cli_credentials_get_domain(creds);
+       creds_password = cli_credentials_get_password(creds);
+
+       if (!strequal(ipc_domain, creds_domain)) {
+               goto done;
+       }
+
+       if (!strequal(ipc_account, creds_account)) {
+               goto done;
+       }
+
+       if (!strcsequal(ipc_password, creds_password)) {
+               goto done;
+       }
+
+       ret = true;
+ done:
+       SAFE_FREE(ipc_account);
+       SAFE_FREE(ipc_domain);
+       SAFE_FREE(ipc_password);
+       TALLOC_FREE(frame);
+       return ret;
+}
+
 static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
                                     fstring dcname,
                                     struct sockaddr_storage *dc_ss)
@@ -794,65 +894,69 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
 /**
  * Helper function to assemble trust password and account name
  */
-static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
-                               char **machine_password,
-                               char **machine_account,
-                               char **machine_krb5_principal)
+static NTSTATUS get_trust_credentials(struct winbindd_domain *domain,
+                                     TALLOC_CTX *mem_ctx,
+                                     bool netlogon,
+                                     struct cli_credentials **_creds)
 {
-       const char *account_name;
-       const char *name = NULL;
+       const struct winbindd_domain *creds_domain = NULL;
+       struct cli_credentials *creds;
+       NTSTATUS status;
 
        /* If we are a DC and this is not our own domain */
 
-       if (IS_DC) {
-               name = domain->name;
+       if (IS_DC && netlogon) {
+               creds_domain = domain;
        } else {
-               struct winbindd_domain *our_domain = find_our_domain();
-
-               if (!our_domain)
-                       return NT_STATUS_INVALID_SERVER_STATE;          
-
-               name = our_domain->name;                
-       }       
-
-       if (!get_trust_pw_clear(name, machine_password,
-                               &account_name, NULL))
-       {
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               creds_domain = find_our_domain();
+               if (creds_domain == NULL) {
+                       return NT_STATUS_INVALID_SERVER_STATE;
+               }
        }
 
-       if ((machine_account != NULL) &&
-           (asprintf(machine_account, "%s$", account_name) == -1))
-       {
-               return NT_STATUS_NO_MEMORY;
+       status = pdb_get_trust_credentials(creds_domain->name,
+                                          creds_domain->alt_name,
+                                          mem_ctx,
+                                          &creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto ipc_fallback;
        }
 
-       /* For now assume our machine account only exists in our domain */
+       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+               cli_credentials_set_kerberos_state(creds,
+                                                  CRED_MUST_USE_KERBEROS);
+       }
 
-       if (machine_krb5_principal != NULL)
-       {
-               struct winbindd_domain *our_domain = find_our_domain();
+       if (domain->primary && lp_security() == SEC_ADS) {
+               cli_credentials_set_kerberos_state(creds,
+                                                  CRED_AUTO_USE_KERBEROS);
+       } else if (!domain->active_directory) {
+               cli_credentials_set_kerberos_state(creds,
+                                                  CRED_DONT_USE_KERBEROS);
+       }
 
-               if (!our_domain) {
-                       return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;                       
-               }
+       if (creds_domain != domain) {
+               /*
+                * We can only use schannel against a direct trust
+                */
+               cli_credentials_set_secure_channel_type(creds,
+                                                       SEC_CHAN_NULL);
+       }
 
-               if (our_domain->alt_name == NULL) {
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
+       *_creds = creds;
+       return NT_STATUS_OK;
 
-               if (asprintf(machine_krb5_principal, "%s$@%s",
-                            account_name, our_domain->alt_name) == -1)
-               {
-                       return NT_STATUS_NO_MEMORY;
-               }
+ ipc_fallback:
+       if (netlogon) {
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
 
-               if (!strupper_m(*machine_krb5_principal)) {
-                       SAFE_FREE(*machine_krb5_principal);
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
+       status = cm_get_ipc_credentials(mem_ctx, &creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
+       *_creds = creds;
        return NT_STATUS_OK;
 }
 
@@ -861,22 +965,20 @@ static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
  to the pipe.
 ************************************************************************/
 
-static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
+static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                                      const int sockfd,
                                      const char *controller,
                                      struct cli_state **cli,
                                      bool *retry)
 {
-       bool try_spnego = false;
        bool try_ipc_auth = false;
-       char *machine_password = NULL;
-       char *machine_krb5_principal = NULL;
-       char *machine_account = NULL;
-       char *ipc_username = NULL;
-       char *ipc_domain = NULL;
-       char *ipc_password = NULL;
+       const char *machine_password = NULL;
+       const char *machine_krb5_principal = NULL;
+       const char *machine_account = NULL;
+       const char *machine_domain = NULL;
        int flags = 0;
-       uint16_t sec_mode = 0;
+       struct cli_credentials *creds = NULL;
+       enum credentials_use_kerberos krb5_state;
 
        struct named_mutex *mutex;
 
@@ -936,7 +1038,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
 
        result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
                                 lp_client_min_protocol(),
-                                lp_client_max_protocol());
+                                lp_winbindd_max_protocol());
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
@@ -945,59 +1047,87 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
 
        if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_NT1 &&
            smb1cli_conn_capabilities((*cli)->conn) & CAP_EXTENDED_SECURITY) {
-               try_spnego = true;
+               try_ipc_auth = true;
        } else if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_SMB2_02) {
-               try_spnego = true;
+               try_ipc_auth = true;
+       } else if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+               /*
+                * If we are forcing on SMB signing, then we must
+                * require authentication unless this is a one-way
+                * trust, and we have no stored user/password
+                */
+               try_ipc_auth = true;
        }
 
-       if (!is_dc_trusted_domain_situation(domain->name) && try_spnego) {
-               result = get_trust_creds(domain, &machine_password,
-                                        &machine_account,
-                                        &machine_krb5_principal);
+       if (try_ipc_auth) {
+               result = get_trust_credentials(domain, talloc_tos(), false, &creds);
                if (!NT_STATUS_IS_OK(result)) {
-                       goto anon_fallback;
+                       DEBUG(1, ("get_trust_credentials(%s) failed: %s\n",
+                                 domain->name, nt_errstr(result)));
+                       goto done;
+               }
+       } else {
+               /*
+                * Without SPNEGO or NTLMSSP (perhaps via SMB2) we
+                * would try and authentication with our machine
+                * account password and fail.  This is very rare in
+                * the modern world however
+                */
+               creds = cli_credentials_init_anon(talloc_tos());
+               if (creds == NULL) {
+                       result = NT_STATUS_NO_MEMORY;
+                       DEBUG(1, ("cli_credentials_init_anon(%s) failed: %s\n",
+                                 domain->name, nt_errstr(result)));
+                       goto done;
                }
+       }
 
-               if (lp_security() == SEC_ADS) {
+       krb5_state = cli_credentials_get_kerberos_state(creds);
 
-                       /* Try a krb5 session */
+       machine_krb5_principal = cli_credentials_get_principal(creds,
+                                                       talloc_tos());
+       if (machine_krb5_principal == NULL) {
+               krb5_state = CRED_DONT_USE_KERBEROS;
+       }
 
-                       (*cli)->use_kerberos = True;
-                       DEBUG(5, ("connecting to %s from %s with kerberos principal "
-                                 "[%s] and realm [%s]\n", controller, lp_netbios_name(),
-                                 machine_krb5_principal, domain->alt_name));
+       machine_account = cli_credentials_get_username(creds);
+       machine_password = cli_credentials_get_password(creds);
+       machine_domain = cli_credentials_get_domain(creds);
 
-                       winbindd_set_locator_kdc_envs(domain);
+       if (krb5_state != CRED_DONT_USE_KERBEROS) {
 
-                       result = cli_session_setup(*cli,
-                                                  machine_krb5_principal,
-                                                  machine_password,
-                                                  strlen(machine_password)+1,
-                                                  machine_password,
-                                                  strlen(machine_password)+1,
-                                                  lp_workgroup());
+               /* Try a krb5 session */
 
-                       if (!NT_STATUS_IS_OK(result)) {
-                               DEBUG(4,("failed kerberos session setup with %s\n",
-                                       nt_errstr(result)));
-                       }
+               (*cli)->use_kerberos = True;
+               DEBUG(5, ("connecting to %s from %s with kerberos principal "
+                         "[%s] and realm [%s]\n", controller, lp_netbios_name(),
+                         machine_krb5_principal, domain->alt_name));
 
-                       if (NT_STATUS_IS_OK(result)) {
-                               /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
-                               result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
-                               if (!NT_STATUS_IS_OK(result)) {
-                                       goto done;
-                               }
-                               goto session_setup_done;
-                       }
+               winbindd_set_locator_kdc_envs(domain);
+
+               result = cli_session_setup(*cli,
+                                          machine_krb5_principal,
+                                          machine_password,
+                                          strlen(machine_password)+1,
+                                          machine_password,
+                                          strlen(machine_password)+1,
+                                          machine_domain);
+
+               if (NT_STATUS_IS_OK(result)) {
+                       goto session_setup_done;
                }
 
+               DEBUG(4,("failed kerberos session setup with %s\n",
+                        nt_errstr(result)));
+       }
+
+       if (krb5_state != CRED_MUST_USE_KERBEROS) {
                /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
                (*cli)->use_kerberos = False;
 
-               DEBUG(5, ("connecting to %s from %s with username "
+               DEBUG(5, ("connecting to %s from %s using NTLMSSP with username "
                          "[%s]\\[%s]\n",  controller, lp_netbios_name(),
-                         lp_workgroup(), machine_account));
+                         machine_domain, machine_account));
 
                result = cli_session_setup(*cli,
                                           machine_account,
@@ -1005,76 +1135,110 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
                                           strlen(machine_password)+1,
                                           machine_password,
                                           strlen(machine_password)+1,
-                                          lp_workgroup());
-               if (!NT_STATUS_IS_OK(result)) {
-                       DEBUG(4, ("authenticated session setup failed with %s\n",
-                               nt_errstr(result)));
+                                          machine_domain);
+       }
+
+       if (NT_STATUS_IS_OK(result)) {
+               goto session_setup_done;
+       }
+
+       /*
+        * If we are not going to validiate the conneciton
+        * with SMB signing, then allow us to fall back to
+        * anonymous
+        */
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)
+           || NT_STATUS_EQUAL(result, NT_STATUS_TRUSTED_DOMAIN_FAILURE)
+           || NT_STATUS_EQUAL(result, NT_STATUS_INVALID_ACCOUNT_NAME)
+           || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
+       {
+               if (cli_credentials_is_anonymous(creds)) {
+                       goto done;
                }
 
-               if (NT_STATUS_IS_OK(result)) {
-                       /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
-                       result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
-                       if (!NT_STATUS_IS_OK(result)) {
-                               goto done;
-                       }
-                       goto session_setup_done;
+               if (!cm_is_ipc_credentials(creds)) {
+                       goto ipc_fallback;
+               }
+
+               if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+                       goto done;
                }
+
+               goto anon_fallback;
+       }
+
+       DEBUG(4, ("authenticated session setup failed with %s\n",
+               nt_errstr(result)));
+
+       goto done;
+
+ ipc_fallback:
+       result = cm_get_ipc_credentials(talloc_tos(), &creds);
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       if (cli_credentials_is_anonymous(creds)) {
+               TALLOC_FREE(creds);
+               goto anon_fallback;
        }
 
-       /* Fall back to non-kerberos session setup with auth_user */
+       machine_account = cli_credentials_get_username(creds);
+       machine_password = cli_credentials_get_password(creds);
+       machine_domain = cli_credentials_get_domain(creds);
 
+       /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the ipc creds. */
        (*cli)->use_kerberos = False;
 
-       cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
+       DEBUG(5, ("connecting to %s from %s using NTLMSSP with username "
+                 "[%s]\\[%s]\n",  controller, lp_netbios_name(),
+                 machine_domain, machine_account));
 
-       sec_mode = smb1cli_conn_server_security_mode((*cli)->conn);
+       result = cli_session_setup(*cli,
+                                  machine_account,
+                                  machine_password,
+                                  strlen(machine_password)+1,
+                                  machine_password,
+                                  strlen(machine_password)+1,
+                                  machine_domain);
 
-       try_ipc_auth = false;
-       if (try_spnego) {
-               try_ipc_auth = true;
-       } else if (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
-               try_ipc_auth = true;
+       if (NT_STATUS_IS_OK(result)) {
+               goto session_setup_done;
        }
 
-       if (try_ipc_auth && (strlen(ipc_username) > 0)) {
+       /*
+        * If we are not going to validiate the conneciton
+        * with SMB signing, then allow us to fall back to
+        * anonymous
+        */
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)
+           || NT_STATUS_EQUAL(result, NT_STATUS_TRUSTED_DOMAIN_FAILURE)
+           || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
+       {
+               goto anon_fallback;
+       }
 
-               /* Only try authenticated if we have a username */
+       DEBUG(4, ("authenticated session setup failed with %s\n",
+               nt_errstr(result)));
 
-               DEBUG(5, ("connecting to %s from %s with username "
-                         "[%s]\\[%s]\n",  controller, lp_netbios_name(),
-                         ipc_domain, ipc_username));
-
-               if (NT_STATUS_IS_OK(cli_session_setup(
-                                           *cli, ipc_username,
-                                           ipc_password, strlen(ipc_password)+1,
-                                           ipc_password, strlen(ipc_password)+1,
-                                           ipc_domain))) {
-                       /* Successful logon with given username. */
-                       result = cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
-                       if (!NT_STATUS_IS_OK(result)) {
-                               goto done;
-                       }
-                       goto session_setup_done;
-               } else {
-                       DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
-                               ipc_domain, ipc_username ));
-               }
-       }
+       goto done;
 
  anon_fallback:
 
+       if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+               goto done;
+       }
+
        /* Fall back to anonymous connection, this might fail later */
        DEBUG(10,("cm_prepare_connection: falling back to anonymous "
                "connection for DC %s\n",
                controller ));
 
-       result = cli_session_setup(*cli, "", NULL, 0, NULL, 0, "");
+       (*cli)->use_kerberos = False;
+
+       result = cli_session_setup(*cli, "", "", 0, "", 0, "");
        if (NT_STATUS_IS_OK(result)) {
                DEBUG(5, ("Connected anonymously\n"));
-               result = cli_init_creds(*cli, "", "", "");
-               if (!NT_STATUS_IS_OK(result)) {
-                       goto done;
-               }
                goto session_setup_done;
        }
 
@@ -1094,6 +1258,13 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
                smbXcli_session_set_disconnect_expired((*cli)->smb2.session);
        }
 
+       result = cli_tree_connect(*cli, "IPC$", "IPC", "", 0);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
+               goto done;
+       }
+
        /* cache the server name for later connections */
 
        saf_store(domain->name, controller);
@@ -1103,37 +1274,13 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
 
        winbindd_set_locator_kdc_envs(domain);
 
-       result = cli_tree_connect(*cli, "IPC$", "IPC", "", 0);
-
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
-               goto done;
-       }
-
        TALLOC_FREE(mutex);
        *retry = False;
 
-       /* set the domain if empty; needed for schannel connections */
-       if ( !(*cli)->domain[0] ) {
-               result = cli_set_domain((*cli), domain->name);
-               if (!NT_STATUS_IS_OK(result)) {
-                       SAFE_FREE(ipc_username);
-                       SAFE_FREE(ipc_domain);
-                       SAFE_FREE(ipc_password);
-                       return result;
-               }
-       }
-
        result = NT_STATUS_OK;
 
  done:
        TALLOC_FREE(mutex);
-       SAFE_FREE(machine_account);
-       SAFE_FREE(machine_password);
-       SAFE_FREE(machine_krb5_principal);
-       SAFE_FREE(ipc_username);
-       SAFE_FREE(ipc_domain);
-       SAFE_FREE(ipc_password);
 
        if (!NT_STATUS_IS_OK(result)) {
                winbind_add_failed_connection_entry(domain, controller, result);
@@ -1468,7 +1615,7 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        int num_dcs = 0;
 
        const char **dcnames = NULL;
-       int num_dcnames = 0;
+       size_t num_dcnames = 0;
 
        struct sockaddr_storage *addrs = NULL;
        int num_addrs = 0;
@@ -1836,9 +1983,10 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 
 /* Close down all open pipes on a connection. */
 
-void invalidate_cm_connection(struct winbindd_cm_conn *conn)
+void invalidate_cm_connection(struct winbindd_domain *domain)
 {
        NTSTATUS result;
+       struct winbindd_cm_conn *conn = &domain->conn;
 
        /* We're closing down a possibly dead
           connection. Don't have impossibly long (10s) timeouts. */
@@ -1924,7 +2072,7 @@ void close_conns_after_fork(void)
                        smbXcli_conn_disconnect(domain->conn.cli->conn, NT_STATUS_OK);
                }
 
-               invalidate_cm_connection(&domain->conn);
+               invalidate_cm_connection(domain);
        }
 
        for (cli_state = winbindd_client_list();
@@ -1980,7 +2128,7 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool
                return NT_STATUS_OK;
        }
 
-       invalidate_cm_connection(&domain->conn);
+       invalidate_cm_connection(domain);
 
        if (!domain->primary && !domain->initialized) {
                /*
@@ -2511,9 +2659,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        struct winbindd_cm_conn *conn;
        NTSTATUS status, result;
        struct netlogon_creds_cli_context *p_creds;
-       char *machine_password = NULL;
-       char *machine_account = NULL;
-       const char *domain_name = NULL;
+       struct cli_credentials *creds = NULL;
 
        if (sid_check_is_our_sam(&domain->sid)) {
                if (domain->rodc == false || need_rw_dc == false) {
@@ -2541,55 +2687,43 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
         * anonymous.
         */
 
-       if ((conn->cli->user_name[0] == '\0') ||
-           (conn->cli->domain[0] == '\0') || 
-           (conn->cli->password == NULL || conn->cli->password[0] == '\0'))
-       {
-               status = get_trust_creds(domain, &machine_password,
-                                        &machine_account, NULL);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10, ("cm_connect_sam: No no user available for "
-                                  "domain %s, trying schannel\n", conn->cli->domain));
-                       goto schannel;
-               }
-               domain_name = domain->name;
-       } else {
-               machine_password = SMB_STRDUP(conn->cli->password);
-               machine_account = SMB_STRDUP(conn->cli->user_name);
-               domain_name = conn->cli->domain;
+       result = get_trust_credentials(domain, talloc_tos(), false, &creds);
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(10, ("cm_connect_sam: No no user available for "
+                          "domain %s, trying schannel\n", domain->name));
+               goto schannel;
        }
 
-       if (!machine_password || !machine_account) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
+       if (cli_credentials_is_anonymous(creds)) {
+               goto anonymous;
        }
 
-       /* We have an authenticated connection. Use a NTLMSSP SPNEGO
-          authenticated SAMR pipe with sign & seal. */
-       status = cli_rpc_pipe_open_spnego(conn->cli,
-                                         &ndr_table_samr,
-                                         NCACN_NP,
-                                         GENSEC_OID_NTLMSSP,
-                                         conn->auth_level,
-                                         smbXcli_conn_remote_name(conn->cli->conn),
-                                         domain_name,
-                                         machine_account,
-                                         machine_password,
-                                         &conn->samr_pipe);
-
+       /*
+        * We have an authenticated connection. Use a SPNEGO
+        * authenticated SAMR pipe with sign & seal.
+        */
+       status = cli_rpc_pipe_open_with_creds(conn->cli,
+                                             &ndr_table_samr,
+                                             NCACN_NP,
+                                             DCERPC_AUTH_TYPE_SPNEGO,
+                                             conn->auth_level,
+                                             smbXcli_conn_remote_name(conn->cli->conn),
+                                             creds,
+                                             &conn->samr_pipe);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
                          "pipe for domain %s using NTLMSSP "
-                         "authenticated pipe: user %s\\%s. Error was "
-                         "%s\n", domain->name, domain_name,
-                         machine_account, nt_errstr(status)));
+                         "authenticated pipe: user %s. Error was "
+                         "%s\n", domain->name,
+                         cli_credentials_get_unparsed_name(creds, talloc_tos()),
+                         nt_errstr(status)));
                goto schannel;
        }
 
        DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
                  "domain %s using NTLMSSP authenticated "
-                 "pipe: user %s\\%s\n", domain->name,
-                 domain_name, machine_account));
+                 "pipe: user %s\n", domain->name,
+                 cli_credentials_get_unparsed_name(creds, talloc_tos())));
 
        status = dcerpc_samr_Connect2(conn->samr_pipe->binding_handle, mem_ctx,
                                      conn->samr_pipe->desthost,
@@ -2715,14 +2849,12 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                ZERO_STRUCT(conn->sam_domain_handle);
                return status;
        } else if (!NT_STATUS_IS_OK(status)) {
-               invalidate_cm_connection(conn);
+               invalidate_cm_connection(domain);
                return status;
        }
 
        *cli = conn->samr_pipe;
        *sam_handle = conn->sam_domain_handle;
-       SAFE_FREE(machine_password);
-       SAFE_FREE(machine_account);
        return status;
 }
 
@@ -2790,6 +2922,7 @@ 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_cli_context *p_creds;
+       struct cli_credentials *creds = NULL;
 
        result = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(result))
@@ -2803,36 +2936,41 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
 
        TALLOC_FREE(conn->lsa_pipe);
 
-       if ((conn->cli->user_name[0] == '\0') ||
-           (conn->cli->domain[0] == '\0') || 
-           (conn->cli->password == NULL || conn->cli->password[0] == '\0')) {
-               DEBUG(10, ("cm_connect_lsa: No no user available for "
-                          "domain %s, trying schannel\n", conn->cli->domain));
+       result = get_trust_credentials(domain, talloc_tos(), false, &creds);
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(10, ("cm_connect_sam: No no user available for "
+                          "domain %s, trying schannel\n", domain->name));
                goto schannel;
        }
 
-       /* We have an authenticated connection. Use a NTLMSSP SPNEGO
-        * authenticated LSA pipe with sign & seal. */
-       result = cli_rpc_pipe_open_spnego
+       if (cli_credentials_is_anonymous(creds)) {
+               goto anonymous;
+       }
+
+       /*
+        * We have an authenticated connection. Use a SPNEGO
+        * authenticated LSA pipe with sign & seal.
+        */
+       result = cli_rpc_pipe_open_with_creds
                (conn->cli, &ndr_table_lsarpc, NCACN_NP,
-                GENSEC_OID_NTLMSSP,
+                DCERPC_AUTH_TYPE_SPNEGO,
                 conn->auth_level,
                 smbXcli_conn_remote_name(conn->cli->conn),
-                conn->cli->domain, conn->cli->user_name, conn->cli->password,
+                creds,
                 &conn->lsa_pipe);
-
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
                          "domain %s using NTLMSSP authenticated pipe: user "
-                         "%s\\%s. Error was %s. Trying schannel.\n",
-                         domain->name, conn->cli->domain,
-                         conn->cli->user_name, nt_errstr(result)));
+                         "%s. Error was %s. Trying schannel.\n",
+                         domain->name,
+                         cli_credentials_get_unparsed_name(creds, talloc_tos()),
+                         nt_errstr(result)));
                goto schannel;
        }
 
        DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
-                 "NTLMSSP authenticated pipe: user %s\\%s\n",
-                 domain->name, conn->cli->domain, conn->cli->user_name ));
+                 "NTLMSSP authenticated pipe: user %s\n",
+                 domain->name, cli_credentials_get_unparsed_name(creds, talloc_tos())));
 
        result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
                                        SEC_FLAG_MAXIMUM_ALLOWED,
@@ -2908,7 +3046,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                        &conn->lsa_policy);
  done:
        if (!NT_STATUS_IS_OK(result)) {
-               invalidate_cm_connection(conn);
+               invalidate_cm_connection(domain);
                return result;
        }
 
@@ -2933,7 +3071,7 @@ NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
                if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
                    NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
                    NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
-                       invalidate_cm_connection(&domain->conn);
+                       invalidate_cm_connection(domain);
                        status = cm_connect_lsa_tcp(domain, mem_ctx, cli);
                }
                if (NT_STATUS_IS_OK(status)) {
@@ -2944,6 +3082,8 @@ NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
                 * we tried twice to connect via ncan_ip_tcp and schannel and
                 * failed - maybe it is a trusted domain we can't connect to ?
                 * do not try tcp next time - gd
+                *
+                * This also prevents NETLOGON over TCP
                 */
                domain->can_do_ncacn_ip_tcp = false;
        }
@@ -2958,19 +3098,20 @@ NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
  session key stored in conn->netlogon_pipe->dc->sess_key.
 ****************************************************************************/
 
-NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
-                            struct rpc_pipe_client **cli)
+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 winbindd_cm_conn *conn;
        NTSTATUS result;
        enum netr_SchannelType sec_chan_type;
-       const char *_account_name;
        const char *account_name;
-       struct samr_Password current_nt_hash;
-       struct samr_Password *previous_nt_hash = NULL;
-       struct netlogon_creds_CredentialState *creds = NULL;
-       bool ok;
+       const char *domain_name;
+       const struct samr_Password *current_nt_hash = NULL;
+       const struct samr_Password *previous_nt_hash = NULL;
+       struct netlogon_creds_CredentialState *netlogon_creds = NULL;
+       struct cli_credentials *creds = NULL;
 
        *cli = NULL;
 
@@ -2990,28 +3131,34 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        conn->netlogon_flags = 0;
        TALLOC_FREE(conn->netlogon_creds);
 
-       if ((!IS_DC) && (!domain->primary)) {
-               goto no_schannel;
+       result = get_trust_credentials(domain, talloc_tos(), true, &creds);
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(10, ("cm_connect_sam: No no user available for "
+                          "domain %s when trying schannel\n", domain->name));
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       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",
+       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));
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name);
-       if (account_name == NULL) {
+       sec_chan_type = cli_credentials_get_secure_channel_type(creds);
+       if (sec_chan_type == SEC_CHAN_NULL) {
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               goto no_schannel;
+       }
+
+       account_name = cli_credentials_get_username(creds);
+       domain_name = cli_credentials_get_domain(creds);
+       current_nt_hash = cli_credentials_get_nt_hash(creds, talloc_tos());
+       if (current_nt_hash == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
        result = rpccli_create_netlogon_creds(domain->dcname,
-                                             domain->name,
+                                             domain_name,
                                              account_name,
                                              sec_chan_type,
                                              msg_ctx,
@@ -3021,17 +3168,15 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                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,
+       result = rpccli_setup_netlogon_creds(conn->cli, transport,
                                             conn->netlogon_creds,
                                             conn->netlogon_force_reauth,
-                                            current_nt_hash,
+                                            *current_nt_hash,
                                             previous_nt_hash);
        conn->netlogon_force_reauth = false;
-       SAFE_FREE(previous_nt_hash);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
                          "unable to setup NETLOGON credentials: %s\n",
@@ -3041,15 +3186,15 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
 
        result = netlogon_creds_cli_get(conn->netlogon_creds,
                                        talloc_tos(),
-                                       &creds);
+                                       &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 = creds->negotiate_flags;
-       TALLOC_FREE(creds);
+       conn->netlogon_flags = netlogon_creds->negotiate_flags;
+       TALLOC_FREE(netlogon_creds);
 
  no_schannel:
        if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
@@ -3060,14 +3205,15 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                                  "must set 'winbind sealed pipes = false' and "
                                  "'require strong key = false' to proceed: %s\n",
                                  domain->name, nt_errstr(result)));
-                       invalidate_cm_connection(conn);
+                       invalidate_cm_connection(domain);
                        return result;
                }
-               result = cli_rpc_pipe_open_noauth(conn->cli,
-                                       &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(conn);
+                       invalidate_cm_connection(domain);
                        return result;
                }
 
@@ -3081,7 +3227,7 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        */
 
        result = cli_rpc_pipe_open_schannel_with_key(
-               conn->cli, &ndr_table_netlogon, NCACN_NP,
+               conn->cli, &ndr_table_netlogon, transport,
                domain->name,
                conn->netlogon_creds,
                &conn->netlogon_pipe);
@@ -3089,7 +3235,7 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
                          "was %s\n", nt_errstr(result)));
 
-               invalidate_cm_connection(conn);
+               invalidate_cm_connection(domain);
                return result;
        }
 
@@ -3097,6 +3243,42 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        return NT_STATUS_OK;
 }
 
+/****************************************************************************
+Open a LSA connection to a DC, suiteable for LSA lookup calls.
+****************************************************************************/
+
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+                            struct rpc_pipe_client **cli)
+{
+       NTSTATUS status;
+
+       if (domain->active_directory && domain->can_do_ncacn_ip_tcp) {
+               status = cm_connect_netlogon_transport(domain, NCACN_IP_TCP, cli);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+                   NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
+                   NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+                       invalidate_cm_connection(domain);
+                       status = cm_connect_netlogon_transport(domain, NCACN_IP_TCP, cli);
+               }
+               if (NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               /*
+                * we tried twice to connect via ncan_ip_tcp and schannel and
+                * failed - maybe it is a trusted domain we can't connect to ?
+                * do not try tcp next time - gd
+                *
+                * This also prevents LSA over TCP
+                */
+               domain->can_do_ncacn_ip_tcp = false;
+       }
+
+       status = cm_connect_netlogon_transport(domain, NCACN_NP, cli);
+
+       return status;
+}
+
 void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
                            void *private_data,
                            uint32_t msg_type,