summaryrefslogtreecommitdiff
path: root/source4/nbt_server
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
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')
-rw-r--r--source4/nbt_server/config.mk1
-rw-r--r--source4/nbt_server/wins/winsserver.c226
-rw-r--r--source4/nbt_server/wins/winswack.c212
-rw-r--r--source4/nbt_server/wins/winswack.h37
4 files changed, 265 insertions, 211 deletions
diff --git a/source4/nbt_server/config.mk b/source4/nbt_server/config.mk
index 61d2a7a3d6..ac342840ac 100644
--- a/source4/nbt_server/config.mk
+++ b/source4/nbt_server/config.mk
@@ -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
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:
diff --git a/source4/nbt_server/wins/winswack.c b/source4/nbt_server/wins/winswack.c
index cedd66603f..9e41d14e45 100644
--- a/source4/nbt_server/wins/winswack.c
+++ b/source4/nbt_server/wins/winswack.c
@@ -24,23 +24,10 @@
#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
index 0000000000..42105f08ff
--- /dev/null
+++ b/source4/nbt_server/wins/winswack.h
@@ -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"