mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
Add async trans/trans2/nttrans calls to libsmb
Logic stolen from Samba4, naturally the specific implementation differs a bit.
This commit is contained in:
parent
23e9fed28c
commit
4b8bc5b03d
@ -4732,6 +4732,27 @@ bool cli_send_nt_trans(struct cli_state *cli,
|
||||
bool cli_receive_nt_trans(struct cli_state *cli,
|
||||
char **param, unsigned int *param_len,
|
||||
char **data, unsigned int *data_len);
|
||||
struct async_req *cli_trans_send(
|
||||
TALLOC_CTX *mem_ctx, struct event_context *ev,
|
||||
struct cli_state *cli, uint8_t trans_cmd,
|
||||
const char *pipe_name, uint16_t fid, uint16_t function, int flags,
|
||||
uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
|
||||
uint8_t *param, uint32_t num_param, uint32_t max_param,
|
||||
uint8_t *data, uint32_t num_data, uint32_t max_data);
|
||||
NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
|
||||
uint16_t **setup, uint8_t *num_setup,
|
||||
uint8_t **param, uint32_t *num_param,
|
||||
uint8_t **data, uint32_t *num_data);
|
||||
NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
|
||||
uint8_t trans_cmd,
|
||||
const char *pipe_name, uint16_t fid, uint16_t function,
|
||||
int flags,
|
||||
uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
|
||||
uint8_t *param, uint32_t num_param, uint32_t max_param,
|
||||
uint8_t *data, uint32_t num_data, uint32_t max_data,
|
||||
uint16_t **rsetup, uint8_t *num_rsetup,
|
||||
uint8_t **rparam, uint32_t *num_rparam,
|
||||
uint8_t **rdata, uint32_t *num_rdata);
|
||||
|
||||
/* The following definitions come from libsmb/conncache.c */
|
||||
|
||||
|
@ -701,3 +701,704 @@ bool cli_receive_nt_trans(struct cli_state *cli,
|
||||
client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct trans_recvblob {
|
||||
uint8_t *data;
|
||||
uint32_t max, total, received;
|
||||
};
|
||||
|
||||
struct cli_trans_state {
|
||||
struct cli_state *cli;
|
||||
struct event_context *ev;
|
||||
uint8_t cmd;
|
||||
uint16_t mid;
|
||||
const char *pipe_name;
|
||||
uint16_t fid;
|
||||
uint16_t function;
|
||||
int flags;
|
||||
uint16_t *setup;
|
||||
uint8_t num_setup, max_setup;
|
||||
uint8_t *param;
|
||||
uint32_t num_param, param_sent;
|
||||
uint8_t *data;
|
||||
uint32_t num_data, data_sent;
|
||||
|
||||
uint8_t num_rsetup;
|
||||
uint16_t *rsetup;
|
||||
struct trans_recvblob rparam;
|
||||
struct trans_recvblob rdata;
|
||||
|
||||
TALLOC_CTX *secondary_request_ctx;
|
||||
};
|
||||
|
||||
static void cli_trans_recv_helper(struct async_req *req);
|
||||
|
||||
static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
|
||||
struct cli_trans_state *state)
|
||||
{
|
||||
TALLOC_CTX *frame;
|
||||
struct async_req *result = NULL;
|
||||
struct cli_request *cli_req;
|
||||
uint8_t wct;
|
||||
uint16_t *vwv;
|
||||
uint8_t *bytes = NULL;
|
||||
uint16_t param_offset;
|
||||
uint16_t this_param = 0;
|
||||
uint16_t this_data = 0;
|
||||
uint32_t useable_space;
|
||||
uint8_t cmd;
|
||||
|
||||
frame = talloc_stackframe();
|
||||
|
||||
cmd = state->cmd;
|
||||
|
||||
if ((state->param_sent != 0) || (state->data_sent != 0)) {
|
||||
/* The secondary commands are one after the primary ones */
|
||||
cmd += 1;
|
||||
}
|
||||
|
||||
param_offset = smb_size - 4;
|
||||
|
||||
switch (cmd) {
|
||||
case SMBtrans:
|
||||
bytes = TALLOC_ZERO_P(talloc_tos(), uint8_t); /* padding */
|
||||
if (bytes == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
bytes = smb_bytes_push_str(
|
||||
bytes, (state->cli->capabilities & CAP_UNICODE) != 0,
|
||||
state->pipe_name);
|
||||
if (bytes == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
wct = 14 + state->num_setup;
|
||||
param_offset += talloc_get_size(bytes);
|
||||
break;
|
||||
case SMBtrans2:
|
||||
bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 3); /* padding */
|
||||
if (bytes == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
bytes[0] = 0;
|
||||
bytes[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
|
||||
bytes[2] = ' ';
|
||||
wct = 14 + state->num_setup;
|
||||
param_offset += talloc_get_size(bytes);
|
||||
break;
|
||||
case SMBtranss:
|
||||
wct = 8;
|
||||
break;
|
||||
case SMBtranss2:
|
||||
wct = 9;
|
||||
break;
|
||||
case SMBnttrans:
|
||||
wct = 19 + state->num_setup;
|
||||
break;
|
||||
case SMBnttranss:
|
||||
wct = 18;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct;
|
||||
|
||||
if (state->param_sent < state->num_param) {
|
||||
this_param = MIN(state->num_param - state->param_sent,
|
||||
useable_space);
|
||||
}
|
||||
|
||||
if (state->data_sent < state->num_data) {
|
||||
this_data = MIN(state->num_data - state->data_sent,
|
||||
useable_space - this_param);
|
||||
}
|
||||
|
||||
vwv = TALLOC_ARRAY(talloc_tos(), uint16_t, wct);
|
||||
if (vwv == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
param_offset += wct * sizeof(uint16_t);
|
||||
|
||||
DEBUG(10, ("num_setup=%u, max_setup=%u, "
|
||||
"param_total=%u, this_param=%u, max_param=%u, "
|
||||
"data_total=%u, this_data=%u, max_data=%u, "
|
||||
"param_offset=%u, param_disp=%u, data_disp=%u\n",
|
||||
(unsigned)state->num_setup, (unsigned)state->max_setup,
|
||||
(unsigned)state->num_param, (unsigned)this_param,
|
||||
(unsigned)state->rparam.max,
|
||||
(unsigned)state->num_data, (unsigned)this_data,
|
||||
(unsigned)state->rdata.max,
|
||||
(unsigned)param_offset,
|
||||
(unsigned)state->param_sent, (unsigned)state->data_sent));
|
||||
|
||||
switch (cmd) {
|
||||
case SMBtrans:
|
||||
case SMBtrans2:
|
||||
SSVAL(vwv + 0, 0, state->num_param);
|
||||
SSVAL(vwv + 1, 0, state->num_data);
|
||||
SSVAL(vwv + 2, 0, state->rparam.max);
|
||||
SSVAL(vwv + 3, 0, state->rdata.max);
|
||||
SCVAL(vwv + 4, 0, state->max_setup);
|
||||
SCVAL(vwv + 4, 1, 0); /* reserved */
|
||||
SSVAL(vwv + 5, 0, state->flags);
|
||||
SIVAL(vwv + 6, 0, 0); /* timeout */
|
||||
SSVAL(vwv + 8, 0, 0); /* reserved */
|
||||
SSVAL(vwv + 9, 0, this_param);
|
||||
SSVAL(vwv +10, 0, param_offset);
|
||||
SSVAL(vwv +11, 0, this_data);
|
||||
SSVAL(vwv +12, 0, param_offset + this_param);
|
||||
SCVAL(vwv +13, 0, state->num_setup);
|
||||
SCVAL(vwv +13, 1, 0); /* reserved */
|
||||
memcpy(vwv + 14, state->setup,
|
||||
sizeof(uint16_t) * state->num_setup);
|
||||
break;
|
||||
case SMBtranss:
|
||||
case SMBtranss2:
|
||||
SSVAL(vwv + 0, 0, state->num_param);
|
||||
SSVAL(vwv + 1, 0, state->num_data);
|
||||
SSVAL(vwv + 2, 0, this_param);
|
||||
SSVAL(vwv + 3, 0, param_offset);
|
||||
SSVAL(vwv + 4, 0, state->param_sent);
|
||||
SSVAL(vwv + 5, 0, this_data);
|
||||
SSVAL(vwv + 6, 0, param_offset + this_param);
|
||||
SSVAL(vwv + 7, 0, state->data_sent);
|
||||
if (cmd == SMBtranss2) {
|
||||
SSVAL(vwv + 8, 0, state->fid);
|
||||
}
|
||||
break;
|
||||
case SMBnttrans:
|
||||
SCVAL(vwv, 0, state->max_setup);
|
||||
SSVAL(vwv, 1, 0); /* reserved */
|
||||
SIVAL(vwv, 3, state->num_param);
|
||||
SIVAL(vwv, 7, state->num_data);
|
||||
SIVAL(vwv, 11, state->rparam.max);
|
||||
SIVAL(vwv, 15, state->rdata.max);
|
||||
SIVAL(vwv, 19, this_param);
|
||||
SIVAL(vwv, 23, param_offset);
|
||||
SIVAL(vwv, 27, this_data);
|
||||
SIVAL(vwv, 31, param_offset + this_param);
|
||||
SCVAL(vwv, 35, state->num_setup);
|
||||
SSVAL(vwv, 36, state->function);
|
||||
memcpy(vwv + 19, state->setup,
|
||||
sizeof(uint16_t) * state->num_setup);
|
||||
break;
|
||||
case SMBnttranss:
|
||||
SSVAL(vwv, 0, 0); /* reserved */
|
||||
SCVAL(vwv, 2, 0); /* reserved */
|
||||
SIVAL(vwv, 3, state->num_param);
|
||||
SIVAL(vwv, 7, state->num_data);
|
||||
SIVAL(vwv, 11, this_param);
|
||||
SIVAL(vwv, 15, param_offset);
|
||||
SIVAL(vwv, 19, state->param_sent);
|
||||
SIVAL(vwv, 23, this_data);
|
||||
SIVAL(vwv, 27, param_offset + this_param);
|
||||
SIVAL(vwv, 31, state->data_sent);
|
||||
SCVAL(vwv, 35, 0); /* reserved */
|
||||
break;
|
||||
}
|
||||
|
||||
bytes = (uint8_t *)talloc_append_blob(
|
||||
talloc_tos(), bytes,
|
||||
data_blob_const(state->param + state->param_sent, this_param));
|
||||
if (bytes == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
state->param_sent += this_param;
|
||||
|
||||
bytes = (uint8_t *)talloc_append_blob(
|
||||
talloc_tos(), bytes,
|
||||
data_blob_const(state->data + state->data_sent, this_data));
|
||||
if (bytes == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
state->data_sent += this_data;
|
||||
|
||||
if ((cmd == SMBtrans) || (cmd == SMBtrans2) || (cmd == SMBnttrans)) {
|
||||
/*
|
||||
* Primary request, retrieve our mid
|
||||
*/
|
||||
result = cli_request_send(mem_ctx, state->ev, state->cli,
|
||||
cmd, 0, wct, vwv,
|
||||
talloc_get_size(bytes), bytes);
|
||||
if (result == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
cli_req = talloc_get_type_abort(result->private_data,
|
||||
struct cli_request);
|
||||
state->mid = cli_req->mid;
|
||||
} else {
|
||||
uint16_t num_bytes = talloc_get_size(bytes);
|
||||
/*
|
||||
* Secondary request, we have to fix up the mid. Thus we do
|
||||
* the chain_cork/chain/uncork ourselves.
|
||||
*/
|
||||
if (!cli_chain_cork(state->cli, state->ev,
|
||||
wct * sizeof(uint16_t) + num_bytes + 3)) {
|
||||
goto fail;
|
||||
}
|
||||
result = cli_request_send(mem_ctx, state->ev, state->cli,
|
||||
cmd, 0, wct, vwv, num_bytes, bytes);
|
||||
if (result == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
cli_req = talloc_get_type_abort(result->private_data,
|
||||
struct cli_request);
|
||||
cli_req->recv_helper.fn = cli_trans_recv_helper;
|
||||
cli_req->recv_helper.priv = state;
|
||||
cli_req->mid = state->mid;
|
||||
client_set_trans_sign_state_off(state->cli, state->mid);
|
||||
cli_chain_uncork(state->cli);
|
||||
}
|
||||
|
||||
client_set_trans_sign_state_on(state->cli, state->mid);
|
||||
|
||||
fail:
|
||||
TALLOC_FREE(frame);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cli_trans_ship_rest(struct async_req *req,
|
||||
struct cli_trans_state *state)
|
||||
{
|
||||
state->secondary_request_ctx = talloc_new(state);
|
||||
if (state->secondary_request_ctx == NULL) {
|
||||
async_req_error(req, NT_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((state->param_sent < state->num_param)
|
||||
|| (state->data_sent < state->num_data)) {
|
||||
struct async_req *cli_req;
|
||||
|
||||
cli_req = cli_ship_trans(state->secondary_request_ctx, state);
|
||||
if (cli_req == NULL) {
|
||||
async_req_error(req, NT_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool cli_trans_oob(uint32_t bufsize, uint32_t offset, uint32_t length)
|
||||
{
|
||||
if ((offset + length < offset) || (offset + length < length)) {
|
||||
/* wrap */
|
||||
return true;
|
||||
}
|
||||
if ((offset > bufsize) || (offset + length > bufsize)) {
|
||||
/* overflow */
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static NTSTATUS cli_pull_trans(struct async_req *req,
|
||||
struct cli_request *cli_req,
|
||||
uint8_t smb_cmd, bool expect_first_reply,
|
||||
uint8_t *pnum_setup, uint16_t **psetup,
|
||||
uint32_t *ptotal_param, uint32_t *pnum_param,
|
||||
uint32_t *pparam_disp, uint8_t **pparam,
|
||||
uint32_t *ptotal_data, uint32_t *pnum_data,
|
||||
uint32_t *pdata_disp, uint8_t **pdata)
|
||||
{
|
||||
uint32_t param_ofs, data_ofs;
|
||||
uint8_t wct;
|
||||
uint16_t *vwv;
|
||||
uint16_t num_bytes;
|
||||
uint8_t *bytes;
|
||||
NTSTATUS status;
|
||||
|
||||
status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
|
||||
|
||||
/*
|
||||
* We can receive something like STATUS_MORE_ENTRIES, so don't use
|
||||
* !NT_STATUS_IS_OK(status) here.
|
||||
*/
|
||||
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (expect_first_reply) {
|
||||
if ((wct != 0) || (num_bytes != 0)) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
switch (smb_cmd) {
|
||||
case SMBtrans:
|
||||
case SMBtrans2:
|
||||
if (wct < 10) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
*ptotal_param = SVAL(vwv + 0, 0);
|
||||
*ptotal_data = SVAL(vwv + 1, 0);
|
||||
*pnum_param = SVAL(vwv + 3, 0);
|
||||
param_ofs = SVAL(vwv + 4, 0);
|
||||
*pparam_disp = SVAL(vwv + 5, 0);
|
||||
*pnum_data = SVAL(vwv + 6, 0);
|
||||
data_ofs = SVAL(vwv + 7, 0);
|
||||
*pdata_disp = SVAL(vwv + 8, 0);
|
||||
*pnum_setup = CVAL(vwv + 9, 0);
|
||||
if (wct < 10 + (*pnum_setup)) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
*psetup = vwv + 10;
|
||||
|
||||
break;
|
||||
case SMBnttrans:
|
||||
if (wct < 18) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
*ptotal_param = IVAL(vwv, 3);
|
||||
*ptotal_data = IVAL(vwv, 7);
|
||||
*pnum_param = IVAL(vwv, 11);
|
||||
param_ofs = IVAL(vwv, 15);
|
||||
*pparam_disp = IVAL(vwv, 19);
|
||||
*pnum_data = IVAL(vwv, 23);
|
||||
data_ofs = IVAL(vwv, 27);
|
||||
*pdata_disp = IVAL(vwv, 31);
|
||||
*pnum_setup = CVAL(vwv, 35);
|
||||
*psetup = vwv + 18;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for buffer overflows. data_ofs needs to be checked against
|
||||
* the incoming buffer length, data_disp against the total
|
||||
* length. Likewise for param_ofs/param_disp.
|
||||
*/
|
||||
|
||||
if (cli_trans_oob(smb_len(cli_req->inbuf), param_ofs, *pnum_param)
|
||||
|| cli_trans_oob(*ptotal_param, *pparam_disp, *pnum_param)
|
||||
|| cli_trans_oob(smb_len(cli_req->inbuf), data_ofs, *pnum_data)
|
||||
|| cli_trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
|
||||
*pparam = (uint8_t *)cli_req->inbuf + 4 + param_ofs;
|
||||
*pdata = (uint8_t *)cli_req->inbuf + 4 + data_ofs;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
|
||||
struct trans_recvblob *blob,
|
||||
uint32_t total, uint32_t thistime,
|
||||
uint8_t *buf, uint32_t displacement)
|
||||
{
|
||||
if (blob->data == NULL) {
|
||||
if (total > blob->max) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
blob->total = total;
|
||||
blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total);
|
||||
if (blob->data == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (total > blob->total) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
|
||||
if (thistime) {
|
||||
memcpy(blob->data + displacement, buf, thistime);
|
||||
blob->received += thistime;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void cli_trans_recv_helper(struct async_req *req)
|
||||
{
|
||||
struct cli_request *cli_req = talloc_get_type_abort(
|
||||
req->private_data, struct cli_request);
|
||||
struct cli_trans_state *state = talloc_get_type_abort(
|
||||
cli_req->recv_helper.priv, struct cli_trans_state);
|
||||
uint8_t num_setup;
|
||||
uint16_t *setup;
|
||||
uint32_t total_param, num_param, param_disp;
|
||||
uint32_t total_data, num_data, data_disp;
|
||||
uint8_t *param, *data;
|
||||
bool sent_all;
|
||||
NTSTATUS status;
|
||||
|
||||
sent_all = (state->param_sent == state->num_param)
|
||||
&& (state->data_sent == state->num_data);
|
||||
|
||||
status = cli_pull_trans(
|
||||
req, cli_req, state->cmd, !sent_all, &num_setup, &setup,
|
||||
&total_param, &num_param, ¶m_disp, ¶m,
|
||||
&total_data, &num_data, &data_disp, &data);
|
||||
|
||||
/*
|
||||
* We can receive something like STATUS_MORE_ENTRIES, so don't use
|
||||
* !NT_STATUS_IS_OK(status) here.
|
||||
*/
|
||||
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
async_req_error(req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sent_all) {
|
||||
cli_trans_ship_rest(req, state);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We've just received a real response. This means that we don't need
|
||||
* the secondary cli_request structures anymore, they have all been
|
||||
* shipped to the server.
|
||||
*/
|
||||
TALLOC_FREE(state->secondary_request_ctx);
|
||||
|
||||
if (num_setup != 0) {
|
||||
TALLOC_FREE(state->rsetup);
|
||||
state->rsetup = (uint16_t *)TALLOC_MEMDUP(
|
||||
state, setup, sizeof(uint16_t) * num_setup);
|
||||
if (state->rsetup == NULL) {
|
||||
async_req_error(req, NT_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
status = cli_trans_pull_blob(
|
||||
state, &state->rparam, total_param, num_param, param,
|
||||
param_disp);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
|
||||
async_req_error(req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = cli_trans_pull_blob(
|
||||
state, &state->rdata, total_data, num_data, data,
|
||||
data_disp);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
|
||||
async_req_error(req, status);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((state->rparam.total == state->rparam.received)
|
||||
&& (state->rdata.total == state->rdata.received)) {
|
||||
client_set_trans_sign_state_off(state->cli, state->mid);
|
||||
async_req_done(req);
|
||||
}
|
||||
}
|
||||
|
||||
struct async_req *cli_trans_send(
|
||||
TALLOC_CTX *mem_ctx, struct event_context *ev,
|
||||
struct cli_state *cli, uint8_t trans_cmd,
|
||||
const char *pipe_name, uint16_t fid, uint16_t function, int flags,
|
||||
uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
|
||||
uint8_t *param, uint32_t num_param, uint32_t max_param,
|
||||
uint8_t *data, uint32_t num_data, uint32_t max_data)
|
||||
{
|
||||
struct async_req *req;
|
||||
struct cli_request *cli_req;
|
||||
struct cli_trans_state *state;
|
||||
|
||||
/*
|
||||
* We can't use it in a chained request chain, we'd get the offset
|
||||
* calculations wrong.
|
||||
*/
|
||||
|
||||
if (cli_in_chain(cli)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((trans_cmd == SMBtrans) || (trans_cmd == SMBtrans2)) {
|
||||
if ((num_param > 0xffff) || (max_param > 0xffff)
|
||||
|| (num_data > 0xffff) || (max_data > 0xffff)) {
|
||||
DEBUG(3, ("Attempt to send invalid trans2 request "
|
||||
"(setup %u, params %u/%u, data %u/%u)\n",
|
||||
(unsigned)num_setup,
|
||||
(unsigned)num_param, (unsigned)max_param,
|
||||
(unsigned)num_data, (unsigned)max_data));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
state = talloc(mem_ctx, struct cli_trans_state);
|
||||
if (state == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
state->cli = cli;
|
||||
state->ev = ev;
|
||||
state->cmd = trans_cmd;
|
||||
state->num_rsetup = 0;
|
||||
state->rsetup = NULL;
|
||||
ZERO_STRUCT(state->rparam);
|
||||
ZERO_STRUCT(state->rdata);
|
||||
state->secondary_request_ctx = NULL;
|
||||
|
||||
if (trans_cmd == SMBtrans) {
|
||||
state->pipe_name = talloc_strdup(state, pipe_name);
|
||||
if (state->pipe_name == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
}
|
||||
if (trans_cmd == SMBtrans2) {
|
||||
state->fid = fid;
|
||||
}
|
||||
if (trans_cmd == SMBnttrans) {
|
||||
state->function = function;
|
||||
}
|
||||
|
||||
state->flags = flags;
|
||||
|
||||
if (setup != NULL) {
|
||||
state->setup = (uint16_t *)TALLOC_MEMDUP(
|
||||
state, setup, sizeof(*setup) * num_setup);
|
||||
if (state->setup == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
state->num_setup = num_setup;
|
||||
} else {
|
||||
state->setup = NULL;
|
||||
state->num_setup = 0;
|
||||
}
|
||||
|
||||
state->max_setup = max_setup;
|
||||
|
||||
if (param != NULL) {
|
||||
state->param = (uint8_t *)TALLOC_MEMDUP(state, param,
|
||||
num_param);
|
||||
if (state->param == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
state->num_param = num_param;
|
||||
} else {
|
||||
state->param = NULL;
|
||||
state->num_param = 0;
|
||||
}
|
||||
|
||||
state->param_sent = 0;
|
||||
state->rparam.max = max_param;
|
||||
|
||||
if (data != NULL) {
|
||||
state->data = (uint8_t *)TALLOC_MEMDUP(state, data, num_data);
|
||||
if (state->data == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
state->num_data = num_data;
|
||||
} else {
|
||||
state->data = NULL;
|
||||
state->num_data = 0;
|
||||
}
|
||||
|
||||
state->data_sent = 0;
|
||||
state->rdata.max = max_data;
|
||||
|
||||
req = cli_ship_trans(state, state);
|
||||
if (req == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
cli_req = talloc_get_type_abort(req->private_data, struct cli_request);
|
||||
cli_req->recv_helper.fn = cli_trans_recv_helper;
|
||||
cli_req->recv_helper.priv = state;
|
||||
|
||||
return req;
|
||||
|
||||
nomem:
|
||||
TALLOC_FREE(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
|
||||
uint16_t **setup, uint8_t *num_setup,
|
||||
uint8_t **param, uint32_t *num_param,
|
||||
uint8_t **data, uint32_t *num_data)
|
||||
{
|
||||
struct cli_request *cli_req = talloc_get_type_abort(
|
||||
req->private_data, struct cli_request);
|
||||
struct cli_trans_state *state = talloc_get_type_abort(
|
||||
cli_req->recv_helper.priv, struct cli_trans_state);
|
||||
|
||||
SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
|
||||
if (req->state == ASYNC_REQ_ERROR) {
|
||||
return req->status;
|
||||
}
|
||||
|
||||
if (setup != NULL) {
|
||||
*setup = talloc_move(mem_ctx, &state->rsetup);
|
||||
*num_setup = state->num_rsetup;
|
||||
} else {
|
||||
TALLOC_FREE(state->rsetup);
|
||||
}
|
||||
|
||||
if (param != NULL) {
|
||||
*param = talloc_move(mem_ctx, &state->rparam.data);
|
||||
*num_param = state->rparam.total;
|
||||
} else {
|
||||
TALLOC_FREE(state->rparam.data);
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
*data = talloc_move(mem_ctx, &state->rdata.data);
|
||||
*num_data = state->rdata.total;
|
||||
} else {
|
||||
TALLOC_FREE(state->rdata.data);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
|
||||
uint8_t trans_cmd,
|
||||
const char *pipe_name, uint16_t fid, uint16_t function,
|
||||
int flags,
|
||||
uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
|
||||
uint8_t *param, uint32_t num_param, uint32_t max_param,
|
||||
uint8_t *data, uint32_t num_data, uint32_t max_data,
|
||||
uint16_t **rsetup, uint8_t *num_rsetup,
|
||||
uint8_t **rparam, uint32_t *num_rparam,
|
||||
uint8_t **rdata, uint32_t *num_rdata)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
struct event_context *ev;
|
||||
struct async_req *req;
|
||||
NTSTATUS status = NT_STATUS_NO_MEMORY;
|
||||
|
||||
if (cli->fd_event != NULL) {
|
||||
/*
|
||||
* Can't use sync call while an async call is in flight
|
||||
*/
|
||||
cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ev = event_context_init(frame);
|
||||
if (ev == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
req = cli_trans_send(frame, ev, cli, trans_cmd,
|
||||
pipe_name, fid, function, flags,
|
||||
setup, num_setup, max_setup,
|
||||
param, num_param, max_param,
|
||||
data, num_data, max_data);
|
||||
if (req == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (req->state < ASYNC_REQ_DONE) {
|
||||
event_loop_once(ev);
|
||||
}
|
||||
|
||||
status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup,
|
||||
rparam, num_rparam, rdata, num_rdata);
|
||||
fail:
|
||||
TALLOC_FREE(frame);
|
||||
return status;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user