From 6799fde75d1ccf93171874fd33f9e89e4472fd81 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Oct 2005 14:38:07 +0000 Subject: r10766: - make it possible to mark a wrepl_request as send only, used for WREPL_REPL_INFORM* messsages - make it possible to close the connection after a request was send used for WREPL_ASSOCIATION_STOP - fix the torture test that tests the assoc context handling between connections, you can issue a request and get the reply on another connection, I think we should not implement that in our server code, as I think it's a security hole, you can cause a windows server to send the replies to someone another client, that doesn't wait for data, and as there're no massage_id in the protocol the client would be confused by a replies that doesn't belong to a query metze (This used to be commit dfc95de8fa7ded8ea92cafe58cf86efcc7920156) --- source4/include/structs.h | 1 + source4/libcli/wrepl/winsrepl.c | 100 ++++++++++++++++++++++++++++++---- source4/libcli/wrepl/winsrepl.h | 14 +++++ source4/torture/nbt/winsreplication.c | 40 +++++++++++--- 4 files changed, 137 insertions(+), 18 deletions(-) diff --git a/source4/include/structs.h b/source4/include/structs.h index 582aee1332..20b8cfa721 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -268,6 +268,7 @@ struct ads_struct; struct wrepl_packet; struct wrepl_associate; +struct wrepl_associate_stop; struct wrepl_pull_table; struct wrepl_pull_names; diff --git a/source4/libcli/wrepl/winsrepl.c b/source4/libcli/wrepl/winsrepl.c index 297dccbf38..31ef1ffbeb 100644 --- a/source4/libcli/wrepl/winsrepl.c +++ b/source4/libcli/wrepl/winsrepl.c @@ -31,6 +31,7 @@ */ static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status) { + talloc_set_destructor(wrepl_socket, NULL); wrepl_socket->dead = True; if (wrepl_socket->fde) { @@ -96,9 +97,31 @@ static void wrepl_handler_send(struct wrepl_socket *wrepl_socket) return; } - DLIST_REMOVE(wrepl_socket->send_queue, req); - DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *); - req->state = WREPL_REQUEST_RECV; + if (req->disconnect_after_send) { + DLIST_REMOVE(wrepl_socket->send_queue, req); + req->status = NT_STATUS_OK; + req->state = WREPL_REQUEST_DONE; + wrepl_socket_dead(wrepl_socket, NT_STATUS_LOCAL_DISCONNECT); + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + if (req->send_only) { + DLIST_REMOVE(wrepl_socket->send_queue, req); + req->status = NT_STATUS_OK; + req->state = WREPL_REQUEST_DONE; + if (req->async.fn) { + EVENT_FD_READABLE(wrepl_socket->fde); + req->async.fn(req); + return; + } + } else { + DLIST_REMOVE(wrepl_socket->send_queue, req); + DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *); + req->state = WREPL_REQUEST_RECV; + } EVENT_FD_READABLE(wrepl_socket->fde); } @@ -289,7 +312,7 @@ failed: static int wrepl_socket_destructor(void *ptr) { struct wrepl_socket *sock = talloc_get_type(ptr, struct wrepl_socket); - wrepl_socket_dead(sock, NT_STATUS_CONNECTION_DISCONNECTED); + wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT); return 0; } @@ -415,7 +438,7 @@ static NTSTATUS wrepl_request_wait(struct wrepl_request *req) connect a wrepl_socket to a WINS server */ struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket, - const char *address) + const char *our_ip, const char *peer_ip) { struct wrepl_request *req; NTSTATUS status; @@ -429,8 +452,12 @@ struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket, DLIST_ADD(wrepl_socket->recv_queue, req); talloc_set_destructor(req, wrepl_request_destructor); - - status = socket_connect(wrepl_socket->sock, iface_best_ip(address), 0, address, + + if (!our_ip) { + our_ip = iface_best_ip(peer_ip); + } + + status = socket_connect(wrepl_socket->sock, our_ip, 0, peer_ip, WINS_REPLICATION_PORT, 0); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) goto failed; @@ -453,9 +480,9 @@ NTSTATUS wrepl_connect_recv(struct wrepl_request *req) /* connect a wrepl_socket to a WINS server - sync API */ -NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *address) +NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *our_ip, const char *peer_ip) { - struct wrepl_request *req = wrepl_connect_send(wrepl_socket, address); + struct wrepl_request *req = wrepl_connect_send(wrepl_socket, our_ip, peer_ip); return wrepl_connect_recv(req); } @@ -618,6 +645,59 @@ NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket, } +/* + stop an association - send +*/ +struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket, + struct wrepl_associate_stop *io) +{ + struct wrepl_packet *packet; + struct wrepl_request *req; + + packet = talloc_zero(wrepl_socket, struct wrepl_packet); + if (packet == NULL) return NULL; + + packet->opcode = WREPL_OPCODE_BITS; + packet->assoc_ctx = io->in.assoc_ctx; + packet->mess_type = WREPL_STOP_ASSOCIATION; + packet->message.stop.reason = io->in.reason; + + req = wrepl_request_send(wrepl_socket, packet); + + if (req && io->in.reason == 0) { + req->send_only = True; + req->disconnect_after_send = True; + } + + talloc_free(packet); + + return req; +} + +/* + stop an association - recv +*/ +NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req, + struct wrepl_associate_stop *io) +{ + struct wrepl_packet *packet=NULL; + NTSTATUS status; + status = wrepl_request_recv(req, req->wrepl_socket, &packet); + NT_STATUS_NOT_OK_RETURN(status); + talloc_free(packet); + return status; +} + +/* + setup an association - sync api +*/ +NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket, + struct wrepl_associate_stop *io) +{ + struct wrepl_request *req = wrepl_associate_stop_send(wrepl_socket, io); + return wrepl_associate_stop_recv(req, io); +} + /* fetch the partner tables - send */ @@ -735,8 +815,6 @@ NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req, io->out.num_names = packet->message.replication.info.reply.num_names; - status = NT_STATUS_NO_MEMORY; - io->out.names = talloc_array(packet, struct wrepl_name, io->out.num_names); if (io->out.names == NULL) goto nomem; diff --git a/source4/libcli/wrepl/winsrepl.h b/source4/libcli/wrepl/winsrepl.h index e78f0464e7..89a4c642b2 100644 --- a/source4/libcli/wrepl/winsrepl.h +++ b/source4/libcli/wrepl/winsrepl.h @@ -69,6 +69,10 @@ struct wrepl_request { DATA_BLOB buffer; + BOOL disconnect_after_send; + + BOOL send_only; + size_t num_read; struct timed_event *te; @@ -91,6 +95,16 @@ struct wrepl_associate { } out; }; +/* + setup an association +*/ +struct wrepl_associate_stop { + struct { + uint32_t assoc_ctx; + uint32_t reason; + } in; +}; + /* pull the partner table */ diff --git a/source4/torture/nbt/winsreplication.c b/source4/torture/nbt/winsreplication.c index 68961ab180..e72ba9c8d6 100644 --- a/source4/torture/nbt/winsreplication.c +++ b/source4/torture/nbt/winsreplication.c @@ -53,18 +53,20 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address) struct wrepl_socket *wrepl_socket2; struct wrepl_associate associate2; struct wrepl_pull_table pull_table; + struct wrepl_packet *rep_packet; + struct wrepl_associate_stop assoc_stop; NTSTATUS status; printf("Test if assoc_ctx is only valid on the conection it was created on\n"); wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL); wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL); - + printf("Setup 2 wrepl connections\n"); - status = wrepl_connect(wrepl_socket1, address); + status = wrepl_connect(wrepl_socket1, NULL, address); CHECK_STATUS(status, NT_STATUS_OK); - status = wrepl_connect(wrepl_socket2, address); + status = wrepl_connect(wrepl_socket2, NULL, address); CHECK_STATUS(status, NT_STATUS_OK); printf("Send a start association request (conn1)\n"); @@ -79,15 +81,39 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address) printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx); - printf("Send a replication table query, with assoc 1 (conn2), should be ignored\n"); + printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n"); pull_table.in.assoc_ctx = associate1.out.assoc_ctx; req = wrepl_pull_table_send(wrepl_socket2, &pull_table); - talloc_free(req); + req->send_only = True; + status = wrepl_request_recv(req, mem_ctx, &rep_packet); + CHECK_STATUS(status, NT_STATUS_OK); printf("Send a association request (conn2), to make sure the last request was ignored\n"); status = wrepl_associate(wrepl_socket2, &associate2); CHECK_STATUS(status, NT_STATUS_OK); + printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n"); + pull_table.in.assoc_ctx = 0; + req = wrepl_pull_table_send(wrepl_socket1, &pull_table); + status = wrepl_request_recv(req, mem_ctx, &rep_packet); + CHECK_STATUS(status, NT_STATUS_OK); + + printf("Send a association request (conn1), to make sure the last request was handled correct\n"); + status = wrepl_associate(wrepl_socket1, &associate2); + CHECK_STATUS(status, NT_STATUS_OK); + + assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx; + assoc_stop.in.reason = 4; + printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason); + status = wrepl_associate_stop(wrepl_socket1, &assoc_stop); + CHECK_STATUS(status, NT_STATUS_END_OF_FILE); + + assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx; + assoc_stop.in.reason = 0; + printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason); + status = wrepl_associate_stop(wrepl_socket2, &assoc_stop); + CHECK_STATUS(status, NT_STATUS_OK); + done: printf("Close 2 wrepl connections\n"); talloc_free(wrepl_socket1); @@ -111,7 +137,7 @@ static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address) wrepl_socket = wrepl_socket_init(mem_ctx, NULL); printf("Setup wrepl connections\n"); - status = wrepl_connect(wrepl_socket, address); + status = wrepl_connect(wrepl_socket, NULL, address); CHECK_STATUS(status, NT_STATUS_OK); @@ -175,7 +201,7 @@ static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address) wrepl_socket = wrepl_socket_init(mem_ctx, NULL); printf("Setup wrepl connections\n"); - status = wrepl_connect(wrepl_socket, address); + status = wrepl_connect(wrepl_socket, NULL, address); CHECK_STATUS(status, NT_STATUS_OK); printf("Send a start association request\n"); -- cgit