summaryrefslogtreecommitdiff
path: root/source4/nbt_server/wins/winsserver.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2005-12-30 12:13:46 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:49:03 -0500
commit805f5d861fe84ff9bc53f974d667434b7d4c60d8 (patch)
tree7f5b91a5bd5e6a36dba28e864a25921d6bbb31ad /source4/nbt_server/wins/winsserver.c
parenta6d0d564597ea793e0a145ff39fafd6a0dfd6c0f (diff)
downloadsamba-805f5d861fe84ff9bc53f974d667434b7d4c60d8.tar.gz
samba-805f5d861fe84ff9bc53f974d667434b7d4c60d8.tar.bz2
samba-805f5d861fe84ff9bc53f974d667434b7d4c60d8.zip
r12606: - fix multihomed registrations
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)
Diffstat (limited to 'source4/nbt_server/wins/winsserver.c')
-rw-r--r--source4/nbt_server/wins/winsserver.c226
1 files changed, 224 insertions, 2 deletions
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index 02b2048f73..a456ed06d5 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -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: