r10766: - make it possible to mark a wrepl_request as send only,
authorStefan Metzmacher <metze@samba.org>
Thu, 6 Oct 2005 14:38:07 +0000 (14:38 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:39:28 +0000 (13:39 -0500)
  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
source4/libcli/wrepl/winsrepl.c
source4/libcli/wrepl/winsrepl.h
source4/torture/nbt/winsreplication.c

index 582aee1332b81962ad72295cd28b9747dd1d6ebe..20b8cfa7218ec85c3736cb7ce8a41b041ec3f3ab 100644 (file)
@@ -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;
 
index 297dccbf388c6e27574443fa88d923544fee4415..31ef1ffbebadbf2898015bda6e3a4e60b7ff8671 100644 (file)
@@ -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;
 
index e78f0464e78a2b8f943f3387782f6c50e7a8c110..89a4c642b2b50f0920f30119fd12ff7cf5726534 100644 (file)
@@ -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
 */
index 68961ab1800b01ab82e24c9b22fd4841d2002855..e72ba9c8d6aead1c75543048ae6a5c19c515c7d5 100644 (file)
@@ -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");