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 "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
+#include "system/time.h"
static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call)
{
return NT_STATUS_OK;
}
+/*
+ * it seems that we don't know all details about the start_association
+ * to support replication with NT4 (it sends 1.1 instead of 5.2)
+ * we ignore the version numbers until we know all details
+ */
+#if 0
if (start->minor_version != 2 || start->major_version != 5) {
/* w2k terminate the connection if the versions doesn't match */
return NT_STATUS_UNKNOWN_REVISION;
}
+#endif
- call->wreplconn->assoc_ctx.stopped = False;
+ call->wreplconn->assoc_ctx.stopped = false;
call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_VALID_ASSOC_CTX;
call->wreplconn->assoc_ctx.peer_ctx = start->assoc_ctx;
start_reply->minor_version = 2;
start_reply->major_version = 5;
+ /*
+ * nt4 uses 41 bytes for the start_association call
+ * so do it the same and as we don't know the meanings of this bytes
+ * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
+ *
+ * if we don't do this nt4 uses an old version of the wins replication protocol
+ * and that would break nt4 <-> samba replication
+ */
+ call->rep_packet.padding = data_blob_talloc(call, NULL, 21);
+ NT_STATUS_HAVE_NO_MEMORY(call->rep_packet.padding.data);
+
+ memset(call->rep_packet.padding.data, 0, call->rep_packet.padding.length);
+
return NT_STATUS_OK;
}
{
struct wrepl_stop *stop_out = &call->rep_packet.message.stop;
- call->wreplconn->assoc_ctx.stopped = True;
+ call->wreplconn->assoc_ctx.stopped = true;
call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
stop_out->reason = 4;
}
/* this will cause to not receive packets anymore and terminate the connection if the reply is send */
- call->terminate_after_send = True;
+ call->terminate_after_send = true;
return wreplsrv_in_stop_assoc_ctx(call);
}
repl_out->command = WREPL_REPL_TABLE_REPLY;
return wreplsrv_fill_wrepl_table(service, call, table_out,
- service->wins_db->local_owner, True);
+ service->wins_db->local_owner, true);
}
static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,
struct wrepl_wins_name *names;
struct winsdb_record *rec;
NTSTATUS status;
- uint32_t i;
+ uint32_t i, j;
+ time_t now = time(NULL);
owner = wreplsrv_find_owner(service, service->table, owner_in->address);
(long long)owner_in->min_version,
(long long)owner_in->max_version);
NT_STATUS_HAVE_NO_MEMORY(filter);
- ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
+ ret = ldb_search(service->wins_db->ldb, call, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "%s", filter);
if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
- talloc_steal(call, res);
DEBUG(10,("WINSREPL: filter '%s' count %d\n", filter, res->count));
if (res->count == 0) {
names = talloc_array(call, struct wrepl_wins_name, res->count);
NT_STATUS_HAVE_NO_MEMORY(names);
- for (i = 0; i < res->count; i++) {
- status = winsdb_record(service->wins_db, res->msgs[i], call, &rec);
+ for (i=0, j=0; i < res->count; i++) {
+ status = winsdb_record(service->wins_db, res->msgs[i], call, now, &rec);
NT_STATUS_NOT_OK_RETURN(status);
- status = wreplsrv_record2wins_name(names, &names[i], rec);
- NT_STATUS_NOT_OK_RETURN(status);
+ /*
+ * it's possible that winsdb_record() made the record RELEASED
+ * because it's expired, but in the database it's still stored
+ * as ACTIVE...
+ *
+ * make sure we really only replicate ACTIVE and TOMBSTONE records
+ */
+ if (rec->state == WREPL_STATE_ACTIVE || rec->state == WREPL_STATE_TOMBSTONE) {
+ status = wreplsrv_record2wins_name(names, &names[j], rec);
+ NT_STATUS_NOT_OK_RETURN(status);
+ j++;
+ }
+
talloc_free(rec);
talloc_free(res->msgs[i]);
}
/* sort the names before we send them */
- qsort(names, res->count, sizeof(struct wrepl_wins_name), (comparison_fn_t)wreplsrv_in_sort_wins_name);
+ qsort(names, j, sizeof(struct wrepl_wins_name), (comparison_fn_t)wreplsrv_in_sort_wins_name);
DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
- res->count, owner_in->address,
+ j, owner_in->address,
(long long)owner_in->min_version,
(long long)owner_in->max_version,
call->wreplconn->partner->address));
- reply_out->num_names = res->count;
+ reply_out->num_names = j;
reply_out->names = names;
return NT_STATUS_OK;
}
if (!call->wreplconn->partner) {
- DEBUG(1,("Failing WINS replication from non-partner %s\n",
- socket_get_peer_addr(call->wreplconn->conn->socket, call)));
- return wreplsrv_in_stop_assoc_ctx(call);
+ struct socket_address *partner_ip = socket_get_peer_addr(call->wreplconn->conn->socket, call);
+
+ call->wreplconn->partner = wreplsrv_find_partner(call->wreplconn->service, partner_ip->addr);
+ if (!call->wreplconn->partner) {
+ DEBUG(1,("Failing WINS replication from non-partner %s\n",
+ partner_ip ? partner_ip->addr : NULL));
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
}
switch (repl_in->command) {
case WREPL_REPL_TABLE_QUERY:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
+ DEBUG(2,("Failing WINS replication TABLE_QUERY from non-push-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_table_query(call);
case WREPL_REPL_SEND_REQUEST:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
+ DEBUG(2,("Failing WINS replication SEND_REQUESET from non-push-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_send_request(call);
case WREPL_REPL_UPDATE:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ DEBUG(2,("Failing WINS replication UPDATE from non-pull-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_update(call);
case WREPL_REPL_UPDATE2:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ DEBUG(2,("Failing WINS replication UPDATE2 from non-pull-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_update2(call);
case WREPL_REPL_INFORM:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ DEBUG(2,("Failing WINS replication INFORM from non-pull-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_inform(call);
case WREPL_REPL_INFORM2:
if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ DEBUG(2,("Failing WINS replication INFORM2 from non-pull-partner %s\n",
+ call->wreplconn->partner->address));
return wreplsrv_in_stop_assoc_ctx(call);
}
status = wreplsrv_in_inform2(call);