mirror of
https://github.com/samba-team/samba.git
synced 2025-02-25 17:57:42 +03:00
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)
This commit is contained in:
parent
ee49ed7a20
commit
d49e67f06f
@ -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;
|
||||
|
||||
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 (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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user