[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-1719-g4abd5f3

Stefan Metzmacher metze at samba.org
Wed May 20 13:43:38 GMT 2009


The branch, master has been updated
       via  4abd5f34d97d759afd92ca854d9fffb382a4f999 (commit)
       via  d7d73b08e993f6ca5948c3bbe653352573c6f43d (commit)
       via  3ef6a5ae9ebefb18755337a83ba5488e8b8edd6e (commit)
       via  c14dd15c6a802729f46857630b1df83987d9a11c (commit)
       via  688945a994660fa905836b55a995bb90c3e8e67a (commit)
       via  d23a1935e8180090474cbbba878d5bc5903579c6 (commit)
      from  d59f84d738401f3ab8ec34aa053af05670a58a89 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 4abd5f34d97d759afd92ca854d9fffb382a4f999
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri May 15 12:07:28 2009 +0200

    s3:smbd: add support for SMB2 Keepalive (SMB2 Echo)
    
    metze

commit d7d73b08e993f6ca5948c3bbe653352573c6f43d
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue May 19 10:47:51 2009 +0200

    s3:smbd: allow SMB 2.002 dialect in SMB1 negprot
    
    We create a dummy SMB2 Negotiate inbuf and pass the
    connection to the SMB2 engine.
    
    metze

commit 3ef6a5ae9ebefb18755337a83ba5488e8b8edd6e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu May 14 15:32:02 2009 +0200

    s3:smbd: add support for SMB2 Negotiate
    
    This is not complete, but a start that makes the
    samba4 smb2 client happy.
    
    metze

commit c14dd15c6a802729f46857630b1df83987d9a11c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue May 19 10:46:35 2009 +0200

    s3:smbd: make negprot_spnego() non static
    
    metze

commit 688945a994660fa905836b55a995bb90c3e8e67a
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu May 14 14:17:28 2009 +0200

    s3:smbd: add infrastructure for SMB2 support
    
    This is disabled by default and activated by
    "max protocol = SMB2".
    
    metze

commit d23a1935e8180090474cbbba878d5bc5903579c6
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue May 19 10:45:38 2009 +0200

    s3:param: add PROTOCOL_SMB2
    
    metze

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

Summary of changes:
 source3/Makefile.in           |    2 +
 source3/include/smb.h         |   10 +-
 source3/param/loadparm.c      |    1 +
 source3/smbd/globals.h        |   82 ++++
 source3/smbd/negprot.c        |    3 +-
 source3/smbd/process.c        |   12 +
 source3/smbd/smb2_keepalive.c |   55 +++
 source3/smbd/smb2_negprot.c   |  163 +++++++
 source3/smbd/smb2_server.c    |  999 +++++++++++++++++++++++++++++++++++++++++
 9 files changed, 1325 insertions(+), 2 deletions(-)
 create mode 100644 source3/smbd/smb2_keepalive.c
 create mode 100644 source3/smbd/smb2_negprot.c
 create mode 100644 source3/smbd/smb2_server.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 31ef29a..f5074e3 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -748,6 +748,8 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
 	       smbd/dmapi.o smbd/signing.o \
 	       smbd/file_access.o \
 	       smbd/dnsregister.o smbd/globals.o \
+	       smbd/smb2_server.o smbd/smb2_negprot.o \
+	       smbd/smb2_keepalive.o \
 	       $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
diff --git a/source3/include/smb.h b/source3/include/smb.h
index fed7468..abcd494 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1518,7 +1518,15 @@ char *strdup(char *s);
 
 /* protocol types. It assumes that higher protocols include lower protocols
    as subsets */
-enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1};
+enum protocol_types {
+	PROTOCOL_NONE,
+	PROTOCOL_CORE,
+	PROTOCOL_COREPLUS,
+	PROTOCOL_LANMAN1,
+	PROTOCOL_LANMAN2,
+	PROTOCOL_NT1,
+	PROTOCOL_SMB2
+};
 
 /* security levels */
 enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER,SEC_DOMAIN,SEC_ADS};
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index da3da63..6da792a 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -685,6 +685,7 @@ static void *lp_local_ptr(struct service *service, void *ptr);
 static void add_to_file_list(const char *fname, const char *subfname);
 
 static const struct enum_list enum_protocol[] = {
+	{PROTOCOL_SMB2, "SMB2"},
 	{PROTOCOL_NT1, "NT1"},
 	{PROTOCOL_LANMAN2, "LANMAN2"},
 	{PROTOCOL_LANMAN1, "LANMAN1"},
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index b646bc3..c5dd97c 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -199,11 +199,93 @@ struct child_pid;
 extern struct child_pid *children;
 extern int num_children;
 
+struct tstream_context;
+struct smbd_smb2_request;
+
+DATA_BLOB negprot_spnego(void);
+
+bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size);
+
+void reply_smb2002(struct smb_request *req, uint16_t choice);
+void smbd_smb2_first_negprot(struct smbd_server_connection *conn,
+			     const uint8_t *inbuf, size_t size);
+
+NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
+				    NTSTATUS status, DATA_BLOB *info);
+NTSTATUS smbd_smb2_request_error(struct smbd_smb2_request *req,
+				 NTSTATUS status);
+NTSTATUS smbd_smb2_request_done(struct smbd_smb2_request *req,
+				DATA_BLOB body, DATA_BLOB *dyn);
+
+NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req);
+NTSTATUS smbd_smb2_request_process_keepalive(struct smbd_smb2_request *req);
+
+struct smbd_smb2_request {
+	TALLOC_CTX *mem_pool;
+
+	struct smbd_server_connection *conn;
+
+	int current_idx;
+
+	struct {
+		/* the NBT header is not allocated */
+		uint8_t nbt_hdr[4];
+		/*
+		 * vector[0] NBT
+		 * .
+		 * vector[1] SMB2
+		 * vector[2] fixed body
+		 * vector[3] dynamic body
+		 * .
+		 * .
+		 * .
+		 * vector[4] SMB2
+		 * vector[5] fixed body
+		 * vector[6] dynamic body
+		 * .
+		 * .
+		 * .
+		 */
+		struct iovec *vector;
+		int vector_count;
+	} in;
+	struct {
+		/* the NBT header is not allocated */
+		uint8_t nbt_hdr[4];
+		/*
+		 * vector[0] NBT
+		 * .
+		 * vector[1] SMB2
+		 * vector[2] fixed body
+		 * vector[3] dynamic body
+		 * .
+		 * .
+		 * .
+		 * vector[4] SMB2
+		 * vector[5] fixed body
+		 * vector[6] dynamic body
+		 * .
+		 * .
+		 * .
+		 */
+		struct iovec *vector;
+		int vector_count;
+	} out;
+};
+
 struct smbd_server_connection {
 	struct fd_event *fde;
 	uint64_t num_requests;
 	struct smb_signing_state *signing_state;
+	bool allow_smb2;
+	struct {
+		struct tevent_context *event_ctx;
+		struct tevent_queue *recv_queue;
+		struct tevent_queue *send_queue;
+		struct tstream_context *stream;
+	} smb2;
 };
