s3: Fix infinite loop in NCACN_IP_TCP asa there is no timeout. Assume lsa_pipe_tcp...
authorBo Yang <boyang@samba.org>
Wed, 6 Jan 2010 04:13:35 +0000 (12:13 +0800)
committerBo Yang <boyang@samba.org>
Wed, 6 Jan 2010 11:19:35 +0000 (19:19 +0800)
Signed-off-by: Bo Yang <boyang@samba.org>
source3/include/proto.h
source3/rpc_client/cli_pipe.c
source3/rpc_client/ndr.c
source3/rpc_client/rpc_transport_np.c
source3/rpc_client/rpc_transport_smbd.c
source3/rpc_client/rpc_transport_sock.c
source3/winbindd/winbindd_cm.c
source3/winbindd/winbindd_rpc.c

index b3921c4..d956ede 100644 (file)
@@ -5396,6 +5396,7 @@ NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
                               const struct ndr_syntax_id *abstract_syntax,
                               struct rpc_cli_transport **presult);
 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p);
+void rpccli_close_np_fd(struct rpc_pipe_client *p);
 
 /* The following definitions come from rpc_client/rpc_transport_smbd.c  */
 
@@ -5426,11 +5427,15 @@ NTSTATUS rpc_transport_smbd_init(TALLOC_CTX *mem_ctx,
                                 struct rpc_cli_smbd_conn *conn,
                                 const struct ndr_syntax_id *abstract_syntax,
                                 struct rpc_cli_transport **presult);
+struct cli_state *rpc_pipe_smbd_smb_conn(struct rpc_pipe_client *p);
 
 /* The following definitions come from rpc_client/rpc_transport_sock.c  */
 
 NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
                                 struct rpc_cli_transport **presult);
+int rpccli_set_sock_timeout(struct rpc_pipe_client *rpccli, int timeout);
+void rpccli_close_sock_fd(struct rpc_pipe_client *rpccli);
+bool rpc_pipe_tcp_connection_ok(struct rpc_pipe_client *rpccli);
 
 /* The following definitions come from rpc_client/cli_samr.c  */
 
index 9653166..48e2f9e 100644 (file)
@@ -3035,12 +3035,30 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
 unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
                                unsigned int timeout)
 {
-       struct cli_state *cli = rpc_pipe_np_smb_conn(rpc_cli);
+       struct cli_state *cli;
 
-       if (cli == NULL) {
-               return 0;
+       if (rpc_cli->transport->transport == NCACN_NP) {
+               cli = rpc_pipe_np_smb_conn(rpc_cli);
+               if (cli == NULL) {
+                       return 0;
+               }
+               return cli_set_timeout(cli, timeout);
+       }
+
+       if (rpc_cli->transport->transport == NCACN_IP_TCP ||
+           rpc_cli->transport->transport == NCALRPC) {
+               return rpccli_set_sock_timeout(rpc_cli, timeout);
        }
-       return cli_set_timeout(cli, timeout);
+
+       if (rpc_cli->transport->transport == NCACN_INTERNAL) {
+               cli = rpc_pipe_smbd_smb_conn(rpc_cli);
+               if (!cli) {
+                       return 0;
+               }
+               return cli_set_timeout(cli, timeout);
+       }
+
+       return 0;
 }
 
 bool rpccli_get_pwd_hash(struct rpc_pipe_client *rpc_cli, uint8_t nt_hash[16])
index 6433a7d..4e8634d 100644 (file)
@@ -182,6 +182,21 @@ NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli,
        }
 
        status = cli_do_rpc_ndr_recv(req, mem_ctx);
+
+       /*
+        * NT_STATUS_IO_TIMEOUT indicates network problem,
+        * tear the connection apart.
+        */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               if (cli->transport->transport == NCACN_IP_TCP ||
+                   cli->transport->transport == NCALRPC) {
+                       rpccli_close_sock_fd(cli);
+               }
+
+               if (cli->transport->transport == NCACN_NP) {
+                       rpccli_close_np_fd(cli);
+               }
+       }
  fail:
        TALLOC_FREE(frame);
        return status;
index de748d9..9f8872c 100644 (file)
@@ -402,3 +402,15 @@ struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
        }
        return state->cli;
 }
+
+void rpccli_close_np_fd(struct rpc_pipe_client *p)
+{
+       struct cli_state *cli = rpc_pipe_np_smb_conn(p);
+       if (cli) {
+               if (cli->fd != -1) {
+                       close(cli->fd);
+                       cli->fd = -1;
+               }
+       }
+       return;
+}
index 171048a..929e553 100644 (file)
@@ -682,3 +682,13 @@ NTSTATUS rpc_transport_smbd_init(TALLOC_CTX *mem_ctx,
        TALLOC_FREE(frame);
        return status;
 }
