1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

smbXcli: rework smb2cli_req to smbXcli_conn/smbXcli_req

metze
This commit is contained in:
Stefan Metzmacher 2011-09-15 12:23:05 +02:00
parent 21b5f1c185
commit 84806eceb2
2 changed files with 166 additions and 171 deletions

View File

@ -90,6 +90,26 @@ struct smbXcli_conn {
struct smb_signing_state *signing;
struct smb_trans_enc_state *trans_enc;
} smb1;
struct {
struct {
uint16_t security_mode;
} client;
struct {
uint32_t capabilities;
uint16_t security_mode;
struct GUID guid;
uint32_t max_trans_size;
uint32_t max_read_size;
uint32_t max_write_size;
NTTIME system_time;
NTTIME start_time;
DATA_BLOB gss_blob;
} server;
uint64_t mid;
} smb2;
};
struct smbXcli_req_state {
@ -127,6 +147,19 @@ struct smbXcli_req_state {
int chain_length;
struct tevent_req **chained_requests;
} smb1;
struct {
const uint8_t *fixed;
uint16_t fixed_len;
const uint8_t *dyn;
uint32_t dyn_len;
uint8_t hdr[64];
uint8_t pad[7]; /* padding space for compounding */
/* always an array of 3 talloc elements */
struct iovec *recv_iov;
} smb2;
};
static int smbXcli_conn_destructor(struct smbXcli_conn *conn)
@ -229,6 +262,11 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
goto error;
}
conn->smb2.client.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
if (conn->mandatory_signing) {
conn->smb2.client.security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
}
talloc_set_destructor(conn, smbXcli_conn_destructor);
return conn;
@ -554,6 +592,17 @@ static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
}
if (num_pending == 0) {
if (conn->smb2.mid < UINT64_MAX) {
/* no more pending requests, so we are done for now */
return true;
}
/*
* If there are no more SMB2 requests possible,
* because we are out of message ids,
* we need to disconnect.
*/
smbXcli_conn_disconnect(conn, NT_STATUS_CONNECTION_ABORTED);
return true;
}
@ -1561,11 +1610,11 @@ bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn)
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
struct smbXcli_conn *conn,
uint16_t cmd,
uint32_t additional_flags,
uint32_t clear_flags,
unsigned int timeout,
uint32_t timeout_msec,
uint32_t pid,
uint32_t tid,
uint64_t uid,
@ -1575,19 +1624,20 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
uint32_t dyn_len)
{
struct tevent_req *req;
struct smb2cli_req_state *state;
struct smbXcli_req_state *state;
uint32_t flags = 0;
req = tevent_req_create(mem_ctx, &state,
struct smb2cli_req_state);
struct smbXcli_req_state);
if (req == NULL) {
return NULL;
}
state->ev = ev;
state->cli = cli;
state->recv_iov = talloc_zero_array(state, struct iovec, 3);
if (state->recv_iov == NULL) {
state->ev = ev;
state->conn = conn;
state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3);
if (state->smb2.recv_iov == NULL) {
TALLOC_FREE(req);
return NULL;
}
@ -1595,26 +1645,32 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
flags |= additional_flags;
flags &= ~clear_flags;
state->fixed = fixed;
state->fixed_len = fixed_len;
state->dyn = dyn;
state->dyn_len = dyn_len;
state->smb2.fixed = fixed;
state->smb2.fixed_len = fixed_len;
state->smb2.dyn = dyn;
state->smb2.dyn_len = dyn_len;
SIVAL(state->hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
SSVAL(state->hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
SSVAL(state->hdr, SMB2_HDR_EPOCH, 1);
SIVAL(state->hdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_OK));
SSVAL(state->hdr, SMB2_HDR_OPCODE, cmd);
SSVAL(state->hdr, SMB2_HDR_CREDIT, 31);
SIVAL(state->hdr, SMB2_HDR_FLAGS, flags);
SIVAL(state->hdr, SMB2_HDR_PID, pid);
SIVAL(state->hdr, SMB2_HDR_TID, tid);
SBVAL(state->hdr, SMB2_HDR_SESSION_ID, uid);
SIVAL(state->smb2.hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
SSVAL(state->smb2.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT_CHARGE, 1);
SIVAL(state->smb2.hdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_OK));
SSVAL(state->smb2.hdr, SMB2_HDR_OPCODE, cmd);
SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT, 31);
SIVAL(state->smb2.hdr, SMB2_HDR_FLAGS, flags);
SIVAL(state->smb2.hdr, SMB2_HDR_PID, pid);
SIVAL(state->smb2.hdr, SMB2_HDR_TID, tid);
SBVAL(state->smb2.hdr, SMB2_HDR_SESSION_ID, uid);
if (timeout > 0) {
switch (cmd) {
case SMB2_OP_CANCEL:
state->one_way = true;
break;
}
if (timeout_msec > 0) {
struct timeval endtime;
endtime = timeval_current_ofs_msec(timeout);
endtime = timeval_current_ofs_msec(timeout_msec);
if (!tevent_req_set_endtime(req, ev, endtime)) {
return req;
}
@ -1624,11 +1680,14 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
}
static void smb2cli_writev_done(struct tevent_req *subreq);
static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
TALLOC_CTX *tmp_mem,
uint8_t *inbuf);
NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
int num_reqs)
{
struct smb2cli_req_state *state;
struct smbXcli_req_state *state;
struct tevent_req *subreq;
struct iovec *iov;
int i, num_iov, nbt_len;
@ -1656,51 +1715,57 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
return NT_STATUS_INTERNAL_ERROR;
}
state = tevent_req_data(reqs[i], struct smb2cli_req_state);
state = tevent_req_data(reqs[i], struct smbXcli_req_state);
if (!cli_state_is_connected(state->cli)) {
if (!smbXcli_conn_is_connected(state->conn)) {
return NT_STATUS_CONNECTION_DISCONNECTED;
}
if (state->cli->smb2.mid == UINT64_MAX) {
if ((state->conn->protocol != PROTOCOL_NONE) &&
(state->conn->protocol < PROTOCOL_SMB2_02)) {
return NT_STATUS_REVISION_MISMATCH;
}
if (state->conn->smb2.mid == UINT64_MAX) {
return NT_STATUS_CONNECTION_ABORTED;
}
mid = state->cli->smb2.mid;
state->cli->smb2.mid += 1;
mid = state->conn->smb2.mid;
state->conn->smb2.mid += 1;
SBVAL(state->hdr, SMB2_HDR_MESSAGE_ID, mid);
SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, mid);
iov[num_iov].iov_base = state->hdr;
iov[num_iov].iov_len = sizeof(state->hdr);
iov[num_iov].iov_base = state->smb2.hdr;
iov[num_iov].iov_len = sizeof(state->smb2.hdr);
num_iov += 1;
iov[num_iov].iov_base = discard_const(state->fixed);
iov[num_iov].iov_len = state->fixed_len;
iov[num_iov].iov_base = discard_const(state->smb2.fixed);
iov[num_iov].iov_len = state->smb2.fixed_len;
num_iov += 1;
if (state->dyn != NULL) {
iov[num_iov].iov_base = discard_const(state->dyn);
iov[num_iov].iov_len = state->dyn_len;
if (state->smb2.dyn != NULL) {
iov[num_iov].iov_base = discard_const(state->smb2.dyn);
iov[num_iov].iov_len = state->smb2.dyn_len;
num_iov += 1;
}
reqlen = sizeof(state->hdr) + state->fixed_len +
state->dyn_len;
reqlen = sizeof(state->smb2.hdr);
reqlen += state->smb2.fixed_len;
reqlen += state->smb2.dyn_len;
if (i < num_reqs-1) {
if ((reqlen % 8) > 0) {
uint8_t pad = 8 - (reqlen % 8);
iov[num_iov].iov_base = state->pad;
iov[num_iov].iov_base = state->smb2.pad;
iov[num_iov].iov_len = pad;
num_iov += 1;
reqlen += pad;
}
SIVAL(state->hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
}
nbt_len += reqlen;
ret = smb2cli_req_set_pending(reqs[i]);
ret = smbXcli_req_set_pending(reqs[i]);
if (!ret) {
return NT_STATUS_NO_MEMORY;
}
@ -1710,13 +1775,17 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
* TODO: Do signing here
*/
state = tevent_req_data(reqs[0], struct smb2cli_req_state);
_smb_setlen_tcp(state->nbt, nbt_len);
iov[0].iov_base = state->nbt;
iov[0].iov_len = sizeof(state->nbt);
state = tevent_req_data(reqs[0], struct smbXcli_req_state);
_smb_setlen_tcp(state->length_hdr, nbt_len);
iov[0].iov_base = state->length_hdr;
iov[0].iov_len = sizeof(state->length_hdr);
subreq = writev_send(state, state->ev, state->cli->conn.outgoing,
state->cli->conn.fd, false, iov, num_iov);
if (state->conn->dispatch_incoming == NULL) {
state->conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
}
subreq = writev_send(state, state->ev, state->conn->outgoing,
state->conn->fd, false, iov, num_iov);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
@ -1726,11 +1795,11 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
struct smbXcli_conn *conn,
uint16_t cmd,
uint32_t additional_flags,
uint32_t clear_flags,
unsigned int timeout,
uint32_t timeout_msec,
uint32_t pid,
uint32_t tid,
uint64_t uid,
@ -1742,9 +1811,9 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
struct tevent_req *req;
NTSTATUS status;
req = smb2cli_req_create(mem_ctx, ev, cli, cmd,
req = smb2cli_req_create(mem_ctx, ev, conn, cmd,
additional_flags, clear_flags,
timeout,
timeout_msec,
pid, tid, uid,
fixed, fixed_len, dyn, dyn_len);
if (req == NULL) {
@ -1765,9 +1834,9 @@ static void smb2cli_writev_done(struct tevent_req *subreq)
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct smb2cli_req_state *state =
struct smbXcli_req_state *state =
tevent_req_data(req,
struct smb2cli_req_state);
struct smbXcli_req_state);
ssize_t nwritten;
int err;
@ -1776,7 +1845,7 @@ static void smb2cli_writev_done(struct tevent_req *subreq)
if (nwritten == -1) {
/* here, we need to notify all pending requests */
NTSTATUS status = map_nt_error_from_unix_common(err);
smb2cli_notify_pending(state->cli, status);
smbXcli_conn_disconnect(state->conn, status);
return;
}
}
@ -1881,68 +1950,40 @@ inval:
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
static struct tevent_req *cli_smb2_find_pending(struct cli_state *cli,
uint64_t mid)
static struct tevent_req *smb2cli_conn_find_pending(struct smbXcli_conn *conn,
uint64_t mid)
{
int num_pending = talloc_array_length(cli->conn.pending);
int i;
size_t num_pending = talloc_array_length(conn->pending);
size_t i;
for (i=0; i<num_pending; i++) {
struct tevent_req *req = cli->conn.pending[i];
struct smb2cli_req_state *state =
struct tevent_req *req = conn->pending[i];
struct smbXcli_req_state *state =
tevent_req_data(req,
struct smb2cli_req_state);
struct smbXcli_req_state);
if (mid == BVAL(state->hdr, SMB2_HDR_MESSAGE_ID)) {
if (mid == BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID)) {
return req;
}
}
return NULL;
}
static void smb2cli_inbuf_received(struct tevent_req *subreq)
static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
TALLOC_CTX *tmp_mem,
uint8_t *inbuf)
{
struct cli_state *cli =
tevent_req_callback_data(subreq,
struct cli_state);
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_req *req;
struct smb2cli_req_state *state = NULL;
struct smbXcli_req_state *state = NULL;
struct iovec *iov;
int i, num_iov;
NTSTATUS status;
uint8_t *inbuf;
ssize_t received;
int err;
size_t num_pending;
bool defer = true;
received = read_smb_recv(subreq, frame, &inbuf, &err);
TALLOC_FREE(subreq);
if (received == -1) {
/*
* We need to close the connection and notify
* all pending requests.
*/
status = map_nt_error_from_unix_common(err);
smb2cli_notify_pending(cli, status);
TALLOC_FREE(frame);
return;
}
status = smb2cli_inbuf_parse_compound(inbuf, frame,
status = smb2cli_inbuf_parse_compound(inbuf, tmp_mem,
&iov, &num_iov);
if (!NT_STATUS_IS_OK(status)) {
/*
* if we cannot parse the incoming pdu,
* the connection becomes unusable.
*
* We need to close the connection and notify
* all pending requests.
*/
smb2cli_notify_pending(cli, status);
TALLOC_FREE(frame);
return;
return status;
}
for (i=0; i<num_iov; i+=3) {
@ -1954,57 +1995,40 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
uint16_t req_opcode;
req = cli_smb2_find_pending(cli, mid);
req = smb2cli_conn_find_pending(conn, mid);
if (req == NULL) {
/*
* TODO: handle oplock breaks and async responses
*/
/*
* We need to close the connection and notify
* all pending requests.
*/
status = NT_STATUS_INVALID_NETWORK_RESPONSE;
smb2cli_notify_pending(cli, status);
TALLOC_FREE(frame);
return;
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
state = tevent_req_data(req, struct smb2cli_req_state);
state = tevent_req_data(req, struct smbXcli_req_state);
req_opcode = SVAL(state->hdr, SMB2_HDR_OPCODE);
req_opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
if (opcode != req_opcode) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE;
smb2cli_notify_pending(cli, status);
TALLOC_FREE(frame);
return;
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (!(flags & SMB2_HDR_FLAG_REDIRECT)) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE;
smb2cli_notify_pending(cli, status);
TALLOC_FREE(frame);
return;
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
status = NT_STATUS(IVAL(inhdr, SMB2_HDR_STATUS));
if ((flags & SMB2_HDR_FLAG_ASYNC) &&
NT_STATUS_EQUAL(status, STATUS_PENDING)) {
uint32_t req_flags = IVAL(state->hdr, SMB2_HDR_FLAGS);
uint32_t req_flags = IVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID);
req_flags |= SMB2_HDR_FLAG_ASYNC;
SBVAL(state->hdr, SMB2_HDR_FLAGS, req_flags);
SBVAL(state->hdr, SMB2_HDR_ASYNC_ID, async_id);
SBVAL(state->smb2.hdr, SMB2_HDR_FLAGS, req_flags);
SBVAL(state->smb2.hdr, SMB2_HDR_ASYNC_ID, async_id);
continue;
}
smb2cli_req_unset_pending(req);
smbXcli_req_unset_pending(req);
/*
* There might be more than one response
* we need to defer the notifications
*/
if ((num_iov == 4) && (talloc_array_length(cli->conn.pending) == 0)) {
if ((num_iov == 4) && (talloc_array_length(conn->pending) == 0)) {
defer = false;
}
@ -2016,53 +2040,24 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
* Note: here we use talloc_reference() in a way
* that does not expose it to the caller.
*/
inbuf_ref = talloc_reference(state->recv_iov, inbuf);
inbuf_ref = talloc_reference(state->smb2.recv_iov, inbuf);
if (tevent_req_nomem(inbuf_ref, req)) {
continue;
}
/* copy the related buffers */
state->recv_iov[0] = cur[0];
state->recv_iov[1] = cur[1];
state->recv_iov[2] = cur[2];
state->smb2.recv_iov[0] = cur[0];
state->smb2.recv_iov[1] = cur[1];
state->smb2.recv_iov[2] = cur[2];
tevent_req_done(req);
}
TALLOC_FREE(frame);
if (!defer) {
return;
if (defer) {
return NT_STATUS_RETRY;
}
num_pending = talloc_array_length(cli->conn.pending);
if (num_pending == 0) {
if (state->cli->smb2.mid < UINT64_MAX) {
/* no more pending requests, so we are done for now */
return;
}
/*
* If there are no more requests possible,
* because we are out of message ids,
* we need to disconnect.
*/
smb2cli_notify_pending(cli, NT_STATUS_CONNECTION_ABORTED);
return;
}
req = cli->conn.pending[0];
state = tevent_req_data(req, struct smb2cli_req_state);
/*
* add the read_smb request that waits for the
* next answer from the server
*/
subreq = read_smb_send(cli->conn.pending, state->ev, cli->conn.fd);
if (subreq == NULL) {
smb2cli_notify_pending(cli, NT_STATUS_NO_MEMORY);
return;
}
tevent_req_set_callback(subreq, smb2cli_inbuf_received, cli);
return NT_STATUS_OK;
}
NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
@ -2070,9 +2065,9 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
const struct smb2cli_req_expected_response *expected,
size_t num_expected)
{
struct smb2cli_req_state *state =
struct smbXcli_req_state *state =
tevent_req_data(req,
struct smb2cli_req_state);
struct smbXcli_req_state);
NTSTATUS status;
size_t body_size;
bool found_status = false;
@ -2103,8 +2098,8 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
found_size = true;
}
status = NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
body_size = SVAL(state->recv_iov[1].iov_base, 0);
status = NT_STATUS(IVAL(state->smb2.recv_iov[0].iov_base, SMB2_HDR_STATUS));
body_size = SVAL(state->smb2.recv_iov[1].iov_base, 0);
for (i=0; i < num_expected; i++) {
if (!NT_STATUS_EQUAL(status, expected[i].status)) {
@ -2132,7 +2127,7 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
}
if (piov != NULL) {
*piov = talloc_move(mem_ctx, &state->recv_iov);
*piov = talloc_move(mem_ctx, &state->smb2.recv_iov);
}
return status;

View File

@ -105,11 +105,11 @@ NTSTATUS smb1cli_req_recv(struct tevent_req *req,
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
struct smbXcli_conn *conn,
uint16_t cmd,
uint32_t additional_flags,
uint32_t clear_flags,
unsigned int timeout,
uint32_t timeout_msec,
uint32_t pid,
uint32_t tid,
uint64_t uid,
@ -127,11 +127,11 @@ struct smb2cli_req_expected_response {
struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
struct smbXcli_conn *conn,
uint16_t cmd,
uint32_t additional_flags,
uint32_t clear_flags,
unsigned int timeout,
uint32_t timeout_msec,
uint32_t pid,
uint32_t tid,
uint64_t uid,