This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "nbt_server/wins/winsdb.h"
#include "libcli/wrepl/winsrepl.h"
#include "system/time.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "param/param.h"
enum _R_ACTION {
R_INVALID,
}
#define R_IS_ACTIVE(r) ((r)->state == WREPL_STATE_ACTIVE)
+#if 0 /* unused */
#define R_IS_RELEASED(r) ((r)->state == WREPL_STATE_RELEASED)
+#endif
#define R_IS_TOMBSTONE(r) ((r)->state == WREPL_STATE_TOMBSTONE)
#define R_IS_UNIQUE(r) ((r)->type == WREPL_TYPE_UNIQUE)
#define R_IS_GROUP(r) ((r)->type == WREPL_TYPE_GROUP)
#define R_IS_SGROUP(r) ((r)->type == WREPL_TYPE_SGROUP)
+#if 0 /* unused */
#define R_IS_MHOMED(r) ((r)->type == WREPL_TYPE_MHOMED)
+#endif
/* blindly overwrite records from the same owner in all cases */
static enum _R_ACTION replace_same_owner(struct winsdb_record *r1, struct wrepl_name *r2)
return R_DO_REPLACE;
}
-static BOOL r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_subset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
{
uint32_t i,j;
size_t len = winsdb_addr_list_length(r1->addresses);
for (i=0; i < len; i++) {
- BOOL found = False;
+ bool found = false;
for (j=0; j < r2->num_addresses; j++) {
if (strcmp(r1->addresses[i]->address, r2->addresses[j].address) != 0) {
continue;
}
if (check_owners && strcmp(r1->addresses[i]->wins_owner, r2->addresses[j].owner) != 0) {
- return False;
+ return false;
}
- found = True;
+ found = true;
break;
}
- if (!found) return False;
+ if (!found) return false;
}
- return True;
+ return true;
}
-static BOOL r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_superset_of_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
{
uint32_t i,j;
size_t len = winsdb_addr_list_length(r1->addresses);
for (i=0; i < r2->num_addresses; i++) {
- BOOL found = False;
+ bool found = false;
for (j=0; j < len; j++) {
if (strcmp(r2->addresses[i].address, r1->addresses[j]->address) != 0) {
continue;
}
if (check_owners && strcmp(r2->addresses[i].owner, r1->addresses[j]->wins_owner) != 0) {
- return False;
+ return false;
}
- found = True;
+ found = true;
break;
}
- if (!found) return False;
+ if (!found) return false;
}
- return True;
+ return true;
}
-static BOOL r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, BOOL check_owners)
+static bool r_1_is_same_as_2_address_list(struct winsdb_record *r1, struct wrepl_name *r2, bool check_owners)
{
size_t len = winsdb_addr_list_length(r1->addresses);
if (len != r2->num_addresses) {
- return False;
+ return false;
}
return r_1_is_superset_of_2_address_list(r1, r2, check_owners);
}
-static BOOL r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
+static bool r_contains_addrs_from_owner(struct winsdb_record *r1, const char *owner)
{
uint32_t i;
size_t len = winsdb_addr_list_length(r1->addresses);
for (i=0; i < len; i++) {
if (strcmp(r1->addresses[i]->wins_owner, owner) == 0) {
- return True;
+ return true;
}
}
- return False;
+ return false;
}
/*
return R_NOT_REPLACE;
}
- if (r_1_is_superset_of_2_address_list(r1, r2, True)) {
+ if (r_1_is_superset_of_2_address_list(r1, r2, true)) {
/* NOT REPLACE */
return R_NOT_REPLACE;
}
- if (r_1_is_same_as_2_address_list(r1, r2, False)) {
+ if (r_1_is_same_as_2_address_list(r1, r2, false)) {
/* REPLACE */
return R_DO_REPLACE;
}
* is unique,active,replica or mhomed,active,replica
*/
- if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
+ if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
/*
* if r1 has a subset(or same) of the addresses of r2
* <=>
return R_DO_PROPAGATE;
}
- if (r_1_is_same_as_2_address_list(r1, r2, True)) {
+ if (r_1_is_same_as_2_address_list(r1, r2, true)) {
/*
* as we're the old owner and the addresses and their
* owners are identical
* is unique,active,replica or mhomed,active,replica
*/
- if (r_1_is_subset_of_2_address_list(r1, r2, False)) {
+ if (r_1_is_subset_of_2_address_list(r1, r2, false)) {
/*
* if r1 has a subset(or same) of the addresses of r2
* <=>
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,
+ rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ rec, rec->addresses,
replica->addresses[i].address,
replica->addresses[i].owner,
- rec->expire_time);
+ rec->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
}
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,
+ rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ rec, rec->addresses,
replica->addresses[i].address,
replica->addresses[i].owner,
- rec->expire_time);
+ rec->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
}
merge->registered_by = NULL;
for (i=0; i < replica->num_addresses; i++) {
- /* TODO: find out if rec->expire_time is correct here */
- merge->addresses = winsdb_addr_list_add(merge->addresses,
+ merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ merge, merge->addresses,
replica->addresses[i].address,
replica->addresses[i].owner,
- merge->expire_time);
+ merge->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
}
len = winsdb_addr_list_length(rec->addresses);
for (i=0; i < len; i++) {
- BOOL found = False;
+ bool found = false;
for (j=0; j < replica->num_addresses; j++) {
if (strcmp(replica->addresses[j].address, rec->addresses[i]->address) == 0) {
- found = True;
+ found = true;
break;
}
}
if (found) continue;
- /* TODO: find out if rec->expire_time is correct here */
- merge->addresses = winsdb_addr_list_add(merge->addresses,
+ merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ merge, merge->addresses,
rec->addresses[i]->address,
rec->addresses[i]->wins_owner,
- merge->expire_time);
+ rec->addresses[i]->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
}
static void r_do_late_release_demand_handler(struct irpc_request *ireq)
{
NTSTATUS status;
- struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
+ struct r_do_challenge_state *state = talloc_get_type(ireq->async.private_data,
struct r_do_challenge_state);
status = irpc_call_recv(ireq);
static NTSTATUS r_do_late_release_demand(struct r_do_challenge_state *state)
{
struct irpc_request *ireq;
- uint32_t *nbt_servers;
+ struct server_id *nbt_servers;
struct nbtd_proxy_wins_release_demand r;
uint32_t i;
DEBUG(4,("late release demand record %s\n",
nbt_name_string(state, &state->replica.name)));
- nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
- if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+ nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+ if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
return NT_STATUS_INTERNAL_ERROR;
}
NT_STATUS_HAVE_NO_MEMORY(ireq);
ireq->async.fn = r_do_late_release_demand_handler;
- ireq->async.private = state;
+ ireq->async.private_data= state;
return NT_STATUS_OK;
}
static void r_do_challenge_handler(struct irpc_request *ireq)
{
NTSTATUS status;
- struct r_do_challenge_state *state = talloc_get_type(ireq->async.private,
+ struct r_do_challenge_state *state = talloc_get_type(ireq->async.private_data,
struct r_do_challenge_state);
- BOOL old_is_subset = False;
- BOOL new_is_subset = False;
- BOOL found = False;
+ bool old_is_subset = false;
+ bool new_is_subset = false;
+ bool found = false;
uint32_t i,j;
uint32_t num_rec_addrs;
}
for (i=0; i < state->replica.num_addresses; i++) {
- found = False;
- new_is_subset = True;
+ found = false;
+ new_is_subset = true;
for (j=0; j < state->r.out.num_addrs; j++) {
if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) {
- found = True;
+ found = true;
break;
}
}
if (found) continue;
- new_is_subset = False;
+ new_is_subset = false;
break;
}
num_rec_addrs = winsdb_addr_list_length(state->rec->addresses);
for (i=0; i < num_rec_addrs; i++) {
- found = False;
- old_is_subset = True;
+ found = false;
+ old_is_subset = true;
for (j=0; j < state->r.out.num_addrs; j++) {
if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) {
- found = True;
+ found = true;
break;
}
}
if (found) continue;
- old_is_subset = False;
+ old_is_subset = false;
break;
}
if (!old_is_subset) {
- r_do_late_release_demand(state);
+ status = r_do_late_release_demand(state);
/*
- * don't free state here, because we pass it down,
+ * only free state on error, because we pass it down,
* and r_do_late_release_demand() will free it
*/
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(state);
+ }
return;
}
{
struct irpc_request *ireq;
struct r_do_challenge_state *state;
- uint32_t *nbt_servers;
+ struct server_id *nbt_servers;
const char **addrs;
uint32_t i;
talloc_steal(state, replica->owner);
talloc_steal(state, replica->addresses);
- nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
- if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+ nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+ if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
return NT_STATUS_INTERNAL_ERROR;
}
NT_STATUS_HAVE_NO_MEMORY(ireq);
ireq->async.fn = r_do_challenge_handler;
- ireq->async.private = state;
+ ireq->async.private_data= state;
talloc_steal(partner, state);
return NT_STATUS_OK;
}
+struct r_do_release_demand_state {
+ struct messaging_context *msg_ctx;
+ struct nbtd_proxy_wins_release_demand r;
+};
+
static void r_do_release_demand_handler(struct irpc_request *ireq)
{
NTSTATUS status;
+ struct r_do_release_demand_state *state = talloc_get_type(ireq->async.private_data,
+ struct r_do_release_demand_state);
+
status = irpc_call_recv(ireq);
/* don't care about the result */
+ talloc_free(state);
}
static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner,
{
NTSTATUS status;
struct irpc_request *ireq;
- uint32_t *nbt_servers;
+ struct server_id *nbt_servers;
const char **addrs;
struct winsdb_addr **addresses;
- struct nbtd_proxy_wins_release_demand r;
+ struct r_do_release_demand_state *state;
uint32_t i;
/*
DEBUG(4,("release demand record %s\n",
nbt_name_string(mem_ctx, &replica->name)));
- nbt_servers = irpc_servers_byname(partner->service->task->msg_ctx, "nbt_server");
- if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
+ state = talloc_zero(mem_ctx, struct r_do_release_demand_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+ state->msg_ctx = partner->service->task->msg_ctx;
+
+ nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server");
+ if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) {
return NT_STATUS_INTERNAL_ERROR;
}
- r.in.name = *rec->name;
- r.in.num_addrs = winsdb_addr_list_length(addresses);
- r.in.addrs = talloc_array(partner, struct nbtd_proxy_wins_addr, r.in.num_addrs);
- NT_STATUS_HAVE_NO_MEMORY(r.in.addrs);
+ state->r.in.name = *rec->name;
+ state->r.in.num_addrs = winsdb_addr_list_length(addresses);
+ state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr,
+ state->r.in.num_addrs);
+ NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs);
/* TODO: fix pidl to handle inline ipv4address arrays */
- addrs = winsdb_addr_string_list(r.in.addrs, addresses);
+ addrs = winsdb_addr_string_list(state->r.in.addrs, addresses);
NT_STATUS_HAVE_NO_MEMORY(addrs);
- for (i=0; i < r.in.num_addrs; i++) {
- r.in.addrs[i].addr = addrs[i];
+ for (i=0; i < state->r.in.num_addrs; i++) {
+ state->r.in.addrs[i].addr = addrs[i];
}
- ireq = IRPC_CALL_SEND(partner->service->task->msg_ctx, nbt_servers[0],
+ ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0],
irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
- &r, partner);
+ &state->r, state);
NT_STATUS_HAVE_NO_MEMORY(ireq);
ireq->async.fn = r_do_release_demand_handler;
- ireq->async.private = NULL;
+ ireq->async.private_data= state;
+ talloc_steal(partner, state);
return NT_STATUS_OK;
}
uint32_t i,j;
uint8_t ret;
size_t len;
- BOOL changed_old_addrs = False;
- BOOL become_owner = True;
+ bool changed_old_addrs = false;
+ bool skip_replica_owned_by_us = false;
+ bool become_owner = true;
+ bool propagate = lp_parm_bool(partner->service->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false);
+ const char *local_owner = partner->service->wins_db->local_owner;
merge = talloc(mem_ctx, struct winsdb_record);
NT_STATUS_HAVE_NO_MEMORY(merge);
len = winsdb_addr_list_length(rec->addresses);
for (i=0; i < len; i++) {
- BOOL found = False;
+ bool found = false;
for (j=0; j < replica->num_addresses; j++) {
if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) {
continue;
}
- found = True;
+ found = true;
if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) {
- changed_old_addrs = True;
+ changed_old_addrs = true;
break;
}
break;
}
- /* if it's also in the replica, it'll added later */
- if (found) continue;
-
/*
* if the address isn't in the replica and is owned by replicas owner,
* it won't be added to the merged record
*/
- if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
- changed_old_addrs = True;
+ if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
+ changed_old_addrs = true;
continue;
}
/*
- * add the address to the merge result, with the old owner and expire_time
+ * add the address to the merge result, with the old owner and expire_time,
+ * the owner and expire_time will be overwritten later if the address is
+ * in the replica too
*/
- merge->addresses = winsdb_addr_list_add(merge->addresses,
+ merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ merge, merge->addresses,
rec->addresses[i]->address,
rec->addresses[i]->wins_owner,
- rec->addresses[i]->expire_time);
+ rec->addresses[i]->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
}
for (i=0; i < replica->num_addresses; i++) {
- /* TODO: find out if rec->expire_time is correct here */
- merge->addresses = winsdb_addr_list_add(merge->addresses,
+ if (propagate &&
+ strcmp(replica->addresses[i].owner, local_owner) == 0) {
+ const struct winsdb_addr *a;
+
+ /*
+ * NOTE: this is different to the windows behavior
+ * and off by default, but it better propagated
+ * name releases
+ */
+ a = winsdb_addr_list_check(merge->addresses,
+ replica->addresses[i].address);
+ if (!a) {
+ /* don't add addresses owned by us */
+ skip_replica_owned_by_us = true;
+ }
+ continue;
+ }
+ merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+ merge, merge->addresses,
replica->addresses[i].address,
replica->addresses[i].owner,
- merge->expire_time);
+ merge->expire_time,
+ false);
NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
}
/* we the old addresses change changed we don't become the owner */
if (changed_old_addrs) {
- become_owner = False;
+ become_owner = false;
+ }
+
+ /*
+ * when we notice another server believes an address
+ * is owned by us and that's not the case
+ * we propagate the result
+ */
+ if (skip_replica_owned_by_us) {
+ become_owner = true;
}
/* if we're the owner of the old record, we'll be the owner of the new one too */
- if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
- become_owner = True;
+ if (strcmp(rec->wins_owner, local_owner)==0) {
+ become_owner = true;
}
/*
*/
len = winsdb_addr_list_length(merge->addresses);
if (len == 0) {
- become_owner = True;
+ become_owner = true;
}
/*
* will be owner of the merge result, otherwise we take the ownership
*/
if (become_owner) {
+ time_t lh = 0;
+
modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
+
+ /*
+ * if we're the owner, the expire time becomes the highest
+ * expire time of owned addresses
+ */
+ len = winsdb_addr_list_length(merge->addresses);
+
+ for (i=0; i < len; i++) {
+ if (strcmp(merge->addresses[i]->wins_owner, local_owner)==0) {
+ lh = MAX(lh, merge->addresses[i]->expire_time);
+ }
+ }
+
+ if (lh != 0) {
+ merge->expire_time = lh;
+ }
}
ret = winsdb_modify(partner->service->wins_db, merge, modify_flags);
NTSTATUS status;
struct winsdb_record *rec = NULL;
enum _R_ACTION action = R_INVALID;
- BOOL same_owner = False;
- BOOL replica_vs_replica = False;
- BOOL local_vs_replica = False;
+ bool same_owner = false;
+ bool replica_vs_replica = false;
+ bool local_vs_replica = false;
+
+ if (replica->name.scope) {
+ TALLOC_CTX *parent;
+ const char *scope;
+
+ /*
+ * Windows 2008 truncates the scope to 237 bytes,
+ * so we do...
+ */
+ parent = talloc_parent(replica->name.scope);
+ scope = talloc_strndup(parent, replica->name.scope, 237);
+ NT_STATUS_HAVE_NO_MEMORY(scope);
+ replica->name.scope = scope;
+ }
status = winsdb_lookup(partner->service->wins_db,
&replica->name, mem_ctx, &rec);
NT_STATUS_NOT_OK_RETURN(status);
if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) {
- local_vs_replica = True;
+ local_vs_replica = true;
} else if (strcmp(rec->wins_owner, owner->address)==0) {
- same_owner = True;
+ same_owner = true;
} else {
- replica_vs_replica = True;
+ replica_vs_replica = true;
}
if (rec->is_static && !same_owner) {
return NT_STATUS_INTERNAL_ERROR;
}
-NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wreplsrv_pull_names_io *names_io)
+NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner,
+ struct wrepl_wins_owner *owner,
+ uint32_t num_names, struct wrepl_name *names)
{
NTSTATUS status;
uint32_t i;
DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n",
- names_io->out.num_names, names_io->in.owner.address,
- (long long)names_io->in.owner.min_version,
- (long long)names_io->in.owner.max_version,
+ num_names, owner->address,
+ (long long)owner->min_version,
+ (long long)owner->max_version,
partner->address));
- for (i=0; i < names_io->out.num_names; i++) {
+ for (i=0; i < 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]);
+ owner, &names[i]);
talloc_free(tmp_mem);
NT_STATUS_NOT_OK_RETURN(status);
}
status = wreplsrv_add_table(partner->service,
partner->service,
&partner->service->table,
- names_io->in.owner.address,
- names_io->in.owner.max_version);
+ owner->address,
+ owner->max_version);
NT_STATUS_NOT_OK_RETURN(status);
return NT_STATUS_OK;