[SCM] Samba Shared Repository - branch v4-0-test updated

Karolin Seeger kseeger at samba.org
Thu Apr 25 06:40:05 MDT 2013


The branch, v4-0-test has been updated
       via  7e140cf Ensure the RECVFILE path in vfs_pwrite_data() operates on a blocking socket.
       via  05e8a78 Ensure the RECVFILE path in vfs_write_data() operates on a blocking socket.
       via  160a9f3 Ensure drain_socket() operates on a blocking socket.
       via  1758eaa Add the internals of is_smb2_recvfile_write.
       via  cd0da23 The guts of the receivefile code changes.
       via  0d190cf Add stub static function that will turn on/off receivefile code path.
       via  5bd69d5 Add extra fields into struct smbd_smb2_request_read_state to support receivefile.
       via  97fc9b9 Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
       via  1828c74 Add utility function get_min_receive_file_size().
       via  6083839 Allow smbd_smb2_request_error_ex() to cope with unread bytes on error.
       via  8854426 Add function smbd_smb2_unread_bytes().
       via  67839e1 If we already have an smb1req attached to the struct smbd_smb2_request, don't recreate it.
       via  07ab7e6 Ensure we don't do an SMB2 aio write if RECVFILE is active.
       via  d94190f smbd: Fix signing when the async echo handler kicks in
       via  9fe3d7d build: Replace #!/usr/bin/env python with passed in PYTHON=
       via  03ef312 build: Remove extra space in shebang
      from  3f8ea16 docs: Fix bug 9809 -- missing entry in specfile

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


- Log -----------------------------------------------------------------
commit 7e140cf2aa36334991b3f71c7fca6d2b8bca0e67
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 8 10:49:03 2013 -0700

    Ensure the RECVFILE path in vfs_pwrite_data() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Sat Apr 20 01:04:05 CEST 2013 on sn-devel-104
    (cherry picked from commit 95f7fc83b251efefcc2a603b936b55e2f0308a72)
    
    The last 13 patches address bug #9412 - SMB2 server doesn't support recvfile.
    
    Autobuild-User(v4-0-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-0-test): Thu Apr 25 14:39:27 CEST 2013 on sn-devel-104

commit 05e8a7892494502d27e34e142ffb1a9883d8ea49
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 8 10:32:10 2013 -0700

    Ensure the RECVFILE path in vfs_write_data() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 1ed710c2ffc91d8b33b87e572a6075e0126b5826)

commit 160a9f3b5ab5ca4e040bbffc172bfcc6b07c556f
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 8 10:16:48 2013 -0700

    Ensure drain_socket() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 1b46db7b24a4f064706c2c7e712452135a3fed34)

commit 1758eaa1c3d41199077b410691e556ef4f512d34
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 11:16:01 2013 -0700

    Add the internals of is_smb2_recvfile_write.
    
    This turns on the real receivefile detection, and completes
    the receivefile code path changes.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 1a7cec37e725c9f29fd71788e15623d904b41c8a)

commit cd0da2355fb41bbb260a774b05fda841fd297208
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 13:24:07 2013 -0700

    The guts of the receivefile code changes.
    
    If an incoming PDU might qualify, only read
    SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN = (SMB2_HEADER + SMB2_WRITE_BODY_LEN)
    bytes rather than the whole PDU.
    
    Next time we're called, use is_smb2_recvfile_write() to decide if
    this is an SMB2_WRITE that fit the receivefile criteria, otherwise
    just read the rest of the PDU.
    
    If we did do a short receivefile read, set up the smb2_req->smb1req->unread_bytes
    value to show what bytes remain in the TCP buffers.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7)

commit 0d190cfcb247c7d311971777cce00b3b1683d916
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 13:19:01 2013 -0700

    Add stub static function that will turn on/off receivefile code path.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit fdcaf0fa360b9590114605d24af545b1d42b9fd5)

commit 5bd69d5d67111298bf05d24488b472fd21b9653e
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 13:17:09 2013 -0700

    Add extra fields into struct smbd_smb2_request_read_state to support receivefile.
    
    Initialize min_recv_size with the size that will trigger the
    receivefile write path.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 4b91097002d73ae5dd2d4ac225f8e9eecca11e49)

commit 97fc9b9af3f5a2b1af04bdb9c3d71ab3a065a022
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 13:14:13 2013 -0700

    Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
    
    This is the 'short' length we'll read in the SMB2_WRITE receivefile
    code path.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 36d4b9d208c0025f054ad8ae4062ca3c81e345d5)

