conn->transport.use_trans_fn = fn;
}
+bool dcerpc_connection_is_connected(const struct dcerpc_connection *conn)
+{
+ if (conn == NULL) {
+ return false;
+ }
+
+ if (conn->transport.stream == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static void dcerpc_connection_dead(struct dcerpc_connection *conn,
+ NTSTATUS error)
+{
+ struct dcerpc_call *call = NULL;
+
+ if (conn == NULL) {
+ return;
+ }
+
+ if (conn->transport.stream == NULL) {
+ return;
+ }
+
+ tevent_queue_stop(conn->transport.write_queue);
+ tevent_queue_stop(conn->calls.out_queue);
+ TALLOC_FREE(conn->loop.subreq);
+ TALLOC_FREE(conn->transport.stream);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, error)) {
+ error = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ if (NT_STATUS_EQUAL(NT_STATUS_OK, error)) {
+ error = NT_STATUS_END_OF_FILE;
+ }
+
+ if (conn->calls.active != NULL) {
+ DLIST_PROMOTE(conn->calls.list, conn->calls.active);
+ }
+
+ if (conn->calls.new_call != NULL) {
+ DLIST_ADD_END(conn->calls.list, conn->calls.new_call, NULL);
+ conn->calls.new_call = NULL;
+ }
+
+ for (call = conn->calls.list; call; call = call->next) {
+ if (call->incoming.req == NULL) {
+ continue;
+ }
+
+ /*
+ * the request was already prepared with
+ * tevent_req_defer_callback().
+ */
+ tevent_req_nterror(call->incoming.req, error);
+ }
+}
+
struct dcerpc_security *dcerpc_security_allocate(
TALLOC_CTX *mem_ctx,
struct dcerpc_connection *conn,
error = dcerpc_read_ncacn_packet_recv(subreq, subreq, &pkt, &pdu);
if (!NT_STATUS_IS_OK(error)) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls
+ dcerpc_connection_dead(conn, error);
return;
}
if (!valid_type) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
if (!allow_fragments) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
}
if (pkt->call_id != conn->calls.active->call_id) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
} else {
if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
if (call == NULL) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
if (call->incoming.handler == NULL) {
TALLOC_FREE(subreq);
- // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+ dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
return;
}
error = call->incoming.handler(call->incoming.req, pkt, pdu);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(error)) {
- // disconnect and notify pending calls
+ dcerpc_connection_dead(conn, error);
return;
}
error = dcerpc_connection_loop_restart(conn, conn->loop.ev);
if (!NT_STATUS_IS_OK(error)) {
- // disconnect and notify pending calls
+ dcerpc_connection_dead(conn, error);
return;
}
}
}
if (state->call != NULL) {
+ if (state->call == state->conn->calls.active) {
+ state->conn->calls.active = NULL;
+ }
ZERO_STRUCT(state->call->incoming);
DLIST_REMOVE(state->conn->calls.list, state->call);
state->call = NULL;
struct dcerpc_do_bind_out_frag *frag =
tevent_req_callback_data(subreq,
struct dcerpc_do_bind_out_frag);
- struct tevent_req *req = frag->req;
+ struct dcerpc_connection *conn = frag->conn;
NTSTATUS status;
bool ok;
/*
+ * always wait1???
* TODO; what if the caller has been free'ed?
+ * TALLOC_FREE(frag->subreq_write)
*/
frag->subreq_wait1 = NULL;
- frag->conn->loop.subreq = NULL;
+ conn->loop.subreq = NULL;
ok = tevent_queue_wait_recv(subreq);
if (!ok) {
- status = NT_STATUS_INTERNAL_ERROR;
TALLOC_FREE(frag);
- if (req) {
- tevent_req_nterror(req, status);
- }
- //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+ dcerpc_connection_dead(conn, NT_STATUS_INTERNAL_ERROR);
return;
}
status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frag);
- if (req) {
- tevent_req_nterror(req, status);
- }
- //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+ dcerpc_connection_dead(conn, status);
return;
}
status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frag);
- if (req) {
- tevent_req_nterror(req, status);
- }
- //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+ dcerpc_connection_dead(conn, status);
return;
}
}
struct dcerpc_do_bind_out_frag *frag =
tevent_req_callback_data(subreq,
struct dcerpc_do_bind_out_frag);
+ struct dcerpc_connection *conn = frag->conn;
struct tevent_req *req = frag->req;
NTSTATUS status;
int ret;
if (ret == -1) {
TALLOC_FREE(frag);
status = map_nt_error_from_unix_common(sys_errno);
- if (req) {
- tevent_req_nterror(req, status);
- }
+ dcerpc_connection_dead(conn, status);
return;
}
struct dcerpc_do_bind_out_frag *frag =
tevent_req_callback_data(subreq,
struct dcerpc_do_bind_out_frag);
- struct tevent_req *req = frag->req;
+ struct dcerpc_connection *conn = frag->conn;
NTSTATUS status;
bool ok;
ok = tevent_queue_wait_recv(subreq);
if (!ok) {
- status = NT_STATUS_INTERNAL_ERROR;
TALLOC_FREE(frag);
- if (req) {
- tevent_req_nterror(req, status);
- }
- //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+ dcerpc_connection_dead(conn, NT_STATUS_INTERNAL_ERROR);
return;
}
status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frag);
- if (req) {
- tevent_req_nterror(req, status);
- }
- //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+ dcerpc_connection_dead(conn, status);
return;
}