s3: Add wbinfo --dc-info
[obnox/samba-ctdb.git] / source3 / winbindd / winbindd_cm.c
index e3a0b59934451fca09dd19b1d100e19b725ee742..8c77adf854bef01ce45c80f3c3142440b3e645ff 100644 (file)
@@ -803,21 +803,6 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
                goto done;
        }
 
-       if (ntohs(peeraddr_in->sin_port) == 139) {
-               struct nmb_name calling;
-               struct nmb_name called;
-
-               make_nmb_name(&calling, global_myname(), 0x0);
-               make_nmb_name(&called, "*SMBSERVER", 0x20);
-
-               if (!cli_session_request(*cli, &calling, &called)) {
-                       DEBUG(8, ("cli_session_request failed for %s\n",
-                                 controller));
-                       result = NT_STATUS_UNSUCCESSFUL;
-                       goto done;
-               }
-       }
-
        result = cli_negprot(*cli);
 
        if (!NT_STATUS_IS_OK(result)) {
@@ -1318,7 +1303,10 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        struct sockaddr_storage *addrs = NULL;
        int num_addrs = 0;
 
-       int i, fd_index;
+       int i;
+       size_t fd_index;
+
+       NTSTATUS status;
 
        *fd = -1;
 
@@ -1336,15 +1324,6 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
                                      &addrs, &num_addrs)) {
                        return False;
                }
-
-               if (!add_string_to_array(mem_ctx, dcs[i].name,
-                                   &dcnames, &num_dcnames)) {
-                       return False;
-               }
-               if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 139,
-                                     &addrs, &num_addrs)) {
-                       return False;
-               }
        }
 
        if ((num_dcnames == 0) || (num_dcnames != num_addrs))
@@ -1353,14 +1332,15 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        if ((addrs == NULL) || (dcnames == NULL))
                return False;
 
-       /* 5 second timeout. */
-       if (!open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) {
+       status = smbsock_any_connect(addrs, dcnames, num_addrs,
+                                    fd, &fd_index, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
                for (i=0; i<num_dcs; i++) {
                        char ab[INET6_ADDRSTRLEN];
                        print_sockaddr(ab, sizeof(ab), &dcs[i].ss);
-                       DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
+                       DEBUG(10, ("find_new_dc: smbsock_any_connect failed for "
                                "domain %s address %s. Error was %s\n",
-                               domain->name, ab, strerror(errno) ));
+                                  domain->name, ab, nt_errstr(status) ));
                        winbind_add_failed_connection_entry(domain,
                                dcs[i].name, NT_STATUS_UNSUCCESSFUL);
                }
@@ -1400,6 +1380,88 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
        goto again;
 }
 
+static char *current_dc_key(TALLOC_CTX *mem_ctx, const char *domain_name)
+{
+       return talloc_asprintf_strupper_m(mem_ctx, "CURRENT_DCNAME/%s",
+                                         domain_name);
+}
+
+static void store_current_dc_in_gencache(const char *domain_name,
+                                        const char *dc_name,
+                                        struct cli_state *cli)
+{
+       char addr[INET6_ADDRSTRLEN];
+       char *key, *value;
+
+       if (cli == NULL) {
+               return;
+       }
+       if (cli->fd == -1) {
+               return;
+       }
+       get_peer_addr(cli->fd, addr, sizeof(addr));
+
+       key = current_dc_key(talloc_tos(), domain_name);
+       if (key == NULL) {
+               goto done;
+       }
+
+       value = talloc_asprintf(talloc_tos(), "%s %s", addr, dc_name);
+       if (value == NULL) {
+               goto done;
+       }
+
+       gencache_set(key, value, 0x7ffffffff);
+done:
+       TALLOC_FREE(value);
+       TALLOC_FREE(key);
+}
+
+bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx,
+                                   const char *domain_name,
+                                   char **p_dc_name, char **p_dc_ip)
+{
+       char *key, *value, *p;
+       bool ret = false;
+       char *dc_name = NULL;
+       char *dc_ip = NULL;
+
+       key = current_dc_key(talloc_tos(), domain_name);
+       if (key == NULL) {
+               goto done;
+       }
+       if (!gencache_get(key, &value, NULL)) {
+               goto done;
+       }
+       p = strchr(value, ' ');
+       if (p == NULL) {
+               goto done;
+       }
+       dc_ip = talloc_strndup(mem_ctx, value, p - value);
+       if (dc_ip == NULL) {
+               goto done;
+       }
+       dc_name = talloc_strdup(mem_ctx, p+1);
+       if (dc_name == NULL) {
+               goto done;
+       }
+
+       if (p_dc_ip != NULL) {
+               *p_dc_ip = dc_ip;
+               dc_ip = NULL;
+       }
+       if (p_dc_name != NULL) {
+               *p_dc_name = dc_name;
+               dc_name = NULL;
+       }
+       ret = true;
+done:
+       TALLOC_FREE(dc_name);
+       TALLOC_FREE(dc_ip);
+       TALLOC_FREE(key);
+       return ret;
+}
+
 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                                   struct winbindd_cm_conn *new_conn)
 {
@@ -1462,23 +1524,11 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                        && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
                        && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
                {
-                       struct sockaddr_storage *addrs = NULL;
-                       int num_addrs = 0;
-                       int dummy = 0;
-
-                       if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 445, &addrs, &num_addrs)) {
-                               set_domain_offline(domain);
-                               talloc_destroy(mem_ctx);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-                       if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 139, &addrs, &num_addrs)) {
-                               set_domain_offline(domain);
-                               talloc_destroy(mem_ctx);
-                               return NT_STATUS_NO_MEMORY;
-                       }
+                       NTSTATUS status;
 
-                       /* 5 second timeout. */
-                       if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
+                       status = smbsock_connect(&domain->dcaddr, NULL, NULL,
+                                                &fd, NULL);
+                       if (!NT_STATUS_IS_OK(status)) {
                                fd = -1;
                        }
                }
@@ -1512,6 +1562,17 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
                        set_global_winbindd_state_online();
                }
                set_domain_online(domain);
+
+               /*
+                * Much as I hate global state, this seems to be the point
+                * where we can be certain that we have a proper connection to
+                * a DC. wbinfo --dc-info needs that information, store it in
+                * gencache with a looong timeout. This will need revisiting
+                * once we start to connect to multiple DCs, wbcDcInfo is
+                * already prepared for that.
+                */
+               store_current_dc_in_gencache(domain->name, domain->dcname,
+                                            new_conn->cli);
        } else {
                /* Ensure we setup the retry handler. */
                set_domain_offline(domain);
@@ -2485,3 +2546,56 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
        *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);
+       }
+}