1
0
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:
Stefan Metzmacher 2005-10-14 12:44:47 +00:00 committed by Gerald (Jerry) Carter
parent ee49ed7a20
commit d49e67f06f
3 changed files with 159 additions and 30 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};