cli_netlogon: Eliminate rpccli_setup_netlogon_creds_with_creds
[samba.git] / source3 / winbindd / winbindd_cm.c
index ff0e081fb08541bfb0ef0c410e34bbcce386d244..b2d14c47b40cc19dac8bebf7cf3ae96cd9a7389b 100644 (file)
@@ -99,7 +99,8 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool
 static void set_dc_type_and_flags( struct winbindd_domain *domain );
 static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain );
 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
-                   struct dc_name_ip **dcs, int *num_dcs);
+                   struct dc_name_ip **dcs, int *num_dcs,
+                   uint32_t request_flags);
 
 /****************************************************************
  Child failed to find DC's. Reschedule check.
@@ -266,7 +267,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
                _exit(1);
        }
 
-       if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
+       if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0)) || (num_dcs == 0)) {
                /* Still offline ? Can't find DC's. */
                messaging_send_buf(winbind_messaging_context(),
                                   pid_to_procid(parent_pid),
@@ -769,7 +770,8 @@ static bool cm_is_ipc_credentials(struct cli_credentials *creds)
 
 static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
                                     fstring dcname,
-                                    struct sockaddr_storage *dc_ss)
+                                    struct sockaddr_storage *dc_ss,
+                                    uint32_t request_flags)
 {
        struct winbindd_domain *our_domain = NULL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
@@ -814,13 +816,17 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
        if (our_domain->active_directory) {
                struct netr_DsRGetDCNameInfo *domain_info = NULL;
 
+               /*
+                * TODO request flags are not respected in the server
+                * (and in some cases, like REQUIRE_PDC, causes an error)
+                */
                result = dcerpc_netr_DsRGetDCName(b,
                                                  mem_ctx,
                                                  our_domain->dcname,
                                                  domain->name,
                                                  NULL,
                                                  NULL,
-                                                 DS_RETURN_DNS_NAME,
+                                                 request_flags|DS_RETURN_DNS_NAME,
                                                  &domain_info,
                                                  &werr);
                if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) {
@@ -936,17 +942,6 @@ static NTSTATUS get_trust_credentials(struct winbindd_domain *domain,
                goto ipc_fallback;
        }
 
-       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_MUST_USE_KERBEROS);
-       } else {
-               cli_credentials_set_kerberos_state(creds,
-                                                  CRED_DONT_USE_KERBEROS);
-       }
-
        if (creds_domain != domain) {
                /*
                 * We can only use schannel against a direct trust
@@ -984,17 +979,18 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                                      bool *retry)
 {
        bool try_ipc_auth = false;
-       const char *machine_password = NULL;
-       const char *machine_krb5_principal = NULL;
+       const char *machine_principal = NULL;
+       const char *machine_realm = NULL;
        const char *machine_account = NULL;
        const char *machine_domain = NULL;
        int flags = 0;
        struct cli_credentials *creds = NULL;
-       enum credentials_use_kerberos krb5_state;
 
        struct named_mutex *mutex;
 
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS tmp_status;
+       NTSTATUS tcon_status = NT_STATUS_NETWORK_NAME_DELETED;
 
        enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
 
@@ -1034,10 +1030,7 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                goto done;
        }
 
-       flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-
-       *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);
@@ -1048,6 +1041,8 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
 
        cli_set_timeout(*cli, 10000); /* 10 seconds */
 
+       set_socket_options(sockfd, lp_socket_options());
+
        result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
                                 lp_client_ipc_min_protocol(),
                                 lp_client_ipc_max_protocol());
@@ -1094,66 +1089,34 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                }
        }
 
-       krb5_state = cli_credentials_get_kerberos_state(creds);
-
-       machine_krb5_principal = cli_credentials_get_principal(creds,
+       machine_principal = cli_credentials_get_principal(creds,
                                                        talloc_tos());
-       if (machine_krb5_principal == NULL) {
-               krb5_state = CRED_DONT_USE_KERBEROS;
-       }
-
+       machine_realm = cli_credentials_get_realm(creds);
        machine_account = cli_credentials_get_username(creds);
-       machine_password = cli_credentials_get_password(creds);
        machine_domain = cli_credentials_get_domain(creds);
 
-       if (krb5_state != CRED_DONT_USE_KERBEROS) {
+       DEBUG(5, ("connecting to %s (%s, %s) with account [%s\\%s] principal "
+                 "[%s] and realm [%s]\n",
+                 controller, domain->name, domain->alt_name,
+                 machine_domain, machine_account,
+                 machine_principal, machine_realm));
 
-               /* Try a krb5 session */
-
-               (*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));
-
-               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 (cli_credentials_is_anonymous(creds)) {
+               goto anon_fallback;
        }
 
-       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 using NTLMSSP with username "
-                         "[%s]\\[%s]\n",  controller, lp_netbios_name(),
-                         machine_domain, machine_account));
-
-               result = cli_session_setup(*cli,
-                                          machine_account,
-                                          machine_password,
-                                          strlen(machine_password)+1,
-                                          machine_password,
-                                          strlen(machine_password)+1,
-                                          machine_domain);
-       }
+       winbindd_set_locator_kdc_envs(domain);
 