commit 1828c74c6c85cdba9689012ac991187b5eb2cfa3
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Apr 1 13:12:55 2013 -0700

    Add utility function get_min_receive_file_size().
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 61da7f00b3f3daebb82e6a5d987883e0897dc4e9)

commit 6083839d1c0372cd172d619b82a2862e9d46f81f
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Mar 19 12:36:52 2013 -0700

    Allow smbd_smb2_request_error_ex() to cope with unread bytes on error.
    
    Drain the socket if a RECVFILE write failed.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 63739440f128229a6a99d0653562d3735ae909fb)

commit 8854426ee1a31be34ab8be3f11c43685ede7141a
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Mar 19 12:24:17 2013 -0700

    Add function smbd_smb2_unread_bytes().
    
    Returns number of bytes left to read for recvfile. Will be
    used in SMB_2_WRITE_FILE code path.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit a36d7633bd3608b71f610fc9df2ad9c66bfdd9c6)

commit 67839e1138d8d9a2e4aa69fdd0eb1e0504a1910d
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Mar 19 12:16:32 2013 -0700

    If we already have an smb1req attached to the struct smbd_smb2_request, don't recreate it.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit ec9fc986da8279f15338b7682c629bfdfc36d016)

commit 07ab7e645de69700b2924465eccd5489c78b457a
Author: Jeremy Allison <jra at samba.org>
Date:   Mon Mar 18 12:00:25 2013 -0700

    Ensure we don't do an SMB2 aio write if RECVFILE is active.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan (metze) Metzmacher <metze at samba.org>
    (cherry picked from commit 9791c1a24822d8b46bf7dd231b615d281b58540b)

commit d94190f96a528c98f300a1c7a014284bd81c8b13
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Apr 19 12:36:08 2013 +0200

    smbd: Fix signing when the async echo handler kicks in
    
    This was introduced as a copy&paste error in 5e0258fc932c
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Christian Ambach <ambi at samba.org>
    (cherry picked from commit 5aa9e552ec70ffbd48495e0d7c28517e726487bf)
    
    Fix bug #9824 - SMB signing and the async echo responder don't work together.

commit 9fe3d7dff7a4e531d97ff002b1deac0ac2fbf633
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Apr 8 15:57:45 2013 +1000

    build: Replace #!/usr/bin/env python with passed in PYTHON=
    
    This means that if we were forced to use a specific python for the build, we
    will put that binary into the top of samba-tool, so it continues to work
    after the install.
    
    Andrew Bartlett
    
    Reviewed-by: Michael Adam <obnox at samba.org>
    (cherry picked from commit 58e3c5323e343dcab1c528c6b6a44925b76cb297)
    
    The last 2 patches address bug #9785 - Fixes to use specified python for runtime
    installation of Samba.

commit 03ef3121ae897789c68a216af690e7207d8a32e0
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Apr 8 08:33:55 2013 +1000

    build: Remove extra space in shebang
    
    Reviewed-by: Michael Adam <obnox at samba.org>
    (cherry picked from commit 45a596fbe9ed2b198956d58784999df780f6dd65)

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

Summary of changes:
 buildtools/wafsamba/samba_python.py |   10 +++
 buildtools/wafsamba/wafsamba.py     |   15 ++++-
 source3/lib/recvfile.c              |   17 ++++-
 source3/smbd/aio.c                  |    5 ++
 source3/smbd/globals.h              |    3 +
 source3/smbd/process.c              |    2 +-
 source3/smbd/smb2_glue.c            |   22 +++++-
 source3/smbd/smb2_server.c          |  130 +++++++++++++++++++++++++++++++++--
 source3/smbd/vfs.c                  |   26 +++++++-
 source3/wscript                     |    2 +-
 wscript                             |    7 +--
 11 files changed, 219 insertions(+), 20 deletions(-)


Changeset truncated at 500 lines:

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index b2172f7..847b431 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -5,6 +5,16 @@ from samba_utils import *
 from samba_autoconf import *
 
 from Configure import conf
