*/
struct iovec *recv_iov;
+ /*
+ * the expected max for the response dyn_len
+ */
+ uint32_t max_dyn_len;
+
uint16_t credit_charge;
bool should_sign;
return conn->smb1.max_xmit;
}
+bool smb1cli_conn_req_possible(struct smbXcli_conn *conn)
+{
+ size_t pending;
+ uint16_t possible = conn->smb1.server.max_mux;
+
+ pending = tevent_queue_length(conn->outgoing);
+ if (pending >= possible) {
+ return false;
+ }
+ pending += talloc_array_length(conn->pending);
+ if (pending >= possible) {
+ return false;
+ }
+
+ return true;
+}
+
uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn)
{
return conn->smb1.server.session_key;
size_t num_pending = talloc_array_length(conn->pending);
uint16_t result;
+ if (conn->protocol == PROTOCOL_NONE) {
+ /*
+ * This is what windows sends on the SMB1 Negprot request
+ * and some vendors reuse the SMB1 MID as SMB2 sequence number.
+ */
+ return 0;
+ }
+
while (true) {
size_t i;
if (subreq != conn->read_smb_req) {
DEBUG(1, ("Internal error: cli_smb_received called with "
"unexpected subreq\n"));
- status = NT_STATUS_INTERNAL_ERROR;
- smbXcli_conn_disconnect(conn, status);
+ smbXcli_conn_disconnect(conn, NT_STATUS_INTERNAL_ERROR);
TALLOC_FREE(frame);
return;
}
* tevent_req_done().
*/
return;
- } else if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
/*
* We got an error, so notify all pending requests
*/
|| (talloc_array_length(conn->pending) != 0));
}
+bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len)
+{
+ uint16_t credits = 1;
+
+ if (conn->smb2.cur_credits == 0) {
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = 0;
+ }
+ return false;
+ }
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ credits = conn->smb2.cur_credits;
+ }
+
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = credits * 65536;
+ }
+
+ return true;
+}
+
uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn)
{
return conn->smb2.server.capabilities;
0, /* timeout */
tcon, session,
fixed, fixed_len,
- NULL, 0);
+ NULL, 0, 0);
if (subreq == NULL) {
return false;
}
const uint8_t *fixed,
uint16_t fixed_len,
const uint8_t *dyn,
- uint32_t dyn_len)
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
{
struct tevent_req *req;
struct smbXcli_req_state *state;
state->smb2.fixed_len = fixed_len;
state->smb2.dyn = dyn;
state->smb2.dyn_len = dyn_len;
+ state->smb2.max_dyn_len = max_dyn_len;
if (state->smb2.should_encrypt) {
SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
}
if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
- charge = (MAX(state->smb2.dyn_len, 1) - 1)/ 65536 + 1;
+ uint32_t max_dyn_len = 1;
+
+ max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len);
+ max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len);
+
+ charge = (max_dyn_len - 1)/ 65536 + 1;
} else {
charge = 1;
}
const uint8_t *fixed,
uint16_t fixed_len,
const uint8_t *dyn,
- uint32_t dyn_len)
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
{
struct tevent_req *req;
NTSTATUS status;
additional_flags, clear_flags,
timeout_msec,
tcon, session,
- fixed, fixed_len, dyn, dyn_len);
+ fixed, fixed_len,
+ dyn, dyn_len,
+ max_dyn_len);
if (req == NULL) {
return NULL;
}
{PROTOCOL_SMB2_22, SMB2_DIALECT_REVISION_222},
{PROTOCOL_SMB2_24, SMB2_DIALECT_REVISION_224},
{PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300},
+ {PROTOCOL_SMB3_02, SMB3_DIALECT_REVISION_302},
};
struct smbXcli_negprot_state {
state->timeout_msec,
NULL, NULL, /* tcon, session */
state->smb2.fixed, sizeof(state->smb2.fixed),
- state->smb2.dyn, dialect_count*2);
+ state->smb2.dyn, dialect_count*2,
+ UINT16_MAX); /* max_dyn_len */
}
static void smbXcli_negprot_smb2_done(struct tevent_req *subreq)
/*
* we got an SMB2 answer, which consumed sequence number 0
- * so we need to use 1 as the next one
+ * so we need to use 1 as the next one.
+ *
+ * we also need to set the current credits to 0
+ * as we consumed the initial one. The SMB2 answer
+ * hopefully grant us a new credit.
*/
conn->smb2.mid = 1;
+ conn->smb2.cur_credits = 0;
tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf);
session->conn->protocol,
recv_iov, 3);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ /*
+ * Sadly some vendors don't sign the
+ * final SMB2 session setup response
+ *
+ * At least Windows and Samba are always doing this
+ * if there's a session key available.
+ */
+ if (conn->mandatory_signing) {
+ return status;
+ }
}
session->smb2->should_sign = false;
return NT_STATUS_OK;
}
+NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
+{
+ if (session->smb2->should_encrypt) {
+ return NT_STATUS_OK;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB2_24) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!(session->conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (session->smb2->signing_key.data == NULL) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ session->smb2->should_encrypt = true;
+ return NT_STATUS_OK;
+}
+
struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx)
{
struct smbXcli_tcon *tcon;