+       result = cli_session_setup_creds(*cli, creds);
        if (NT_STATUS_IS_OK(result)) {
                goto session_setup_done;
        }
 
+       DEBUG(1, ("authenticated session setup to %s using %s failed with %s\n",
+                 controller,
+                 cli_credentials_get_unparsed_name(creds, talloc_tos()),
+                 nt_errstr(result)));
+
        /*
         * If we are not going to validiate the conneciton
         * with SMB signing, then allow us to fall back to
@@ -1165,10 +1128,6 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
            || NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)
            || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
        {
-               if (cli_credentials_is_anonymous(creds)) {
-                       goto done;
-               }
-
                if (!cm_is_ipc_credentials(creds)) {
                        goto ipc_fallback;
                }
@@ -1180,45 +1139,37 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                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)) {
+       TALLOC_FREE(creds);
+       tmp_status = cm_get_ipc_credentials(talloc_tos(), &creds);
+       if (!NT_STATUS_IS_OK(tmp_status)) {
+               result = tmp_status;
                goto done;
        }
 
        if (cli_credentials_is_anonymous(creds)) {
-               TALLOC_FREE(creds);
                goto anon_fallback;
        }
 
        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;
-
        DEBUG(5, ("connecting to %s from %s using NTLMSSP with username "
                  "[%s]\\[%s]\n",  controller, lp_netbios_name(),
                  machine_domain, machine_account));
 
-       result = cli_session_setup(*cli,
-                                  machine_account,
-                                  machine_password,
-                                  strlen(machine_password)+1,
-                                  machine_password,
-                                  strlen(machine_password)+1,
-                                  machine_domain);
-
+       result = cli_session_setup_creds(*cli, creds);
        if (NT_STATUS_IS_OK(result)) {
                goto session_setup_done;
        }
 
+       DEBUG(1, ("authenticated session setup to %s using %s failed with %s\n",
+                 controller,
+                 cli_credentials_get_unparsed_name(creds, talloc_tos()),
+                 nt_errstr(result)));
+
        /*
         * If we are not going to validiate the conneciton
         * with SMB signing, then allow us to fall back to
@@ -1233,34 +1184,34 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                goto anon_fallback;
        }
 
-       DEBUG(4, ("authenticated session setup failed with %s\n",
-               nt_errstr(result)));
-
        goto done;
 
  anon_fallback:
+       TALLOC_FREE(creds);
 
        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 "
+       DEBUG(5,("cm_prepare_connection: falling back to anonymous "
                "connection for DC %s\n",
                controller ));
 
-       (*cli)->use_kerberos = False;
-
-       result = cli_session_setup(*cli, "", "", 0, "", 0, "");
+       result = cli_session_setup_anon(*cli);
        if (NT_STATUS_IS_OK(result)) {
                DEBUG(5, ("Connected anonymously\n"));
                goto session_setup_done;
        }
 
+       DEBUG(1, ("anonymous session setup to %s failed with %s\n",
+                 controller, nt_errstr(result)));
+
        /* We can't session setup */
        goto done;
 
  session_setup_done:
+       TALLOC_FREE(creds);
 
        /*
         * This should be a short term hack until
@@ -1273,17 +1224,17 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
                smbXcli_session_set_disconnect_expired((*cli)->smb2.session);
        }
 
-       result = cli_tree_connect(*cli, "IPC$", "IPC", "", 0);
-
+       result = cli_tree_connect(*cli, "IPC$", "IPC", NULL);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
                goto done;
        }
+       tcon_status = result;
 
        /* cache the server name for later connections */
 
        saf_store(domain->name, controller);