+
+ at conf
+def SAMBA_CHECK_PYTHON(conf, mandatory=True):
+    # enable tool to build python extensions
+    conf.find_program('python', var='PYTHON', mandatory=mandatory)
+    conf.check_tool('python')
+    path_python = conf.find_program('python')
+    conf.env.PYTHON_SPECIFIED = (conf.env.PYTHON != path_python)
+    conf.check_python_version((2,4,2))
+
 @conf
 def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
     if conf.env["python_headers_checked"] == []:
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index f7156ec..3559cc1 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -696,14 +696,25 @@ def copy_and_fix_python_path(task):
         replacement="""sys.path.insert(0, "%s")
 sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
 
+    shebang = None
+
+    if task.env["PYTHON"][0] == "/":
+        replacement_shebang = "#!%s" % task.env["PYTHON"]
+    else:
+        replacement_shebang = "#!/usr/bin/env %s" % task.env["PYTHON"]
+
     installed_location=task.outputs[0].bldpath(task.env)
     source_file = open(task.inputs[0].srcpath(task.env))
     installed_file = open(installed_location, 'w')
+    lineno = 0
     for line in source_file:
         newline = line
-        if pattern in line:
+        if lineno == 0 and task.env["PYTHON_SPECIFIED"] == True and line[:2] == "#!":
+            newline = replacement_shebang
+        elif pattern in line:
             newline = line.replace(pattern, replacement)
         installed_file.write(newline)
+        lineno = lineno + 1
     installed_file.close()
     os.chmod(installed_location, 0755)
     return 0
@@ -727,6 +738,8 @@ def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
                             target=inst_file)
         bld.add_manual_dependency(bld.path.find_or_declare(inst_file), bld.env["PYTHONARCHDIR"])
         bld.add_manual_dependency(bld.path.find_or_declare(inst_file), bld.env["PYTHONDIR"])
+        bld.add_manual_dependency(bld.path.find_or_declare(inst_file), str(bld.env["PYTHON_SPECIFIED"]))
+        bld.add_manual_dependency(bld.path.find_or_declare(inst_file), bld.env["PYTHON"])
         file = inst_file
     if base_name:
         file = os.path.join(base_name, file)
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index c53ba77..72f4257 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -240,6 +240,7 @@ ssize_t sys_recvfile(int fromfd,
 /*****************************************************************
  Throw away "count" bytes from the client socket.
  Returns count or -1 on error.
+ Must only operate on a blocking socket.
 *****************************************************************/
 
 ssize_t drain_socket(int sockfd, size_t count)
@@ -247,6 +248,7 @@ ssize_t drain_socket(int sockfd, size_t count)
 	size_t total = 0;
 	size_t bufsize = MIN(TRANSFER_BUF_SIZE,count);
 	char *buffer = NULL;
+	int old_flags = 0;
 
 	if (count == 0) {
 		return 0;
@@ -257,6 +259,12 @@ ssize_t drain_socket(int sockfd, size_t count)
 		return -1;
 	}
 
+	old_flags = fcntl(sockfd, F_GETFL, 0);
+	if (set_blocking(sockfd, true) == -1) {
+		free(buffer);
+		return -1;
+	}
+
 	while (total < count) {
 		ssize_t read_ret;
 		size_t toread = MIN(bufsize,count - total);
@@ -265,12 +273,17 @@ ssize_t drain_socket(int sockfd, size_t count)
 		read_ret = sys_read(sockfd, buffer, toread);
 		if (read_ret <= 0) {
 			/* EOF or socket error. */
-			free(buffer);
-			return -1;
+			count = (size_t)-1;
+			goto out;
 		}
 		total += read_ret;
 	}
 
+  out:
+
 	free(buffer);
+	if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+		return -1;
+	}
 	return count;
 }
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 3f553eb..e8be408 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -861,6 +861,11 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
 		return NT_STATUS_RETRY;
 	}
 
+	if (smbreq->unread_bytes) {
+		/* Can't do async with recvfile. */
+		return NT_STATUS_RETRY;
+	}
+
 	if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
 		return NT_STATUS_NO_MEMORY;
 	}
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 51f55bf..16ac24b 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -246,6 +246,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 					 uint32_t defer_time);
 
 struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req);
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req);
 void remove_smb2_chained_fsp(files_struct *fsp);
 
 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
@@ -540,6 +541,8 @@ struct smbd_smb2_request {
 #define SMBD_SMB2_OUT_DYN_PTR(req)   (uint8_t *)(SMBD_SMB2_OUT_DYN_IOV(req)->iov_base)
 #define SMBD_SMB2_OUT_DYN_LEN(req)   (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
 
+#define SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN (SMB2_HDR_BODY + 0x30)
+
 	struct {
 		/*
 		 * vector[0] TRANSPORT HEADER (empty)
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index f03a20f..8add79d 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -2412,7 +2412,7 @@ static void smbd_server_connection_read_handler(
 				    &unread_bytes,
 				    &encrypted,
 				    &inbuf_len, &seqnum,
-				    false /* trusted channel */);
+				    !from_client /* trusted channel */);
 
 	if (from_client) {
 		smbd_unlock_socket(sconn);
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 1b2b4dd..54135b5 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -28,9 +28,13 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
 	struct smb_request *smbreq;
 	const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
 
-	smbreq = talloc_zero(req, struct smb_request);
-	if (smbreq == NULL) {
-		return NULL;
+	if (req->smb1req) {
+		smbreq = req->smb1req;
+	} else {
+		smbreq = talloc_zero(req, struct smb_request);
+		if (smbreq == NULL) {
+			return NULL;
+		}
 	}
 
 	smbreq->request_time = req->request_time;
@@ -55,6 +59,18 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
 }
 
 /*********************************************************
+ Are there unread bytes for recvfile ?
+*********************************************************/
+
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req)
+{
+	if (req->smb1req) {
+		return req->smb1req->unread_bytes;
+	}
+	return 0;
+}
+
+/*********************************************************
  Called from file_free() to remove any chained fsp pointers.
 *********************************************************/
 
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 62d1074..29d4f7c 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2621,11 +2621,21 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
 {
 	DATA_BLOB body;
 	uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
+	size_t unread_bytes = smbd_smb2_unread_bytes(req);
 
 	DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
 		  req->current_idx, nt_errstr(status), info ? " +info" : "",
 		  location));
 
+	if (unread_bytes) {
+		/* Recvfile error. Drain incoming socket. */
+		size_t ret = drain_socket(req->sconn->sock, unread_bytes);
+		if (ret != unread_bytes) {
+			smbd_server_connection_terminate(req->sconn,
+				"Failed to drain SMB2 socket\n");
+		}
+	}
+
 	body.data = outhdr + SMB2_HDR_BODY;
 	body.length = 8;
 	SSVAL(body.data, 0, 9);
@@ -2821,6 +2831,8 @@ struct smbd_smb2_request_read_state {
 		uint8_t nbt[NBT_HDR_SIZE];
 		bool done;
 	} hdr;
+	bool doing_receivefile;
+	size_t min_recv_size;
 	size_t pktlen;
 	uint8_t *pktbuf;
 };
@@ -2832,6 +2844,17 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 					 size_t *_count);
 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
 
+static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
+{
+	if (smb2_req->do_signing) {
+		return 0;
+	}
+	if (smb2_req->do_encryption) {
+		return 0;
+	}
+	return (size_t)lp_min_receive_file_size();
+}
+
 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbd_server_connection *sconn)
@@ -2853,6 +2876,7 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 	state->smb2_req->sconn = sconn;
+	state->min_recv_size = get_min_receive_file_size(state->smb2_req);
 
 	subreq = tstream_readv_pdu_queue_send(state->smb2_req,
 					state->ev,
@@ -2868,6 +2892,47 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
+static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
+{
+	uint32_t flags;
+
+	if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
+		/* Transform header. Cannot recvfile. */
+		return false;
+	}
+	if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
+		/* Not SMB2. Normal error path will cope. */
+		return false;
+	}
+	if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
+		/* Not SMB2. Normal error path will cope. */
+		return false;
+	}
+	if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
+		/* Needs to be a WRITE. */
+		return false;
+	}
+	if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
+		/* Chained. Cannot recvfile. */
+		return false;
+	}
+	flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
+	if (flags & SMB2_HDR_FLAG_CHAINED) {
+		/* Chained. Cannot recvfile. */
+		return false;
+	}
+	if (flags & SMB2_HDR_FLAG_SIGNED) {
+		/* Signed. Cannot recvfile. */
+		return false;
+	}
+
+	DEBUG(10,("Doing recvfile write len = %u\n",
+		(unsigned int)(state->pktlen -
+		SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
+
+	return true;
+}
+
 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 					 void *private_data,
 					 TALLOC_CTX *mem_ctx,
@@ -2877,12 +2942,38 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 	struct smbd_smb2_request_read_state *state =
 		talloc_get_type_abort(private_data,
 		struct smbd_smb2_request_read_state);
-	struct iovec *vector;
+	struct iovec *vector = NULL;
+	size_t min_recvfile_size = UINT32_MAX;
 
 	if (state->pktlen > 0) {
-		/* if there're no remaining bytes, we're done */
-		*_vector = NULL;
-		*_count = 0;
+		if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
+			/*
+			 * Not a possible receivefile write.
+			 * Read the rest of the data.
+			 */
+			state->doing_receivefile = false;
+			vector = talloc_array(mem_ctx, struct iovec, 1);
+			if (vector == NULL) {
+				return -1;
+			}
+			vector[0].iov_base = (void *)(state->pktbuf +
+				SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+			vector[0].iov_len = (state->pktlen -
+				SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+			*_vector = vector;
+			*_count = 1;
+		} else {
+			/*
+			 * Either this is a receivefile write so we've
+			 * done a short read, or if not we have all the data.
+			 * Either way, we're done and
+			 * smbd_smb2_request_read_done() will handle
+			 * and short read case by looking at the
+			 * state->doing_receivefile value.
+			 */
+			*_vector = NULL;
+			*_count = 0;
+		}
 		return 0;
 	}
 
@@ -2928,7 +3019,26 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 	}
 
 	vector[0].iov_base = (void *)state->pktbuf;
-	vector[0].iov_len = state->pktlen;
+
+	if (state->min_recv_size != 0) {
+		min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+		min_recvfile_size += state->min_recv_size;
+	}
+
+	if (state->pktlen > min_recvfile_size) {
+		/*
+		 * Might be a receivefile write. Read the SMB2 HEADER +
+		 * SMB2_WRITE header first. Set 'doing_receivefile'
+		 * as we're *attempting* receivefile write. If this
+		 * turns out not to be a SMB2_WRITE request or otherwise
+		 * not suitable then we'll just read the rest of the data
+		 * the next time this function is called.
+		 */
+		vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+		state->doing_receivefile = true;
+	} else {
+		vector[0].iov_len = state->pktlen;
+	}
 
 	*_vector = vector;
 	*_count = 1;
@@ -2991,6 +3101,16 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
 		return;
 	}
 
+	if (state->doing_receivefile) {
+		state->smb2_req->smb1req = talloc_zero(state->smb2_req,
+						struct smb_request);
+		if (tevent_req_nomem(state->smb2_req->smb1req, req)) {
+			return;
+		}
+		state->smb2_req->smb1req->unread_bytes =
+			state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+	}
+
 	state->smb2_req->current_idx = 1;
 
 	tevent_req_done(req);
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 581a025..124981c 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -428,14 +428,25 @@ ssize_t vfs_write_data(struct smb_request *req,
 	ssize_t ret;
 
 	if (req && req->unread_bytes) {
+		int sockfd = req->sconn->sock;
+		int old_flags;
 		SMB_ASSERT(req->unread_bytes == N);
 		/* VFS_RECVFILE must drain the socket
 		 * before returning. */
 		req->unread_bytes = 0;
-		return SMB_VFS_RECVFILE(req->sconn->sock,
+		/* Ensure the socket is blocking. */
+		old_flags = fcntl(sockfd, F_GETFL, 0);
+		if (set_blocking(sockfd, true) == -1) {
+			return (ssize_t)-1;
+		}
+		ret = SMB_VFS_RECVFILE(sockfd,
 					fsp,
 					(off_t)-1,
 					N);
+		if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+			return (ssize_t)-1;
+		}
+		return ret;
 	}
 
 	while (total < N) {
@@ -461,14 +472,25 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
 	ssize_t ret;
 
 	if (req && req->unread_bytes) {
+		int sockfd = req->sconn->sock;
+		int old_flags;
 		SMB_ASSERT(req->unread_bytes == N);
 		/* VFS_RECVFILE must drain the socket
 		 * before returning. */
 		req->unread_bytes = 0;
-		return SMB_VFS_RECVFILE(req->sconn->sock,
+		/* Ensure the socket is blocking. */
+		old_flags = fcntl(sockfd, F_GETFL, 0);
+		if (set_blocking(sockfd, true) == -1) {
+			return (ssize_t)-1;
+		}
+		ret = SMB_VFS_RECVFILE(sockfd,
 					fsp,
 					offset,
 					N);
+		if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+			return (ssize_t)-1;
+		}
+		return ret;
 	}
 
 	while (total < N) {
diff --git a/source3/wscript b/source3/wscript
index e1672e0..00432c4 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#!/usr/bin/env python
 
 srcdir=".."
 
diff --git a/wscript b/wscript
index c8dcccd..de518ac 100644
--- a/wscript
+++ b/wscript
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#!/usr/bin/env python
 
 srcdir = '.'
 blddir = 'bin'
@@ -82,13 +82,10 @@ def configure(conf):
 
     conf.RECURSE('lib/replace')
 
-    conf.find_program('python', var='PYTHON', mandatory=True)
     conf.find_program('perl', var='PERL', mandatory=True)
     conf.find_program('xsltproc', var='XSLTPROC')
 
-    # enable tool to build python extensions
-    conf.check_tool('python')
-    conf.check_python_version((2,4,2))
+    conf.SAMBA_CHECK_PYTHON(mandatory=True)
     conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=True)
 
     if sys.platform == 'darwin' and not conf.env['HAVE_ENVIRON_DECL']:


-- 
Samba Shared Repository


More information about the samba-cvs mailing list