summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/librpc/rpc/dcerpc.c35
-rw-r--r--source4/librpc/rpc/dcerpc.h5
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c6
-rw-r--r--source4/librpc/rpc/dcerpc_smb2.c6
-rw-r--r--source4/librpc/rpc/dcerpc_sock.c33
5 files changed, 57 insertions, 28 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 820516ba11..79e897313d 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -37,14 +37,17 @@ NTSTATUS dcerpc_init(void)
return NT_STATUS_OK;
}
+static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
static void dcerpc_ship_next_request(struct dcerpc_connection *c);
/* destroy a dcerpc connection */
-static int dcerpc_connection_destructor(struct dcerpc_connection *c)
+static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
{
- if (c->transport.shutdown_pipe) {
- c->transport.shutdown_pipe(c);
+ if (conn->dead) {
+ conn->free_skipped = True;
+ return -1;
}
+ dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
return 0;
}
@@ -553,6 +556,14 @@ static int dcerpc_req_dequeue(struct rpc_request *req)
*/
static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
{
+ if (conn->dead) return;
+
+ conn->dead = true;
+
+ if (conn->transport.shutdown_pipe) {
+ conn->transport.shutdown_pipe(conn, status);
+ }
+
/* all pending requests get the error */
while (conn->pending) {
struct rpc_request *req = conn->pending;
@@ -563,6 +574,11 @@ static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS stat
req->async.callback(req);
}
}
+
+ talloc_set_destructor(conn, NULL);
+ if (conn->free_skipped) {
+ talloc_free(conn);
+ }
}
/*
@@ -657,18 +673,7 @@ static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event
struct timeval t, void *private)
{
struct rpc_request *req = talloc_get_type(private, struct rpc_request);
-
- if (req->state == RPC_REQUEST_DONE) {
- return;
- }
-
- dcerpc_req_dequeue(req);
-
- req->status = NT_STATUS_IO_TIMEOUT;
- req->state = RPC_REQUEST_DONE;
- if (req->async.callback) {
- req->async.callback(req);
- }
+ dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
}
/*
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 8fed56584d..c6dbc35477 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -57,11 +57,14 @@ struct dcerpc_connection {
const char *binding_string;
struct event_context *event_ctx;
+ bool dead;
+ bool free_skipped;
+
struct dcerpc_transport {
enum dcerpc_transport_t transport;
void *private;
- NTSTATUS (*shutdown_pipe)(struct dcerpc_connection *);
+ NTSTATUS (*shutdown_pipe)(struct dcerpc_connection *, NTSTATUS status);
const char *(*peer_name)(struct dcerpc_connection *);
diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
index d6d2cf0dfb..55fc37d84f 100644
--- a/source4/librpc/rpc/dcerpc_smb.c
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -326,14 +326,14 @@ static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, B
/*
shutdown SMB pipe connection
*/
-static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
+static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
{
struct smb_private *smb = c->transport.private;
union smb_close io;
struct smbcli_request *req;
/* maybe we're still starting up */
- if (!smb) return NT_STATUS_OK;
+ if (!smb) return status;
io.close.level = RAW_CLOSE_CLOSE;
io.close.in.file.fnum = smb->fnum;
@@ -346,7 +346,7 @@ static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
talloc_free(smb);
- return NT_STATUS_OK;
+ return status;
}
/*
diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c
index 20d1c7c211..d2ab47898e 100644
--- a/source4/librpc/rpc/dcerpc_smb2.c
+++ b/source4/librpc/rpc/dcerpc_smb2.c
@@ -299,14 +299,14 @@ static NTSTATUS smb2_send_request(struct dcerpc_connection *c, DATA_BLOB *blob,
/*
shutdown SMB pipe connection
*/
-static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c)
+static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
{
struct smb2_private *smb = c->transport.private;
struct smb2_close io;
struct smb2_request *req;
/* maybe we're still starting up */
- if (!smb) return NT_STATUS_OK;
+ if (!smb) return status;
ZERO_STRUCT(io);
io.in.file.handle = smb->handle;
@@ -318,7 +318,7 @@ static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c)
talloc_free(smb);
- return NT_STATUS_OK;
+ return status;
}
/*
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
index ae7d00b669..fd54a20afc 100644
--- a/source4/librpc/rpc/dcerpc_sock.c
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -48,12 +48,34 @@ static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
{
struct sock_private *sock = p->transport.private;
- if (sock && sock->sock != NULL) {
+ if (!sock) return;
+
+ if (sock->fde) {
+ talloc_free(sock->fde);
+ sock->fde = NULL;
+ }
+
+ if (sock->sock) {
talloc_free(sock->fde);
+ sock->fde = NULL;
talloc_free(sock->sock);
sock->sock = NULL;
}
+ if (sock->packet) {
+ packet_recv_disable(sock->packet);
+ packet_set_fde(sock->packet, NULL);
+ packet_set_socket(sock->packet, NULL);
+ }
+
+ if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
+ status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
+ status = NT_STATUS_END_OF_FILE;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
p->transport.recv_data(p, NULL, status);
}
@@ -172,15 +194,15 @@ static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data,
/*
shutdown sock pipe connection
*/
-static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p)
+static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p, NTSTATUS status)
{
struct sock_private *sock = p->transport.private;
if (sock && sock->sock) {
- sock_dead(p, NT_STATUS_OK);
+ sock_dead(p, status);
}
- return NT_STATUS_OK;
+ return status;
}
/*
@@ -253,7 +275,7 @@ static void continue_socket_connect(struct composite_context *ctx)
sock->server_name = strupper_talloc(sock, s->target_hostname);
sock->fde = event_add_fd(conn->event_ctx, sock->sock, socket_get_fd(sock->sock),
- 0, sock_io_handler, conn);
+ EVENT_FD_READ, sock_io_handler, conn);
conn->transport.private = sock;
@@ -272,7 +294,6 @@ static void continue_socket_connect(struct composite_context *ctx)
packet_set_event_context(sock->packet, conn->event_ctx);
packet_set_fde(sock->packet, sock->fde);
packet_set_serialise(sock->packet);
- packet_recv_disable(sock->packet);
packet_set_initial_read(sock->packet, 16);
/* ensure we don't get SIGPIPE */