Fix value overflow (one too many 'f's ).
[obnox/samba-ctdb.git] / source3 / winbindd / winbindd_cm.c
index 5a6f9e2f6b951f633466e649f6003977685aff7a..d76fce7a51fe1d4b1d73735165b4cd053ec079fd 100644 (file)
@@ -1380,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, 0x7fffffff);
+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)
 {
@@ -1480,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);
@@ -2461,15 +2554,42 @@ void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
                            DATA_BLOB *data)
 {
        struct winbindd_domain *domain;
+       char *freeit = NULL;
+       char *addr;
 
        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"));
+           || (data->data[data->length-1] != '\0')) {
+               DEBUG(1, ("invalid msg_ip_dropped message: not a valid "
+                         "string\n"));
                return;
        }
+
+       addr = (char *)data->data;
+       DEBUG(10, ("IP %s dropped\n", addr));
+
+       if (!is_ipaddress(addr)) {
+               char *slash;
+               /*
+                * Some code sends us ip addresses with the /netmask
+                * suffix
+                */
+               slash = strchr(addr, '/');
+               if (slash == NULL) {
+                       DEBUG(1, ("invalid msg_ip_dropped message: %s",
+                                 addr));
+                       return;
+               }
+               freeit = talloc_strndup(talloc_tos(), addr, slash-addr);
+               if (freeit == NULL) {
+                       DEBUG(1, ("talloc failed\n"));
+                       return;
+               }
+               addr = freeit;
+               DEBUG(10, ("Stripped /netmask to IP %s\n", addr));
+       }
+
        for (domain = domain_list(); domain != NULL; domain = domain->next) {
                char sockaddr[INET6_ADDRSTRLEN];
                if (domain->conn.cli == NULL) {
@@ -2480,11 +2600,12 @@ void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
                }
                client_socket_addr(domain->conn.cli->fd, sockaddr,
                                   sizeof(sockaddr));
-               if (strequal(sockaddr, (char *)data->data)) {
+               if (strequal(sockaddr, addr)) {
                        close(domain->conn.cli->fd);
                        domain->conn.cli->fd = -1;
                }
        }
+       TALLOC_FREE(freeit);
 }
 
 extern struct winbindd_child *children;