winbindd: Retry on expired session in cm_connect_netlogon
[obnox/samba/samba-obnox.git] / source3 / winbindd / winbindd_cm.c
index 0a633696d9a0e1a17295e4d582673de4f52ce2a8..f593d24619b7d999aeb44ddbdec11181fad6a459 100644 (file)
@@ -446,7 +446,7 @@ void set_domain_offline(struct winbindd_domain *domain)
                messaging_send_buf(winbind_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_DOMAIN_OFFLINE,
-                                  (uint8 *)domain->name,
+                                  (uint8_t *)domain->name,
                                   strlen(domain->name) + 1);
        }
 
@@ -532,7 +532,7 @@ static void set_domain_online(struct winbindd_domain *domain)
                messaging_send_buf(winbind_messaging_context(),
                                   pid_to_procid(parent_pid),
                                   MSG_WINBIND_DOMAIN_ONLINE,
-                                  (uint8 *)domain->name,
+                                  (uint8_t *)domain->name,
                                   strlen(domain->name) + 1);
        }
 
@@ -1162,6 +1162,7 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
        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_NO_LOGON_SERVERS)
            || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
        {
                if (cli_credentials_is_anonymous(creds)) {
@@ -1225,6 +1226,8 @@ static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
         */
        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_NO_LOGON_SERVERS)
            || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
        {
                goto anon_fallback;
@@ -1350,7 +1353,7 @@ static bool add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
 }
 
 static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
-                                 struct sockaddr_storage *pss, uint16 port,
+                                 struct sockaddr_storage *pss, uint16_t port,
                                  struct sockaddr_storage **addrs, int *num)
 {
        *addrs = talloc_realloc(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
@@ -1381,7 +1384,9 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        const char *dc_name;
        fstring nbtname;
-
+#ifdef HAVE_ADS
+       bool is_ad_domain = false;
+#endif
        ip_list.ss = *pss;
        ip_list.port = 0;
 
@@ -1390,6 +1395,12 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
           None of these failures should be considered critical for now */
 
        if ((lp_security() == SEC_ADS) && (domain->alt_name != NULL)) {
+               is_ad_domain = true;
+       } else if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+               is_ad_domain = domain->active_directory;
+       }
+
+       if (is_ad_domain) {
                ADS_STRUCT *ads;
                ADS_STATUS ads_status;
                char addr[INET6_ADDRSTRLEN];
@@ -2201,7 +2212,7 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
        WERROR werr;
        struct netr_DomainTrustList trusts;
        int i;
-       uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
+       uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST |
                        NETR_TRUST_FLAG_OUTBOUND |
                        NETR_TRUST_FLAG_INBOUND);
        struct rpc_pipe_client *cli;
@@ -2672,6 +2683,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        NTSTATUS status, result;
        struct netlogon_creds_cli_context *p_creds;
        struct cli_credentials *creds = NULL;
+       bool retry = false; /* allow one retry attempt for expired session */
 
        if (sid_check_is_our_sam(&domain->sid)) {
                if (domain->rodc == false || need_rw_dc == false) {
@@ -2679,6 +2691,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                }
        }
 
+retry:
        status = init_dc_connection_rpc(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -2722,6 +2735,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                              smbXcli_conn_remote_name(conn->cli->conn),
                                              creds,
                                              &conn->samr_pipe);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
                          "pipe for domain %s using NTLMSSP "
@@ -2742,6 +2763,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                      SEC_FLAG_MAXIMUM_ALLOWED,
                                      &conn->sam_connect_handle,
                                      &result);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->samr_pipe);
+               retry = true;
+               goto retry;
+       }
+
        if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
                goto open_domain;
        }
@@ -2779,6 +2808,13 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                (conn->cli, &ndr_table_samr, NCACN_NP,
                 creds, p_creds, &conn->samr_pipe);
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
                          "domain %s using schannel. Error was %s\n",
