summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/wrepl_server/wrepl_in_call.c150
-rw-r--r--source4/wrepl_server/wrepl_server.c23
-rw-r--r--source4/wrepl_server/wrepl_server.h16
3 files changed, 159 insertions, 30 deletions
diff --git a/source4/wrepl_server/wrepl_in_call.c b/source4/wrepl_server/wrepl_in_call.c
index 444fda544b..9158b1a741 100644
--- a/source4/wrepl_server/wrepl_in_call.c
+++ b/source4/wrepl_server/wrepl_in_call.c
@@ -32,21 +32,96 @@
static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call)
{
- struct wrepl_stop *stop;
+ struct wrepl_start *start = &call->req_packet.message.start;
+ struct wrepl_start *start_reply = &call->rep_packet.message.start_reply;
+
+ if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
+ /*
+ *if the assoc_ctx doesn't match ignore the packet
+ */
+ if ((call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx)
+ && (call->req_packet.assoc_ctx != 0)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ } else {
+ call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_INVALID_ASSOC_CTX;
+ return NT_STATUS_OK;
+ }
- call->rep_packet.opcode = WREPL_OPCODE_BITS;
- call->rep_packet.assoc_ctx = 0;
- call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
- stop = &call->rep_packet.message.stop;
- stop->reason = 4;
+ if (start->minor_version != 2 || start->major_version != 5) {
+ /* w2k terminate the connection if the versions doesn't match */
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ 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;
+
+ call->rep_packet.mess_type = WREPL_START_ASSOCIATION_REPLY;
+ start_reply->assoc_ctx = call->wreplconn->assoc_ctx.our_ctx;
+ start_reply->minor_version = 2;
+ start_reply->major_version = 5;
return NT_STATUS_OK;
}
+static NTSTATUS wreplsrv_in_stop_assoc_ctx(struct wreplsrv_in_call *call)
+{
+ struct wrepl_stop *stop_out = &call->rep_packet.message.stop;
+
+ call->wreplconn->assoc_ctx.stopped = True;
+
+ call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
+ stop_out->reason = 4;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS wreplsrv_in_stop_association(struct wreplsrv_in_call *call)
+{
+ /*
+ * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
+ */
+ if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
+ /*
+ *if the assoc_ctx doesn't match ignore the packet
+ */
+ if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ /* when the opcode bits are set the connection should be directly terminated */
+ return NT_STATUS_CONNECTION_RESET;
+ }
+
+ if (call->wreplconn->assoc_ctx.stopped) {
+ /* this causes the connection to be directly terminated */
+ return NT_STATUS_CONNECTION_RESET;
+ }
+
+ /* this will cause to not receive packets anymore and terminate the connection if the reply is send */
+ call->wreplconn->terminate = True;
+ return wreplsrv_in_stop_assoc_ctx(call);
+}
+
static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
{
struct wrepl_replication *repl_in = &call->req_packet.message.replication;
- struct wrepl_stop *stop_out;
+
+ /*
+ * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
+ */
+ if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
+ /*
+ *if the assoc_ctx doesn't match ignore the packet
+ */
+ if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ if (!call->wreplconn->partner) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
switch (repl_in->command) {
case WREPL_REPL_TABLE_QUERY:
@@ -67,43 +142,64 @@ static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
break;
}
- call->rep_packet.opcode = WREPL_OPCODE_BITS;
+ return ERROR_INVALID_PARAMETER;
+}
+
+static NTSTATUS wreplsrv_in_invalid_assoc_ctx(struct wreplsrv_in_call *call)
+{
+ struct wrepl_start *start = &call->rep_packet.message.start;
+
+ call->rep_packet.opcode = 0x00008583;
call->rep_packet.assoc_ctx = 0;
- call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
- stop_out = &call->rep_packet.message.stop;
- stop_out->reason = 4;
+ call->rep_packet.mess_type = WREPL_START_ASSOCIATION;
+
+ start->assoc_ctx = 0x0000000a;
+ start->minor_version = 0x0001;
+ start->major_version = 0x0000;
+
+ call->rep_packet.padding = data_blob_talloc(call, NULL, 4);
+ memset(call->rep_packet.padding.data, '\0', call->rep_packet.padding.length);
return NT_STATUS_OK;
}
NTSTATUS wreplsrv_in_call(struct wreplsrv_in_call *call)
{
- struct wrepl_stop *stop_out;
+ NTSTATUS status;
- /* TODO: check opcode and assoc_ctx */
+ if (!(call->req_packet.opcode & WREPL_OPCODE_BITS)
+ && (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX)) {
+ return wreplsrv_in_invalid_assoc_ctx(call);
+ }
switch (call->req_packet.mess_type) {
case WREPL_START_ASSOCIATION:
- return wreplsrv_in_start_association(call);
-
- case WREPL_START_ASSOCIATION_REPLY:
- /* this is not valid here */
+ status = wreplsrv_in_start_association(call);
break;
+ case WREPL_START_ASSOCIATION_REPLY:
+ /* this is not valid here, so we ignore it */
+ return ERROR_INVALID_PARAMETER;
+
case WREPL_STOP_ASSOCIATION:
- /* this is not valid here */
+ status = wreplsrv_in_stop_association(call);
break;
case WREPL_REPLICATION:
- return wreplsrv_in_replication(call);
+ status = wreplsrv_in_replication(call);
+ break;
+ default:
+ /* everythingelse is also not valid here, so we ignore it */
+ return ERROR_INVALID_PARAMETER;
}
- call->rep_packet.opcode = WREPL_OPCODE_BITS;
- call->rep_packet.assoc_ctx = 0;
- call->rep_packet.mess_type = WREPL_STOP_ASSOCIATION;
- call->rep_packet.padding = data_blob(NULL, 0);
- stop_out = &call->rep_packet.message.stop;
- stop_out->reason = 4;
+ if (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX) {
+ return wreplsrv_in_invalid_assoc_ctx(call);
+ }
- return NT_STATUS_OK;
-}
+ if (NT_STATUS_IS_OK(status)) {
+ call->rep_packet.opcode = WREPL_OPCODE_BITS;
+ call->rep_packet.assoc_ctx = call->wreplconn->assoc_ctx.peer_ctx;
+ }
+ return status;
+}
diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c
index 50be38e8d6..63fb6cd902 100644
--- a/source4/wrepl_server/wrepl_server.c
+++ b/source4/wrepl_server/wrepl_server.c
@@ -57,6 +57,8 @@ static void wreplsrv_accept(struct stream_connection *conn)
return;
}
+ /* TODO: find out if it's a partner */
+
conn->private = wreplconn;
irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
@@ -130,7 +132,7 @@ static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
packet_in_blob.data = wreplconn->partial.data + 4;
packet_in_blob.length = wreplconn->partial.length - 4;
- call = talloc(wreplconn, struct wreplsrv_in_call);
+ call = talloc_zero(wreplconn, struct wreplsrv_in_call);
if (!call) {
status = NT_STATUS_NO_MEMORY;
goto failed;
@@ -165,7 +167,13 @@ static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
wreplconn->processing = True;
status = wreplsrv_in_call(call);
wreplconn->processing = False;
- if (!NT_STATUS_IS_OK(status)) goto failed;
+ if (NT_STATUS_IS_ERR(status)) goto failed;
+ if (!NT_STATUS_IS_OK(status)) {
+ /* w2k just ignores invalid packets, so we do */
+ DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
+ talloc_free(call);
+ return;
+ }
/* and now encode the reply */
packet_out_wrap.packet = call->rep_packet;
@@ -194,7 +202,11 @@ static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
}
DLIST_ADD_END(wreplconn->send_queue, rep, struct data_blob_list_item *);
- EVENT_FD_READABLE(conn->event.fde);
+ if (wreplconn->terminate) {
+ EVENT_FD_NOT_READABLE(conn->event.fde);
+ } else {
+ EVENT_FD_READABLE(conn->event.fde);
+ }
return;
failed:
@@ -226,6 +238,11 @@ static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
}
}
+ if (wreplconn->terminate) {
+ wreplsrv_terminate_connection(wreplconn, "connection terminated after all pending packets are send");
+ return;
+ }
+
EVENT_FD_NOT_WRITEABLE(conn->event.fde);
return;
diff --git a/source4/wrepl_server/wrepl_server.h b/source4/wrepl_server/wrepl_server.h
index f8bd59dbdb..bbf4a4b98f 100644
--- a/source4/wrepl_server/wrepl_server.h
+++ b/source4/wrepl_server/wrepl_server.h
@@ -27,6 +27,9 @@ struct wreplsrv_partner;
struct wreplsrv_pull_partner_item;
struct wreplsrv_push_partner_item;
+#define WREPLSRV_VALID_ASSOC_CTX 0x12345678
+#define WREPLSRV_INVALID_ASSOC_CTX 0x0000000a
+
/*
state of an incoming wrepl call
*/
@@ -60,6 +63,13 @@ struct wreplsrv_in_connection {
*/
const char *our_ip;
+ /* keep track of the assoc_ctx's */
+ struct {
+ BOOL stopped;
+ uint32_t our_ctx;
+ uint32_t peer_ctx;
+ } assoc_ctx;
+
/* the partial input on the connection */
DATA_BLOB partial;
size_t partial_read;
@@ -70,6 +80,12 @@ struct wreplsrv_in_connection {
*/
BOOL processing;
+ /*
+ * if this is set we no longer accept incoming packets
+ * and terminate the connection after we have send all packets
+ */
+ BOOL terminate;
+
/* the list of outgoing DATA_BLOB's that needs to be send */
struct data_blob_list_item *send_queue;
};