summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/structs.h1
-rw-r--r--source4/libcli/nbt/libnbt.h33
-rw-r--r--source4/libcli/nbt/namerefresh.c4
-rw-r--r--source4/libcli/nbt/nameregister.c169
-rw-r--r--source4/libcli/nbt/nbtsocket.c28
-rw-r--r--source4/librpc/idl/nbt.idl14
6 files changed, 228 insertions, 21 deletions
diff --git a/source4/include/structs.h b/source4/include/structs.h
index d8164c9b06..1781ee09ec 100644
--- a/source4/include/structs.h
+++ b/source4/include/structs.h
@@ -159,6 +159,7 @@ struct nbt_name_register;
struct nbt_name_refresh;
struct nbt_name_register_bcast;
struct nbt_name_refresh_wins;
+struct nbt_name_register_wins;
struct messaging_context;
struct stream_connection;
diff --git a/source4/libcli/nbt/libnbt.h b/source4/libcli/nbt/libnbt.h
index c126f59280..63711490fe 100644
--- a/source4/libcli/nbt/libnbt.h
+++ b/source4/libcli/nbt/libnbt.h
@@ -113,7 +113,13 @@ struct nbt_name_socket {
const char *, int );
void *private;
} incoming;
-
+
+ /* what to do with unexpected replies */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ const char *, int );
+ void *private;
+ } unexpected;
};
@@ -161,6 +167,7 @@ struct nbt_name_register {
uint16_t nb_flags;
BOOL register_demand;
BOOL broadcast;
+ BOOL multi_homed;
uint32_t ttl;
int timeout; /* in seconds */
int retries;
@@ -184,9 +191,10 @@ struct nbt_name_register_bcast {
} in;
};
-/* wins name refresh with multiple wins servers to try and multiple
+
+/* wins name register with multiple wins servers to try and multiple
addresses to register */
-struct nbt_name_refresh_wins {
+struct nbt_name_register_wins {
struct {
struct nbt_name name;
const char **wins_servers;
@@ -201,6 +209,7 @@ struct nbt_name_refresh_wins {
};
+
/* a name refresh request */
struct nbt_name_refresh {
struct {
@@ -220,3 +229,21 @@ struct nbt_name_refresh {
uint8_t rcode;
} out;
};
+
+/* wins name refresh with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_refresh_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
diff --git a/source4/libcli/nbt/namerefresh.c b/source4/libcli/nbt/namerefresh.c
index d8dbede727..99d79054a6 100644
--- a/source4/libcli/nbt/namerefresh.c
+++ b/source4/libcli/nbt/namerefresh.c
@@ -141,8 +141,8 @@ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
struct refresh_wins_state {
struct nbt_name_socket *nbtsock;
struct nbt_name_refresh *io;
- char **wins_servers;
- char **addresses;
+ const char **wins_servers;
+ const char **addresses;
int address_idx;
struct nbt_name_request *req;
};
diff --git a/source4/libcli/nbt/nameregister.c b/source4/libcli/nbt/nameregister.c
index 9e9a1e1710..b0ed1ae89c 100644
--- a/source4/libcli/nbt/nameregister.c
+++ b/source4/libcli/nbt/nameregister.c
@@ -40,7 +40,11 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
packet->qdcount = 1;
packet->arcount = 1;
- packet->operation = NBT_OPCODE_REGISTER;
+ if (io->in.multi_homed) {
+ packet->operation = NBT_OPCODE_MULTI_HOME_REG;
+ } else {
+ packet->operation = NBT_OPCODE_REGISTER;
+ }
if (io->in.broadcast) {
packet->operation |= NBT_FLAG_BROADCAST;
}
@@ -221,6 +225,7 @@ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *n
state->io->in.nb_flags = io->in.nb_flags;
state->io->in.register_demand = False;
state->io->in.broadcast = True;
+ state->io->in.multi_homed = False;
state->io->in.ttl = io->in.ttl;
state->io->in.timeout = 1;
state->io->in.retries = 2;
@@ -264,3 +269,165 @@ NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
return nbt_name_register_bcast_recv(c);
}
+
+
+/*
+ a wins name register with multiple WINS servers and multiple
+ addresses to register. Try each WINS server in turn, until we get a
+ reply for each address
+*/
+struct register_wins_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_register *io;
+ const char **wins_servers;
+ const char **addresses;
+ int address_idx;
+ struct nbt_name_request *req;
+};
+
+
+/*
+ state handler for WINS multi-homed multi-server name register
+*/
+static void name_register_wins_handler(struct nbt_name_request *req)
+{
+ struct composite_context *c = talloc_get_type(req->async.private,
+ struct composite_context);
+ struct register_wins_state *state = talloc_get_type(c->private,
+ struct register_wins_state);
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(state->req, state, state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /* the register timed out - try the next WINS server */
+ state->wins_servers++;
+ state->address_idx = 0;
+ if (state->wins_servers[0] == NULL) {
+ c->state = SMBCLI_REQUEST_ERROR;
+ c->status = status;
+ goto done;
+ }
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.address = state->addresses[0];
+ state->req = nbt_name_register_send(state->nbtsock, state->io);
+ if (state->req == NULL) {
+ c->state = SMBCLI_REQUEST_ERROR;
+ c->status = NT_STATUS_NO_MEMORY;
+ } else {
+ state->req->async.fn = name_register_wins_handler;
+ state->req->async.private = c;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ c->state = SMBCLI_REQUEST_ERROR;
+ c->status = status;
+ } else {
+ if (state->io->out.rcode == 0 &&
+ state->addresses[state->address_idx+1] != NULL) {
+ /* register our next address */
+ state->io->in.address = state->addresses[++(state->address_idx)];
+ state->req = nbt_name_register_send(state->nbtsock, state->io);
+ if (state->req == NULL) {
+ c->state = SMBCLI_REQUEST_ERROR;
+ c->status = NT_STATUS_NO_MEMORY;
+ } else {
+ state->req->async.fn = name_register_wins_handler;
+ state->req->async.private = c;
+ }
+ } else {
+ c->state = SMBCLI_REQUEST_DONE;
+ c->status = NT_STATUS_OK;
+ }
+ }
+
+done:
+ if (c->state >= SMBCLI_REQUEST_DONE &&
+ c->async.fn) {
+ c->async.fn(c);
+ }
+}
+
+/*
+ the async send call for a multi-server WINS register
+*/
+struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io)
+{
+ struct composite_context *c;
+ struct register_wins_state *state;
+
+ c = talloc_zero(nbtsock, struct composite_context);
+ if (c == NULL) goto failed;
+
+ state = talloc(c, struct register_wins_state);
+ if (state == NULL) goto failed;
+
+ state->io = talloc(state, struct nbt_name_register);
+ if (state->io == NULL) goto failed;
+
+ state->wins_servers = str_list_copy(state, io->in.wins_servers);
+ if (state->wins_servers == NULL ||
+ state->wins_servers[0] == NULL) goto failed;
+
+ state->addresses = str_list_copy(state, io->in.addresses);
+ if (state->addresses == NULL ||
+ state->addresses[0] == NULL) goto failed;
+
+ state->io->in.name = io->in.name;
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.address = io->in.addresses[0];
+ state->io->in.nb_flags = io->in.nb_flags;
+ state->io->in.broadcast = False;
+ state->io->in.register_demand = False;
+ state->io->in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?False:True;
+ state->io->in.ttl = io->in.ttl;
+ state->io->in.timeout = 3;
+ state->io->in.retries = 2;
+
+ state->nbtsock = nbtsock;
+ state->address_idx = 0;
+
+ state->req = nbt_name_register_send(nbtsock, state->io);
+ if (state->req == NULL) goto failed;
+
+ state->req->async.fn = name_register_wins_handler;
+ state->req->async.private = c;
+
+ c->private = state;
+ c->state = SMBCLI_REQUEST_SEND;
+ c->event_ctx = nbtsock->event_ctx;
+
+ return c;
+
+failed:
+ talloc_free(c);
+ return NULL;
+}
+
+/*
+ multi-homed WINS name register - recv side
+*/
+NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ NTSTATUS status;
+ status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct register_wins_state *state =
+ talloc_get_type(c->private, struct register_wins_state);
+ io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]);
+ io->out.rcode = state->io->out.rcode;
+ }
+ talloc_free(c);
+ return status;
+}
+
+/*
+ multi-homed WINS register - sync interface
+*/
+NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ struct composite_context *c = nbt_name_register_wins_send(nbtsock, io);
+ return nbt_name_register_wins_recv(c, mem_ctx, io);
+}
diff --git a/source4/libcli/nbt/nbtsocket.c b/source4/libcli/nbt/nbtsocket.c
index 38b356338c..c771d3b4f5 100644
--- a/source4/libcli/nbt/nbtsocket.c
+++ b/source4/libcli/nbt/nbtsocket.c
@@ -82,10 +82,10 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
}
DLIST_REMOVE(nbtsock->send_queue, req);
+ req->state = NBT_REQUEST_WAIT;
if (req->is_reply) {
talloc_free(req);
} else {
- req->state = NBT_REQUEST_WAIT;
EVENT_FD_READABLE(nbtsock->fde);
nbtsock->num_pending++;
}
@@ -122,7 +122,11 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event
req->te = event_add_timed(req->nbtsock->event_ctx, req,
timeval_add(&t, req->timeout, 0),
nbt_name_socket_timeout, req);
- DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
+ if (req->state != NBT_REQUEST_SEND) {
+ req->state = NBT_REQUEST_SEND;
+ DLIST_ADD_END(req->nbtsock->send_queue, req,
+ struct nbt_name_request *);
+ }
EVENT_FD_WRITEABLE(req->nbtsock->fde);
return;
}
@@ -206,8 +210,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
/* find the matching request */
req = idr_find(nbtsock->idr, packet->name_trn_id);
if (req == NULL) {
- DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
- packet->name_trn_id));
+ if (nbtsock->unexpected.handler) {
+ nbtsock->unexpected.handler(nbtsock, packet, src_addr, src_port);
+ } else {
+ DEBUG(2,("Failed to match request for incoming name packet id 0x%04x on %p\n",
+ packet->name_trn_id, nbtsock));
+ }
talloc_free(tmp_ctx);
return;
}
@@ -227,13 +235,11 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
req->num_retries = 0;
req->received_wack = True;
if (packet->answers[0].ttl != 0) {
- req->timeout = MIN(packet->answers[0].ttl, 20);
+ req->timeout = MIN(packet->answers[0].ttl, 20);
}
- req->te = event_add_timed(req->nbtsock->event_ctx, req,
- timeval_current_ofs(req->timeout, 0),
- nbt_name_socket_timeout, req);
- DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
- EVENT_FD_WRITEABLE(req->nbtsock->fde);
+ req->te = event_add_timed(req->nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
talloc_free(tmp_ctx);
return;
}
@@ -319,6 +325,7 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
nbtsock->send_queue = NULL;
nbtsock->num_pending = 0;
nbtsock->incoming.handler = NULL;
+ nbtsock->unexpected.handler = NULL;
nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock,
socket_get_fd(nbtsock->sock), 0,
@@ -375,6 +382,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
UINT16_MAX);
}
if (id == -1) goto failed;
+
request->name_trn_id = id;
req->name_trn_id = id;
diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl
index 08dde1f018..859cecd593 100644
--- a/source4/librpc/idl/nbt.idl
+++ b/source4/librpc/idl/nbt.idl
@@ -26,11 +26,15 @@ interface nbt
/* the opcodes are in the operation field, masked with
NBT_OPCODE */
- const int NBT_OPCODE_QUERY = (0<<11);
- const int NBT_OPCODE_REGISTER = (5<<11);
- const int NBT_OPCODE_RELEASE = (6<<11);
- const int NBT_OPCODE_WACK = (7<<11);
- const int NBT_OPCODE_REFRESH = (8<<11);
+ typedef enum {
+ NBT_OPCODE_QUERY = (0x0<<11),
+ NBT_OPCODE_REGISTER = (0x5<<11),
+ NBT_OPCODE_RELEASE = (0x6<<11),
+ NBT_OPCODE_WACK = (0x7<<11),
+ NBT_OPCODE_REFRESH = (0x8<<11),
+ NBT_OPCODE_REFRESH2 = (0x9<<11),
+ NBT_OPCODE_MULTI_HOME_REG = (0xf<<11)
+ } nbt_opcode;
/* rcode values */
typedef enum {