mirror of
https://github.com/samba-team/samba.git
synced 2025-01-24 02:04:21 +03:00
libcli/raw: make multi fragmented nttrans requests possible
metze (This used to be commit a6aa055097313975299f214d8ebe8d45aa51d10a)
This commit is contained in:
parent
1bc344cf52
commit
efaf4cedb2
@ -537,6 +537,10 @@ _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
|
||||
}
|
||||
|
||||
struct smb_raw_nttrans_recv_state {
|
||||
uint32_t params_total;
|
||||
uint32_t data_total;
|
||||
uint32_t params_left;
|
||||
uint32_t data_left;
|
||||
bool got_first;
|
||||
uint32_t recvd_data;
|
||||
uint32_t recvd_param;
|
||||
@ -569,6 +573,9 @@ failed:
|
||||
return smbcli_request_destroy(req);
|
||||
}
|
||||
|
||||
static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req,
|
||||
struct smb_raw_nttrans_recv_state *state);
|
||||
|
||||
/*
|
||||
* This helper returns SMBCLI_REQUEST_RECV until all data has arrived
|
||||
*/
|
||||
@ -599,6 +606,10 @@ static enum smbcli_request_state smb_raw_nttrans_recv_helper(struct smbcli_reque
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (state->params_left > 0 || state->data_left > 0) {
|
||||
return smb_raw_nttrans_ship_rest(req, state);
|
||||
}
|
||||
|
||||
/* this is the first packet of the response */
|
||||
SMBCLI_CHECK_MIN_WCT(req, 18);
|
||||
|
||||
@ -716,7 +727,12 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
|
||||
{
|
||||
struct smbcli_request *req;
|
||||
struct smb_raw_nttrans_recv_state *state;
|
||||
uint8_t *outdata, *outparam;
|
||||
uint32_t ofs;
|
||||
size_t space_left;
|
||||
DATA_BLOB params_chunk;
|
||||
uint32_t params_ofs;
|
||||
DATA_BLOB data_chunk;
|
||||
uint32_t data_ofs;
|
||||
int align = 0;
|
||||
|
||||
/* only align if there are parameters or data */
|
||||
@ -725,10 +741,7 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
|
||||
}
|
||||
|
||||
req = smbcli_request_setup(tree, SMBnttrans,
|
||||
19 + parms->in.setup_count,
|
||||
align +
|
||||
parms->in.params.length +
|
||||
parms->in.data.length);
|
||||
19 + parms->in.setup_count, align);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
@ -740,33 +753,81 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
|
||||
}
|
||||
|
||||
/* fill in SMB parameters */
|
||||
outparam = req->out.data + align;
|
||||
outdata = outparam + parms->in.params.length;
|
||||
|
||||
if (align != 0) {
|
||||
memset(req->out.data, 0, align);
|
||||
}
|
||||
|
||||
ofs = PTR_DIFF(req->out.data,req->out.hdr)+align;
|
||||
|
||||
/* see how much bytes of the params block we can ship in the first request */
|
||||
space_left = raw_trans_space_left(req);
|
||||
|
||||
params_chunk.length = MIN(parms->in.params.length, space_left);
|
||||
params_chunk.data = parms->in.params.data;
|
||||
params_ofs = ofs;
|
||||
|
||||
state->params_left = parms->in.params.length - params_chunk.length;
|
||||
|
||||
if (state->params_left > 0) {
|
||||
/* we copy the whole params block, if needed we can optimize that latter */
|
||||
state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length);
|
||||
if (!state->io.in.params.data) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(state->io.in.params.data,
|
||||
parms->in.params.data,
|
||||
parms->in.params.length);
|
||||
}
|
||||
|
||||
/* see how much bytes of the data block we can ship in the first request */
|
||||
space_left -= params_chunk.length;
|
||||
|
||||
#if TORTURE_TRANS_DATA
|
||||
if (space_left > 1) {
|
||||
space_left /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
data_chunk.length = MIN(parms->in.data.length, space_left);
|
||||
data_chunk.data = parms->in.data.data;
|
||||
data_ofs = params_ofs + params_chunk.length;
|
||||
|
||||
state->data_left = parms->in.data.length - data_chunk.length;
|
||||
|
||||
if (state->data_left > 0) {
|
||||
/* we copy the whole params block, if needed we can optimize that latter */
|
||||
state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length);
|
||||
if (!state->io.in.data.data) {
|
||||
smbcli_request_destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(state->io.in.data.data,
|
||||
parms->in.data.data,
|
||||
parms->in.data.length);
|
||||
}
|
||||
|
||||
state->params_total = parms->in.params.length;
|
||||
state->data_total = parms->in.data.length;
|
||||
|
||||
SCVAL(req->out.vwv, 0, parms->in.max_setup);
|
||||
SSVAL(req->out.vwv, 1, 0); /* reserved */
|
||||
SIVAL(req->out.vwv, 3, parms->in.params.length);
|
||||
SIVAL(req->out.vwv, 7, parms->in.data.length);
|
||||
SIVAL(req->out.vwv, 11, parms->in.max_param);
|
||||
SIVAL(req->out.vwv, 15, parms->in.max_data);
|
||||
SIVAL(req->out.vwv, 19, parms->in.params.length);
|
||||
SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
|
||||
SIVAL(req->out.vwv, 27, parms->in.data.length);
|
||||
SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
|
||||
SIVAL(req->out.vwv, 19, params_chunk.length);
|
||||
SIVAL(req->out.vwv, 23, params_ofs);
|
||||
SIVAL(req->out.vwv, 27, data_chunk.length);
|
||||
SIVAL(req->out.vwv, 31, data_ofs);
|
||||
SCVAL(req->out.vwv, 35, parms->in.setup_count);
|
||||
SSVAL(req->out.vwv, 36, parms->in.function);
|
||||
memcpy(req->out.vwv + VWV(19), parms->in.setup,
|
||||
sizeof(uint16_t) * parms->in.setup_count);
|
||||
if (parms->in.params.length) {
|
||||
memcpy(outparam, parms->in.params.data, parms->in.params.length);
|
||||
}
|
||||
if (parms->in.data.length) {
|
||||
memcpy(outdata, parms->in.data.data, parms->in.data.length);
|
||||
}
|
||||
|
||||
smbcli_req_append_blob(req, ¶ms_chunk);
|
||||
smbcli_req_append_blob(req, &data_chunk);
|
||||
|
||||
/* add the helper which will check that all multi-part replies are
|
||||
in before an async client callack will be issued */
|
||||
@ -781,6 +842,106 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
|
||||
return req;
|
||||
}
|
||||
|
||||
static enum smbcli_request_state smb_raw_nttrans_ship_next(struct smbcli_request *req,
|
||||
struct smb_raw_nttrans_recv_state *state)
|
||||
{
|
||||
struct smbcli_request *req2;
|
||||
size_t space_left;
|
||||
DATA_BLOB params_chunk;
|
||||
uint32_t ofs;
|
||||
uint32_t params_ofs = 0;
|
||||
uint32_t params_disp = 0;
|
||||
DATA_BLOB data_chunk;
|
||||
uint32_t data_ofs = 0;
|
||||
uint32_t data_disp = 0;
|
||||
|
||||
req2 = smbcli_request_setup(req->tree, SMBnttranss, 18, 0);
|
||||
if (!req2) {
|
||||
goto nomem;
|
||||
}
|
||||
req2->mid = req->mid;
|
||||
SSVAL(req2->out.hdr, HDR_MID, req2->mid);
|
||||
|
||||
ofs = PTR_DIFF(req2->out.data,req2->out.hdr);
|
||||
|
||||
/* see how much bytes of the params block we can ship in the first request */
|
||||
space_left = raw_trans_space_left(req2);
|
||||
|
||||
params_disp = state->io.in.params.length - state->params_left;
|
||||
params_chunk.length = MIN(state->params_left, space_left);
|
||||
params_chunk.data = state->io.in.params.data + params_disp;
|
||||
params_ofs = ofs;
|
||||
|
||||
state->params_left -= params_chunk.length;
|
||||
|
||||
/* see how much bytes of the data block we can ship in the first request */
|
||||
space_left -= params_chunk.length;
|
||||
|
||||
#if TORTURE_TRANS_DATA
|
||||
if (space_left > 1) {
|
||||
space_left /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
data_disp = state->io.in.data.length - state->data_left;
|
||||
data_chunk.length = MIN(state->data_left, space_left);
|
||||
data_chunk.data = state->io.in.data.data + data_disp;
|
||||
data_ofs = params_ofs+params_chunk.length;
|
||||
|
||||
state->data_left -= data_chunk.length;
|
||||
|
||||
SSVAL(req2->out.vwv,0, 0); /* reserved */
|
||||
SCVAL(req2->out.vwv,2, 0); /* reserved */
|
||||
SIVAL(req2->out.vwv,3, state->params_total);
|
||||
SIVAL(req2->out.vwv,7, state->data_total);
|
||||
SIVAL(req2->out.vwv,11, params_chunk.length);
|
||||
SIVAL(req2->out.vwv,15, params_ofs);
|
||||
SIVAL(req2->out.vwv,19, params_disp);
|
||||
SIVAL(req2->out.vwv,23, data_chunk.length);
|
||||
SIVAL(req2->out.vwv,27, data_ofs);
|
||||
SIVAL(req2->out.vwv,31, data_disp);
|
||||
SCVAL(req2->out.vwv,35, 0); /* reserved */
|
||||
|
||||
smbcli_req_append_blob(req2, ¶ms_chunk);
|
||||
smbcli_req_append_blob(req2, &data_chunk);
|
||||
|
||||
/*
|
||||
* it's a one way request but we need
|
||||
* the seq_num, so we destroy req2 by hand
|
||||
*/
|
||||
if (!smbcli_request_send(req2)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req->seq_num = req2->seq_num;
|
||||
smbcli_request_destroy(req2);
|
||||
|
||||
return SMBCLI_REQUEST_RECV;
|
||||
|
||||
nomem:
|
||||
req->status = NT_STATUS_NO_MEMORY;
|
||||
failed:
|
||||
if (req2) {
|
||||
req->status = smbcli_request_destroy(req2);
|
||||
}
|
||||
return SMBCLI_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req,
|
||||
struct smb_raw_nttrans_recv_state *state)
|
||||
{
|
||||
enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR;
|
||||
|
||||
while (state->params_left > 0 || state->data_left > 0) {
|
||||
ret = smb_raw_nttrans_ship_next(req, state);
|
||||
if (ret != SMBCLI_REQUEST_RECV) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
receive a SMB nttrans response allocating the necessary memory
|
||||
|
Loading…
x
Reference in New Issue
Block a user