From b0fc1bfbcbacc61350fdd6e96306fe49d7fc0d6f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Feb 2005 23:53:52 +0000 Subject: r5454: moved the WINS server code into its own directory (This used to be commit 0bb997127fe6c49361d9f1eaeda5d9321601a52a) --- source4/nbt_server/config.mk | 23 ++- source4/nbt_server/wins/winsclient.c | 231 ++++++++++++++++++++++++++++ source4/nbt_server/wins/winsdb.c | 279 ++++++++++++++++++++++++++++++++++ source4/nbt_server/wins/winsdb.h | 52 +++++++ source4/nbt_server/wins/winsserver.c | 283 +++++++++++++++++++++++++++++++++++ source4/nbt_server/wins/winswack.c | 213 ++++++++++++++++++++++++++ source4/nbt_server/winsclient.c | 231 ---------------------------- source4/nbt_server/winsdb.c | 279 ---------------------------------- source4/nbt_server/winsdb.h | 52 ------- source4/nbt_server/winsserver.c | 283 ----------------------------------- source4/nbt_server/winswack.c | 213 -------------------------- 11 files changed, 1074 insertions(+), 1065 deletions(-) create mode 100644 source4/nbt_server/wins/winsclient.c create mode 100644 source4/nbt_server/wins/winsdb.c create mode 100644 source4/nbt_server/wins/winsdb.h create mode 100644 source4/nbt_server/wins/winsserver.c create mode 100644 source4/nbt_server/wins/winswack.c delete mode 100644 source4/nbt_server/winsclient.c delete mode 100644 source4/nbt_server/winsdb.c delete mode 100644 source4/nbt_server/winsdb.h delete mode 100644 source4/nbt_server/winsserver.c delete mode 100644 source4/nbt_server/winswack.c (limited to 'source4/nbt_server') diff --git a/source4/nbt_server/config.mk b/source4/nbt_server/config.mk index 144a12e9e2..bda10b2deb 100644 --- a/source4/nbt_server/config.mk +++ b/source4/nbt_server/config.mk @@ -1,5 +1,18 @@ # NBTD server subsystem +####################### +# Start SUBSYSTEM NBTD_WINS +[SUBSYSTEM::NBTD_WINS] +ADD_OBJ_FILES = \ + nbt_server/wins/winsserver.o \ + nbt_server/wins/winsclient.o \ + nbt_server/wins/winsdb.o \ + nbt_server/wins/winswack.o +REQUIRED_SUBSYSTEMS = \ + LIBCLI_NBT LIBCLI_WINS +# End SUBSYSTEM NBTD_WINS +####################### + ####################### # Start SUBSYSTEM NBTD [SUBSYSTEM::NBTD] @@ -10,13 +23,9 @@ ADD_OBJ_FILES = \ nbt_server/register.o \ nbt_server/query.o \ nbt_server/nodestatus.o \ - nbt_server/winsclient.o \ nbt_server/defense.o \ - nbt_server/packet.o \ - nbt_server/winsserver.o \ - nbt_server/winsdb.o \ - nbt_server/winswack.o + nbt_server/packet.o REQUIRED_SUBSYSTEMS = \ - LIBCLI_NBT -# End SUBSYSTEM SMB + LIBCLI_NBT NBTD_WINS +# End SUBSYSTEM NBTD ####################### diff --git a/source4/nbt_server/wins/winsclient.c b/source4/nbt_server/wins/winsclient.c new file mode 100644 index 0000000000..cfb68a3aaf --- /dev/null +++ b/source4/nbt_server/wins/winsclient.c @@ -0,0 +1,231 @@ +/* + Unix SMB/CIFS implementation. + + wins client name registration and refresh + + Copyright (C) Andrew Tridgell 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. +*/ + +#include "includes.h" +#include "nbt_server/nbt_server.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" +#include "lib/events/events.h" +#include "smbd/service_task.h" + + +/* we send WINS client requests using our primary network interface +*/ +static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface) +{ + struct nbtd_server *nbtsrv = iface->nbtsrv; + return nbtsrv->interfaces->nbtsock; +} + + +static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te, + struct timeval t, void *private); + +/* + retry a WINS name registration +*/ +static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te, + struct timeval t, void *private) +{ + struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name); + nbtd_winsclient_register(iname); +} + + +/* + called when a wins name refresh has completed +*/ +static void nbtd_wins_refresh_handler(struct composite_context *c) +{ + NTSTATUS status; + struct nbt_name_refresh_wins io; + struct nbtd_iface_name *iname = talloc_get_type(c->async.private, + struct nbtd_iface_name); + TALLOC_CTX *tmp_ctx = talloc_new(iname); + + status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + /* our WINS server is dead - start registration over + from scratch */ + DEBUG(2,("Failed to refresh %s with WINS server %s\n", + nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); + talloc_free(tmp_ctx); + nbtd_winsclient_register(iname); + return; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("Name refresh failure with WINS for %s - %s\n", + nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status))); + talloc_free(tmp_ctx); + return; + } + + if (io.out.rcode != 0) { + DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n", + io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), + nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode)))); + iname->nb_flags |= NBT_NM_CONFLICT; + talloc_free(tmp_ctx); + return; + } + + DEBUG(4,("Refreshed name %s with WINS server %s\n", + nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); + /* success - start a periodic name refresh */ + iname->nb_flags |= NBT_NM_ACTIVE; + if (iname->wins_server) { + talloc_free(iname->wins_server); + } + iname->wins_server = talloc_steal(iname, io.out.wins_server); + + iname->registration_time = timeval_current(); + event_add_timed(iname->iface->nbtsrv->task->event_ctx, + iname, + timeval_add(&iname->registration_time, iname->ttl/2, 0), + nbtd_wins_refresh, + iname); + + talloc_free(tmp_ctx); +} + + +/* + refresh a WINS name registration +*/ +static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te, + struct timeval t, void *private) +{ + struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name); + struct nbtd_interface *iface = iname->iface; + struct nbt_name_refresh_wins io; + struct composite_context *c; + TALLOC_CTX *tmp_ctx = talloc_new(iname); + + /* setup a wins name refresh request */ + io.in.name = iname->name; + io.in.wins_servers = str_list_make(tmp_ctx, iname->wins_server, NULL); + io.in.addresses = nbtd_address_list(iface, tmp_ctx); + io.in.nb_flags = iname->nb_flags; + io.in.ttl = iname->ttl; + + c = nbt_name_refresh_wins_send(wins_socket(iface), &io); + if (c == NULL) { + talloc_free(tmp_ctx); + return; + } + talloc_steal(c, io.in.addresses); + + c->async.fn = nbtd_wins_refresh_handler; + c->async.private = iname; + + talloc_free(tmp_ctx); +} + + +/* + called when a wins name register has completed +*/ +static void nbtd_wins_register_handler(struct composite_context *c) +{ + NTSTATUS status; + struct nbt_name_register_wins io; + struct nbtd_iface_name *iname = talloc_get_type(c->async.private, + struct nbtd_iface_name); + TALLOC_CTX *tmp_ctx = talloc_new(iname); + + status = nbt_name_register_wins_recv(c, tmp_ctx, &io); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + /* none of the WINS servers responded - try again + periodically */ + int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300); + event_add_timed(iname->iface->nbtsrv->task->event_ctx, + iname, + timeval_current_ofs(wins_retry_time, 0), + nbtd_wins_register_retry, + iname); + talloc_free(tmp_ctx); + return; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("Name register failure with WINS for %s - %s\n", + nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status))); + talloc_free(tmp_ctx); + return; + } + + if (io.out.rcode != 0) { + DEBUG(1,("WINS server %s rejected name register of %s - %s\n", + io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), + nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode)))); + iname->nb_flags |= NBT_NM_CONFLICT; + talloc_free(tmp_ctx); + return; + } + + /* success - start a periodic name refresh */ + iname->nb_flags |= NBT_NM_ACTIVE; + if (iname->wins_server) { + talloc_free(iname->wins_server); + } + iname->wins_server = talloc_steal(iname, io.out.wins_server); + + iname->registration_time = timeval_current(); + event_add_timed(iname->iface->nbtsrv->task->event_ctx, + iname, + timeval_add(&iname->registration_time, iname->ttl/2, 0), + nbtd_wins_refresh, + iname); + + DEBUG(3,("Registered %s with WINS server %s\n", + nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); + + talloc_free(tmp_ctx); +} + +/* + register a name with our WINS servers +*/ +void nbtd_winsclient_register(struct nbtd_iface_name *iname) +{ + struct nbtd_interface *iface = iname->iface; + struct nbt_name_register_wins io; + struct composite_context *c; + + /* setup a wins name register request */ + io.in.name = iname->name; + io.in.wins_servers = lp_wins_server_list(); + io.in.addresses = nbtd_address_list(iface, iname); + io.in.nb_flags = iname->nb_flags; + io.in.ttl = iname->ttl; + + c = nbt_name_register_wins_send(wins_socket(iface), &io); + if (c == NULL) { + talloc_free(io.in.addresses); + return; + } + talloc_steal(c, io.in.addresses); + + c->async.fn = nbtd_wins_register_handler; + c->async.private = iname; +} diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c new file mode 100644 index 0000000000..4b547bc644 --- /dev/null +++ b/source4/nbt_server/wins/winsdb.c @@ -0,0 +1,279 @@ +/* + Unix SMB/CIFS implementation. + + WINS database routines + + Copyright (C) Andrew Tridgell 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. +*/ + +#include "includes.h" +#include "nbt_server/nbt_server.h" +#include "nbt_server/wins/winsdb.h" +#include "lib/ldb/include/ldb.h" +#include "db_wrap.h" +#include "system/time.h" + +/* + save the min/max version IDs for the database +*/ +static BOOL winsdb_save_version(struct wins_server *winssrv) +{ + int i, ret = 0; + struct ldb_context *ldb = winssrv->wins_db->ldb; + struct ldb_message *msg = ldb_msg_new(winssrv); + if (msg == NULL) goto failed; + + msg->dn = talloc_strdup(msg, "CN=VERSION"); + if (msg->dn == NULL) goto failed; + + ret |= ldb_msg_add_fmt(ldb, msg, "minVersion", "%llu", winssrv->min_version); + ret |= ldb_msg_add_fmt(ldb, msg, "maxVersion", "%llu", winssrv->max_version); + if (ret != 0) goto failed; + + for (i=0;inum_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + ret = ldb_modify(ldb, msg); + if (ret != 0) ret = ldb_add(ldb, msg); + if (ret != 0) goto failed; + + talloc_free(msg); + return True; + +failed: + talloc_free(msg); + return False; +} + +/* + allocate a new version id for a record +*/ +static uint64_t winsdb_allocate_version(struct wins_server *winssrv) +{ + winssrv->max_version++; + if (!winsdb_save_version(winssrv)) { + return 0; + } + return winssrv->max_version; +} + +/* + allocate a new version id for a record +*/ +static void winsdb_remove_version(struct wins_server *winssrv, uint64_t version) +{ + if (version == winssrv->min_version) { + winssrv->min_version++; + winsdb_save_version(winssrv); + } +} + +/* + load a WINS entry from the database +*/ +struct winsdb_record *winsdb_load(struct wins_server *winssrv, + struct nbt_name *name, TALLOC_CTX *mem_ctx) +{ + struct ldb_message **res = NULL; + int ret; + struct winsdb_record *rec; + struct ldb_message_element *el; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + const char *expr; + int i; + + expr = talloc_asprintf(tmp_ctx, "dn=NAME=%s", nbt_name_string(tmp_ctx, name)); + if (expr == NULL) goto failed; + + /* find the record in the WINS database */ + ret = ldb_search(winssrv->wins_db->ldb, NULL, LDB_SCOPE_ONELEVEL, expr, NULL, &res); + if (res != NULL) { + talloc_steal(tmp_ctx, res); + } + if (ret != 1) goto failed; + + rec = talloc(tmp_ctx, struct winsdb_record); + if (rec == NULL) goto failed; + + /* parse it into a more convenient winsdb_record structure */ + rec->name = name; + rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED); + rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0); + rec->expire_time = ldap_string_to_time(ldb_msg_find_string(res[0], "expires", NULL)); + rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL); + rec->version = ldb_msg_find_uint64(res[0], "version", 0); + talloc_steal(rec, rec->registered_by); + + el = ldb_msg_find_element(res[0], "address"); + if (el == NULL) goto failed; + + rec->addresses = talloc_array(rec, const char *, el->num_values+1); + if (rec->addresses == NULL) goto failed; + + for (i=0;inum_values;i++) { + rec->addresses[i] = talloc_steal(rec->addresses, el->values[i].data); + } + rec->addresses[i] = NULL; + + /* see if it has already expired */ + if (rec->state == WINS_REC_ACTIVE && + rec->expire_time <= time(NULL)) { + DEBUG(5,("WINS: expiring name %s (expired at %s)\n", + nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time))); + rec->state = WINS_REC_RELEASED; + } + + talloc_steal(mem_ctx, rec); + talloc_free(tmp_ctx); + return rec; + +failed: + talloc_free(tmp_ctx); + return NULL; +} + + +/* + form a ldb_message from a winsdb_record +*/ +static struct ldb_message *winsdb_message(struct wins_server *winssrv, + struct winsdb_record *rec, TALLOC_CTX *mem_ctx) +{ + int i, ret=0; + struct ldb_context *ldb = winssrv->wins_db->ldb; + struct ldb_message *msg = ldb_msg_new(mem_ctx); + if (msg == NULL) goto failed; + + msg->dn = talloc_asprintf(msg, "NAME=%s", nbt_name_string(msg, rec->name)); + if (msg->dn == NULL) goto failed; + ret |= ldb_msg_add_fmt(ldb, msg, "active", "%u", rec->state); + ret |= ldb_msg_add_fmt(ldb, msg, "nbFlags", "0x%04x", rec->nb_flags); + ret |= ldb_msg_add_string(ldb, msg, "registeredBy", rec->registered_by); + ret |= ldb_msg_add_string(ldb, msg, "expires", + ldap_timestring(msg, rec->expire_time)); + ret |= ldb_msg_add_fmt(ldb, msg, "version", "%llu", rec->version); + for (i=0;rec->addresses[i];i++) { + ret |= ldb_msg_add_string(ldb, msg, "address", rec->addresses[i]); + } + if (ret != 0) goto failed; + return msg; + +failed: + talloc_free(msg); + return NULL; +} + +/* + save a WINS record into the database +*/ +uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec) +{ + struct ldb_context *ldb = winssrv->wins_db->ldb; + struct ldb_message *msg; + TALLOC_CTX *tmp_ctx = talloc_new(winssrv); + int ret; + + rec->version = winsdb_allocate_version(winssrv); + if (rec->version == 0) goto failed; + + msg = winsdb_message(winssrv, rec, tmp_ctx); + if (msg == NULL) goto failed; + ret = ldb_add(ldb, msg); + if (ret != 0) goto failed; + + talloc_free(tmp_ctx); + return NBT_RCODE_OK; + +failed: + talloc_free(tmp_ctx); + return NBT_RCODE_SVR; +} + + +/* + modify a WINS record in the database +*/ +uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec) +{ + struct ldb_context *ldb = winssrv->wins_db->ldb; + struct ldb_message *msg; + TALLOC_CTX *tmp_ctx = talloc_new(winssrv); + int ret; + int i; + + rec->version = winsdb_allocate_version(winssrv); + if (rec->version == 0) goto failed; + + msg = winsdb_message(winssrv, rec, tmp_ctx); + if (msg == NULL) goto failed; + + for (i=0;inum_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + ret = ldb_modify(ldb, msg); + if (ret != 0) goto failed; + + talloc_free(tmp_ctx); + return NBT_RCODE_OK; + +failed: + talloc_free(tmp_ctx); + return NBT_RCODE_SVR; +} + + +/* + delete a WINS record from the database +*/ +uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec) +{ + struct ldb_context *ldb = winssrv->wins_db->ldb; + TALLOC_CTX *tmp_ctx = talloc_new(winssrv); + int ret; + const char *dn; + + winsdb_remove_version(winssrv, rec->version); + + dn = talloc_asprintf(tmp_ctx, "NAME=%s", nbt_name_string(tmp_ctx, rec->name)); + if (dn == NULL) goto failed; + + ret = ldb_delete(ldb, dn); + if (ret != 0) goto failed; + + talloc_free(tmp_ctx); + return NBT_RCODE_OK; + +failed: + talloc_free(tmp_ctx); + return NBT_RCODE_SVR; +} + + +/* + connect to the WINS database +*/ +NTSTATUS winsdb_init(struct wins_server *winssrv) +{ + winssrv->wins_db = ldb_wrap_connect(winssrv, lp_wins_url(), 0, NULL); + if (winssrv->wins_db == NULL) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + return NT_STATUS_OK; +} diff --git a/source4/nbt_server/wins/winsdb.h b/source4/nbt_server/wins/winsdb.h new file mode 100644 index 0000000000..6d395461c6 --- /dev/null +++ b/source4/nbt_server/wins/winsdb.h @@ -0,0 +1,52 @@ +/* + Unix SMB/CIFS implementation. + + WINS server structures + + Copyright (C) Andrew Tridgell 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. +*/ + +enum wins_record_state { + WINS_REC_RELEASED =0, + WINS_REC_ACTIVE =1 +}; + +/* + each record in the database contains the following information +*/ +struct winsdb_record { + struct nbt_name *name; + uint16_t nb_flags; + enum wins_record_state state; + time_t expire_time; + const char *registered_by; + const char **addresses; + uint64_t version; +}; + +struct wins_server { + /* wins server database handle */ + struct ldb_wrap *wins_db; + + uint32_t min_ttl; + uint32_t max_ttl; + + /* these are the minimum and maximum record version IDs in the + database. They are needed for replication */ + uint64_t min_version; + uint64_t max_version; +}; diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c new file mode 100644 index 0000000000..2212748777 --- /dev/null +++ b/source4/nbt_server/wins/winsserver.c @@ -0,0 +1,283 @@ +/* + Unix SMB/CIFS implementation. + + core wins server handling + + Copyright (C) Andrew Tridgell 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. +*/ + +#include "includes.h" +#include "nbt_server/nbt_server.h" +#include "nbt_server/wins/winsdb.h" +#include "system/time.h" + +/* + work out the ttl we will use given a client requested ttl +*/ +uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl) +{ + ttl = MIN(ttl, winssrv->max_ttl); + ttl = MAX(ttl, winssrv->min_ttl); + return ttl; +} + +/* + register a new name with WINS +*/ +static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + struct nbt_name *name = &packet->questions[0].name; + uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl); + uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags; + const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; + struct winsdb_record rec; + + rec.name = name; + rec.nb_flags = nb_flags; + rec.state = WINS_REC_ACTIVE; + rec.expire_time = time(NULL) + ttl; + rec.registered_by = src_address; + if (IS_GROUP_NAME(name, nb_flags)) { + rec.addresses = str_list_make(packet, "255.255.255.255", NULL); + } else { + rec.addresses = str_list_make(packet, address, NULL); + } + if (rec.addresses == NULL) return NBT_RCODE_SVR; + + DEBUG(4,("WINS: accepted registration of %s with address %s\n", + nbt_name_string(packet, name), rec.addresses[0])); + + return winsdb_add(winssrv, &rec); +} + + +/* + update the ttl on an existing record +*/ +static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + struct winsdb_record *rec, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl); + const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; + time_t now = time(NULL); + + if (now + ttl > rec->expire_time) { + rec->expire_time = now + ttl; + } + rec->registered_by = src_address; + + DEBUG(5,("WINS: refreshed registration of %s at %s\n", + nbt_name_string(packet, rec->name), address)); + + return winsdb_modify(winssrv, rec); +} + +/* + register a name +*/ +static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + struct nbt_name *name = &packet->questions[0].name; + struct winsdb_record *rec; + uint8_t rcode = NBT_RCODE_OK; + uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags; + const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; + + /* as a special case, the local master browser name is always accepted + for registration, but never stored */ + if (name->type == NBT_NAME_MASTER) { + goto done; + } + + rec = winsdb_load(winssrv, name, packet); + if (rec == NULL) { + rcode = wins_register_new(nbtsock, packet, src_address, src_port); + goto done; + } else if (rec->state != WINS_REC_ACTIVE) { + winsdb_delete(winssrv, rec); + rcode = wins_register_new(nbtsock, packet, src_address, src_port); + goto done; + } + + /* its an active name - first see if the registration is of the right type */ + if ((rec->nb_flags & NBT_NM_GROUP) && !(nb_flags & NBT_NM_GROUP)) { + DEBUG(2,("WINS: Attempt to register unique name %s when group name is active\n", + nbt_name_string(packet, name))); + rcode = NBT_RCODE_ACT; + goto done; + } + + /* if its an active unique name, and the registration is for a group, then + see if the unique name owner still wants the name */ + if (!(rec->nb_flags & NBT_NM_GROUP) && (nb_flags & NBT_NM_GROUP)) { + wins_register_wack(nbtsock, packet, rec, src_address, src_port); + return; + } + + /* if the registration is for a group, then just update the expiry time + and we are done */ + if (IS_GROUP_NAME(name, nb_flags)) { + wins_update_ttl(nbtsock, packet, rec, src_address, src_port); + goto done; + } + + /* if the registration is for an address that is currently active, then + just update the expiry time */ + if (str_list_check(rec->addresses, address)) { + wins_update_ttl(nbtsock, packet, rec, src_address, src_port); + goto done; + } + + /* 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_address, src_port); + return; + +done: + nbtd_name_registration_reply(nbtsock, packet, src_address, src_port, rcode); +} + + + +/* + query a name +*/ +static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + struct nbt_name *name = &packet->questions[0].name; + struct winsdb_record *rec; + + rec = winsdb_load(winssrv, name, packet); + if (rec == NULL || rec->state != WINS_REC_ACTIVE) { + nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port); + return; + } + + nbtd_name_query_reply(nbtsock, packet, src_address, src_port, name, + 0, rec->nb_flags, rec->addresses); +} + +/* + release a name +*/ +static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + struct nbt_name *name = &packet->questions[0].name; + struct winsdb_record *rec; + + rec = winsdb_load(winssrv, name, packet); + if (rec == NULL || + rec->state != WINS_REC_ACTIVE || + IS_GROUP_NAME(name, rec->nb_flags)) { + goto done; + } + + /* we only allow releases from an owner - other releases are + silently ignored */ + if (str_list_check(rec->addresses, src_address)) { + const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; + + DEBUG(4,("WINS: released name %s at %s\n", nbt_name_string(rec, rec->name), address)); + str_list_remove(rec->addresses, address); + if (rec->addresses[0] == NULL) { + rec->state = WINS_REC_RELEASED; + } + winsdb_modify(winssrv, rec); + } + +done: + /* we match w2k3 by always giving a positive reply to name releases. */ + nbtd_name_release_reply(nbtsock, packet, src_address, src_port, NBT_RCODE_OK); +} + + +/* + answer a name query +*/ +void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, + struct nbtd_interface); + struct wins_server *winssrv = iface->nbtsrv->winssrv; + if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) { + return; + } + + switch (packet->operation & NBT_OPCODE) { + case NBT_OPCODE_QUERY: + nbtd_winsserver_query(nbtsock, packet, src_address, src_port); + break; + + case NBT_OPCODE_REGISTER: + case NBT_OPCODE_REFRESH: + case NBT_OPCODE_REFRESH2: + case NBT_OPCODE_MULTI_HOME_REG: + nbtd_winsserver_register(nbtsock, packet, src_address, src_port); + break; + + case NBT_OPCODE_RELEASE: + nbtd_winsserver_release(nbtsock, packet, src_address, src_port); + break; + } + +} + +/* + startup the WINS server, if configured +*/ +NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv) +{ + if (!lp_wins_support()) { + nbtsrv->winssrv = NULL; + return NT_STATUS_OK; + } + + nbtsrv->winssrv = talloc(nbtsrv, struct wins_server); + NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv); + + nbtsrv->winssrv->max_ttl = lp_max_wins_ttl(); + nbtsrv->winssrv->min_ttl = lp_min_wins_ttl(); + + return winsdb_init(nbtsrv->winssrv); +} diff --git a/source4/nbt_server/wins/winswack.c b/source4/nbt_server/wins/winswack.c new file mode 100644 index 0000000000..8c7841d095 --- /dev/null +++ b/source4/nbt_server/wins/winswack.c @@ -0,0 +1,213 @@ +/* + Unix SMB/CIFS implementation. + + "secure" wins server WACK processing + + Copyright (C) Andrew Tridgell 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. +*/ + +#include "includes.h" +#include "nbt_server/nbt_server.h" +#include "nbt_server/wins/winsdb.h" +#include "system/time.h" + +struct wack_state { + struct wins_server *winssrv; + struct nbt_name_socket *nbtsock; + struct nbt_name_packet *request_packet; + struct winsdb_record *rec; + const char *src_address; + int src_port; + 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_address, state->src_port, NBT_RCODE_ACT); + DEBUG(4,("WINS: denied name registration request for %s from %s\n", + nbt_name_string(state, state->rec->name), state->src_address)); + talloc_free(state); +} + +/* + allow a registration request +*/ +static void wins_wack_allow(struct wack_state *state) +{ + uint32_t ttl; + time_t now = time(NULL); + struct winsdb_record *rec = state->rec, *rec2; + + rec2 = winsdb_load(state->winssrv, rec->name, state); + if (rec2 == NULL || rec2->version != rec->version) { + 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_address, state->src_port, NBT_RCODE_OK); + + rec->addresses = str_list_add(rec->addresses, state->reg_address); + if (rec->addresses == NULL) goto failed; + + ttl = wins_server_ttl(state->winssrv, state->request_packet->additional[0].ttl); + if (now + ttl > rec->expire_time) { + rec->expire_time = now + ttl; + } + rec->registered_by = state->src_address; + + winsdb_modify(state->winssrv, rec); + + 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;rec->addresses[i];) { + if (!str_list_check(state->query.out.reply_addrs, rec->addresses[i])) { + str_list_remove(rec->addresses, rec->addresses[i]); + } else { + 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 char *src_address, int src_port) +{ + 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->src_port = src_port; + state->owner_addresses = rec->addresses; + state->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; + state->src_address = talloc_strdup(state, src_address); + if (state->src_address == 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 * str_list_length(rec->addresses); + nbtd_wack_reply(nbtsock, packet, src_address, src_port, 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_address, src_port, NBT_RCODE_SVR); +} diff --git a/source4/nbt_server/winsclient.c b/source4/nbt_server/winsclient.c deleted file mode 100644 index cfb68a3aaf..0000000000 --- a/source4/nbt_server/winsclient.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - wins client name registration and refresh - - Copyright (C) Andrew Tridgell 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. -*/ - -#include "includes.h" -#include "nbt_server/nbt_server.h" -#include "libcli/raw/libcliraw.h" -#include "libcli/composite/composite.h" -#include "lib/events/events.h" -#include "smbd/service_task.h" - - -/* we send WINS client requests using our primary network interface -*/ -static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface) -{ - struct nbtd_server *nbtsrv = iface->nbtsrv; - return nbtsrv->interfaces->nbtsock; -} - - -static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te, - struct timeval t, void *private); - -/* - retry a WINS name registration -*/ -static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te, - struct timeval t, void *private) -{ - struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name); - nbtd_winsclient_register(iname); -} - - -/* - called when a wins name refresh has completed -*/ -static void nbtd_wins_refresh_handler(struct composite_context *c) -{ - NTSTATUS status; - struct nbt_name_refresh_wins io; - struct nbtd_iface_name *iname = talloc_get_type(c->async.private, - struct nbtd_iface_name); - TALLOC_CTX *tmp_ctx = talloc_new(iname); - - status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io); - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { - /* our WINS server is dead - start registration over - from scratch */ - DEBUG(2,("Failed to refresh %s with WINS server %s\n", - nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); - talloc_free(tmp_ctx); - nbtd_winsclient_register(iname); - return; - } - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1,("Name refresh failure with WINS for %s - %s\n", - nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status))); - talloc_free(tmp_ctx); - return; - } - - if (io.out.rcode != 0) { - DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n", - io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), - nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode)))); - iname->nb_flags |= NBT_NM_CONFLICT; - talloc_free(tmp_ctx); - return; - } - - DEBUG(4,("Refreshed name %s with WINS server %s\n", - nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); - /* success - start a periodic name refresh */ - iname->nb_flags |= NBT_NM_ACTIVE; - if (iname->wins_server) { - talloc_free(iname->wins_server); - } - iname->wins_server = talloc_steal(iname, io.out.wins_server); - - iname->registration_time = timeval_current(); - event_add_timed(iname->iface->nbtsrv->task->event_ctx, - iname, - timeval_add(&iname->registration_time, iname->ttl/2, 0), - nbtd_wins_refresh, - iname); - - talloc_free(tmp_ctx); -} - - -/* - refresh a WINS name registration -*/ -static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te, - struct timeval t, void *private) -{ - struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name); - struct nbtd_interface *iface = iname->iface; - struct nbt_name_refresh_wins io; - struct composite_context *c; - TALLOC_CTX *tmp_ctx = talloc_new(iname); - - /* setup a wins name refresh request */ - io.in.name = iname->name; - io.in.wins_servers = str_list_make(tmp_ctx, iname->wins_server, NULL); - io.in.addresses = nbtd_address_list(iface, tmp_ctx); - io.in.nb_flags = iname->nb_flags; - io.in.ttl = iname->ttl; - - c = nbt_name_refresh_wins_send(wins_socket(iface), &io); - if (c == NULL) { - talloc_free(tmp_ctx); - return; - } - talloc_steal(c, io.in.addresses); - - c->async.fn = nbtd_wins_refresh_handler; - c->async.private = iname; - - talloc_free(tmp_ctx); -} - - -/* - called when a wins name register has completed -*/ -static void nbtd_wins_register_handler(struct composite_context *c) -{ - NTSTATUS status; - struct nbt_name_register_wins io; - struct nbtd_iface_name *iname = talloc_get_type(c->async.private, - struct nbtd_iface_name); - TALLOC_CTX *tmp_ctx = talloc_new(iname); - - status = nbt_name_register_wins_recv(c, tmp_ctx, &io); - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { - /* none of the WINS servers responded - try again - periodically */ - int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300); - event_add_timed(iname->iface->nbtsrv->task->event_ctx, - iname, - timeval_current_ofs(wins_retry_time, 0), - nbtd_wins_register_retry, - iname); - talloc_free(tmp_ctx); - return; - } - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1,("Name register failure with WINS for %s - %s\n", - nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status))); - talloc_free(tmp_ctx); - return; - } - - if (io.out.rcode != 0) { - DEBUG(1,("WINS server %s rejected name register of %s - %s\n", - io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), - nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode)))); - iname->nb_flags |= NBT_NM_CONFLICT; - talloc_free(tmp_ctx); - return; - } - - /* success - start a periodic name refresh */ - iname->nb_flags |= NBT_NM_ACTIVE; - if (iname->wins_server) { - talloc_free(iname->wins_server); - } - iname->wins_server = talloc_steal(iname, io.out.wins_server); - - iname->registration_time = timeval_current(); - event_add_timed(iname->iface->nbtsrv->task->event_ctx, - iname, - timeval_add(&iname->registration_time, iname->ttl/2, 0), - nbtd_wins_refresh, - iname); - - DEBUG(3,("Registered %s with WINS server %s\n", - nbt_name_string(tmp_ctx, &iname->name), iname->wins_server)); - - talloc_free(tmp_ctx); -} - -/* - register a name with our WINS servers -*/ -void nbtd_winsclient_register(struct nbtd_iface_name *iname) -{ - struct nbtd_interface *iface = iname->iface; - struct nbt_name_register_wins io; - struct composite_context *c; - - /* setup a wins name register request */ - io.in.name = iname->name; - io.in.wins_servers = lp_wins_server_list(); - io.in.addresses = nbtd_address_list(iface, iname); - io.in.nb_flags = iname->nb_flags; - io.in.ttl = iname->ttl; - - c = nbt_name_register_wins_send(wins_socket(iface), &io); - if (c == NULL) { - talloc_free(io.in.addresses); - return; - } - talloc_steal(c, io.in.addresses); - - c->async.fn = nbtd_wins_register_handler; - c->async.private = iname; -} diff --git a/source4/nbt_server/winsdb.c b/source4/nbt_server/winsdb.c deleted file mode 100644 index 66e84c668b..0000000000 --- a/source4/nbt_server/winsdb.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - WINS database routines - - Copyright (C) Andrew Tridgell 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. -*/ - -#include "includes.h" -#include "nbt_server/nbt_server.h" -#include "nbt_server/winsdb.h" -#include "lib/ldb/include/ldb.h" -#include "db_wrap.h" -#include "system/time.h" - -/* - save the min/max version IDs for the database -*/ -static BOOL winsdb_save_version(struct wins_server *winssrv) -{ - int i, ret = 0; - struct ldb_context *ldb = winssrv->wins_db->ldb; - struct ldb_message *msg = ldb_msg_new(winssrv); - if (msg == NULL) goto failed; - - msg->dn = talloc_strdup(msg, "CN=VERSION"); - if (msg->dn == NULL) goto failed; - - ret |= ldb_msg_add_fmt(ldb, msg, "minVersion", "%llu", winssrv->min_version); - ret |= ldb_msg_add_fmt(ldb, msg, "maxVersion", "%llu", winssrv->max_version); - if (ret != 0) goto failed; - - for (i=0;inum_elements;i++) { - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; - } - - ret = ldb_modify(ldb, msg); - if (ret != 0) ret = ldb_add(ldb, msg); - if (ret != 0) goto failed; - - talloc_free(msg); - return True; - -failed: - talloc_free(msg); - return False; -} - -/* - allocate a new version id for a record -*/ -static uint64_t winsdb_allocate_version(struct wins_server *winssrv) -{ - winssrv->max_version++; - if (!winsdb_save_version(winssrv)) { - return 0; - } - return winssrv->max_version; -} - -/* - allocate a new version id for a record -*/ -static void winsdb_remove_version(struct wins_server *winssrv, uint64_t version) -{ - if (version == winssrv->min_version) { - winssrv->min_version++; - winsdb_save_version(winssrv); - } -} - -/* - load a WINS entry from the database -*/ -struct winsdb_record *winsdb_load(struct wins_server *winssrv, - struct nbt_name *name, TALLOC_CTX *mem_ctx) -{ - struct ldb_message **res = NULL; - int ret; - struct winsdb_record *rec; - struct ldb_message_element *el; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - const char *expr; - int i; - - expr = talloc_asprintf(tmp_ctx, "dn=NAME=%s", nbt_name_string(tmp_ctx, name)); - if (expr == NULL) goto failed; - - /* find the record in the WINS database */ - ret = ldb_search(winssrv->wins_db->ldb, NULL, LDB_SCOPE_ONELEVEL, expr, NULL, &res); - if (res != NULL) { - talloc_steal(tmp_ctx, res); - } - if (ret != 1) goto failed; - - rec = talloc(tmp_ctx, struct winsdb_record); - if (rec == NULL) goto failed; - - /* parse it into a more convenient winsdb_record structure */ - rec->name = name; - rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED); - rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0); - rec->expire_time = ldap_string_to_time(ldb_msg_find_string(res[0], "expires", NULL)); - rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL); - rec->version = ldb_msg_find_uint64(res[0], "version", 0); - talloc_steal(rec, rec->registered_by); - - el = ldb_msg_find_element(res[0], "address"); - if (el == NULL) goto failed; - - rec->addresses = talloc_array(rec, const char *, el->num_values+1); - if (rec->addresses == NULL) goto failed; - - for (i=0;inum_values;i++) { - rec->addresses[i] = talloc_steal(rec->addresses, el->values[i].data); - } - rec->addresses[i] = NULL; - - /* see if it has already expired */ - if (rec->state == WINS_REC_ACTIVE && - rec->expire_time <= time(NULL)) { - DEBUG(5,("WINS: expiring name %s (expired at %s)\n", - nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time))); - rec->state = WINS_REC_RELEASED; - } - - talloc_steal(mem_ctx, rec); - talloc_free(tmp_ctx); - return rec; - -failed: - talloc_free(tmp_ctx); - return NULL; -} - - -/* - form a ldb_message from a winsdb_record -*/ -static struct ldb_message *winsdb_message(struct wins_server *winssrv, - struct winsdb_record *rec, TALLOC_CTX *mem_ctx) -{ - int i, ret=0; - struct ldb_context *ldb = winssrv->wins_db->ldb; - struct ldb_message *msg = ldb_msg_new(mem_ctx); - if (msg == NULL) goto failed; - - msg->dn = talloc_asprintf(msg, "NAME=%s", nbt_name_string(msg, rec->name)); - if (msg->dn == NULL) goto failed; - ret |= ldb_msg_add_fmt(ldb, msg, "active", "%u", rec->state); - ret |= ldb_msg_add_fmt(ldb, msg, "nbFlags", "0x%04x", rec->nb_flags); - ret |= ldb_msg_add_string(ldb, msg, "registeredBy", rec->registered_by); - ret |= ldb_msg_add_string(ldb, msg, "expires", - ldap_timestring(msg, rec->expire_time)); - ret |= ldb_msg_add_fmt(ldb, msg, "version", "%llu", rec->version); - for (i=0;rec->addresses[i];i++) { - ret |= ldb_msg_add_string(ldb, msg, "address", rec->addresses[i]); - } - if (ret != 0) goto failed; - return msg; - -failed: - talloc_free(msg); - return NULL; -} - -/* - save a WINS record into the database -*/ -uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec) -{ - struct ldb_context *ldb = winssrv->wins_db->ldb; - struct ldb_message *msg; - TALLOC_CTX *tmp_ctx = talloc_new(winssrv); - int ret; - - rec->version = winsdb_allocate_version(winssrv); - if (rec->version == 0) goto failed; - - msg = winsdb_message(winssrv, rec, tmp_ctx); - if (msg == NULL) goto failed; - ret = ldb_add(ldb, msg); - if (ret != 0) goto failed; - - talloc_free(tmp_ctx); - return NBT_RCODE_OK; - -failed: - talloc_free(tmp_ctx); - return NBT_RCODE_SVR; -} - - -/* - modify a WINS record in the database -*/ -uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec) -{ - struct ldb_context *ldb = winssrv->wins_db->ldb; - struct ldb_message *msg; - TALLOC_CTX *tmp_ctx = talloc_new(winssrv); - int ret; - int i; - - rec->version = winsdb_allocate_version(winssrv); - if (rec->version == 0) goto failed; - - msg = winsdb_message(winssrv, rec, tmp_ctx); - if (msg == NULL) goto failed; - - for (i=0;inum_elements;i++) { - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; - } - - ret = ldb_modify(ldb, msg); - if (ret != 0) goto failed; - - talloc_free(tmp_ctx); - return NBT_RCODE_OK; - -failed: - talloc_free(tmp_ctx); - return NBT_RCODE_SVR; -} - - -/* - delete a WINS record from the database -*/ -uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec) -{ - struct ldb_context *ldb = winssrv->wins_db->ldb; - TALLOC_CTX *tmp_ctx = talloc_new(winssrv); - int ret; - const char *dn; - - winsdb_remove_version(winssrv, rec->version); - - dn = talloc_asprintf(tmp_ctx, "NAME=%s", nbt_name_string(tmp_ctx, rec->name)); - if (dn == NULL) goto failed; - - ret = ldb_delete(ldb, dn); - if (ret != 0) goto failed; - - talloc_free(tmp_ctx); - return NBT_RCODE_OK; - -failed: - talloc_free(tmp_ctx); - return NBT_RCODE_SVR; -} - - -/* - connect to the WINS database -*/ -NTSTATUS winsdb_init(struct wins_server *winssrv) -{ - winssrv->wins_db = ldb_wrap_connect(winssrv, lp_wins_url(), 0, NULL); - if (winssrv->wins_db == NULL) { - return NT_STATUS_INTERNAL_DB_ERROR; - } - - return NT_STATUS_OK; -} diff --git a/source4/nbt_server/winsdb.h b/source4/nbt_server/winsdb.h deleted file mode 100644 index 6d395461c6..0000000000 --- a/source4/nbt_server/winsdb.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - WINS server structures - - Copyright (C) Andrew Tridgell 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. -*/ - -enum wins_record_state { - WINS_REC_RELEASED =0, - WINS_REC_ACTIVE =1 -}; - -/* - each record in the database contains the following information -*/ -struct winsdb_record { - struct nbt_name *name; - uint16_t nb_flags; - enum wins_record_state state; - time_t expire_time; - const char *registered_by; - const char **addresses; - uint64_t version; -}; - -struct wins_server { - /* wins server database handle */ - struct ldb_wrap *wins_db; - - uint32_t min_ttl; - uint32_t max_ttl; - - /* these are the minimum and maximum record version IDs in the - database. They are needed for replication */ - uint64_t min_version; - uint64_t max_version; -}; diff --git a/source4/nbt_server/winsserver.c b/source4/nbt_server/winsserver.c deleted file mode 100644 index 6d8770431e..0000000000 --- a/source4/nbt_server/winsserver.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - core wins server handling - - Copyright (C) Andrew Tridgell 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. -*/ - -#include "includes.h" -#include "nbt_server/nbt_server.h" -#include "nbt_server/winsdb.h" -#include "system/time.h" - -/* - work out the ttl we will use given a client requested ttl -*/ -uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl) -{ - ttl = MIN(ttl, winssrv->max_ttl); - ttl = MAX(ttl, winssrv->min_ttl); - return ttl; -} - -/* - register a new name with WINS -*/ -static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - struct nbt_name *name = &packet->questions[0].name; - uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl); - uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags; - const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; - struct winsdb_record rec; - - rec.name = name; - rec.nb_flags = nb_flags; - rec.state = WINS_REC_ACTIVE; - rec.expire_time = time(NULL) + ttl; - rec.registered_by = src_address; - if (IS_GROUP_NAME(name, nb_flags)) { - rec.addresses = str_list_make(packet, "255.255.255.255", NULL); - } else { - rec.addresses = str_list_make(packet, address, NULL); - } - if (rec.addresses == NULL) return NBT_RCODE_SVR; - - DEBUG(4,("WINS: accepted registration of %s with address %s\n", - nbt_name_string(packet, name), rec.addresses[0])); - - return winsdb_add(winssrv, &rec); -} - - -/* - update the ttl on an existing record -*/ -static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - struct winsdb_record *rec, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl); - const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; - time_t now = time(NULL); - - if (now + ttl > rec->expire_time) { - rec->expire_time = now + ttl; - } - rec->registered_by = src_address; - - DEBUG(5,("WINS: refreshed registration of %s at %s\n", - nbt_name_string(packet, rec->name), address)); - - return winsdb_modify(winssrv, rec); -} - -/* - register a name -*/ -static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - struct nbt_name *name = &packet->questions[0].name; - struct winsdb_record *rec; - uint8_t rcode = NBT_RCODE_OK; - uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags; - const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; - - /* as a special case, the local master browser name is always accepted - for registration, but never stored */ - if (name->type == NBT_NAME_MASTER) { - goto done; - } - - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL) { - rcode = wins_register_new(nbtsock, packet, src_address, src_port); - goto done; - } else if (rec->state != WINS_REC_ACTIVE) { - winsdb_delete(winssrv, rec); - rcode = wins_register_new(nbtsock, packet, src_address, src_port); - goto done; - } - - /* its an active name - first see if the registration is of the right type */ - if ((rec->nb_flags & NBT_NM_GROUP) && !(nb_flags & NBT_NM_GROUP)) { - DEBUG(2,("WINS: Attempt to register unique name %s when group name is active\n", - nbt_name_string(packet, name))); - rcode = NBT_RCODE_ACT; - goto done; - } - - /* if its an active unique name, and the registration is for a group, then - see if the unique name owner still wants the name */ - if (!(rec->nb_flags & NBT_NM_GROUP) && (nb_flags & NBT_NM_GROUP)) { - wins_register_wack(nbtsock, packet, rec, src_address, src_port); - return; - } - - /* if the registration is for a group, then just update the expiry time - and we are done */ - if (IS_GROUP_NAME(name, nb_flags)) { - wins_update_ttl(nbtsock, packet, rec, src_address, src_port); - goto done; - } - - /* if the registration is for an address that is currently active, then - just update the expiry time */ - if (str_list_check(rec->addresses, address)) { - wins_update_ttl(nbtsock, packet, rec, src_address, src_port); - goto done; - } - - /* 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_address, src_port); - return; - -done: - nbtd_name_registration_reply(nbtsock, packet, src_address, src_port, rcode); -} - - - -/* - query a name -*/ -static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - struct nbt_name *name = &packet->questions[0].name; - struct winsdb_record *rec; - - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL || rec->state != WINS_REC_ACTIVE) { - nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port); - return; - } - - nbtd_name_query_reply(nbtsock, packet, src_address, src_port, name, - 0, rec->nb_flags, rec->addresses); -} - -/* - release a name -*/ -static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - struct nbt_name *name = &packet->questions[0].name; - struct winsdb_record *rec; - - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL || - rec->state != WINS_REC_ACTIVE || - IS_GROUP_NAME(name, rec->nb_flags)) { - goto done; - } - - /* we only allow releases from an owner - other releases are - silently ignored */ - if (str_list_check(rec->addresses, src_address)) { - const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; - - DEBUG(4,("WINS: released name %s at %s\n", nbt_name_string(rec, rec->name), address)); - str_list_remove(rec->addresses, address); - if (rec->addresses[0] == NULL) { - rec->state = WINS_REC_RELEASED; - } - winsdb_modify(winssrv, rec); - } - -done: - /* we match w2k3 by always giving a positive reply to name releases. */ - nbtd_name_release_reply(nbtsock, packet, src_address, src_port, NBT_RCODE_OK); -} - - -/* - answer a name query -*/ -void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, - struct nbt_name_packet *packet, - const char *src_address, int src_port) -{ - struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, - struct nbtd_interface); - struct wins_server *winssrv = iface->nbtsrv->winssrv; - if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) { - return; - } - - switch (packet->operation & NBT_OPCODE) { - case NBT_OPCODE_QUERY: - nbtd_winsserver_query(nbtsock, packet, src_address, src_port); - break; - - case NBT_OPCODE_REGISTER: - case NBT_OPCODE_REFRESH: - case NBT_OPCODE_REFRESH2: - case NBT_OPCODE_MULTI_HOME_REG: - nbtd_winsserver_register(nbtsock, packet, src_address, src_port); - break; - - case NBT_OPCODE_RELEASE: - nbtd_winsserver_release(nbtsock, packet, src_address, src_port); - break; - } - -} - -/* - startup the WINS server, if configured -*/ -NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv) -{ - if (!lp_wins_support()) { - nbtsrv->winssrv = NULL; - return NT_STATUS_OK; - } - - nbtsrv->winssrv = talloc(nbtsrv, struct wins_server); - NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv); - - nbtsrv->winssrv->max_ttl = lp_max_wins_ttl(); - nbtsrv->winssrv->min_ttl = lp_min_wins_ttl(); - - return winsdb_init(nbtsrv->winssrv); -} diff --git a/source4/nbt_server/winswack.c b/source4/nbt_server/winswack.c deleted file mode 100644 index da8efff8d9..0000000000 --- a/source4/nbt_server/winswack.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - "secure" wins server WACK processing - - Copyright (C) Andrew Tridgell 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. -*/ - -#include "includes.h" -#include "nbt_server/nbt_server.h" -#include "nbt_server/winsdb.h" -#include "system/time.h" - -struct wack_state { - struct wins_server *winssrv; - struct nbt_name_socket *nbtsock; - struct nbt_name_packet *request_packet; - struct winsdb_record *rec; - const char *src_address; - int src_port; - 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_address, state->src_port, NBT_RCODE_ACT); - DEBUG(4,("WINS: denied name registration request for %s from %s\n", - nbt_name_string(state, state->rec->name), state->src_address)); - talloc_free(state); -} - -/* - allow a registration request -*/ -static void wins_wack_allow(struct wack_state *state) -{ - uint32_t ttl; - time_t now = time(NULL); - struct winsdb_record *rec = state->rec, *rec2; - - rec2 = winsdb_load(state->winssrv, rec->name, state); - if (rec2 == NULL || rec2->version != rec->version) { - 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_address, state->src_port, NBT_RCODE_OK); - - rec->addresses = str_list_add(rec->addresses, state->reg_address); - if (rec->addresses == NULL) goto failed; - - ttl = wins_server_ttl(state->winssrv, state->request_packet->additional[0].ttl); - if (now + ttl > rec->expire_time) { - rec->expire_time = now + ttl; - } - rec->registered_by = state->src_address; - - winsdb_modify(state->winssrv, rec); - - 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;rec->addresses[i];) { - if (!str_list_check(state->query.out.reply_addrs, rec->addresses[i])) { - str_list_remove(rec->addresses, rec->addresses[i]); - } else { - 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 char *src_address, int src_port) -{ - 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->src_port = src_port; - state->owner_addresses = rec->addresses; - state->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr; - state->src_address = talloc_strdup(state, src_address); - if (state->src_address == 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 * str_list_length(rec->addresses); - nbtd_wack_reply(nbtsock, packet, src_address, src_port, 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_address, src_port, NBT_RCODE_SVR); -} -- cgit