r23792: convert Samba4 to GPLv3
[samba.git] / source4 / libcli / nbt / nameregister.c
index 4701d0c1bcdc7a843e6cc2331fc9c2dc8a395749..7b03667fec7fc55756e807a267c0d104b6889881 100644 (file)
@@ -7,7 +7,7 @@
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "libcli/nbt/libnbt.h"
-#include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
-#include "system/network.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
 
 /*
   send a nbt name registration request
@@ -34,13 +33,18 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
 {
        struct nbt_name_request *req;
        struct nbt_name_packet *packet;
+       struct socket_address *dest;
 
        packet = talloc_zero(nbtsock, struct nbt_name_packet);
        if (packet == NULL) return NULL;
 
        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;
        }
@@ -70,9 +74,12 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
        packet->additional[0].rdata.netbios.addresses[0].ipaddr = 
                talloc_strdup(packet->additional, io->in.address);
        if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
-       
-       req = nbt_name_request_send(nbtsock, io->in.dest_addr, lp_nbt_port(), packet,
-                                   timeval_current_ofs(io->in.timeout, 0), False);
+
+       dest = socket_address_from_strings(packet, nbtsock->sock->backend_name, 
+                                          io->in.dest_addr, lp_nbt_port());
+       if (dest == NULL) goto failed;
+       req = nbt_name_request_send(nbtsock, dest, packet,
+                                   io->in.timeout, io->in.retries, False);
        if (req == NULL) goto failed;
 
        talloc_free(packet);
@@ -100,7 +107,7 @@ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
        }
        
        packet = req->replies[0].packet;
-       io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].reply_addr);
+       io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
 
        if (packet->ancount != 1 ||
            packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
@@ -143,7 +150,6 @@ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
 struct register_bcast_state {
        struct nbt_name_socket *nbtsock;
        struct nbt_name_register *io;
-       int num_sends;
        struct nbt_name_request *req;
 };
 
@@ -151,49 +157,47 @@ struct register_bcast_state {
 /*
   state handler for 4 stage name registration
 */
-static void name_register_handler(struct nbt_name_request *req)
+static void name_register_bcast_handler(struct nbt_name_request *req)
 {
        struct composite_context *c = talloc_get_type(req->async.private, struct composite_context);
-       struct register_bcast_state *state = talloc_get_type(c->private, struct register_bcast_state);
+       struct register_bcast_state *state = talloc_get_type(c->private_data, struct register_bcast_state);
        NTSTATUS status;
 
        status = nbt_name_register_recv(state->req, state, state->io);
        if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               /* the registration timed out - good, send the next one */
-               state->num_sends++;
-               if (state->num_sends == 4) {
+               if (state->io->in.register_demand == True) {
                        /* all done */
-                       c->state = SMBCLI_REQUEST_DONE;
+                       c->state = COMPOSITE_STATE_DONE;
                        c->status = NT_STATUS_OK;
                        goto done;
                }
-               if (state->num_sends == 3) {
-                       state->io->in.register_demand = True;
-               }
+
+               /* the registration timed out - good, send the demand */
+               state->io->in.register_demand = True;
+               state->io->in.retries         = 0;
                state->req = nbt_name_register_send(state->nbtsock, state->io);
                if (state->req == NULL) {
-                       c->state = SMBCLI_REQUEST_ERROR;
+                       c->state = COMPOSITE_STATE_ERROR;
                        c->status = NT_STATUS_NO_MEMORY;
                } else {
-                       state->req->async.fn      = name_register_handler;
+                       state->req->async.fn      = name_register_bcast_handler;
                        state->req->async.private = c;
                }
        } else if (!NT_STATUS_IS_OK(status)) {
-               c->state = SMBCLI_REQUEST_ERROR;
+               c->state = COMPOSITE_STATE_ERROR;
                c->status = status;
        } else {
-               c->state = SMBCLI_REQUEST_ERROR;
+               c->state = COMPOSITE_STATE_ERROR;
                c->status = NT_STATUS_CONFLICTING_ADDRESSES;
-               DEBUG(3,("Name registration conflict from %s for %s<%02x> with ip %s - rcode %d\n",
+               DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
                         state->io->out.reply_from, 
-                        state->io->out.name.name,
-                        state->io->out.name.type,
+                        nbt_name_string(state, &state->io->out.name),
                         state->io->out.reply_addr,
                         state->io->out.rcode));
        }
 
 done:
-       if (c->state >= SMBCLI_REQUEST_DONE &&
+       if (c->state >= COMPOSITE_STATE_DONE &&
            c->async.fn) {
                c->async.fn(c);
        }
@@ -203,7 +207,7 @@ done:
   the async send call for a 4 stage name registration
 */
 struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock,
-                                                     struct nbt_name_register_bcast *io)
+                                                      struct nbt_name_register_bcast *io)
 {
        struct composite_context *c;
        struct register_bcast_state *state;
@@ -223,21 +227,22 @@ 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;
 
-       state->num_sends = 0;
        state->nbtsock = nbtsock;
 
        state->req = nbt_name_register_send(nbtsock, state->io);
        if (state->req == NULL) goto failed;
 
-       state->req->async.fn      = name_register_handler;
+       state->req->async.fn      = name_register_bcast_handler;
        state->req->async.private = c;
 
-       c->private   = state;
-       c->state     = SMBCLI_REQUEST_SEND;
-       c->event_ctx = nbtsock->event_ctx;
+       c->private_data = state;
+       c->state        = COMPOSITE_STATE_IN_PROGRESS;
+       c->event_ctx    = nbtsock->event_ctx;
 
        return c;
 
@@ -266,3 +271,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_data, 
+                                                           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 = COMPOSITE_STATE_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 = COMPOSITE_STATE_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 = COMPOSITE_STATE_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 = COMPOSITE_STATE_ERROR;
+                               c->status = NT_STATUS_NO_MEMORY;
+                       } else {
+                               state->req->async.fn      = name_register_wins_handler;
+                               state->req->async.private = c;
+                       }
+               } else {
+                       c->state = COMPOSITE_STATE_DONE;
+                       c->status = NT_STATUS_OK;
+               }
+       }
+
+done:
+       if (c->state >= COMPOSITE_STATE_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_data = state;
+       c->state        = COMPOSITE_STATE_IN_PROGRESS;
+       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_data, 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);
+}