X-Git-Url: http://git.samba.org/samba.git/?p=kai%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source4%2Fwrepl_server%2Fwrepl_scavenging.c;h=a5cd36797d5193cf8a08a3ea69075b0ce2eed278;hp=a19604d4165f2d55ce762f2bca30ed65666938f0;hb=1284308a35f4983609fd77633b6137fdf8df6c75;hpb=c05019a04bbfc882092a55f8e97682abd2c3ec8b diff --git a/source4/wrepl_server/wrepl_scavenging.c b/source4/wrepl_server/wrepl_scavenging.c index a19604d4165..a5cd36797d5 100644 --- a/source4/wrepl_server/wrepl_scavenging.c +++ b/source4/wrepl_server/wrepl_scavenging.c @@ -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, @@ -16,55 +16,68 @@ 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 . */ #include "includes.h" -#include "dlinklist.h" -#include "lib/events/events.h" -#include "lib/socket/socket.h" -#include "smbd/service_task.h" -#include "smbd/service_stream.h" -#include "lib/messaging/irpc.h" #include "librpc/gen_ndr/ndr_winsrepl.h" #include "wrepl_server/wrepl_server.h" #include "nbt_server/wins/winsdb.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_errors.h" -#include "libcli/composite/composite.h" -#include "libcli/wrepl/winsrepl.h" -#include "wrepl_server/wrepl_out_helpers.h" #include "system/time.h" +#include "smbd/service_task.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "librpc/gen_ndr/ndr_nbt.h" + +const char *wreplsrv_owner_filter(struct wreplsrv_service *service, + TALLOC_CTX *mem_ctx, + const char *wins_owner) +{ + if (strcmp(wins_owner, service->wins_db->local_owner) == 0) { + return talloc_asprintf(mem_ctx, "(|(winsOwner=%s)(winsOwner=0.0.0.0))", + wins_owner); + } + + return talloc_asprintf(mem_ctx, "(&(winsOwner=%s)(!(winsOwner=0.0.0.0)))", + wins_owner); +} static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem) { NTSTATUS status; struct winsdb_record *rec = NULL; struct ldb_result *res = NULL; + const char *owner_filter; const char *filter; uint32_t i; int ret; time_t now = time(NULL); const char *now_timestr; const char *action; - const char *old_state; + const char *old_state=NULL; + const char *new_state=NULL; uint32_t modify_flags; - BOOL modify_record; - BOOL delete_record; - BOOL delete_tombstones; + bool modify_record; + bool delete_record; + bool delete_tombstones; struct timeval tombstone_extra_time; now_timestr = ldb_timestring(tmp_mem, now); NT_STATUS_HAVE_NO_MEMORY(now_timestr); + owner_filter = wreplsrv_owner_filter(service, tmp_mem, + service->wins_db->local_owner); + NT_STATUS_HAVE_NO_MEMORY(owner_filter); filter = talloc_asprintf(tmp_mem, - "(&(winsOwner=%s)(objectClass=winsRecord)" - "(expireTime<=%s)(!(isStatic=1)))", - WINSDB_OWNER_LOCAL, now_timestr); + "(&%s(objectClass=winsRecord)" + "(expireTime<=%s))", + owner_filter, now_timestr); NT_STATUS_HAVE_NO_MEMORY(filter); - ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); + ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION; talloc_steal(tmp_mem, res); + DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count)); tombstone_extra_time = timeval_add(&service->startup_time, service->config.tombstone_extra_timeout, @@ -72,46 +85,46 @@ static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *servi delete_tombstones = timeval_expired(&tombstone_extra_time); for (i=0; i < res->count; i++) { - status = winsdb_record(res->msgs[i], tmp_mem, &rec); + /* + * we pass '0' as 'now' here, + * because we want to get the raw timestamps which are in the DB + */ + status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec); NT_STATUS_NOT_OK_RETURN(status); - - if (rec->is_static) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (rec->expire_time > now) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + talloc_free(res->msgs[i]); modify_flags = 0; - modify_record = False; - delete_record = False; + modify_record = false; + delete_record = false; switch (rec->state) { case WREPL_STATE_ACTIVE: old_state = "active"; - rec->state = WREPL_STATE_RELEASED; - rec->expire_time= service->config.tombstone_interval + now; + new_state = "active"; + if (!rec->is_static) { + new_state = "released"; + rec->state = WREPL_STATE_RELEASED; + rec->expire_time= service->config.tombstone_interval + now; + } modify_flags = 0; - modify_record = True; + modify_record = true; break; case WREPL_STATE_RELEASED: old_state = "released"; + new_state = "tombstone"; rec->state = WREPL_STATE_TOMBSTONE; rec->expire_time= service->config.tombstone_timeout + now; modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; - modify_record = True; + modify_record = true; break; case WREPL_STATE_TOMBSTONE: old_state = "tombstone"; + new_state = "tombstone"; if (!delete_tombstones) break; - delete_record = True; + new_state = "deleted"; + delete_record = true; break; case WREPL_STATE_RESERVED: @@ -132,11 +145,11 @@ static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *servi } if (ret != NBT_RCODE_OK) { - DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s): error:%u\n", - action, nbt_name_string(rec, rec->name), old_state, ret)); + DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s -> owned:%s): error:%u\n", + action, nbt_name_string(rec, rec->name), old_state, new_state, ret)); } else { - DEBUG(4,("WINS scavenging: %s name: %s (owned:%s)\n", - action, nbt_name_string(rec, rec->name), old_state)); + DEBUG(4,("WINS scavenging: %s name: %s (owned:%s -> owned:%s)\n", + action, nbt_name_string(rec, rec->name), old_state, new_state)); } talloc_free(rec); @@ -150,29 +163,35 @@ static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_s NTSTATUS status; struct winsdb_record *rec = NULL; struct ldb_result *res = NULL; + const char *owner_filter; const char *filter; uint32_t i; int ret; time_t now = time(NULL); const char *now_timestr; const char *action; - const char *old_state; + const char *old_state=NULL; + const char *new_state=NULL; uint32_t modify_flags; - BOOL modify_record; - BOOL delete_record; - BOOL delete_tombstones; + bool modify_record; + bool delete_record; + bool delete_tombstones; struct timeval tombstone_extra_time; now_timestr = ldb_timestring(tmp_mem, now); NT_STATUS_HAVE_NO_MEMORY(now_timestr); + owner_filter = wreplsrv_owner_filter(service, tmp_mem, + service->wins_db->local_owner); + NT_STATUS_HAVE_NO_MEMORY(owner_filter); filter = talloc_asprintf(tmp_mem, - "(&(!(winsOwner=%s))(objectClass=winsRecord)" - "(!(recordState=%u))(expireTime<=%s)(!(isStatic=1)))", - WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr); + "(&(!%s)(objectClass=winsRecord)" + "(!(recordState=%u))(expireTime<=%s))", + owner_filter, WREPL_STATE_ACTIVE, now_timestr); NT_STATUS_HAVE_NO_MEMORY(filter); - ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); + ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION; talloc_steal(tmp_mem, res); + DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count)); tombstone_extra_time = timeval_add(&service->startup_time, service->config.tombstone_extra_timeout, @@ -180,24 +199,17 @@ static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_s delete_tombstones = timeval_expired(&tombstone_extra_time); for (i=0; i < res->count; i++) { - status = winsdb_record(res->msgs[i], tmp_mem, &rec); + /* + * we pass '0' as 'now' here, + * because we want to get the raw timestamps which are in the DB + */ + status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec); NT_STATUS_NOT_OK_RETURN(status); - - if (rec->is_static) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (rec->expire_time > now) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + talloc_free(res->msgs[i]); modify_flags = 0; - modify_record = False; - delete_record = False; + modify_record = false; + delete_record = false; switch (rec->state) { case WREPL_STATE_ACTIVE: @@ -207,16 +219,19 @@ static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_s case WREPL_STATE_RELEASED: old_state = "released"; + new_state = "tombstone"; rec->state = WREPL_STATE_TOMBSTONE; rec->expire_time= service->config.tombstone_timeout + now; modify_flags = 0; - modify_record = True; + modify_record = true; break; case WREPL_STATE_TOMBSTONE: old_state = "tombstone"; + new_state = "tombstone"; if (!delete_tombstones) break; - delete_record = True; + new_state = "deleted"; + delete_record = true; break; case WREPL_STATE_RESERVED: @@ -237,11 +252,11 @@ static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_s } if (ret != NBT_RCODE_OK) { - DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n", - action, nbt_name_string(rec, rec->name), old_state, ret)); + DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s -> replica:%s): error:%u\n", + action, nbt_name_string(rec, rec->name), old_state, new_state, ret)); } else { - DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n", - action, nbt_name_string(rec, rec->name), old_state)); + DEBUG(4,("WINS scavenging: %s name: %s (replica:%s -> replica:%s)\n", + action, nbt_name_string(rec, rec->name), old_state, new_state)); } talloc_free(rec); @@ -250,48 +265,158 @@ static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_s return NT_STATUS_OK; } +struct verify_state { + struct messaging_context *msg_ctx; + struct wreplsrv_service *service; + struct winsdb_record *rec; + struct nbtd_proxy_wins_challenge r; +}; + +static void verify_handler(struct irpc_request *ireq) +{ + struct verify_state *s = talloc_get_type(ireq->async.private, + struct verify_state); + struct winsdb_record *rec = s->rec; + const char *action; + const char *old_state = "active"; + const char *new_state = "active"; + const char *new_owner = "replica"; + uint32_t modify_flags = 0; + bool modify_record = false; + bool delete_record = false; + bool different = false; + int ret; + NTSTATUS status; + uint32_t i, j; + + /* + * - if the name isn't present anymore remove our record + * - if the name is found and not a normal group check if the addresses match, + * - if they don't match remove the record + * - if they match do nothing + * - if an error happens do nothing + */ + status = irpc_call_recv(ireq); + if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { + delete_record = true; + new_state = "deleted"; + } else if (NT_STATUS_IS_OK(status) && rec->type != WREPL_TYPE_GROUP) { + for (i=0; i < s->r.out.num_addrs; i++) { + bool found = false; + for (j=0; rec->addresses[j]; j++) { + if (strcmp(s->r.out.addrs[i].addr, rec->addresses[j]->address) == 0) { + found = true; + break; + } + } + if (!found) { + different = true; + break; + } + } + } else if (NT_STATUS_IS_OK(status) && rec->type == WREPL_TYPE_GROUP) { + if (s->r.out.num_addrs != 1 || strcmp(s->r.out.addrs[0].addr, "255.255.255.255") != 0) { + different = true; + } + } + + if (different) { + /* + * if the reply from the owning wins server has different addresses + * then take the ownership of the record and make it a tombstone + * this will then hopefully replicated to the original owner of the record + * which will then propagate it's own record, so that the current record will + * be replicated to to us + */ + DEBUG(0,("WINS scavenging: replica %s verify got different addresses from winsserver: %s: tombstoning record\n", + nbt_name_string(rec, rec->name), rec->wins_owner)); + + rec->state = WREPL_STATE_TOMBSTONE; + rec->expire_time= time(NULL) + s->service->config.tombstone_timeout; + for (i=0; rec->addresses[i]; i++) { + rec->addresses[i]->expire_time = rec->expire_time; + } + modify_record = true; + modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; + new_state = "tombstone"; + new_owner = "owned"; + } else if (NT_STATUS_IS_OK(status)) { + /* if the addresses are the same, just update the timestamps */ + rec->expire_time = time(NULL) + s->service->config.verify_interval; + for (i=0; rec->addresses[i]; i++) { + rec->addresses[i]->expire_time = rec->expire_time; + } + modify_record = true; + modify_flags = 0; + new_state = "active"; + } + + if (modify_record) { + action = "modify"; + ret = winsdb_modify(s->service->wins_db, rec, modify_flags); + } else if (delete_record) { + action = "delete"; + ret = winsdb_delete(s->service->wins_db, rec); + } else { + action = "skip"; + ret = NBT_RCODE_OK; + } + + if (ret != NBT_RCODE_OK) { + DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s -> %s:%s): error:%u\n", + action, nbt_name_string(rec, rec->name), old_state, new_owner, new_state, ret)); + } else { + DEBUG(4,("WINS scavenging: %s name: %s (replica:%s -> %s:%s): %s: %s\n", + action, nbt_name_string(rec, rec->name), old_state, new_owner, new_state, + rec->wins_owner, nt_errstr(status))); + } + + talloc_free(s); +} + static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem) { NTSTATUS status; struct winsdb_record *rec = NULL; struct ldb_result *res = NULL; + const char *owner_filter; const char *filter; uint32_t i; int ret; time_t now = time(NULL); const char *now_timestr; - const char *action; - const char *old_state; - BOOL modify_flags; - BOOL modify_record; - BOOL delete_record; + struct irpc_request *ireq; + struct verify_state *s; + struct server_id *nbt_servers; + + nbt_servers = irpc_servers_byname(service->task->msg_ctx, tmp_mem, "nbt_server"); + if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) { + return NT_STATUS_INTERNAL_ERROR; + } now_timestr = ldb_timestring(tmp_mem, now); NT_STATUS_HAVE_NO_MEMORY(now_timestr); + owner_filter = wreplsrv_owner_filter(service, tmp_mem, + service->wins_db->local_owner); + NT_STATUS_HAVE_NO_MEMORY(owner_filter); filter = talloc_asprintf(tmp_mem, - "(&(!(winsOwner=%s))(objectClass=winsRecord)" - "(recordState=%u)(expireTime<=%s)(!(isStatic=1)))", - WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr); + "(&(!%s)(objectClass=winsRecord)" + "(recordState=%u)(expireTime<=%s))", + owner_filter, WREPL_STATE_ACTIVE, now_timestr); NT_STATUS_HAVE_NO_MEMORY(filter); - ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); + ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION; talloc_steal(tmp_mem, res); + DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count)); for (i=0; i < res->count; i++) { - status = winsdb_record(res->msgs[i], tmp_mem, &rec); + /* + * we pass '0' as 'now' here, + * because we want to get the raw timestamps which are in the DB + */ + status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec); NT_STATUS_NOT_OK_RETURN(status); - - if (rec->is_static) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (rec->expire_time > now) { - DEBUG(0,("%s: corrupted record: %s\n", - __location__, nbt_name_string(rec, rec->name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + talloc_free(res->msgs[i]); if (rec->state != WREPL_STATE_ACTIVE) { DEBUG(0,("%s: corrupted record: %s\n", @@ -299,39 +424,41 @@ static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_servi return NT_STATUS_INTERNAL_DB_CORRUPTION; } - old_state = "active"; - - modify_flags = 0; - modify_record = False; - delete_record = False; - /* - * TODO: ask the owning wins server if the record still exists, - * if not delete the record + * ask the owning wins server if the record still exists, + * if not delete the record + * + * TODO: NOTE: this is a simpliefied version, to verify that + * a record still exist, I assume that w2k3 uses + * DCERPC calls or some WINSREPL packets for this, + * but we use a wins name query */ - DEBUG(0,("TODO: ask wins server '%s' if '%s' with version_id:%llu still exists\n", - rec->wins_owner, nbt_name_string(rec, rec->name), rec->version)); - - if (modify_record) { - action = "modify"; - ret = winsdb_modify(service->wins_db, rec, modify_flags); - } else if (delete_record) { - action = "delete"; - ret = winsdb_delete(service->wins_db, rec); - } else { - action = "skip"; - ret = NBT_RCODE_OK; - } - - if (ret != NBT_RCODE_OK) { - DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n", - action, nbt_name_string(rec, rec->name), old_state, ret)); - } else { - DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n", - action, nbt_name_string(rec, rec->name), old_state)); - } - - talloc_free(rec); + DEBUG(0,("ask wins server '%s' if '%s' with version_id:%llu still exists\n", + rec->wins_owner, nbt_name_string(rec, rec->name), + (unsigned long long)rec->version)); + + s = talloc_zero(tmp_mem, struct verify_state); + NT_STATUS_HAVE_NO_MEMORY(s); + s->msg_ctx = service->task->msg_ctx; + s->service = service; + s->rec = talloc_steal(s, rec); + + s->r.in.name = *rec->name; + s->r.in.num_addrs = 1; + s->r.in.addrs = talloc_array(s, struct nbtd_proxy_wins_addr, s->r.in.num_addrs); + NT_STATUS_HAVE_NO_MEMORY(s->r.in.addrs); + /* TODO: fix pidl to handle inline ipv4address arrays */ + s->r.in.addrs[0].addr = rec->wins_owner; + + ireq = IRPC_CALL_SEND(s->msg_ctx, nbt_servers[0], + irpc, NBTD_PROXY_WINS_CHALLENGE, + &s->r, s); + NT_STATUS_HAVE_NO_MEMORY(ireq); + + ireq->async.fn = verify_handler; + ireq->async.private = s; + + talloc_steal(service, s); } return NT_STATUS_OK; @@ -341,15 +468,28 @@ NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service) { NTSTATUS status; TALLOC_CTX *tmp_mem; + bool skip_first_run = false; if (!timeval_expired(&service->scavenging.next_run)) { return NT_STATUS_OK; } + if (timeval_is_zero(&service->scavenging.next_run)) { + skip_first_run = true; + } + service->scavenging.next_run = timeval_current_ofs(service->config.scavenging_interval, 0); status = wreplsrv_periodic_schedule(service, service->config.scavenging_interval); NT_STATUS_NOT_OK_RETURN(status); + /* + * if it's the first time this functions is called (startup) + * the next_run is zero, in this case we should not do scavenging + */ + if (skip_first_run) { + return NT_STATUS_OK; + } + if (service->scavenging.processing) { return NT_STATUS_OK; } @@ -357,23 +497,26 @@ NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service) DEBUG(4,("wreplsrv_scavenging_run(): start\n")); tmp_mem = talloc_new(service); - service->scavenging.processing = True; + NT_STATUS_HAVE_NO_MEMORY(tmp_mem); + service->scavenging.processing = true; status = wreplsrv_scavenging_owned_records(service,tmp_mem); - service->scavenging.processing = False; + service->scavenging.processing = false; talloc_free(tmp_mem); NT_STATUS_NOT_OK_RETURN(status); tmp_mem = talloc_new(service); - service->scavenging.processing = True; + NT_STATUS_HAVE_NO_MEMORY(tmp_mem); + service->scavenging.processing = true; status = wreplsrv_scavenging_replica_non_active_records(service, tmp_mem); - service->scavenging.processing = False; + service->scavenging.processing = false; talloc_free(tmp_mem); NT_STATUS_NOT_OK_RETURN(status); tmp_mem = talloc_new(service); - service->scavenging.processing = True; + NT_STATUS_HAVE_NO_MEMORY(tmp_mem); + service->scavenging.processing = true; status = wreplsrv_scavenging_replica_active_records(service, tmp_mem); - service->scavenging.processing = False; + service->scavenging.processing = false; talloc_free(tmp_mem); NT_STATUS_NOT_OK_RETURN(status);