-       if (domain->alt_name && (*cli)->use_kerberos) {
+       if (domain->alt_name) {
                saf_store(domain->alt_name, controller);
        }
 
@@ -1296,8 +1247,15 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
 
  done:
        TALLOC_FREE(mutex);
+       TALLOC_FREE(creds);
+
+       if (NT_STATUS_IS_OK(result)) {
+               result = tcon_status;
+       }
 
        if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(1, ("Failed to prepare SMB connection to %s: %s\n",
+                         controller, nt_errstr(result)));
                winbind_add_failed_connection_entry(domain, controller, result);
                if ((*cli) != NULL) {
                        cli_shutdown(*cli);
@@ -1372,12 +1330,13 @@ static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
 
 /*******************************************************************
  convert an ip to a name
+ For an AD Domain, it checks the requirements of the request flags.
 *******************************************************************/
 
-static bool dcip_to_name(TALLOC_CTX *mem_ctx,
-               const struct winbindd_domain *domain,
-               struct sockaddr_storage *pss,
-               char **name)
+static bool dcip_check_name(TALLOC_CTX *mem_ctx,
+                           const struct winbindd_domain *domain,
+                           struct sockaddr_storage *pss,
+                           char **name, uint32_t request_flags)
 {
        struct ip_service ip_list;
        uint32_t nt_version = NETLOGON_NT_VERSION_1;
@@ -1409,6 +1368,8 @@ static bool dcip_to_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 +1381,7 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
                        }
                        namecache_store(*name, 0x20, 1, &ip_list);
 
-                       DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
+                       DEBUG(10,("dcip_check_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
 
                        if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
                                if (ads_closest_dc(ads)) {
@@ -1501,7 +1462,8 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
 *******************************************************************/
 
 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
-                   struct dc_name_ip **dcs, int *num_dcs)
+                   struct dc_name_ip **dcs, int *num_dcs,
+                   uint32_t request_flags)
 {
        fstring dcname;
        struct  sockaddr_storage ss;
@@ -1515,7 +1477,7 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
 
        /* If not our domain, get the preferred DC, by asking our primary DC */
        if ( !is_our_domain
-               && get_dc_name_via_netlogon(domain, dcname, &ss)
+               && get_dc_name_via_netlogon(domain, dcname, &ss, request_flags)
                && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
                       num_dcs) )
        {
@@ -1632,7 +1594,8 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
 
 static bool find_new_dc(TALLOC_CTX *mem_ctx,
                        struct winbindd_domain *domain,
-                       char **dcname, struct sockaddr_storage *pss, int *fd)
+                       char **dcname, struct sockaddr_storage *pss, int *fd,
+                       uint32_t request_flags)
 {
        struct dc_name_ip *dcs = NULL;
        int num_dcs = 0;
@@ -1651,7 +1614,7 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        *fd = -1;
 
  again:
-       if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
+       if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs, request_flags) || (num_dcs == 0))
                return False;
 
        for (i=0; i<num_dcs; i++) {
@@ -1699,7 +1662,7 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        }
 
        /* Try to figure out the name */
-       if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
+       if (dcip_check_name(mem_ctx, domain, pss, dcname, request_flags)) {
                return True;
        }
 
@@ -1825,13 +1788,15 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
                                                 table,
                                                 session_info,
                                                 NULL,
+                                                NULL,
                                                 winbind_messaging_context(),
                                                 &cli);
        } else {
                status = rpc_pipe_open_internal(mem_ctx,
-                                               &table->syntax_id,
+                                               table,
                                                session_info,
                                                NULL,
+                                               NULL,
                                                winbind_messaging_context(),
                                                &cli);
        }
@@ -1849,12 +1814,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 = need_rw_dc ? DS_WRITABLE_REQUIRED : 0;
 
        if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
                set_domain_offline(domain);
@@ -1870,39 +1837,39 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
           before talking to it. It going down may have
           triggered the reconnection. */
 
-       if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
+       if (saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache(domain->name, saf_servername))) {
+               struct sockaddr_storage ss;
+               char *dcname = NULL;
+               bool resolved = true;
 
-               DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
-                       saf_servername, domain->name ));
+               DEBUG(10, ("cm_open_connection: saf_servername is '%s' for domain %s\n",
+                          saf_servername, domain->name));
 
                /* convert an ip address to a name */
