r12606: - fix multihomed registrations
authorStefan Metzmacher <metze@samba.org>
Fri, 30 Dec 2005 12:13:46 +0000 (12:13 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:49:03 +0000 (13:49 -0500)
  always remove the addresses which are no longer valid
- use the wins_challenge_send/recv calls which are also used by the replication
  challenge

metze
(This used to be commit 037b5d9f3661fd7a121d1db0a50dc7743d62a5e1)

source4/nbt_server/config.mk
source4/nbt_server/wins/winsserver.c
source4/nbt_server/wins/winswack.c
source4/nbt_server/wins/winswack.h [new file with mode: 0644]

index 61d2a7a3d60e723a591e5dd5c77f0c457424ec9b..ac342840ace8ed7c8722a396efa7d543c129e04d 100644 (file)
@@ -17,6 +17,7 @@ OBJ_FILES = \
                wins/winsserver.o \
                wins/winsclient.o \
                wins/winswack.o
+PRIVATE_PROTO_HEADER = wins/winswack_proto.h
 REQUIRED_SUBSYSTEMS = \
                LIBCLI_NBT WINSDB
 # End SUBSYSTEM NBTD_WINS
index 02b2048f730a1298af2b57289a14e2386158c95a..a456ed06d5828fd5f4ea9b850a22e2891007aff3 100644 (file)
@@ -24,7 +24,9 @@
 #include "includes.h"
 #include "nbt_server/nbt_server.h"
 #include "nbt_server/wins/winsdb.h"
+#include "nbt_server/wins/winswack.h"
 #include "system/time.h"
+#include "libcli/composite/composite.h"
 #include "smbd/service_task.h"
 
 /*
@@ -163,6 +165,226 @@ static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
        return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
 }
 
+struct wack_state {
+       struct wins_server *winssrv;
+       struct nbt_name_socket *nbtsock;
+       struct nbt_name_packet *request_packet;
+       struct winsdb_record *rec;
+       struct nbt_peer_socket src;
+       const char *reg_address;
+       enum wrepl_name_type new_type;
+       struct wins_challenge_io io;
+       NTSTATUS status;
+};
+
+/*
+  deny a registration request
+*/
+static void wins_wack_deny(struct wack_state *s)
+{
+       nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
+                                    &s->src, NBT_RCODE_ACT);
+       DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
+                nbt_name_string(s, s->rec->name), s->src.addr, s->src.port));
+       talloc_free(s);
+}
+
+/*
+  allow a registration request
+*/
+static void wins_wack_allow(struct wack_state *s)
+{
+       NTSTATUS status;
+       uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
+       struct winsdb_record *rec = s->rec, *rec2;
+       uint32_t i,j;
+
+       status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
+       if (!NT_STATUS_IS_OK(status) ||
+           rec2->version != rec->version ||
+           strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
+               DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
+                        nbt_name_string(s, rec->name)));
+               wins_wack_deny(s);
+               return;
+       }
+
+       /*
+        * if the old name owner doesn't hold the name anymore
+        * handle the request as new registration for the new name owner
+        */
+       if (!NT_STATUS_IS_OK(s->status)) {
+               uint8_t rcode;
+
+               winsdb_delete(s->winssrv->wins_db, rec);
+               rcode = wins_register_new(s->nbtsock, s->request_packet, &s->src, s->new_type);
+               if (rcode != NBT_RCODE_OK) {
+                       DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
+                                nbt_name_string(s, rec->name)));
+                       wins_wack_deny(s);
+                       return;
+               }
+               goto done;
+       }
+
+       rec->expire_time = time(NULL) + ttl;
+       rec->registered_by = s->src.addr;
+
+       /*
+        * now remove all addresses that're the client doesn't hold anymore
+        * and update the time stamp and owner for the ownes that are still there
+        */
+       for (i=0; rec->addresses[i]; i++) {
+               BOOL found = False;
+               for (j=0; j < s->io.out.num_addresses; j++) {
+                       if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
+
+                       found = True;
+                       break;
+               }
+               if (found) {
+                       rec->addresses[i]->wins_owner = WINSDB_OWNER_LOCAL;
+                       rec->addresses[i]->expire_time = rec->expire_time;
+                       continue;
+               }
+
+               winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
+       }
+
+       rec->addresses = winsdb_addr_list_add(rec->addresses,
+                                             s->reg_address,
+                                             WINSDB_OWNER_LOCAL,
+                                             rec->expire_time);
+       if (rec->addresses == NULL) goto failed;
+
+       /* if we have more than one address, this becomes implicit a MHOMED record */
+       if (winsdb_addr_list_length(rec->addresses) > 1) {
+               rec->type = WREPL_TYPE_MHOMED;
+       }
+
+       winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
+
+       DEBUG(4,("WINS: accepted registration of %s with address %s\n",
+                nbt_name_string(s, rec->name), s->reg_address));
+
+done:
+       nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
+                                    &s->src, NBT_RCODE_OK);
+failed:
+       talloc_free(s);
+}
+
+/*
+  called when a name query to a current owner completes
+*/
+static void wack_wins_challenge_handler(struct composite_context *c_req)
+{
+       struct wack_state *s = talloc_get_type(c_req->async.private_data,
+                                              struct wack_state);
+       BOOL found;
+       uint32_t i;
+
+       s->status = wins_challenge_recv(c_req, s, &s->io);
+
+       /*
+        * if the owner denies it holds the name, then allow
+        * the registration
+        */
+       if (!NT_STATUS_IS_OK(s->status)) {
+               wins_wack_allow(s);
+               return;
+       }
+
+       if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
+               DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
+                        nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
+               wins_wack_deny(s);
+               return;
+       }
+
+       /*
+        * if the owner still wants the name and doesn't reply
+        * with the address trying to be registered, then deny
+        * the registration
+        */
+       found = False;
+       for (i=0; i < s->io.out.num_addresses; i++) {
+               if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
+
+               found = True;
+               break;
+       }
+       if (!found) {
+               wins_wack_deny(s);
+               return;
+       }
+
+       wins_wack_allow(s);
+       return;
+}
+
+
+/*
+  a client has asked to register a unique name that someone else owns. We
+  need to ask each of the current owners if they still want it. If they do
+  then reject the registration, otherwise allow it
+*/
+static void wins_register_wack(struct nbt_name_socket *nbtsock, 
+                              struct nbt_name_packet *packet, 
+                              struct winsdb_record *rec,
+                              const struct nbt_peer_socket *src,
+                              enum wrepl_name_type new_type)
+{
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       struct wack_state *s;
+       struct composite_context *c_req;
+       uint32_t ttl;
+
+       s = talloc_zero(nbtsock, struct wack_state);
+       if (s == NULL) goto failed;
+
+       /* package up the state variables for this wack request */
+       s->winssrv              = winssrv;
+       s->nbtsock              = nbtsock;
+       s->request_packet       = talloc_steal(s, packet);
+       s->rec                  = talloc_steal(s, rec);
+       s->reg_address          = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
+       s->new_type             = new_type;
+       s->src.port             = src->port;
+       s->src.addr             = talloc_strdup(s, src->addr);
+       if (s->src.addr == NULL) goto failed;
+
+       s->io.in.nbtd_server    = iface->nbtsrv;
+       s->io.in.event_ctx      = iface->nbtsrv->task->event_ctx;
+       s->io.in.name           = rec->name;
+       s->io.in.num_addresses  = winsdb_addr_list_length(rec->addresses);
+       s->io.in.addresses      = winsdb_addr_string_list(s, rec->addresses);
+       if (s->io.in.addresses == NULL) goto failed;
+
+       /*
+        * send a WACK to the client, specifying the maximum time it could
+         * take to check with the owner, plus some slack
+        */
+       ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
+       nbtd_wack_reply(nbtsock, packet, src, ttl);
+
+       /*
+        * send the challenge to the old addresses
+        */
+       c_req = wins_challenge_send(s, &s->io);
+       if (c_req == NULL) goto failed;
+
+       c_req->async.fn                 = wack_wins_challenge_handler;
+       c_req->async.private_data       = s;
+       return;
+
+failed:
+       talloc_free(s);
+       nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
+}
+
 /*
   register a name
 */
