s3: Add "smbcontrol winbindd ip-dropped <local-ip>"
[metze/samba/wip.git] / source3 / winbindd / winbindd_cm.c
index 32afe40cae61ccfbf97081bb329d5ef342173634..ece68f1a1d3f55f0fbf16649792883e83ce2d8d9 100644 (file)
@@ -174,9 +174,6 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
        pid_t parent_pid = sys_getpid();
        char *lfile = NULL;
 
-       /* Stop zombies */
-       CatchChild();
-
        if (domain->dc_probe_pid != (pid_t)-1) {
                /*
                 * We might already have a DC probe
@@ -1592,21 +1589,11 @@ void close_conns_after_fork(void)
 
 static bool connection_ok(struct winbindd_domain *domain)
 {
-       if (domain->conn.cli == NULL) {
-               DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
-                         "cli!\n", domain->dcname, domain->name));
-               return False;
-       }
+       bool ok;
 
-       if (!domain->conn.cli->initialised) {
-               DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
-                         "initialised!\n", domain->dcname, domain->name));
-               return False;
-       }
-
-       if (domain->conn.cli->fd == -1) {
-               DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
-                         "never started (fd == -1)\n", 
+       ok = cli_state_is_connected(domain->conn.cli);
+       if (!ok) {
+               DEBUG(3, ("connection_ok: Connection to %s for domain %s is not connected\n",
                          domain->dcname, domain->name));
                return False;
        }
@@ -1632,6 +1619,12 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
                return NT_STATUS_OK;
        }
 
+       if (!winbindd_can_contact_domain(domain)) {
+               invalidate_cm_connection(&domain->conn);
+               domain->initialized = True;
+               return NT_STATUS_OK;
+       }
+
        if (connection_ok(domain)) {
                if (!domain->initialized) {
                        set_dc_type_and_flags(domain);
@@ -1660,6 +1653,23 @@ NTSTATUS init_dc_connection(struct winbindd_domain *domain)
        return init_dc_connection_network(domain);
 }
 
+static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain)
+{
+       NTSTATUS status;
+
+       status = init_dc_connection(domain);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (!domain->internal && domain->conn.cli == NULL) {
+               /* happens for trusted domains without inbound trust */
+               return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+       }
+
+       return NT_STATUS_OK;
+}
+
 /******************************************************************************
  Set the trust flags (direction and forest location) for a domain
 ******************************************************************************/
@@ -1755,9 +1765,6 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
 
                        domain->initialized = True;
 
-                       if ( !winbindd_can_contact_domain( domain) )
-                               domain->internal = True;
-
                        break;
                }               
        }
@@ -2009,17 +2016,18 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        char *machine_account = NULL;
        char *domain_name = NULL;
 
-       result = init_dc_connection(domain);
+       result = init_dc_connection_rpc(domain);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
        }
 
        conn = &domain->conn;
 
-       if (conn->samr_pipe != NULL) {
+       if (rpccli_is_connected(conn->samr_pipe)) {
                goto done;
        }
 
+       TALLOC_FREE(conn->samr_pipe);
 
        /*
         * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
@@ -2191,7 +2199,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
        DEBUG(10,("cm_connect_lsa_tcp\n"));
 
-       status = init_dc_connection(domain);
+       status = init_dc_connection_rpc(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2200,7 +2208,8 @@ 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 == PIPE_AUTH_LEVEL_PRIVACY) {
+           conn->lsa_pipe_tcp->auth->auth_level == PIPE_AUTH_LEVEL_PRIVACY &&
+           rpccli_is_connected(conn->lsa_pipe_tcp)) {
                goto done;
        }
 
@@ -2236,16 +2245,18 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        struct dcinfo *p_dcinfo;
 
-       result = init_dc_connection(domain);
+       result = init_dc_connection_rpc(domain);
        if (!NT_STATUS_IS_OK(result))
                return result;
 
        conn = &domain->conn;
 
-       if (conn->lsa_pipe != NULL) {
+       if (rpccli_is_connected(conn->lsa_pipe)) {
                goto done;
        }
 
+       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')) {
@@ -2366,18 +2377,20 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
 
        *cli = NULL;
 
-       result = init_dc_connection(domain);
+       result = init_dc_connection_rpc(domain);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
        }
 
        conn = &domain->conn;
 
-       if (conn->netlogon_pipe != NULL) {
+       if (rpccli_is_connected(conn->netlogon_pipe)) {
                *cli = conn->netlogon_pipe;
                return NT_STATUS_OK;
        }
 
+       TALLOC_FREE(conn->netlogon_pipe);
+
        result = cli_rpc_pipe_open_noauth(conn->cli,
                                          &ndr_table_netlogon.syntax_id,
                                          &netlogon_pipe);
@@ -2456,15 +2469,72 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
                          "was %s\n", nt_errstr(result)));
 
-               /* make sure we return something besides OK */
-               return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
+               invalidate_cm_connection(conn);
+               return result;
        }
 
        /*
-        * Try NetSamLogonEx for AD domains
+        * 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 = domain->active_directory;
+       domain->can_do_samlogon_ex = true;
 
        *cli = conn->netlogon_pipe;
        return NT_STATUS_OK;
 }
+
+void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
+                           void *private_data,
+                           uint32_t msg_type,
+                           struct server_id server_id,
+                           DATA_BLOB *data)
+{
+       struct winbindd_domain *domain;
+
+       if ((data == NULL)
+           || (data->data == NULL)
+           || (data->length == 0)
+           || (data->data[data->length-1] != '\0')
+           || !is_ipaddress((char *)data->data)) {
+               DEBUG(1, ("invalid msg_ip_dropped message\n"));
+               return;
+       }
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
+               char sockaddr[INET6_ADDRSTRLEN];
+               if (domain->conn.cli == NULL) {
+                       continue;
+               }
+               if (domain->conn.cli->fd == -1) {
+                       continue;
+               }
+               client_socket_addr(domain->conn.cli->fd, sockaddr,
+                                  sizeof(sockaddr));
+               if (strequal(sockaddr, (char *)data->data)) {
+                       close(domain->conn.cli->fd);
+                       domain->conn.cli->fd = -1;
+               }
+       }
+}
+
+extern struct winbindd_child *children;
+
+void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
+                                  void *private_data,
+                                  uint32_t msg_type,
+                                  struct server_id server_id,
+                                  DATA_BLOB *data)
+{
+       struct winbindd_child *child;
+
+       winbind_msg_ip_dropped(msg_ctx, private_data, msg_type,
+                              server_id, data);
+
+
+       for (child = children; child != NULL; child = child->next) {
+               messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+                                  msg_type, data->data, data->length);
+       }
+}