mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
r15524: fix a problem with rpc faults from bind and alter context
requests. The fix involves using the same packet queue mechanism for
these requests as normal requests, which also simplifies the code
somewhat
(This used to be commit 2e7f5add13
)
This commit is contained in:
parent
3590835ee6
commit
428873fd70
@ -489,6 +489,16 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason)
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
a bind or alter context has failed
|
||||
*/
|
||||
static void dcerpc_composite_fail(struct rpc_request *req)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
composite_error(c, req->status);
|
||||
}
|
||||
|
||||
/*
|
||||
mark the dcerpc connection dead. All outstanding requests get an error
|
||||
*/
|
||||
@ -504,26 +514,12 @@ static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS stat
|
||||
req->async.callback(req);
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->bind_private) {
|
||||
/* a bind was in flight - fail it */
|
||||
struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
|
||||
composite_error(c, status);
|
||||
}
|
||||
|
||||
if (conn->alter_private) {
|
||||
/* a alter context was in flight - fail it */
|
||||
struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
|
||||
composite_error(c, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
forward declarations of the recv_data handlers for the 3 types of packets we need
|
||||
to handle
|
||||
forward declarations of the recv_data handlers for the types of
|
||||
packets we need to handle
|
||||
*/
|
||||
static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
|
||||
static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
|
||||
static void dcerpc_request_recv_data(struct dcerpc_connection *c,
|
||||
DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
|
||||
|
||||
@ -555,41 +551,20 @@ static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NT
|
||||
dcerpc_connection_dead(conn, status);
|
||||
}
|
||||
|
||||
switch (pkt.ptype) {
|
||||
case DCERPC_PKT_BIND_NAK:
|
||||
case DCERPC_PKT_BIND_ACK:
|
||||
if (conn->bind_private) {
|
||||
talloc_steal(conn->bind_private, blob->data);
|
||||
dcerpc_bind_recv_data(conn, &pkt);
|
||||
}
|
||||
break;
|
||||
|
||||
case DCERPC_PKT_ALTER_RESP:
|
||||
if (conn->alter_private) {
|
||||
talloc_steal(conn->alter_private, blob->data);
|
||||
dcerpc_alter_recv_data(conn, &pkt);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* assume its an ordinary request */
|
||||
dcerpc_request_recv_data(conn, blob, &pkt);
|
||||
break;
|
||||
}
|
||||
dcerpc_request_recv_data(conn, blob, &pkt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Receive a bind reply from the transport
|
||||
*/
|
||||
static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
|
||||
static void dcerpc_bind_recv_handler(struct rpc_request *req,
|
||||
DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct dcerpc_connection *conn;
|
||||
|
||||
c = talloc_get_type(conn->bind_private, struct composite_context);
|
||||
|
||||
/* mark the connection as not waiting for a bind reply */
|
||||
conn->bind_private = NULL;
|
||||
c = talloc_get_type(req->async.private, struct composite_context);
|
||||
|
||||
if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
|
||||
DEBUG(2,("dcerpc: bind_nak reason %d\n",
|
||||
@ -606,6 +581,8 @@ static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_p
|
||||
return;
|
||||
}
|
||||
|
||||
conn = req->p->conn;
|
||||
|
||||
conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
|
||||
conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
|
||||
|
||||
@ -623,21 +600,26 @@ static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_p
|
||||
}
|
||||
|
||||
/*
|
||||
handle timeouts of dcerpc bind and alter context requests
|
||||
handle timeouts of individual dcerpc requests
|
||||
*/
|
||||
static void bind_timeout_handler(struct event_context *ev,
|
||||
struct timed_event *te,
|
||||
struct timeval t, void *private)
|
||||
static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private)
|
||||
{
|
||||
struct composite_context *ctx =
|
||||
talloc_get_type(private, struct composite_context);
|
||||
struct dcerpc_pipe *timeout_pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
|
||||
struct rpc_request *req = talloc_get_type(private, struct rpc_request);
|
||||
|
||||
SMB_ASSERT(timeout_pipe->conn->bind_private != NULL);
|
||||
timeout_pipe->conn->bind_private = NULL;
|
||||
composite_error(ctx, NT_STATUS_IO_TIMEOUT);
|
||||
if (req->state != RPC_REQUEST_PENDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
req->status = NT_STATUS_IO_TIMEOUT;
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
DLIST_REMOVE(req->p->conn->pending, req);
|
||||
if (req->async.callback) {
|
||||
req->async.callback(req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a async dcerpc bind request
|
||||
*/
|
||||
@ -649,6 +631,13 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
|
||||
struct composite_context *c;
|
||||
struct ncacn_packet pkt;
|
||||
DATA_BLOB blob;
|
||||
struct rpc_request *req;
|
||||
|
||||
/* we allocate a dcerpc_request so we can be in the same
|
||||
request queue as normal requests, but most of the request
|
||||
fields are not used as there is no call id */
|
||||
req = talloc_zero(mem_ctx, struct rpc_request);
|
||||
if (req == NULL) return NULL;
|
||||
|
||||
c = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (c == NULL) return NULL;
|
||||
@ -691,7 +680,15 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
|
||||
}
|
||||
|
||||
p->conn->transport.recv_data = dcerpc_recv_data;
|
||||
p->conn->bind_private = c;
|
||||
|
||||
req->state = RPC_REQUEST_PENDING;
|
||||
req->call_id = pkt.call_id;
|
||||
req->async.private = c;
|
||||
req->async.callback = dcerpc_composite_fail;
|
||||
req->p = p;
|
||||
req->recv_handler = dcerpc_bind_recv_handler;
|
||||
|
||||
DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
|
||||
|
||||
c->status = p->conn->transport.send_request(p->conn, &blob,
|
||||
True);
|
||||
@ -699,9 +696,9 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
event_add_timed(c->event_ctx, c,
|
||||
event_add_timed(c->event_ctx, req,
|
||||
timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
|
||||
bind_timeout_handler, c);
|
||||
dcerpc_timeout_handler, req);
|
||||
|
||||
return c;
|
||||
|
||||
@ -845,6 +842,13 @@ static void dcerpc_request_recv_data(struct dcerpc_connection *c,
|
||||
|
||||
talloc_steal(req, raw_packet->data);
|
||||
|
||||
if (req->recv_handler != NULL) {
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
DLIST_REMOVE(c->pending, req);
|
||||
req->recv_handler(req, raw_packet, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pkt->ptype == DCERPC_PKT_FAULT) {
|
||||
DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
|
||||
req->fault_code = pkt->u.fault.status;
|
||||
@ -911,27 +915,6 @@ req_done:
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
handle timeouts of individual dcerpc requests
|
||||
*/
|
||||
static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private)
|
||||
{
|
||||
struct rpc_request *req = talloc_get_type(private, struct rpc_request);
|
||||
|
||||
if (req->state != RPC_REQUEST_PENDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
req->status = NT_STATUS_IO_TIMEOUT;
|
||||
req->state = RPC_REQUEST_DONE;
|
||||
DLIST_REMOVE(req->p->conn->pending, req);
|
||||
if (req->async.callback) {
|
||||
req->async.callback(req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
make sure requests are cleaned up
|
||||
*/
|
||||
@ -969,6 +952,8 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
|
||||
req->fault_code = 0;
|
||||
req->async_call = async;
|
||||
req->async.callback = NULL;
|
||||
req->async.private = NULL;
|
||||
req->recv_handler = NULL;
|
||||
|
||||
if (object != NULL) {
|
||||
req->object = talloc_memdup(req, object, sizeof(*object));
|
||||
@ -1301,7 +1286,15 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
|
||||
s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
|
||||
NDR_OUT, st);
|
||||
if (strcmp(s1, s2) != 0) {
|
||||
#if 1
|
||||
printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
|
||||
#else
|
||||
/* this is sometimes useful */
|
||||
printf("VALIDATE ERROR\n");
|
||||
file_save("wire.dat", s1, strlen(s1));
|
||||
file_save("gen.dat", s2, strlen(s2));
|
||||
system("diff -u wire.dat gen.dat");
|
||||
#endif
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
@ -1517,17 +1510,15 @@ uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
|
||||
/*
|
||||
Receive an alter reply from the transport
|
||||
*/
|
||||
static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
|
||||
static void dcerpc_alter_recv_handler(struct rpc_request *req,
|
||||
DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct dcerpc_pipe *recv_pipe;
|
||||
|
||||
c = talloc_get_type(conn->alter_private, struct composite_context);
|
||||
c = talloc_get_type(req->async.private, struct composite_context);
|
||||
recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
|
||||
|
||||
/* mark the connection as not waiting for a alter context reply */
|
||||
conn->alter_private = NULL;
|
||||
|
||||
if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
|
||||
pkt->u.alter_resp.num_results == 1 &&
|
||||
pkt->u.alter_resp.ctx_list[0].result != 0) {
|
||||
@ -1568,8 +1559,15 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
|
||||
struct composite_context *c;
|
||||
struct ncacn_packet pkt;
|
||||
DATA_BLOB blob;
|
||||
struct rpc_request *req;
|
||||
|
||||
c = talloc_zero(mem_ctx, struct composite_context);
|
||||
/* we allocate a dcerpc_request so we can be in the same
|
||||
request queue as normal requests, but most of the request
|
||||
fields are not used as there is no call id */
|
||||
req = talloc_zero(mem_ctx, struct rpc_request);
|
||||
if (req == NULL) return NULL;
|
||||
|
||||
c = talloc_zero(req, struct composite_context);
|
||||
if (c == NULL) return NULL;
|
||||
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
@ -1610,16 +1608,24 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
|
||||
}
|
||||
|
||||
p->conn->transport.recv_data = dcerpc_recv_data;
|
||||
p->conn->alter_private = c;
|
||||
|
||||
req->state = RPC_REQUEST_PENDING;
|
||||
req->call_id = pkt.call_id;
|
||||
req->async.private = c;
|
||||
req->async.callback = dcerpc_composite_fail;
|
||||
req->p = p;
|
||||
req->recv_handler = dcerpc_alter_recv_handler;
|
||||
|
||||
DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
|
||||
|
||||
c->status = p->conn->transport.send_request(p->conn, &blob, True);
|
||||
if (!NT_STATUS_IS_OK(c->status)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
event_add_timed(c->event_ctx, c,
|
||||
event_add_timed(c->event_ctx, req,
|
||||
timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
|
||||
bind_timeout_handler, c);
|
||||
dcerpc_timeout_handler, req);
|
||||
|
||||
return c;
|
||||
|
||||
|
@ -84,12 +84,6 @@ struct dcerpc_connection {
|
||||
/* Sync requests waiting to be shipped */
|
||||
struct rpc_request *request_queue;
|
||||
|
||||
/* private pointer for pending binds */
|
||||
void *bind_private;
|
||||
|
||||
/* private pointer for pending alter context requests */
|
||||
void *alter_private;
|
||||
|
||||
/* the next context_id to be assigned */
|
||||
uint32_t next_context_id;
|
||||
};
|
||||
@ -232,6 +226,11 @@ struct rpc_request {
|
||||
uint32_t flags;
|
||||
uint32_t fault_code;
|
||||
|
||||
/* this is used to distinguish bind and alter_context requests
|
||||
from normal requests */
|
||||
void (*recv_handler)(struct rpc_request *conn,
|
||||
DATA_BLOB *blob, struct ncacn_packet *pkt);
|
||||
|
||||
const struct GUID *object;
|
||||
uint16_t opnum;
|
||||
DATA_BLOB request_data;
|
||||
|
Loading…
Reference in New Issue
Block a user