-               if (is_ipaddress( saf_servername ) ) {
-                       char *dcname = NULL;
-                       struct sockaddr_storage ss;
-
+               if (is_ipaddress(saf_servername)) {
                        if (!interpret_string_addr(&ss, saf_servername,
-                                               AI_NUMERICHOST)) {
+                                                  AI_NUMERICHOST)) {
                                TALLOC_FREE(mem_ctx);
                                return NT_STATUS_UNSUCCESSFUL;
                        }
-                       if (dcip_to_name(mem_ctx, domain, &ss, &dcname)) {
-                               domain->dcname = talloc_strdup(domain,
-                                                              dcname);
-                               if (domain->dcname == NULL) {
-                                       TALLOC_FREE(mem_ctx);
-                                       return NT_STATUS_NO_MEMORY;
-                               }
-                       } else {
-                               winbind_add_failed_connection_entry(
-                                       domain, saf_servername,
-                                       NT_STATUS_UNSUCCESSFUL);
-                       }
                } else {
-                       domain->dcname = talloc_strdup(domain, saf_servername);
+                       if (!resolve_name(saf_servername, &ss, 0x20, true)) {
+                               resolved = false;
+                       }
+               }
+
+               if (resolved && dcip_check_name(mem_ctx, domain, &ss, &dcname, request_flags)) {
+                       domain->dcname = talloc_strdup(domain,
+                                                      dcname);
                        if (domain->dcname == NULL) {
                                TALLOC_FREE(mem_ctx);
                                return NT_STATUS_NO_MEMORY;
                        }
+
+                       domain->dcaddr = ss;
+               } else {
+                       winbind_add_failed_connection_entry(domain, saf_servername,
+                                                           NT_STATUS_UNSUCCESSFUL);
                }
        }
 
@@ -1913,12 +1880,12 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 
                result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
 
-               DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
-                       domain->dcname ? domain->dcname : "", domain->name ));
+               DEBUG(10, ("cm_open_connection: dcname is '%s' for domain %s\n",
+                          domain->dcname ? domain->dcname : "", domain->name));
 
-               if (domain->dcname != NULL
-                       && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
-                       && (resolve_name(domain->dcname, &domain->dcaddr, 0x20, true)))
+               if (domain->dcname != NULL &&
+                   NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
+                                                             domain->dcname)))
                {
                        NTSTATUS status;
 
@@ -1931,7 +1898,7 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                }
 
                if ((fd == -1) &&
-                   !find_new_dc(mem_ctx, domain, &dcname, &domain->dcaddr, &fd))
+                   !find_new_dc(mem_ctx, domain, &dcname, &domain->dcaddr, &fd, request_flags))
                {
                        /* This is the one place where we will
                           set the global winbindd offline state
@@ -2071,7 +2038,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);
@@ -2161,7 +2128,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);
@@ -2650,11 +2617,11 @@ 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_creds_ctx != NULL) {
                if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
                        return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
                }
-               *ppdc = domain->conn.netlogon_creds;
+               *ppdc = domain->conn.netlogon_creds_ctx;
                return NT_STATUS_OK;
        }
 
@@ -2663,7 +2630,7 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
                return result;
        }
 
-       if (domain->conn.netlogon_creds == NULL) {
+       if (domain->conn.netlogon_creds_ctx == NULL) {
                return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
        }
 
@@ -2671,7 +2638,7 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
                return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
        }
 
-       *ppdc = domain->conn.netlogon_creds;
+       *ppdc = domain->conn.netlogon_creds_ctx;
        return NT_STATUS_OK;
 }
 
@@ -2959,10 +2926,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;
        }
 
@@ -3267,12 +3236,12 @@ 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)) {
-               DEBUG(10, ("cm_connect_sam: No user available for "
-                          "domain %s when trying schannel\n", domain->name));
+               DBG_DEBUG("No user available for domain %s when trying "
+                         "schannel\n", domain->name);
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
@@ -3284,14 +3253,35 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 
        sec_chan_type = cli_credentials_get_secure_channel_type(creds);
        if (sec_chan_type == SEC_CHAN_NULL) {
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               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",
+                                  domain->name);
+                       return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               }
+
+               DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
+                          "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);
+               if (!NT_STATUS_IS_OK(result)) {
+                       invalidate_cm_connection(domain);
+                       return result;
+               }
+
+               *cli = conn->netlogon_pipe;
+               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",
@@ -3299,10 +3289,10 @@ 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);
+       result = rpccli_setup_netlogon_creds(conn->cli, transport,
+                                            conn->netlogon_creds_ctx,
+                                            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, "
@@ -3311,7 +3301,7 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
                return result;
        }
 
-       result = netlogon_creds_cli_get(conn->netlogon_creds,
+       result = netlogon_creds_cli_get(conn->netlogon_creds_ctx,
                                        talloc_tos(),
                                        &netlogon_creds);
        if (!NT_STATUS_IS_OK(result)) {
@@ -3355,7 +3345,7 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
        result = cli_rpc_pipe_open_schannel_with_creds(
                conn->cli, &ndr_table_netlogon, transport,
                creds,
-               conn->netlogon_creds,
+               conn->netlogon_creds_ctx,
                &conn->netlogon_pipe);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
@@ -3370,7 +3360,7 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 }
 
 /****************************************************************************
-Open a LSA connection to a DC, suiteable for LSA lookup calls.
+Open a NETLOGON connection to a DC, suiteable for SamLogon calls.
 ****************************************************************************/
 
 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,