r335: added much better handling of servers that die unexpectedly during a
authorAndrew Tridgell <tridge@samba.org>
Fri, 23 Apr 2004 04:21:22 +0000 (04:21 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:51:33 +0000 (12:51 -0500)
request (a dead socket). I discovered this when testing against Sun's
PC-NetLink.

cleaned up the naming of some of the samr requests

add IDL and test code for samr_QueryGroupMember(),
samr_SetMemberAttributesOfGroup() and samr_Shutdown().  (actually, I
didn't leave the samr_Shutdown() test in, as its fatal to windows
servers due to doing exactly what it says it does).
(This used to be commit 925bc2622c105dee4ffff809c6c35cd209a839f8)

source4/lib/util_sock.c
source4/libcli/raw/clisocket.c
source4/libcli/raw/clitransport.c
source4/libcli/raw/rawrequest.c
source4/libcli/raw/rawtrans.c
source4/librpc/idl/samr.idl
source4/librpc/rpc/dcerpc_smb.c
source4/librpc/rpc/dcerpc_tcp.c
source4/torture/rpc/autoidl.c
source4/torture/rpc/samr.c

index 95e0c5fe0cbdf59714d2b7680dfd56612b41bef5..57d3715cfc01e2b18716377272ce54b48d029241 100644 (file)
@@ -187,6 +187,11 @@ ssize_t read_data(int fd, char *buffer, size_t N)
        ssize_t ret;
        size_t total=0;  
  
+       if (fd == -1) {
+               errno = EIO;
+               return -1;
+       }
+
        while (total < N) {
                ret = sys_read(fd,buffer + total,N - total);
                if (ret == 0) {
@@ -209,6 +214,11 @@ ssize_t write_data(int fd, const char *buffer, size_t N)
        size_t total=0;
        ssize_t ret;
 
+       if (fd == -1) {
+               errno = EIO;
+               return -1;
+       }
+
        while (total < N) {
                ret = sys_write(fd, buffer + total, N - total);
                if (ret == -1) {
index f596cba8548970b4de983a6fb947d2776ea98164..4dae7d517dba50bd8f9a0429b55989c589051103 100644 (file)
@@ -74,15 +74,25 @@ BOOL cli_sock_connect(struct cli_socket *sock, struct in_addr *ip, int port)
 }
 
 
+/****************************************************************************
+ mark the socket as dead
+****************************************************************************/
+void cli_sock_dead(struct cli_socket *sock)
+{
+       if (sock->fd != -1) {
+               close(sock->fd);
+               sock->fd = -1;
+       }
+}
+
 /****************************************************************************
  reduce socket reference count - if it becomes zero then close
 ****************************************************************************/
 void cli_sock_close(struct cli_socket *sock)
 {
        sock->reference_count--;
-       if (sock->reference_count <= 0 && sock->fd != -1) {
-               close(sock->fd);
-               sock->fd = -1;
+       if (sock->reference_count <= 0) {
+               cli_sock_dead(sock);
        }
 }
 
@@ -99,6 +109,11 @@ void cli_sock_set_options(struct cli_socket *sock, const char *options)
 ****************************************************************************/
 ssize_t cli_sock_write(struct cli_socket *sock, const char *data, size_t len)
 {
+       if (sock->fd == -1) {
+               errno = EIO;
+               return -1;
+       }
+
        return write_data(sock->fd, data, len);
 }
 
@@ -108,6 +123,11 @@ ssize_t cli_sock_write(struct cli_socket *sock, const char *data, size_t len)
 ****************************************************************************/
 ssize_t cli_sock_read(struct cli_socket *sock, char *data, size_t len)
 {
+       if (sock->fd == -1) {
+               errno = EIO;
+               return -1;
+       }
+
        return read_data(sock->fd, data, len);
 }
 
index 62152bbe4d96d6620709761ac465752959c3c140..b8eef65c7f205866512e08e62eb7a44ceac7350d 100644 (file)
@@ -60,6 +60,14 @@ void cli_transport_close(struct cli_transport *transport)
        }
 }
 
+/*
+  mark the transport as dead
+*/
+void cli_transport_dead(struct cli_transport *transport)
+{
+       cli_sock_dead(transport->socket);
+}
+
 
 
 /****************************************************************************
index 321d43f2202b3577f921482403c153843101b322..35a2d363df4374ac11340ed9d9feb2fb2c50a74d 100644 (file)
@@ -40,9 +40,11 @@ NTSTATUS cli_request_destroy(struct cli_request *req)
           _send() call fails completely */
        if (!req) return NT_STATUS_UNSUCCESSFUL;
 
-       /* remove it from the list of pending requests (a null op if
-          its not in the list) */
-       DLIST_REMOVE(req->transport->pending_requests, req);
+       if (req->transport) {
+               /* remove it from the list of pending requests (a null op if
+                  its not in the list) */
+               DLIST_REMOVE(req->transport->pending_requests, req);
+       }
 
        /* ahh, its so nice to destroy a complex structure in such a
           simple way! */
@@ -306,11 +308,12 @@ BOOL cli_request_receive(struct cli_request *req)
        /* keep receiving packets until this one is replied to */
        while (!req->in.buffer) {
                if (!cli_transport_select(req->transport)) {
+                       req->status = NT_STATUS_UNSUCCESSFUL;
                        return False;
                }
 
                if (!cli_request_receive_next(req->transport)) {
-                       cli_transport_close(req->transport);
+                       cli_transport_dead(req->transport);
                        req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
                        return False;
                }
index f7a3b4aa43ede982386179a5b1bffd0c31c4faf9..1fd91b29d773208dddbf96be1392172c66810ee0 100644 (file)
@@ -64,7 +64,6 @@ NTSTATUS smb_raw_trans2_recv(struct cli_request *req,
        parms->out.params.data = NULL;
 
        if (!cli_request_receive(req)) {
-               req->status = NT_STATUS_UNSUCCESSFUL;
                return cli_request_destroy(req);
        }
        
index 8f8a96a81995d6776483082d0421148ad521401f..170ccda08bdafd41edec736961eb710e3108f254 100644 (file)
 
        /******************/
        /* Function: 0x04 */
-       NTSTATUS samr_Shutdown ();
+
+       /*
+         shutdown the SAM - once you call this the SAM will be dead
+       */
+       NTSTATUS samr_Shutdown (
+               [in,ref]   policy_handle *handle
+               );
 
        /******************/
        /* Function: 0x05 */
                [in]                      uint32 rid
                );
 
+
        /************************/
        /* Function    0x19     */
-       NTSTATUS samr_QUERY_GROUPMEM();
+       /*
+         this isn't really valid IDL, but it does work. I suspect
+         I need to do some more pidl work to get this really right
+       */
+       typedef struct {
+               uint32 count;
+               uint32 v[count];
+       } samr_intArray;
+
+       typedef struct {
+               samr_intArray *rids;
+               samr_intArray *unknown7;
+       } samr_ridArray;
+
+       NTSTATUS samr_QueryGroupMember(
+               [in,ref]  policy_handle *handle,
+               [out]     uint32 *count,
+               [out]     samr_ridArray rids
+               );
+
 
        /************************/
        /* Function    0x1a     */
-       NTSTATUS samr_SET_MEMBER_ATTRIBUTES_OF_GROUP();
+
+       /*
+         win2003 seems to accept any data at all for the two integers
+         below, and doesn't seem to do anything with them that I can
+         see. Weird. I really expected the first integer to be a rid
+         and the second to be the attributes for that rid member.
+       */
+       NTSTATUS samr_SetMemberAttributesOfGroup(
+               [in,ref]  policy_handle *handle,
+               [in]      uint32 unknown1,
+               [in]      uint32 unknown2
+               );
 
 
        /************************/
 
        /************************/
        /* Function    0x1f     */
-       NTSTATUS samr_AddAliasMem(
+       NTSTATUS samr_AddAliasMember(
                [in,ref]  policy_handle *handle,
                [in,ref]  dom_sid2      *sid
                );
 
        /************************/
        /* Function    0x20     */
-       NTSTATUS samr_DelAliasMem(
+       NTSTATUS samr_DeleteAliasMember(
                [in,ref] policy_handle *handle,
                [in,ref] dom_sid2      *sid
                );
                [out]       dom_sid2      *sid
                );
 
+
        /************************/
        /* Function    0x42     */
        NTSTATUS samr_SET_DSRM_PASSWORD();
 
        /************************/
        /* Function    0x43     */
-       NTSTATUS samr_VALIDATE_PASSWORD();
 
+       /*
+         I haven't been able to work out the format of this one yet.
+         Seems to start with a switch level for a union?
+       */
+       NTSTATUS samr_ValidatePassword();
 }
index 7822231b82649961a2db6dc832eaf97ead270e19..3d646944ac5a2c99435ad1295c0f0e6f53c604bf 100644 (file)
@@ -75,6 +75,7 @@ static NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p,
        DATA_BLOB payload;
 
        status = smb_raw_trans_recv(req, mem_ctx, &trans);
+
        /* STATUS_BUFFER_OVERFLOW means that there is more data
           available via SMBreadX */
        if (!NT_STATUS_IS_OK(status) && 
index 77b536b10cbb16d1afdc5d102a939744ac337d7c..1b016b89578d1ec72ab43361b7136e045656cf3b 100644 (file)
@@ -29,6 +29,18 @@ struct tcp_private {
        uint32 port;
 };
 
+
+/*
+  mark the socket dead
+*/
+static void tcp_sock_dead(struct tcp_private *tcp)
+{
+       if (tcp && tcp->fd != -1) {
+               close(tcp->fd);
+               tcp->fd = -1;
+       }
+}
+
 static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p, 
                             TALLOC_CTX *mem_ctx,
                             DATA_BLOB *blob)
@@ -45,7 +57,8 @@ static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p,
 
        ret = read_data(tcp->fd, blob1.data, blob1.length);
        if (ret != blob1.length) {
-               return NT_STATUS_NET_WRITE_FAULT;
+               tcp_sock_dead(tcp);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
 
        /* this could be a ncacn_http endpoint - this doesn't work
@@ -54,7 +67,8 @@ static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p,
                memmove(blob1.data, blob1.data+14, 2);
                ret = read_data(tcp->fd, blob1.data+2, 14);
                if (ret != 14) {
-                       return NT_STATUS_NET_WRITE_FAULT;
+                       tcp_sock_dead(tcp);
+                       return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
                }
        }
 
@@ -74,7 +88,8 @@ static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p,
 
        ret = read_data(tcp->fd, blob->data + blob1.length, frag_length - blob1.length);
        if (ret != frag_length - blob1.length) {
-               return NT_STATUS_NET_WRITE_FAULT;
+               tcp_sock_dead(tcp);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
 
        return NT_STATUS_OK;
@@ -90,7 +105,8 @@ static NTSTATUS tcp_full_request(struct dcerpc_pipe *p,
 
        ret = write_data(tcp->fd, request_blob->data, request_blob->length);
        if (ret != request_blob->length) {
-               return NT_STATUS_NET_WRITE_FAULT;
+               tcp_sock_dead(tcp);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
 
        return tcp_raw_recv(p, mem_ctx, reply_blob);
@@ -120,7 +136,8 @@ static NTSTATUS tcp_initial_request(struct dcerpc_pipe *p,
 
        ret = write_data(tcp->fd, blob->data, blob->length);
        if (ret != blob->length) {
-               return NT_STATUS_NET_WRITE_FAULT;
+               tcp_sock_dead(tcp);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
 
        return NT_STATUS_OK;
@@ -134,9 +151,7 @@ static NTSTATUS tcp_shutdown_pipe(struct dcerpc_pipe *p)
 {
        struct tcp_private *tcp = p->transport.private;
 
-       if (tcp) {
-               close(tcp->fd);
-       }
+       tcp_sock_dead(tcp);
 
        return NT_STATUS_OK;
 }
index ae4126688f029d04bdc4ce4bd093070c77fa89b0..6021f10c4930ef26b04dc2f631e81cd6f53b12a0 100644 (file)
@@ -112,6 +112,11 @@ static void try_expand(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table
                                              insert_ofs, insert_ofs+n, depth+1);
                        }
                        return;
+               } else {
+#if 0
+                       print_depth(depth);
+                       printf("expand by %d gives fault 0x%x\n", n, p->last_fault_code);
+#endif
                }
                if (p->last_fault_code == 5) {
                        reopen(&p, iface);
@@ -222,7 +227,7 @@ static void test_scan_call(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_ta
 
 static void test_auto_scan(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table *iface)
 {
-       test_scan_call(mem_ctx, iface, 0x41);
+       test_scan_call(mem_ctx, iface, 0x26);
 }
 
 BOOL torture_rpc_autoidl(int dummy)
index 95d21e20e4a82b3b4058f73d76ca298c087ffa21..7433627743bd87d0fd0fd45a2a00c408d37f68a5 100644 (file)
@@ -701,30 +701,30 @@ static BOOL test_AddMemberToAlias(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                                  struct policy_handle *domain_handle,
                                  const struct dom_sid *domain_sid)
 {
-       struct samr_AddAliasMem r;
-       struct samr_DelAliasMem d;
+       struct samr_AddAliasMember r;
+       struct samr_DeleteAliasMember d;
        NTSTATUS status;
        BOOL ret = True;
        struct dom_sid *sid;
 
        sid = dom_sid_add_rid(mem_ctx, domain_sid, 512);
 
-       printf("testing AddAliasMem\n");
+       printf("testing AddAliasMember\n");
        r.in.handle = alias_handle;
        r.in.sid = sid;
 
-       status = dcerpc_samr_AddAliasMem(p, mem_ctx, &r);
+       status = dcerpc_samr_AddAliasMember(p, mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
-               printf("AddAliasMem failed - %s\n", nt_errstr(status));
+               printf("AddAliasMember failed - %s\n", nt_errstr(status));
                ret = False;
        }
 
        d.in.handle = alias_handle;
        d.in.sid = sid;
 
-       status = dcerpc_samr_DelAliasMem(p, mem_ctx, &d);
+       status = dcerpc_samr_DeleteAliasMember(p, mem_ctx, &d);
        if (!NT_STATUS_IS_OK(status)) {
-               printf("DelAliasMem failed - %s\n", nt_errstr(status));
+               printf("DelAliasMember failed - %s\n", nt_errstr(status));
                ret = False;
        }
 
@@ -2177,6 +2177,8 @@ static BOOL test_AddGroupMember(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        struct samr_AddGroupMember r;
        struct samr_DeleteGroupMember d;
+       struct samr_QueryGroupMember q;
+       struct samr_SetMemberAttributesOfGroup s;
        BOOL ret = True;
        uint32 rid;
 
@@ -2214,6 +2216,25 @@ static BOOL test_AddGroupMember(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                return False;
        }
 
+       /* this one is quite strange. I am using random inputs in the
+          hope of triggering an error that might give us a clue */
+       s.in.handle = group_handle;
+       s.in.unknown1 = random();
+       s.in.unknown2 = random();
+
+       status = dcerpc_samr_SetMemberAttributesOfGroup(p, mem_ctx, &s);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("SetMemberAttributesOfGroup failed - %s\n", nt_errstr(status));
+               return False;
+       }
+
+       q.in.handle = group_handle;
+
+       status = dcerpc_samr_QueryGroupMember(p, mem_ctx, &q);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("QueryGroupMember failed - %s\n", nt_errstr(status));
+               return False;
+       }
 
        status = dcerpc_samr_DeleteGroupMember(p, mem_ctx, &d);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2319,6 +2340,8 @@ static BOOL test_OpenDomain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
        ZERO_STRUCT(user_handle);
        ZERO_STRUCT(alias_handle);
+       ZERO_STRUCT(group_handle);
+       ZERO_STRUCT(domain_handle);
 
        printf("Testing OpenDomain\n");