[SCM] Samba Shared Repository - branch v4-0-test updated - release-4-0-0alpha4-42-g8e96f2e

Andrew Tridgell tridge at samba.org
Sat Jun 7 05:11:20 GMT 2008


The branch, v4-0-test has been updated
       via  8e96f2edb003d997e71e9e237463882696279d0f (commit)
       via  8e919dcb0826a5b25d037ee6144af5f7cb21f3ae (commit)
       via  0643b5a2bfc401d8318964241ad522eb427a170e (commit)
       via  388f4fde3655146bf57b4c51c59c39f475aa7fe8 (commit)
      from  dcdfee611ccc0ae798e3eea2cfdf3c7642dc5677 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test


- Log -----------------------------------------------------------------
commit 8e96f2edb003d997e71e9e237463882696279d0f
Merge: 8e919dcb0826a5b25d037ee6144af5f7cb21f3ae dcdfee611ccc0ae798e3eea2cfdf3c7642dc5677
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 6 22:11:00 2008 -0700

    Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test

commit 8e919dcb0826a5b25d037ee6144af5f7cb21f3ae
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 6 22:10:30 2008 -0700

    added server side SMB2 signing

commit 0643b5a2bfc401d8318964241ad522eb427a170e
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 6 10:54:17 2008 -0700

    handle NULL fields in blob comparison

commit 388f4fde3655146bf57b4c51c59c39f475aa7fe8
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 6 10:53:00 2008 -0700

    ensure we don't end up with a partially initialised EA structure

-----------------------------------------------------------------------

Summary of changes:
 source/libcli/raw/raweas.c         |    2 +
 source/libcli/smb2/session.c       |    8 ++-
 source/libcli/smb2/signing.c       |   74 +++++++++---------------------------
 source/libcli/smb2/transport.c     |   32 ++++++++++-----
 source/smb_server/smb2/negprot.c   |   13 ++++++-
 source/smb_server/smb2/receive.c   |   36 +++++++++++++++++
 source/smb_server/smb2/sesssetup.c |    9 ++++
 source/smb_server/smb_server.h     |    2 +
 source/torture/gentest.c           |    4 +-
 9 files changed, 108 insertions(+), 72 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/libcli/raw/raweas.c b/source/libcli/raw/raweas.c
index 07b517a..6317c49 100644
--- a/source/libcli/raw/raweas.c
+++ b/source/libcli/raw/raweas.c
@@ -131,6 +131,8 @@ uint_t ea_pull_struct(const DATA_BLOB *blob,
 	uint8_t nlen;
 	uint16_t vlen;
 
+	ZERO_STRUCTP(ea);
+
 	if (blob->length < 6) {
 		return 0;
 	}
diff --git a/source/libcli/smb2/session.c b/source/libcli/smb2/session.c
index 54915d8..42fd484 100644
--- a/source/libcli/smb2/session.c
+++ b/source/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/source/libcli/smb2/signing.c b/source/libcli/smb2/signing.c
index 16c0ff9..fb2c22d 100644
--- a/source/libcli/smb2/signing.c
+++ b/source/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/source/libcli/smb2/transport.c b/source/libcli/smb2/transport.c
index 561b6e5..a9a9efb 100644
--- a/source/libcli/smb2/transport.c
+++ b/source/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/source/smb_server/smb2/negprot.c b/source/smb_server/smb2/negprot.c
index 4479ae2..2da3900 100644
--- a/source/smb_server/smb2/negprot.c
+++ b/source/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/source/smb_server/smb2/receive.c b/source/smb_server/smb2/receive.c
index dea7c9e..3def8fe 100644
--- a/source/smb_server/smb2/receive.c
+++ b/source/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/source/smb_server/smb2/sesssetup.c b/source/smb_server/smb2/sesssetup.c
index d386bfc..482dd18 100644
--- a/source/smb_server/smb2/sesssetup.c
+++ b/source/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/source/smb_server/smb_server.h b/source/smb_server/smb_server.h
index 776fe1b..ac3e0f3 100644
--- a/source/smb_server/smb_server.h
+++ b/source/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;
diff --git a/source/torture/gentest.c b/source/torture/gentest.c
index 60243a5..15cf321 100644
--- a/source/torture/gentest.c
+++ b/source/torture/gentest.c
@@ -1459,7 +1459,9 @@ again:
 } while(0)
 
 #define CHECK_BLOB_EQUAL(field) do { \
-	if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
+	if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \
+	    (parm[1].field.data == NULL && parm[0].field.data != NULL) || \
+	    (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \
 		current_op.mismatch = #field; \
 		printf("Mismatch in %s\n", #field); \
 		return false; \


-- 
Samba Shared Repository


More information about the samba-cvs mailing list