+
+struct cli_state *rpc_pipe_smbd_smb_conn(struct rpc_pipe_client *p)
+{
+       struct rpc_transport_smbd_state *state = talloc_get_type(p->transport->priv,
+               struct rpc_transport_smbd_state);
+       if (!state || !state->conn) {
+               return NULL;
+       }
+       return state->conn->cli;
+}
index 4ab6500..df060e6 100644 (file)
@@ -24,6 +24,7 @@
 
 struct rpc_transport_sock_state {
        int fd;
+       int timeout;
 };
 
 static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
@@ -51,6 +52,7 @@ static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
                priv, struct rpc_transport_sock_state);
        struct tevent_req *req, *subreq;
        struct rpc_sock_read_state *state;
+       struct timeval endtime;
 
        req = tevent_req_create(mem_ctx, &state, struct rpc_sock_read_state);
        if (req == NULL) {
@@ -61,10 +63,16 @@ static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->transp = sock_transp;
+       endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
        subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
        if (subreq == NULL) {
                goto fail;
        }
+
+       if (!tevent_req_set_endtime(subreq, ev, endtime)) {
+               goto fail;
+       }
+
        tevent_req_set_callback(subreq, rpc_sock_read_done, req);
        return req;
  fail:
@@ -121,6 +129,7 @@ static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
                priv, struct rpc_transport_sock_state);
        struct tevent_req *req, *subreq;
        struct rpc_sock_write_state *state;
+       struct timeval endtime;
 
        req = tevent_req_create(mem_ctx, &state, struct rpc_sock_write_state);
        if (req == NULL) {
@@ -131,10 +140,16 @@ static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->transp = sock_transp;
+       endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
        subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
        if (subreq == NULL) {
                goto fail;
        }
+
+       if (!tevent_req_set_endtime(subreq, ev, endtime)) {
+               goto fail;
+       }
+
        tevent_req_set_callback(subreq, rpc_sock_write_done, req);
        return req;
  fail:
@@ -193,6 +208,7 @@ NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
        result->priv = state;
 
        state->fd = fd;
+       state->timeout = 10000; /* 10 seconds. */
        talloc_set_destructor(state, rpc_transport_sock_state_destructor);
 
        result->trans_send = NULL;
@@ -205,3 +221,40 @@ NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
        *presult = result;
        return NT_STATUS_OK;
 }
+
+int rpccli_set_sock_timeout(struct rpc_pipe_client *cli, int timeout)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       int orig_timeout;
+       if (!state) {
+               return 0;
+       }
+       orig_timeout = state->timeout;
+       state->timeout = timeout;
+       return orig_timeout;
+}
+
+void rpccli_close_sock_fd(struct rpc_pipe_client *cli)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       if (state) {
+               if (state->fd != -1) {
+                       close(state->fd);
+                       state->fd = -1;
+               }
+       }
+       return;
+}
+
+bool rpc_pipe_tcp_connection_ok(struct rpc_pipe_client *cli)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       if (state && state->fd != -1) {
+               return true;
+       }
+
+       return false;
+}
index 36b769b..479602a 100644 (file)
@@ -2214,7 +2214,8 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
        if (conn->lsa_pipe_tcp &&
            conn->lsa_pipe_tcp->transport->transport == NCACN_IP_TCP &&
-           conn->lsa_pipe_tcp->auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+           conn->lsa_pipe_tcp->auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY &&
+           rpc_pipe_tcp_connection_ok(conn->lsa_pipe_tcp)) {
                goto done;
        }
 
index e700376..424f2f3 100644 (file)
@@ -1286,12 +1286,8 @@ NTSTATUS winbindd_lookup_names(TALLOC_CTX *mem_ctx,
         * This call can take a long time
         * allow the server to time out.
         * 35 seconds should do it.
-        * NB
-        * only do this when the undelying transport is named pipe.
         */
-       if (cli->transport->transport == NCACN_NP) {
-               orig_timeout = rpccli_set_timeout(cli, 35000);
-       }
+       orig_timeout = rpccli_set_timeout(cli, 35000);
 
        status = lookup_names_fn(cli,
                                 mem_ctx,
@@ -1304,9 +1300,7 @@ NTSTATUS winbindd_lookup_names(TALLOC_CTX *mem_ctx,
                                 types);
 
        /* And restore our original timeout. */
-       if (cli->transport->transport == NCACN_NP) {
-               rpccli_set_timeout(cli, orig_timeout);
-       }
+       rpccli_set_timeout(cli, orig_timeout);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;