@@ -2793,6 +2829,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                      SEC_FLAG_MAXIMUM_ALLOWED,
                                      &conn->sam_connect_handle,
                                      &result);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->samr_pipe);
+               retry = true;
+               goto retry;
+       }
+
        if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
                goto open_domain;
        }
@@ -2819,6 +2863,13 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr,
                                          &conn->samr_pipe);
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -2828,6 +2879,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                                      SEC_FLAG_MAXIMUM_ALLOWED,
                                      &conn->sam_connect_handle,
                                      &result);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->samr_pipe);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
                          "for domain %s Error was %s\n",
@@ -2949,7 +3008,9 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        struct netlogon_creds_cli_context *p_creds;
        struct cli_credentials *creds = NULL;
+       bool retry = false; /* allow one retry attempt for expired session */
 
+retry:
        result = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(result))
                return result;
@@ -2984,6 +3045,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                 smbXcli_conn_remote_name(conn->cli->conn),
                 creds,
                 &conn->lsa_pipe);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        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 "
@@ -3001,6 +3070,13 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
                                        SEC_FLAG_MAXIMUM_ALLOWED,
                                        &conn->lsa_policy);
+       if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->lsa_pipe);
+               retry = true;
+               goto retry;
+       }
+
        if (NT_STATUS_IS_OK(result)) {
                goto done;
        }
@@ -3036,6 +3112,13 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                (conn->cli, &ndr_table_lsarpc, NCACN_NP,
                 creds, p_creds, &conn->lsa_pipe);
 
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
                          "domain %s using schannel. Error was %s\n",
@@ -3048,6 +3131,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
                                        SEC_FLAG_MAXIMUM_ALLOWED,
                                        &conn->lsa_policy);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->lsa_pipe);
+               retry = true;
+               goto retry;
+       }
+
        if (NT_STATUS_IS_OK(result)) {
                goto done;
        }
@@ -3061,7 +3152,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
 
        if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
                result = NT_STATUS_DOWNGRADE_DETECTED;
-               DEBUG(1, ("Unwilling to make LSA connection to domain %s"
+               DEBUG(1, ("Unwilling to make LSA connection to domain %s "
                          "without connection level security, "
                          "must set 'winbind sealed pipes = false' and "
                          "'require strong key = false' to proceed: %s\n",
@@ -3072,6 +3163,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        result = cli_rpc_pipe_open_noauth(conn->cli,
                                          &ndr_table_lsarpc,
                                          &conn->lsa_pipe);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+           && !retry) {
+               invalidate_cm_connection(domain);
+               retry = true;
+               goto retry;
+       }
+
        if (!NT_STATUS_IS_OK(result)) {
                goto done;
        }
@@ -3079,6 +3178,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
                                        SEC_FLAG_MAXIMUM_ALLOWED,
                                        &conn->lsa_policy);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+               invalidate_cm_connection(domain);
+               TALLOC_FREE(conn->lsa_pipe);
+               retry = true;
+               goto retry;
+       }
+
  done:
        if (!NT_STATUS_IS_OK(result)) {
                invalidate_cm_connection(domain);
@@ -3178,7 +3285,6 @@ 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;
-               goto no_schannel;
        }
 
        result = rpccli_create_netlogon_creds_with_creds(creds,
@@ -3217,7 +3323,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
        conn->netlogon_flags = netlogon_creds->negotiate_flags;
        TALLOC_FREE(netlogon_creds);
 
- no_schannel:
        if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
                if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
                        result = NT_STATUS_DOWNGRADE_DETECTED;
@@ -3301,6 +3406,14 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        }
 
        status = cm_connect_netlogon_transport(domain, NCACN_NP, cli);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+               /*
+                * SMB2 session expired, needs reauthentication. Drop
+                * connection and retry.
+                */
+               invalidate_cm_connection(domain);
+               status = cm_connect_netlogon_transport(domain, NCACN_NP, cli);
+       }
 
        return status;
 }