+
 extern struct smbd_server_connection *smbd_server_conn;
 
 void smbd_init_globals(void);
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index e548c58..6d15f48 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -166,7 +166,7 @@ static void reply_lanman2(struct smb_request *req, uint16 choice)
  Generate the spnego negprot reply blob. Return the number of bytes used.
 ****************************************************************************/
 
-static DATA_BLOB negprot_spnego(void)
+DATA_BLOB negprot_spnego(void)
 {
 	DATA_BLOB blob;
 	nstring dos_name;
@@ -481,6 +481,7 @@ static const struct {
 	void (*proto_reply_fn)(struct smb_request *req, uint16 choice);
 	int protocol_level;
 } supported_protocols[] = {
+	{"SMB 2.002",               "SMB2",     reply_smb2002,  PROTOCOL_SMB2},
 	{"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
 	{"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
 	{"POSIX 2",                 "NT1",      reply_nt1,      PROTOCOL_NT1},
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 0647b99..5cad8bf 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -1448,6 +1448,14 @@ static void process_smb(struct smbd_server_connection *conn,
 		goto done;
 	}
 
+	if (smbd_server_conn->allow_smb2) {
+		if (smbd_is_smb2_header(inbuf, nread)) {
+			smbd_smb2_first_negprot(smbd_server_conn, inbuf, nread);
+			return;
+		}
+		smbd_server_conn->allow_smb2 = false;
+	}
+
 	show_msg((char *)inbuf);
 
 	construct_reply((char *)inbuf,nread,unread_bytes,seqnum,encrypted,deferred_pcd);
@@ -2009,6 +2017,10 @@ void smbd_process(void)
 		exit_server("failed to create smbd_server_connection");
 	}
 
+	if (lp_maxprotocol() == PROTOCOL_SMB2) {
+		smbd_server_conn->allow_smb2 = true;
+	}
+
 	/* Ensure child is set to blocking mode */
 	set_blocking(smbd_server_fd(),True);
 
diff --git a/source3/smbd/smb2_keepalive.c b/source3/smbd/smb2_keepalive.c
new file mode 100644
index 0000000..0028fd3
--- /dev/null
+++ b/source3/smbd/smb2_keepalive.c
@@ -0,0 +1,55 @@
+/*
+   Unix SMB/CIFS implementation.
+   Core SMB2 server
+
+   Copyright (C) Stefan Metzmacher 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/globals.h"
+#include "../source4/libcli/smb2/smb2_constants.h"
+
+NTSTATUS smbd_smb2_request_process_keepalive(struct smbd_smb2_request *req)
+{
+	const uint8_t *inbody;
+	int i = req->current_idx;
+	DATA_BLOB outbody;
+	size_t expected_body_size = 0x04;
+	size_t body_size;
+
+	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
+
+	body_size = SVAL(inbody, 0x00);
+	if (body_size != expected_body_size) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	/* TODO: update some time stamps */
+
+	outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
+	if (outbody.data == NULL) {
+		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
+	}
+
+	SSVAL(outbody.data, 0x00, 0x04);	/* struct size */
+	SSVAL(outbody.data, 0x02, 0);		/* reserved */
+
+	return smbd_smb2_request_done(req, outbody, NULL);
+}
diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
new file mode 100644
index 0000000..38dfe6d
--- /dev/null
+++ b/source3/smbd/smb2_negprot.c
@@ -0,0 +1,163 @@
+/*
+   Unix SMB/CIFS implementation.
+   Core SMB2 server
+
+   Copyright (C) Stefan Metzmacher 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/globals.h"
+#include "../source4/libcli/smb2/smb2_constants.h"
+
+extern enum protocol_types Protocol;
+
+/*
+ * this is the entry point if SMB2 is selected via
+ * the SMB negprot
+ */
+void reply_smb2002(struct smb_request *req, uint16_t choice)
+{
+	uint8_t *smb2_inbuf;
+	uint8_t *smb2_hdr;
+	uint8_t *smb2_body;
+	uint8_t *smb2_dyn;
+	size_t len = 4 + SMB2_HDR_BODY + 0x24 + 2;
+
+	smb2_inbuf = talloc_zero_array(talloc_tos(), uint8_t, len);
+	if (smb2_inbuf == NULL) {
+		DEBUG(0, ("Could not push spnego blob\n"));
+		reply_nterror(req, NT_STATUS_NO_MEMORY);
+		return;
+	}
+	smb2_hdr = smb2_inbuf + 4;
+	smb2_body = smb2_hdr + SMB2_HDR_BODY;
+	smb2_dyn = smb2_body + 0x24;
+
+	SIVAL(smb2_hdr, SMB2_HDR_PROTOCOL_ID,	SMB2_MAGIC);
+	SIVAL(smb2_hdr, SMB2_HDR_LENGTH,	SMB2_HDR_BODY);
+
+	SSVAL(smb2_body, 0x00, 0x0024);	/* struct size */
+	SSVAL(smb2_body, 0x02, 0x0001);	/* dialect count */
+
+	SSVAL(smb2_dyn,  0x00, 0x0202);	/* dialect 2.002 */
+
+	req->outbuf = NULL;
+
+	smbd_smb2_first_negprot(smbd_server_conn, smb2_inbuf, len);
+	return;
+}
+
+NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
+{
+	const uint8_t *inbody;
+	const uint8_t *indyn = NULL;
+	int i = req->current_idx;
+	DATA_BLOB outbody;
+	DATA_BLOB outdyn;
+	DATA_BLOB negprot_spnego_blob;
+	uint16_t security_offset;
+	DATA_BLOB security_buffer;
+	size_t expected_body_size = 0x24;
+	size_t body_size;
+	size_t expected_dyn_size = 0;
+	size_t c;
+	uint16_t dialect_count;
+	uint16_t dialect;
+
+/* TODO: drop the connection with INVALI_PARAMETER */
+
+	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
+
+	body_size = SVAL(inbody, 0x00);
+	if (body_size != expected_body_size) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	dialect_count = SVAL(inbody, 0x02);
+	if (dialect_count == 0) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	expected_dyn_size = dialect_count * 2;
+	if (req->in.vector[i+2].iov_len < expected_dyn_size) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+	indyn = (const uint8_t *)req->in.vector[i+2].iov_base;
+
+	for (c=0; c < dialect_count; c++) {
+		dialect = SVAL(indyn, c*2);
+		if (dialect == 0x0202) {
+			break;
+		}
+	}
+
+	if (dialect != 0x0202) {
+		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+	}
+
+	Protocol = PROTOCOL_SMB2;
+
+	if (get_remote_arch() != RA_SAMBA) {
+		set_remote_arch(RA_VISTA);
+	}
+
+	/* negprot_spnego() returns a the server guid in the first 16 bytes */
+	negprot_spnego_blob = negprot_spnego();
+	if (negprot_spnego_blob.data == NULL) {
+		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
+	}
+	talloc_steal(req, negprot_spnego_blob.data);
+
+	if (negprot_spnego_blob.length < 16) {
+		return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
+	}
+
+	security_offset = SMB2_HDR_BODY + 0x40;
+	security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
+					  negprot_spnego_blob.length - 16);
+
+	outbody = data_blob_talloc(req->out.vector, NULL, 0x40);
+	if (outbody.data == NULL) {
+		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
+	}
+
+	SSVAL(outbody.data, 0x00, 0x40 + 1);	/* struct size */
+/*TODO: indicate signing enabled */
+	SSVAL(outbody.data, 0x02, 0);		/* security mode */
+	SSVAL(outbody.data, 0x04, dialect);	/* dialect revision */
+	SSVAL(outbody.data, 0x06, 0);		/* reserved */
+	memcpy(outbody.data + 0x08,
+	       negprot_spnego_blob.data, 16);	/* server guid */
+	SIVAL(outbody.data, 0x18, 0);		/* capabilities */
+	SIVAL(outbody.data, 0x1C, 0x00010000);	/* max transact size */
+	SIVAL(outbody.data, 0x20, 0x00010000);	/* max read size */
+	SIVAL(outbody.data, 0x24, 0x00010000);	/* max write size */
+	SBVAL(outbody.data, 0x28, 0);		/* system time */
+	SBVAL(outbody.data, 0x30, 0);		/* server start time */
+	SSVAL(outbody.data, 0x38,
+	      security_offset);			/* security buffer offset */
+	SSVAL(outbody.data, 0x3A,
+	      security_buffer.length);		/* security buffer length */
+	SIVAL(outbody.data, 0x3C, 0);		/* reserved */
+
+	outdyn = security_buffer;
+
+	return smbd_smb2_request_done(req, outbody, &outdyn);
+}
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
new file mode 100644
index 0000000..9be6a73
--- /dev/null
+++ b/source3/smbd/smb2_server.c
@@ -0,0 +1,999 @@
+/*
+   Unix SMB/CIFS implementation.
+   Core SMB2 server
+
+   Copyright (C) Stefan Metzmacher 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/globals.h"
+#include "../source4/libcli/smb2/smb2_constants.h"
+#include "../lib/tsocket/tsocket.h"
+
+bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
+{
+	if (size < (4 + SMB2_HDR_BODY)) {
+		return false;
+	}
+
+	if (IVAL(inbuf, 4) != SMB2_MAGIC) {
+		return false;
+	}
+
+	return true;
+}
+
+static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *conn)
+{
+	NTSTATUS status;
+	int ret;
+
+	TALLOC_FREE(conn->fde);
+
+	conn->smb2.event_ctx = smbd_event_context();
+
+	conn->smb2.recv_queue = tevent_queue_create(conn, "smb2 recv queue");
+	if (conn->smb2.recv_queue == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	conn->smb2.send_queue = tevent_queue_create(conn, "smb2 send queue");
+	if (conn->smb2.send_queue == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	ret = tstream_bsd_existing_socket(conn, smbd_server_fd(),
+					  &conn->smb2.stream);
+	if (ret == -1) {
+		status = map_nt_error_from_unix(errno);
+		return status;
+	}
+
+	/* Ensure child is set to non-blocking mode */
+	set_blocking(smbd_server_fd(),false);
+	return NT_STATUS_OK;
+}
+


-- 
Samba Shared Repository


More information about the samba-cvs mailing list