@@ -263,7 +485,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
                 * TODO: is this correct?
                 */
                if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
-                       wins_register_wack(nbtsock, packet, rec, src);
+                       wins_register_wack(nbtsock, packet, rec, src, new_type);
                        return;
                }
 
@@ -282,7 +504,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
                 * we have to do a WACK to see if the current owner is willing
                 * to give up its claim
                 */
-               wins_register_wack(nbtsock, packet, rec, src);
+               wins_register_wack(nbtsock, packet, rec, src, new_type);
                return;
 
        case WREPL_TYPE_GROUP:
index cedd66603f51887a234b420865043f56d5731eb5..9e41d14e45c76eb486a2f3ead27f4e8c20de42e4 100644 (file)
 #include "includes.h"
 #include "nbt_server/nbt_server.h"
 #include "nbt_server/wins/winsdb.h"
+#include "nbt_server/wins/winswack.h"
 #include "system/time.h"
 #include "libcli/composite/composite.h"
 
-struct wins_challenge_io {
-       struct {
-               struct nbtd_server *nbtd_server;
-               struct event_context *event_ctx;
-               struct nbt_name *name;
-               uint32_t num_addresses;
-               const char **addresses;
-       } in;
-       struct {
-               uint32_t num_addresses;
-               const char **addresses;
-       } out;
-};
-
 struct wins_challenge_state {
        struct wins_challenge_io *io;
        uint32_t current_address;
@@ -78,7 +65,7 @@ static void wins_challenge_handler(struct nbt_name_request *req)
        composite_done(ctx);
 }
 
