summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/wrepl_server/wrepl_apply_records.c339
1 files changed, 292 insertions, 47 deletions
diff --git a/source4/wrepl_server/wrepl_apply_records.c b/source4/wrepl_server/wrepl_apply_records.c
index 877314bcfb..acb981124d 100644
--- a/source4/wrepl_server/wrepl_apply_records.c
+++ b/source4/wrepl_server/wrepl_apply_records.c
@@ -34,23 +34,24 @@
#include "ldb/include/ldb.h"
#include "libcli/composite/composite.h"
#include "libcli/wrepl/winsrepl.h"
+#include "system/time.h"
enum _R_ACTION {
- R_DO_ADD = 1,
- R_DO_REPLACE = 2,
- R_NOT_REPLACE = 3,
- R_DO_MHOMED_MERGE = 4,
- R_DO_RELEASE_DEMAND = 5,
- R_DO_SGROUP_MERGE = 6
+ R_INVALID,
+ R_DO_REPLACE,
+ R_NOT_REPLACE,
+ R_DO_CHALLENGE,
+ R_DO_RELEASE_DEMAND,
+ R_DO_SGROUP_MERGE
};
static const char *_R_ACTION_enum_string(enum _R_ACTION action)
{
switch (action) {
- case R_DO_ADD: return "ADD";
+ case R_INVALID: return "INVALID";
case R_DO_REPLACE: return "REPLACE";
case R_NOT_REPLACE: return "NOT_REPLACE";
- case R_DO_MHOMED_MERGE: return "MHOMED_MERGE";
+ case R_DO_CHALLENGE: return "CHALLEGNE";
case R_DO_RELEASE_DEMAND: return "RELEASE_DEMAND";
case R_DO_SGROUP_MERGE: return "SGROUP_MERGE";
}
@@ -74,6 +75,30 @@ static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_
return R_DO_REPLACE;
}
+static BOOL r_is_subset_address_list(struct winsdb_record *r1, struct wrepl_name *r2)
+{
+ uint32_t i,j;
+ size_t len = winsdb_addr_list_length(r1->addresses);
+
+ for (i=0; i < len; i++) {
+ BOOL found = False;
+ for (j=0; j < r2->num_addresses; j++) {
+ if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
+ continue;
+ }
+
+ if (strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
+ return False;
+ }
+ found = True;
+ break;
+ }
+ if (!found) return False;
+ }
+
+ return True;
+}
+
/*
UNIQUE,ACTIVE vs. UNIQUE,ACTIVE with different ip(s) => REPLACE
UNIQUE,ACTIVE vs. UNIQUE,TOMBSTONE with different ip(s) => NOT REPLACE
@@ -247,6 +272,7 @@ static enum _R_ACTION replace_mhomed_replica_vs_X_replica(struct winsdb_record *
active:
_UA_UA_SI_U<00> => REPLACE
_UA_UA_DI_P<00> => NOT REPLACE
+_UA_UA_DI_O<00> => NOT REPLACE
_UA_UA_DI_N<00> => REPLACE
_UA_UT_SI_U<00> => NOT REPLACE
_UA_UT_DI_U<00> => NOT REPLACE
@@ -259,7 +285,9 @@ _UA_SA_DI_R<00> => REPLACE
_UA_ST_SI_U<00> => NOT REPLACE
_UA_ST_DI_U<00> => NOT REPLACE
_UA_MA_SI_U<00> => REPLACE
+_UA_MA_SP_U<00> => REPLACE
_UA_MA_DI_P<00> => NOT REPLACE
+_UA_MA_DI_O<00> => NOT REPLACE
_UA_MA_DI_N<00> => REPLACE
_UA_MT_SI_U<00> => NOT REPLACE
_UA_MT_DI_U<00> => NOT REPLACE
@@ -297,10 +325,33 @@ static enum _R_ACTION replace_unique_owned_vs_X_replica(struct winsdb_record *r1
return R_NOT_REPLACE;
}
- /* TODO: handle MHOMED merging and release damands */
+ if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
+ /* REPLACE and send a release demand to the old name owner */
+ return R_DO_RELEASE_DEMAND;
+ }
- /* NOT REPLACE */
- return R_NOT_REPLACE;
+ /*
+ * here we only have unique,active,owned vs.
+ * is unique,active,replica or mhomed,active,replica
+ */
+
+ if (r_is_subset_address_list(r1, r2)) {
+ /*
+ * if r1 has a subset(or same) of the addresses of r2
+ * <=>
+ * if r2 has a superset(or same) of the addresses of r1
+ *
+ * then replace the record
+ */
+ return R_DO_REPLACE;
+ }
+
+ /*
+ * in any other case, we need to do
+ * a name request to the old name holder
+ * to see if it's still there...
+ */
+ return R_DO_CHALLENGE;
}
/*
@@ -432,11 +483,11 @@ _MA_MA_SP_U<00> => REPLACE
_MA_MA_SM_U<00> => REPLACE
_MA_MA_SB_P<00> => MHOMED_MERGE
_MA_MA_SB_A<00> => MHOMED_MERGE
-_MA_MA_SB_C<00> => NOT REPLACE
+_MA_MA_SB_PRA<00> => NOT REPLACE
_MA_MA_SB_O<00> => NOT REPLACE
_MA_MA_SB_N<00> => REPLACE
Test Replica vs. owned active: some more UNIQUE,MHOMED combinations
-_MA_UA_SB_A<00> => MHOMED_MERGE
+_MA_UA_SB_P<00> => MHOMED_MERGE
released:
_MR_UA_SI<00> => REPLACE
@@ -468,88 +519,278 @@ static enum _R_ACTION replace_mhomed_owned_vs_X_replica(struct winsdb_record *r1
return R_NOT_REPLACE;
}
- /* TODO: handle MHOMED merging and release demands */
+ if (R_IS_GROUP(r2) || R_IS_SGROUP(r2)) {
+ /* REPLACE and send a release demand to the old name owner */
+ return R_DO_RELEASE_DEMAND;
+ }
- /* NOT REPLACE */
- return R_NOT_REPLACE;
+ /*
+ * here we only have mhomed,active,owned vs.
+ * is unique,active,replica or mhomed,active,replica
+ */
+
+ if (r_is_subset_address_list(r1, r2)) {
+ /*
+ * if r1 has a subset(or same) of the addresses of r2
+ * <=>
+ * if r2 has a superset(or same) of the addresses of r1
+ *
+ * then replace the record
+ */
+ return R_DO_REPLACE;
+ }
+
+ /*
+ * in any other case, we need to do
+ * a name request to the old name holder
+ * to see if it's still there...
+ */
+ return R_DO_CHALLENGE;
+}
+
+static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ struct winsdb_record *rec;
+ uint32_t i;
+ uint8_t ret;
+
+ rec = talloc(mem_ctx, struct winsdb_record);
+ NT_STATUS_HAVE_NO_MEMORY(rec);
+
+ rec->name = &replica->name;
+ rec->type = replica->type;
+ rec->state = replica->state;
+ rec->node = replica->node;
+ rec->is_static = replica->is_static;
+ rec->expire_time= time(NULL) + partner->service->config.verify_interval;
+ rec->version = replica->version_id;
+ rec->wins_owner = replica->owner;
+ rec->addresses = winsdb_addr_list_make(rec);
+ NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
+ rec->registered_by = NULL;
+
+ for (i=0; i < replica->num_addresses; i++) {
+ /* TODO: find out if rec->expire_time is correct here */
+ rec->addresses = winsdb_addr_list_add(rec->addresses,
+ replica->addresses[i].address,
+ replica->addresses[i].owner,
+ rec->expire_time);
+ NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
+ }
+
+ ret = winsdb_add(partner->service->wins_db, rec, 0);
+ if (ret != NBT_RCODE_OK) {
+ DEBUG(0,("Failed to add record %s: %u\n",
+ nbt_name_string(mem_ctx, &replica->name), ret));
+ return NT_STATUS_FOOBAR;
+ }
+
+ DEBUG(0,("added record %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+
+ return NT_STATUS_OK;
}
+static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct winsdb_record *rec,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ uint32_t i;
+ uint8_t ret;
+
+ rec->name = &replica->name;
+ rec->type = replica->type;
+ rec->state = replica->state;
+ rec->node = replica->node;
+ rec->is_static = replica->is_static;
+ rec->expire_time= time(NULL) + partner->service->config.verify_interval;
+ rec->version = replica->version_id;
+ rec->wins_owner = replica->owner;
+ rec->addresses = winsdb_addr_list_make(rec);
+ NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
+ rec->registered_by = NULL;
+
+ for (i=0; i < replica->num_addresses; i++) {
+ /* TODO: find out if rec->expire_time is correct here */
+ rec->addresses = winsdb_addr_list_add(rec->addresses,
+ replica->addresses[i].address,
+ replica->addresses[i].owner,
+ rec->expire_time);
+ NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
+ }
+
+ ret = winsdb_modify(partner->service->wins_db, rec, 0);
+ if (ret != NBT_RCODE_OK) {
+ DEBUG(0,("Failed to replace record %s: %u\n",
+ nbt_name_string(mem_ctx, &replica->name), ret));
+ return NT_STATUS_FOOBAR;
+ }
+
+ DEBUG(0,("replaced record %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS r_not_replace(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct winsdb_record *rec,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ DEBUG(0,("TODO: not replace record %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct winsdb_record *rec,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ /* TODO: !!! */
+ DEBUG(0,("TODO: challenge record %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct winsdb_record *rec,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ NTSTATUS status;
+ struct winsdb_addr **addresses;
+
+ /*
+ * we need to get a reference to the old addresses,
+ * as we need to send a release demand to them after replacing the record
+ * and r_do_replace() will modify rec->addresses
+ */
+ addresses = rec->addresses;
+
+ status = r_do_replace(partner, mem_ctx, rec, owner, replica);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* TODO: !!! */
+ DEBUG(0,("TODO: send release demand for %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
+ TALLOC_CTX *mem_ctx,
+ struct winsdb_record *rec,
+ struct wrepl_wins_owner *owner,
+ struct wrepl_name *replica)
+{
+ /* TODO: !!! */
+ DEBUG(0,("TODO: sgroup merge record %s\n",
+ nbt_name_string(mem_ctx, &replica->name)));
+ return NT_STATUS_OK;
+}
static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner,
TALLOC_CTX *mem_ctx,
struct wrepl_wins_owner *owner,
- struct wrepl_name *name)
+ struct wrepl_name *replica)
{
NTSTATUS status;
struct winsdb_record *rec = NULL;
- enum _R_ACTION action = R_NOT_REPLACE;
+ enum _R_ACTION action = R_INVALID;
BOOL same_owner = False;
BOOL replica_vs_replica = False;
BOOL local_vs_replica = False;
+ DEBUG(0,("apply record %s: from: %s %llu\n",
+ nbt_name_string(mem_ctx, &replica->name), owner->address, replica->version_id));
+
status = winsdb_lookup(partner->service->wins_db,
- &name->name, mem_ctx, &rec);
+ &replica->name, mem_ctx, &rec);
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
- rec = NULL;
- action = R_DO_ADD;
- status = NT_STATUS_OK;
+ return r_do_add(partner, mem_ctx, owner, replica);
}
+ DEBUG(0,("apply record %s: s1: %s\n",
+ nbt_name_string(mem_ctx, &replica->name), nt_errstr(status)));
NT_STATUS_NOT_OK_RETURN(status);
- if (rec) {
- if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
- local_vs_replica = True;
- } else if (strcmp(rec->wins_owner, owner->address)==0) {
- same_owner = True;
- } else {
- replica_vs_replica = True;
- }
+ if (strcmp(rec->wins_owner, WINSDB_OWNER_LOCAL)==0) {
+ local_vs_replica = True;
+ } else if (strcmp(rec->wins_owner, owner->address)==0) {
+ same_owner = True;
+ } else {
+ replica_vs_replica = True;
}
- if (rec && same_owner) {
- action = replace_same_owner(rec, name);
- } else if (rec && replica_vs_replica) {
+ DEBUG(0,("apply record %s: s2: lvr:%d so:%d rvr:%d\n",
+ nbt_name_string(mem_ctx, &replica->name), local_vs_replica, same_owner, replica_vs_replica));
+
+ if (rec->is_static && !same_owner) {
+ /* TODO: this is just assumed and needs to be tested more */
+ action = R_NOT_REPLACE;
+ } else if (same_owner) {
+ action = replace_same_owner(rec, replica);
+ } else if (replica_vs_replica) {
switch (rec->type) {
case WREPL_TYPE_UNIQUE:
- action = replace_unique_replica_vs_X_replica(rec, name);
+ action = replace_unique_replica_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_GROUP:
- action = replace_group_replica_vs_X_replica(rec, name);
+ action = replace_group_replica_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_SGROUP:
- action = replace_sgroup_replica_vs_X_replica(rec, name);
+ action = replace_sgroup_replica_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_MHOMED:
- action = replace_mhomed_replica_vs_X_replica(rec, name);
+ action = replace_mhomed_replica_vs_X_replica(rec, replica);
break;
}
- } else if (rec && local_vs_replica) {
+ } else if (local_vs_replica) {
switch (rec->type) {
case WREPL_TYPE_UNIQUE:
- action = replace_unique_owned_vs_X_replica(rec, name);
+ action = replace_unique_owned_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_GROUP:
- action = replace_group_owned_vs_X_replica(rec, name);
+ action = replace_group_owned_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_SGROUP:
- action = replace_sgroup_owned_vs_X_replica(rec, name);
+ action = replace_sgroup_owned_vs_X_replica(rec, replica);
break;
case WREPL_TYPE_MHOMED:
- action = replace_mhomed_owned_vs_X_replica(rec, name);
+ action = replace_mhomed_owned_vs_X_replica(rec, replica);
break;
}
}
- /* TODO: !!! */
- DEBUG(0,("TODO: apply record %s: %s\n",
- nbt_name_string(mem_ctx, &name->name), _R_ACTION_enum_string(action)));
+ DEBUG(0,("apply record %s: %s\n",
+ nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action)));
- return NT_STATUS_OK;
+ switch (action) {
+ case R_INVALID: break;
+ case R_DO_REPLACE:
+ return r_do_replace(partner, mem_ctx, rec, owner, replica);
+ case R_NOT_REPLACE:
+ return r_not_replace(partner, mem_ctx, rec, owner, replica);
+ case R_DO_CHALLENGE:
+ return r_do_challenge(partner, mem_ctx, rec, owner, replica);
+ case R_DO_RELEASE_DEMAND:
+ return r_do_release_demand(partner, mem_ctx, rec, owner, replica);
+ case R_DO_SGROUP_MERGE:
+ return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica);
+ }
+
+ return NT_STATUS_INTERNAL_ERROR;
}
NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
{
- TALLOC_CTX *tmp_mem = talloc_new(partner);
NTSTATUS status;
uint32_t i;
@@ -560,9 +801,13 @@ NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsr
partner->address));
for (i=0; i < names_io->out.num_names; i++) {
+ TALLOC_CTX *tmp_mem = talloc_new(partner);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_mem);
+
status = wreplsrv_apply_one_record(partner, tmp_mem,
&names_io->in.owner,
&names_io->out.names[i]);
+ talloc_free(tmp_mem);
NT_STATUS_NOT_OK_RETURN(status);
}