summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/smb2/session.c8
-rw-r--r--source4/libcli/smb2/signing.c74
-rw-r--r--source4/libcli/smb2/transport.c32
-rw-r--r--source4/smb_server/smb2/negprot.c13
-rw-r--r--source4/smb_server/smb2/receive.c36
-rw-r--r--source4/smb_server/smb2/sesssetup.c9
-rw-r--r--source4/smb_server/smb_server.h2
7 files changed, 103 insertions, 71 deletions
diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index 54915d8535..42fd4840a1 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -188,11 +188,13 @@ static void session_request_handler(struct smb2_request *req)
}
if (session->transport->signing.doing_signing) {
- c->status = smb2_start_signing(session->transport);
- if (!NT_STATUS_IS_OK(c->status)) {
- composite_error(c, c->status);
+ if (session->transport->signing.session_key.length != 16) {
+ DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
+ (unsigned)session->transport->signing.session_key.length));
+ composite_error(c, NT_STATUS_ACCESS_DENIED);
return;
}
+ session->transport->signing.signing_started = true;
}
composite_done(c);
diff --git a/source4/libcli/smb2/signing.c b/source4/libcli/smb2/signing.c
index 16c0ff99c1..fb2c22db4e 100644
--- a/source4/libcli/smb2/signing.c
+++ b/source4/libcli/smb2/signing.c
@@ -26,41 +26,13 @@
#include "lib/crypto/crypto.h"
/*
- NOTE: this code does not yet interoperate with the windows SMB2
- implementation. We are waiting on feedback on the docs to find out
- why
- */
-
-
-/*
- setup signing on a transport
- */
-NTSTATUS smb2_start_signing(struct smb2_transport *transport)
-{
- if (transport->signing.session_key.length != 16) {
- DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
- (unsigned)transport->signing.session_key.length));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- transport->signing.signing_started = true;
- return NT_STATUS_OK;
-}
-
-/*
sign an outgoing message
*/
-NTSTATUS smb2_sign_message(struct smb2_request *req)
+NTSTATUS smb2_sign_message(struct smb2_request_buffer *buf, DATA_BLOB session_key)
{
- struct smb2_request_buffer *buf = &req->out;
- uint64_t session_id;
struct HMACSHA256Context m;
uint8_t res[32];
-
- if (!req->transport->signing.doing_signing ||
- !req->transport->signing.signing_started) {
- return NT_STATUS_OK;
- }
+ uint64_t session_id;
if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
/* can't sign non-SMB2 messages */
@@ -74,9 +46,9 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
return NT_STATUS_OK;
}
- if (req->transport->signing.session_key.length != 16) {
+ if (session_key.length != 16) {
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
- (unsigned)req->transport->signing.session_key.length));
+ (unsigned)session_key.length));
return NT_STATUS_ACCESS_DENIED;
}
@@ -85,7 +57,7 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
SIVAL(buf->hdr, SMB2_HDR_FLAGS, IVAL(buf->hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
ZERO_STRUCT(m);
- hmac_sha256_init(req->transport->signing.session_key.data, 16, &m);
+ hmac_sha256_init(session_key.data, 16, &m);
hmac_sha256_update(buf->buffer+NBT_HDR_SIZE, buf->size-NBT_HDR_SIZE, &m);
hmac_sha256_final(res, &m);
@@ -93,66 +65,56 @@ NTSTATUS smb2_sign_message(struct smb2_request *req)
memcpy(buf->hdr + SMB2_HDR_SIGNATURE, res, 16);
- if (DEBUGLVL(5)) {
- /* check our own signature */
- smb2_check_signature(req->transport, buf->buffer, buf->size);
- }
-
return NT_STATUS_OK;
}
/*
check an incoming signature
*/
-NTSTATUS smb2_check_signature(struct smb2_transport *transport,
- uint8_t *buffer, uint_t length)
+NTSTATUS smb2_check_signature(struct smb2_request_buffer *buf, DATA_BLOB session_key)
{
uint64_t session_id;
struct HMACSHA256Context m;
uint8_t res[SHA256_DIGEST_LENGTH];
uint8_t sig[16];
- if (!transport->signing.signing_started ||
- !transport->signing.doing_signing) {
- return NT_STATUS_OK;
- }
-
- if (length < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
+ if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) {
/* can't check non-SMB2 messages */
return NT_STATUS_OK;
}
- session_id = BVAL(buffer+NBT_HDR_SIZE, SMB2_HDR_SESSION_ID);
+ session_id = BVAL(buf->hdr, SMB2_HDR_SESSION_ID);
if (session_id == 0) {
/* don't sign messages with a zero session_id. See
MS-SMB2 3.2.4.1.1 */
return NT_STATUS_OK;
}
- if (transport->signing.session_key.length == 0) {
+ if (session_key.length == 0) {
/* we don't have the session key yet */
return NT_STATUS_OK;
}
- if (transport->signing.session_key.length != 16) {
+ if (session_key.length != 16) {
DEBUG(2,("Wrong session key length %u for SMB2 signing\n",
- (unsigned)transport->signing.session_key.length));
+ (unsigned)session_key.length));
return NT_STATUS_ACCESS_DENIED;
}
- memcpy(sig, buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, 16);
+ memcpy(sig, buf->hdr+SMB2_HDR_SIGNATURE, 16);
- memset(buffer + NBT_HDR_SIZE + SMB2_HDR_SIGNATURE, 0, 16);
+ memset(buf->hdr + SMB2_HDR_SIGNATURE, 0, 16);
ZERO_STRUCT(m);
- hmac_sha256_init(transport->signing.session_key.data, 16, &m);
- hmac_sha256_update(buffer+NBT_HDR_SIZE, length-NBT_HDR_SIZE, &m);
+ hmac_sha256_init(session_key.data, 16, &m);
+ hmac_sha256_update(buf->hdr, buf->size-NBT_HDR_SIZE, &m);
hmac_sha256_final(res, &m);
- memcpy(buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, sig, 16);
+ memcpy(buf->hdr+SMB2_HDR_SIGNATURE, sig, 16);
if (memcmp(res, sig, 16) != 0) {
- DEBUG(0,("Bad SMB2 signature for message of size %u\n", length));
+ DEBUG(0,("Bad SMB2 signature for message of size %u\n",
+ (unsigned)buf->size-NBT_HDR_SIZE));
dump_data(0, sig, 16);
dump_data(0, res, 16);
return NT_STATUS_ACCESS_DENIED;
diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index 561b6e528e..a9a9efb3aa 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -205,12 +205,6 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
goto error;
}
- status = smb2_check_signature(transport, buffer, len);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(buffer);
- return status;
- }
-
flags = IVAL(hdr, SMB2_HDR_FLAGS);
seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
@@ -241,6 +235,18 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
+ if (transport->signing.signing_started &&
+ transport->signing.doing_signing) {
+ status = smb2_check_signature(&req->in,
+ transport->signing.session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* the spec says to ignore packets with a bad signature */
+ talloc_free(buffer);
+ return status;
+ }
+ }
+
+
if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
if (flags & 0x00000002) {
req->cancel.can_cancel = true;
@@ -346,11 +352,15 @@ void smb2_transport_send(struct smb2_request *req)
return;
}
- status = smb2_sign_message(req);
- if (!NT_STATUS_IS_OK(status)) {
- req->state = SMB2_REQUEST_ERROR;
- req->status = status;
- return;
+ /* possibly sign the message */
+ if (req->transport->signing.doing_signing &&
+ req->transport->signing.signing_started) {
+ status = smb2_sign_message(&req->out, req->transport->signing.session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ req->state = SMB2_REQUEST_ERROR;
+ req->status = status;
+ return;
+ }
}
blob = data_blob_const(req->out.buffer, req->out.size);
diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c
index 4479ae2da1..2da39001ab 100644
--- a/source4/smb_server/smb2/negprot.c
+++ b/source4/smb_server/smb2/negprot.c
@@ -111,7 +111,18 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
boot_time = timeval_current(); /* TODO: fix me */
ZERO_STRUCT(io->out);
- io->out.security_mode = 0; /* no signing yet */
+ switch (lp_server_signing(req->smb_conn->lp_ctx)) {
+ case SMB_SIGNING_OFF:
+ io->out.security_mode = 0;
+ break;
+ case SMB_SIGNING_SUPPORTED:
+ case SMB_SIGNING_AUTO:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ break;
+ case SMB_SIGNING_REQUIRED:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ break;
+ }
io->out.dialect_revision = SMB2_DIALECT_REVISION;
io->out.capabilities = 0;
io->out.max_transact_size = lp_parm_ulong(req->smb_conn->lp_ctx, NULL,
diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c
index dea7c9e79e..3def8fe563 100644
--- a/source4/smb_server/smb2/receive.c
+++ b/source4/smb_server/smb2/receive.c
@@ -29,6 +29,8 @@
#include "lib/stream/packet.h"
#include "ntvfs/ntvfs.h"
#include "param/param.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
/* fill in the bufinfo */
@@ -233,6 +235,20 @@ void smb2srv_send_reply(struct smb2srv_request *req)
_smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
}
+ /* if the request was signed or doing_signing is true, then we
+ must sign the reply */
+ if (req->session &&
+ (req->smb_conn->doing_signing ||
+ (IVAL(req->in.hdr, SMB2_HDR_FLAGS) & SMB2_HDR_FLAG_SIGNED))) {
+ status = smb2_sign_message(&req->out,
+ req->session->session_info->session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+ return;
+ }
+ }
+
+
blob = data_blob_const(req->out.buffer, req->out.size);
status = packet_send(req->smb_conn->packet, blob);
if (!NT_STATUS_IS_OK(status)) {
@@ -275,18 +291,38 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
uint16_t opcode;
uint32_t tid;
uint64_t uid;
+ uint32_t flags;
opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
tid = IVAL(req->in.hdr, SMB2_HDR_TID);
uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
+ flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
errno = 0;
+ /* supporting signing is mandatory in SMB2, and is per-packet. So we
+ should check the signature on any incoming packet that is signed, and
+ should give a signed reply to any signed request */
+ if (flags & SMB2_HDR_FLAG_SIGNED) {
+ NTSTATUS status;
+ if (req->session == NULL) {
+ /* we can't check signing with no session */
+ smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
+ return NT_STATUS_OK;
+ }
+ status = smb2_check_signature(&req->in,
+ req->session->session_info->session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ smb2srv_send_error(req, status);
+ return NT_STATUS_OK;
+ }
+ }
+
/* TODO: check the seqnum */
switch (opcode) {
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index d386bfc72d..482dd181c2 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -177,6 +177,15 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
gensec_update_send(smb_sess->gensec_ctx, io->smb2.in.secblob,
smb2srv_sesssetup_callback, callback_ctx);
+
+ /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
+ This is deliberate as windows does not set it even when it does
+ set SMB2_NEGOTIATE_SIGNING_REQUIRED */
+ if ((io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
+ lp_server_signing(req->smb_conn->lp_ctx) == SMB_SIGNING_REQUIRED) {
+ req->smb_conn->doing_signing = true;
+ }
+
return;
nomem:
status = NT_STATUS_NO_MEMORY;
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index 776fe1b71b..ac3e0f3bd3 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -376,6 +376,8 @@ struct smbsrv_connection {
struct share_context *share_context;
struct loadparm_context *lp_ctx;
+
+ bool doing_signing;
};
struct model_ops;