From d49e67f06f55054f23dbef609b4debb11c157ffa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 14 Oct 2005 12:44:47 +0000 Subject: r11014: r10139@SERNOX: metze | 2005-09-10 10:32:36 +0200 - w2k just ignores invalid packets, so we do now - w2k only checks the assoc_ctx when the opcode has the sepcific obcode bit's set - terminate the connection, when getting a WREPL_STOP_ASSOCIATION packet - some more special error handling proper torture test for all this cases are following later metze (This used to be commit 42b69461aad3942dde361d61b950445dd39882aa) --- source4/wrepl_server/wrepl_in_call.c | 150 ++++++++++++++++++++++++++++------- source4/wrepl_server/wrepl_server.c | 23 +++++- source4/wrepl_server/wrepl_server.h | 16 ++++ 3 files changed, 159 insertions(+), 30 deletions(-) (limited to 'source4') 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; }; -- cgit