summaryrefslogtreecommitdiff
path: root/libcli
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2012-07-23 10:14:53 +0200
committerStefan Metzmacher <metze@samba.org>2012-07-23 18:19:36 +0200
commit6b9321071c97f740689a36ecf48d9d66f4a19e8e (patch)
tree08d1499433123d58f5f1bd27aa047b262d82343f /libcli
parent6e651dfdc0af9805827ad2ea7fc29675ab6fe74b (diff)
downloadsamba-6b9321071c97f740689a36ecf48d9d66f4a19e8e.tar.gz
libcli/smb: encrypt SMB2 traffic if nedded/desired.
metze
Diffstat (limited to 'libcli')
-rw-r--r--libcli/smb/smbXcli_base.c82
1 files changed, 79 insertions, 3 deletions
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index f69a6a79fcf..b85c5ab9a85 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -193,6 +193,7 @@ struct smbXcli_req_state {
const uint8_t *dyn;
uint32_t dyn_len;
+ uint8_t transform[SMB2_TF_HDR_SIZE];
uint8_t hdr[SMB2_HDR_BODY];
uint8_t pad[7]; /* padding space for compounding */
@@ -207,6 +208,7 @@ struct smbXcli_req_state {
uint16_t credit_charge;
bool should_sign;
+ bool should_encrypt;
bool signing_skipped;
bool notify_async;
@@ -2416,11 +2418,22 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
uid = session->smb2.session_id;
state->smb2.should_sign = session->smb2.should_sign;
+ state->smb2.should_encrypt = session->smb2.should_encrypt;
+
+ /* TODO: turn on encryption based on the tree connect. */
if (cmd == SMB2_OP_SESSSETUP &&
session->smb2.signing_key.length != 0) {
state->smb2.should_sign = true;
}
+
+ if (cmd == SMB2_OP_SESSSETUP) {
+ state->smb2.should_encrypt = false;
+ }
+
+ if (state->smb2.should_encrypt) {
+ state->smb2.should_sign = false;
+ };
}
state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3);
@@ -2437,6 +2450,11 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
state->smb2.dyn = dyn;
state->smb2.dyn_len = dyn_len;
+ if (state->smb2.should_encrypt) {
+ SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(state->smb2.transform, SMB2_TF_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_OPCODE, cmd);
@@ -2496,11 +2514,11 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
/*
* 1 for the nbt length
- * per request: HDR, fixed, dyn, padding
+ * per request: TRANSFORM, HDR, fixed, dyn, padding
* -1 because the last one does not need padding
*/
- iov = talloc_array(reqs[0], struct iovec, 1 + 4*num_reqs - 1);
+ iov = talloc_array(reqs[0], struct iovec, 1 + 5*num_reqs - 1);
if (iov == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -2509,6 +2527,7 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
nbt_len = 0;
for (i=0; i<num_reqs; i++) {
+ int tf_iov;
int hdr_iov;
size_t reqlen;
bool ret;
@@ -2518,6 +2537,7 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
uint16_t credits;
uint64_t mid;
const DATA_BLOB *signing_key = NULL;
+ const DATA_BLOB *encryption_key = NULL;
if (!tevent_req_is_in_progress(reqs[i])) {
return NT_STATUS_INTERNAL_ERROR;
@@ -2601,6 +2621,17 @@ skip_credits:
if (signing_key && signing_key->length == 0) {
signing_key = NULL;
}
+
+ if (state->smb2.should_encrypt) {
+ encryption_key = &state->session->smb2.encryption_key;
+ }
+ }
+
+ if (encryption_key) {
+ tf_iov = num_iov;
+ iov[num_iov].iov_base = state->smb2.transform;
+ iov[num_iov].iov_len = sizeof(state->smb2.transform);
+ num_iov += 1;
}
hdr_iov = num_iov;
@@ -2633,7 +2664,48 @@ skip_credits:
SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
}
- if (signing_key) {
+ if (encryption_key) {
+ NTSTATUS status;
+ uint8_t *buf;
+ int vi;
+
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE, mid);
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE+8,
+ state->session->smb2.channel_nonce);
+ SBVAL(state->smb2.transform, SMB2_TF_MSG_SIZE,
+ reqlen);
+
+ buf = talloc_array(iov, uint8_t, reqlen);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ reqlen += SMB2_TF_HDR_SIZE;
+
+ /*
+ * We copy the buffers before encrypting them,
+ * this is at least currently needed for the
+ * to keep state->smb2.hdr.
+ *
+ * Also the callers may expect there buffers
+ * to be const.
+ */
+ for (vi = hdr_iov; vi < num_iov; vi++) {
+ struct iovec *v = &iov[vi];
+ const uint8_t *o = (const uint8_t *)v->iov_base;
+
+ memcpy(buf, o, v->iov_len);
+ v->iov_base = (void *)buf;
+ buf += v->iov_len;
+ }
+
+ status = smb2_signing_encrypt_pdu(*encryption_key,
+ state->session->conn->protocol,
+ &iov[tf_iov], num_iov - tf_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else if (signing_key) {
NTSTATUS status;
status = smb2_signing_sign_pdu(*signing_key,
@@ -3070,6 +3142,10 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
* status to the caller.
*/
signing_key = NULL;
+ } else if (state->smb2.should_encrypt) {
+ if (cur[0].iov_len != SMB2_TF_HDR_SIZE) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
}
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||