1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-12 09:18:10 +03:00

we now support pdu fragmentation on both input and output in the rpc

server code
(This used to be commit 4dac951718)
This commit is contained in:
Andrew Tridgell 2003-12-12 05:30:00 +00:00
parent dab0deae83
commit 9d8ef74eac
2 changed files with 103 additions and 41 deletions

View File

@ -100,6 +100,7 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
(*p)->ops = ops;
(*p)->private = NULL;
(*p)->call_list = NULL;
(*p)->cli_max_recv_frag = 0;
/* make sure the endpoint server likes the connection */
status = ops->connect(*p);
@ -128,6 +129,7 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
{
struct ndr_push *push;
struct dcerpc_packet pkt;
struct dcesrv_call_reply *rep;
NTSTATUS status;
/* setup a bind_ack */
@ -157,8 +159,15 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
return status;
}
call->data = ndr_push_blob(push);
SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length);
rep = talloc(call->mem_ctx, sizeof(*rep));
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
rep->data = ndr_push_blob(push);
SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
return NT_STATUS_OK;
}
@ -173,6 +182,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
uint32 if_version, transfer_syntax_version;
struct dcerpc_packet pkt;
struct ndr_push *push;
struct dcesrv_call_reply *rep;
NTSTATUS status;
if (call->pkt.u.bind.num_contexts != 1 ||
@ -202,6 +212,10 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_fault(call, DCERPC_FAULT_TODO);
}
if (call->dce->cli_max_recv_frag == 0) {
call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
}
/* setup a bind_ack */
pkt.rpc_vers = 5;
pkt.rpc_vers_minor = 0;
@ -241,8 +255,15 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return status;
}
call->data = ndr_push_blob(push);
SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length);
rep = talloc(call->mem_ctx, sizeof(*rep));
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
rep->data = ndr_push_blob(push);
SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
return NT_STATUS_OK;
}
@ -259,7 +280,6 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
void *r;
NTSTATUS status;
DATA_BLOB stub;
struct dcerpc_packet pkt;
opnum = call->pkt.u.request.opnum;
@ -302,34 +322,62 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
stub = ndr_push_blob(push);
/* form the dcerpc response packet */
pkt.rpc_vers = 5;
pkt.rpc_vers_minor = 0;
pkt.drep[0] = 0x10; /* Little endian */
pkt.drep[1] = 0;
pkt.drep[2] = 0;
pkt.drep[3] = 0;
pkt.auth_length = 0;
pkt.call_id = call->pkt.call_id;
pkt.ptype = DCERPC_PKT_RESPONSE;
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
pkt.u.response.alloc_hint = stub.length;
pkt.u.response.context_id = call->pkt.u.request.context_id;
pkt.u.response.cancel_count = 0;
pkt.u.response.stub_and_verifier = stub;
do {
uint32 length;
struct dcesrv_call_reply *rep;
struct dcerpc_packet pkt;
push = ndr_push_init_ctx(call->mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
rep = talloc(call->mem_ctx, sizeof(*rep));
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
length = stub.length;
if (length + DCERPC_RESPONSE_LENGTH > call->dce->cli_max_recv_frag) {
length = call->dce->cli_max_recv_frag - DCERPC_RESPONSE_LENGTH;
}
call->data = ndr_push_blob(push);
SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length);
/* form the dcerpc response packet */
pkt.rpc_vers = 5;
pkt.rpc_vers_minor = 0;
pkt.drep[0] = 0x10; /* Little endian */
pkt.drep[1] = 0;
pkt.drep[2] = 0;
pkt.drep[3] = 0;
pkt.auth_length = 0;
pkt.call_id = call->pkt.call_id;
pkt.ptype = DCERPC_PKT_RESPONSE;
pkt.pfc_flags = 0;
if (!call->replies) {
pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
}
if (length == stub.length) {
pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
}
pkt.u.response.alloc_hint = stub.length;
pkt.u.response.context_id = call->pkt.u.request.context_id;
pkt.u.response.cancel_count = 0;
pkt.u.response.stub_and_verifier.data = stub.data;
pkt.u.response.stub_and_verifier.length = length;
push = ndr_push_init_ctx(call->mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
rep->data = ndr_push_blob(push);
SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
stub.data += length;
stub.length -= length;
} while (stub.length != 0);
return NT_STATUS_OK;
}
@ -357,7 +405,7 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
}
call->mem_ctx = mem_ctx;
call->dce = dce;
call->data = data_blob(NULL, 0);
call->replies = NULL;
ndr = ndr_pull_init_blob(data, mem_ctx);
if (!ndr) {
@ -454,22 +502,29 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
{
struct dcesrv_call_state *call;
struct dcesrv_call_reply *rep;
call = dce->call_list;
if (!call) {
if (!call || !call->replies) {
return NT_STATUS_FOOBAR;
}
if (data->length >= call->data.length) {
data->length = call->data.length;
rep = call->replies;
if (data->length >= rep->data.length) {
data->length = rep->data.length;
}
memcpy(data->data, call->data.data, data->length);
call->data.length -= data->length;
call->data.data += data->length;
memcpy(data->data, rep->data.data, data->length);
rep->data.length -= data->length;
rep->data.data += data->length;
if (call->data.length == 0) {
/* we're done with this call */
if (rep->data.length == 0) {
/* we're done with this section of the call */
DLIST_REMOVE(call->replies, rep);
}
if (call->replies == NULL) {
/* we're done with the whole call */
DLIST_REMOVE(dce->call_list, call);
talloc_destroy(call->mem_ctx);
}

View File

@ -43,7 +43,11 @@ struct dcesrv_call_state {
struct dcesrv_state *dce;
TALLOC_CTX *mem_ctx;
struct dcerpc_packet pkt;
DATA_BLOB data;
struct dcesrv_call_reply {
struct dcesrv_call_reply *next, *prev;
DATA_BLOB data;
} *replies;
};
/* the state associated with a dcerpc server connection */
@ -66,6 +70,9 @@ struct dcesrv_state {
/* the state of the current calls */
struct dcesrv_call_state *call_list;
/* the maximum size the client wants to receive */
uint32 cli_max_recv_frag;
/* private data for the endpoint server */
void *private;
};