diff options
author | Stefan Metzmacher <metze@samba.org> | 2005-12-30 12:13:46 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:49:03 -0500 |
commit | 805f5d861fe84ff9bc53f974d667434b7d4c60d8 (patch) | |
tree | 7f5b91a5bd5e6a36dba28e864a25921d6bbb31ad /source4/nbt_server/wins/winsserver.c | |
parent | a6d0d564597ea793e0a145ff39fafd6a0dfd6c0f (diff) | |
download | samba-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.c | 226 |
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: |