-static NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
+NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
 {
        NTSTATUS status = ctx->status;
        struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
@@ -95,7 +82,7 @@ static NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *m
        return status;
 }
 
-static struct composite_context *wins_challenge_send(TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
+struct composite_context *wins_challenge_send(TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
 {
        struct composite_context *result;
        struct wins_challenge_state *state;
@@ -256,199 +243,6 @@ failed:
        return NULL;
 }
 
-struct wack_state {
-       struct wins_server *winssrv;
-       struct nbt_name_socket *nbtsock;
-       struct nbt_name_packet *request_packet;
-       struct winsdb_record *rec;
-       struct nbt_peer_socket src;
-       const char **owner_addresses;
-       const char *reg_address;
-       struct nbt_name_query query;
-};
-
-
-/*
-  deny a registration request
-*/
-static void wins_wack_deny(struct wack_state *state)
-{
-       nbtd_name_registration_reply(state->nbtsock, state->request_packet, 
-                                    &state->src, NBT_RCODE_ACT);
-       DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
-                nbt_name_string(state, state->rec->name), state->src.addr, state->src.port));
-       talloc_free(state);
-}
-
-/*
-  allow a registration request
-*/
-static void wins_wack_allow(struct wack_state *state)
-{
-       NTSTATUS status;
-       uint32_t ttl = wins_server_ttl(state->winssrv, state->request_packet->additional[0].ttl);
-       struct winsdb_record *rec = state->rec, *rec2;
-
-       status = winsdb_lookup(state->winssrv->wins_db, rec->name, state, &rec2);
-       if (!NT_STATUS_IS_OK(status)
-           || rec2->version != rec->version
-           || strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
-               DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
-                        nbt_name_string(state, rec->name)));
-               wins_wack_deny(state);
-               return;
-       }
-
-       nbtd_name_registration_reply(state->nbtsock, state->request_packet, 
-                                    &state->src, NBT_RCODE_OK);
-
-       rec->expire_time = time(NULL) + ttl;
-       rec->registered_by = state->src.addr;
-
-       /* TODO: is it correct to only add this address? */
-       rec->addresses = winsdb_addr_list_add(rec->addresses,
-                                             state->reg_address,
-                                             WINSDB_OWNER_LOCAL,
-                                             rec->expire_time);
-       if (rec->addresses == NULL) goto failed;
-
-       /* if we have more than one address, this becomes implicit a MHOMED record */
-       if (winsdb_addr_list_length(rec->addresses) > 1) {
-               rec->type = WREPL_TYPE_MHOMED;
-       }
-
-       winsdb_modify(state->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
-
-       DEBUG(4,("WINS: accepted registration of %s with address %s\n",
-                nbt_name_string(state, rec->name), state->reg_address));
-
-failed:
-       talloc_free(state);
-}
-
-/*
-  called when a name query to a current owner completes
-*/
-static void wins_wack_handler(struct nbt_name_request *req)
-{
-       struct wack_state *state = talloc_get_type(req->async.private, struct wack_state);
-       NTSTATUS status;
-       int i;
-       struct winsdb_record *rec = state->rec;
-
-       status = nbt_name_query_recv(req, state, &state->query);
-
-       /* if we timed out then try the next owner address, if any */
-       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               state->owner_addresses++;
-               if (state->owner_addresses[0] == NULL) {
-                       wins_wack_allow(state);
-                       return;
-               }
-               state->query.in.dest_addr = state->owner_addresses[0];
-
-               req = nbt_name_query_send(state->nbtsock, &state->query);
-               if (req == NULL) goto failed;
-
-               req->async.fn = wins_wack_handler;
-               req->async.private = state;
-               return;
-       }
-
-       /* if the owner denies it holds the name, then allow
-          the registration */
-       if (!NT_STATUS_IS_OK(status)) {
-               wins_wack_allow(state);
-               return;
-       }
-
-       /* if the owner still wants the name and doesn't reply
-          with the address trying to be registered, then deny
-          the registration */
-       if (!str_list_check(state->query.out.reply_addrs, state->reg_address)) {
-               wins_wack_deny(state);
-               return;
-       }
-
-       /* we are going to allow the registration, but first remove any addresses
-          from the record that aren't in the reply from the client */
-       for (i=0; state->query.out.reply_addrs[i]; i++) {
-               if (!winsdb_addr_list_check(rec->addresses, state->query.out.reply_addrs[i])) {
-                       winsdb_addr_list_remove(rec->addresses, state->query.out.reply_addrs[i]);
-               }
-       }
-
-       wins_wack_allow(state);
-       return;
-
-failed:
-       talloc_free(state);
-}
-
-
-/*
-  a client has asked to register a unique name that someone else owns. We
-  need to ask each of the current owners if they still want it. If they do
-  then reject the registration, otherwise allow it
-*/
-void wins_register_wack(struct nbt_name_socket *nbtsock, 
-                       struct nbt_name_packet *packet, 
-                       struct winsdb_record *rec,
-                       const struct nbt_peer_socket *src)
-{
-       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
-                                                      struct nbtd_interface);
-       struct wins_server *winssrv = iface->nbtsrv->winssrv;
-       struct wack_state *state;
-       struct nbt_name_request *req;
-       uint32_t ttl;
-
-       state = talloc(nbtsock, struct wack_state);
-       if (state == NULL) goto failed;
-
-       /* package up the state variables for this wack request */
-       state->winssrv         = winssrv;
-       state->nbtsock         = nbtsock;
-       state->request_packet  = talloc_steal(state, packet);
-       state->rec             = talloc_steal(state, rec);
-       state->owner_addresses = winsdb_addr_string_list(state, rec->addresses);
-       if (state->owner_addresses == NULL) goto failed;
-       state->reg_address     = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
-       state->src.port        = src->port;
-       state->src.addr        = talloc_strdup(state, src->addr);
-       if (state->src.addr == NULL) goto failed;
-
-       /* setup a name query to the first address */
-       state->query.in.name        = *rec->name;
-       state->query.in.dest_addr   = state->owner_addresses[0];
-       state->query.in.broadcast   = False;
-       state->query.in.wins_lookup = True;
-       state->query.in.timeout     = 1;
-       state->query.in.retries     = 2;
-
-       /* the LOGON type is a nasty hack */
-       if (rec->name->type == NBT_NAME_LOGON) {
-               wins_wack_allow(state);
-               return;
-       }
-
-       /* send a WACK to the client, specifying the maximum time it could
-          take to check with the owner, plus some slack */
-       ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
-       nbtd_wack_reply(nbtsock, packet, src, ttl);
-
-       req = nbt_name_query_send(nbtsock, &state->query);
-       if (req == NULL) goto failed;
-
-       req->async.fn = wins_wack_handler;
-       req->async.private = state;
-       return; 
-
-failed:
-       talloc_free(state);
-       nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
-}
-
 /*
   wrepl_server needs to be able to do a name query request, but some windows
   servers always send the reply to port 137, regardless of the request
diff --git a/source4/nbt_server/wins/winswack.h b/source4/nbt_server/wins/winswack.h
new file mode 100644 (file)
index 0000000..42105f0
--- /dev/null
@@ -0,0 +1,37 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   wins server WACK processing
+
+   Copyright (C) Stefan Metzmacher     2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct wins_challenge_io {
+       struct {
+               struct nbtd_server *nbtd_server;
+               struct event_context *event_ctx;
+               struct nbt_name *name;
+               uint32_t num_addresses;
+               const char **addresses;
+       } in;
+       struct {
+               uint32_t num_addresses;
+               const char **addresses;
+       } out;
+};
+
+#include "nbt_server/wins/winswack_proto.h"