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

Stefan Metzmacher metze at samba.org
Fri Mar 9 00:48:02 UTC 2018


The branch, v4-6-test has been updated
       via  ae55cfe s3:smbd: Do not crash if we fail to init the session table
       via  8fe0589 libsmb: Use smb2 tcon if conn_protocol >= SMB2_02
       via  3dadbb3 torture: Add test for channel sequence number handling
       via  597aba1 smbXcli: Add "force_channel_sequence"
       via  082c08e smbd: Fix channel sequence number checks for long-running requests
       via  c3bce29 smbd: Remove a "!" from an if-condition for easier readability
       via  65992c6 torture4: Fix typos
       via  dc5dbc6 smbd: Fix a typo
       via  b726719 s3:smb2_server: allow logoff, close, unlock, cancel and echo on expired sessions
       via  7118165 s3:smbd: return the correct error for cancelled SMB2 notifies on expired sessions
       via  f0e7a7c s4:torture: add smb2.session.expire2 test
      from  d0c6802 Revert "HEIMDAL:kdc: fix memory leak when decryption AuthorizationData"

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-6-test


- Log -----------------------------------------------------------------
commit ae55cfefd7cf6445fa61ee7f7c66d41edb9379f3
Author: Andreas Schneider <asn at samba.org>
Date:   Mon Feb 19 18:07:50 2018 +0100

    s3:smbd: Do not crash if we fail to init the session table
    
    This should the following segfault with SMB1:
    
      #6  sig_fault (sig=<optimized out>) at ../lib/util/fault.c:94
      #7  <signal handler called>
      #8  smbXsrv_session_create (conn=conn at entry=0x5654d3512af0, now=now at entry=131594481900356690, _session=_session at entry=0x7ffc93a778e8)
          at ../source3/smbd/smbXsrv_session.c:1212
      #9  0x00007f7618aa21ef in reply_sesssetup_and_X (req=req at entry=0x5654d35174b0) at ../source3/smbd/sesssetup.c:961
      #10 0x00007f7618ae17b0 in switch_message (type=<optimized out>, req=req at entry=0x5654d35174b0) at ../source3/smbd/process.c:1726
      #11 0x00007f7618ae3550 in construct_reply (deferred_pcd=0x0, encrypted=false, seqnum=0, unread_bytes=0, size=140, inbuf=0x0, xconn=0x5654d35146d0)
          at ../source3/smbd/process.c:1762
      #12 process_smb (xconn=xconn at entry=0x5654d3512af0, inbuf=<optimized out>, nread=140, unread_bytes=0, seqnum=0, encrypted=<optimized out>,
          deferred_pcd=deferred_pcd at entry=0x0) at ../source3/smbd/process.c:2008
      #13 0x00007f7618ae4c41 in smbd_server_connection_read_handler (xconn=0x5654d3512af0, fd=40) at ../source3/smbd/process.c:2608
      #14 0x00007f761587eedb in epoll_event_loop_once () from /lib64/libtevent.so.0
    
    Inspection the core shows that:
      conn->client-session_table is NULL
      conn->protocol is PROTOCOL_NONE
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13315
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit a89a7146563f2d9eb8bc02f1c090158ee499c878)
    
    Autobuild-User(v4-6-test): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(v4-6-test): Fri Mar  9 01:47:40 CET 2018 on sn-devel-144

commit 8fe0589cb1f8ac33aed689fe6507f4527412660b
Author: Dan Robertson <drobertson at tripwire.com>
Date:   Thu Feb 22 20:47:11 2018 +0000

    libsmb: Use smb2 tcon if conn_protocol >= SMB2_02
    
    When the connection protocol is SMB2 the tid from the smb1 member is
    used instead of smb2 in cli_state_set_tid which often results in a null
    deref.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13310
    
    Signed-off-by: Dan Robertson <drobertson at tripwire.com>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    (cherry picked from commit b67ffaf518c971817b167b41bf6226cddfdcfd2f)

commit 3dadbb3556eec40bb568ca2298b5f1553d2b509b
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Jan 11 11:55:39 2018 +0100

    torture: Add test for channel sequence number handling
    
    We run into an assert when the csn wraps
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=13215
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Sun Jan 14 14:47:15 CET 2018 on sn-devel-144
    
    (cherry picked from commit 0abe16a5343de9a69bb5cccbad9809b28b642f45)

commit 597aba166c3e088411581599c5d5b860611fc1e2
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Jan 11 11:25:49 2018 +0100

    smbXcli: Add "force_channel_sequence"
    
    This enables use of the channel sequence number even for
    non-multi-channel servers. This makes our client invalid, but we need to
    protect against broken clients with tests.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=13215
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit cd288a08500b1cc38ef26e5cb8ef754b4da658b6)

commit 082c08efb4dc9aad0f3a5223c7fbbc853105104f
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Jan 11 15:34:45 2018 +0100

    smbd: Fix channel sequence number checks for long-running requests
    
    When the client's supplied csn overflows and hits a pending, long-running
    request's csn, we panic. Fix this by counting the overflows in
    smbXsrv_open_global0->channel_generation
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=13215
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 0b57434151a8334a6e9b9b7542824ce4915421a2)

commit c3bce29f1e465c86cc37229f74202428d8178986
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Jan 10 14:59:08 2018 +0100

    smbd: Remove a "!" from an if-condition for easier readability
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=13215
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 03f65a7cdc91091a171269cfebc9916f2f678388)

commit 65992c6b4a452a3f235d28a7ea1739acc9f6740e
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Jan 10 15:51:56 2018 +0100

    torture4: Fix typos
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 71cee27962cba53da3249bd3f5ece32a1d10071d)

commit dc5dbc6acd11edc3ca96ae683e38d6c61318549f
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Jan 10 14:29:01 2018 +0100

    smbd: Fix a typo
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit e8636e7ab75f89e89ef054b5d4aa6c07fddcbe2a)

commit b7267199ddd79f79360769cd732a9079a7ce09bd
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Dec 20 14:05:54 2017 +0100

    s3:smb2_server: allow logoff, close, unlock, cancel and echo on expired sessions
    
    Windows client at least doesn't have code to replay
    a SMB2 Close after getting NETWORK_SESSION_EXPIRED,
    which locks out a the client and generates an endless
    loop around NT_STATUS_SHARING_VIOLATION.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13197
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 7118165d6338c926ac1a2b958bde221a205b5ca5
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 21 14:47:06 2017 +0100

    s3:smbd: return the correct error for cancelled SMB2 notifies on expired sessions
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13197
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit f0e7a7c96b06ee56b734640cbb59d4a741dd6e0b
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 21 12:53:02 2017 +0100

    s4:torture: add smb2.session.expire2 test
    
    This demonstrates the interaction of NT_STATUS_NETWORK_SESSION_EXPIRED
    and various SMB2 opcodes.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13197
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

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

Summary of changes:
 libcli/smb/smbXcli_base.c       |  15 +-
 libcli/smb/smbXcli_base.h       |   4 +
 source3/librpc/idl/smbXsrv.idl  |   3 +-
 source3/libsmb/clientgen.c      |   2 +-
 source3/smbd/globals.h          |   1 +
 source3/smbd/negprot.c          |  23 ++-
 source3/smbd/notify.c           |  17 +-
 source3/smbd/smb2_lock.c        |  17 ++
 source3/smbd/smb2_server.c      |  46 ++++-
 source4/libcli/smb2/keepalive.c |   7 +-
 source4/torture/smb2/replay.c   | 117 +++++++++++--
 source4/torture/smb2/session.c  | 362 ++++++++++++++++++++++++++++++++++++++++
 12 files changed, 585 insertions(+), 29 deletions(-)


Changeset truncated at 500 lines:

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 239e5eb..d1e532d 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -138,6 +138,8 @@ struct smbXcli_conn {
 
 		uint8_t io_priority;
 
+		bool force_channel_sequence;
+
 		uint8_t preauth_sha512[64];
 	} smb2;
 
@@ -532,6 +534,17 @@ const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn)
 	return &conn->smb1.server.guid;
 }
 
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn)
+{
+	return conn->smb2.force_channel_sequence;
+}
+
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+					     bool v)
+{
+	conn->smb2.force_channel_sequence = v;
+}
+
 struct smbXcli_conn_samba_suicide_state {
 	struct smbXcli_conn *conn;
 	struct iovec iov;
@@ -2896,7 +2909,7 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
 	uint32_t flags = 0;
 	uint32_t tid = 0;
 	uint64_t uid = 0;
-	bool use_channel_sequence = false;
+	bool use_channel_sequence = conn->smb2.force_channel_sequence;
 	uint16_t channel_sequence = 0;
 	bool use_replay_flag = false;
 
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index 2594f07..336b1cb 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -58,6 +58,10 @@ uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn);
 NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn);
 const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn);
 const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn);
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn);
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+					     bool v);
+
 
 struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
 						   struct tevent_context *ev,
diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl
index 1bfa51e..d3f8d30 100644
--- a/source3/librpc/idl/smbXsrv.idl
+++ b/source3/librpc/idl/smbXsrv.idl
@@ -430,7 +430,8 @@ interface smbXsrv
 		uint32					durable_timeout_msec;
 		boolean8				durable;
 		DATA_BLOB				backend_cookie;
-		hyper					channel_sequence;
+		uint16					channel_sequence;
+		hyper					channel_generation;
 	} smbXsrv_open_global0;
 
 	typedef union {
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index e675f95..305f567 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -384,7 +384,7 @@ uint32_t cli_state_set_tid(struct cli_state *cli, uint32_t tid)
 	uint32_t ret;
 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
 		ret = smb2cli_tcon_current_id(cli->smb2.tcon);
-		smb2cli_tcon_set_id(cli->smb1.tcon, tid);
+		smb2cli_tcon_set_id(cli->smb2.tcon, tid);
 	} else {
 		ret = smb1cli_tcon_current_id(cli->smb1.tcon);
 		smb1cli_tcon_set_id(cli->smb1.tcon, tid);
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index d3b9800..efcf3e9 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -733,6 +733,7 @@ struct smbd_smb2_request {
 	 * adapted again in reply.
 	 */
 	bool request_counters_updated;
+	uint64_t channel_generation;
 
 	/*
 	 * The sub request for async backend calls.
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 838ff45..96199d3 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -65,6 +65,8 @@ static void reply_lanman1(struct smb_request *req, uint16_t choice)
 	time_t t = time(NULL);
 	struct smbXsrv_connection *xconn = req->xconn;
 	uint16_t raw;
+	NTSTATUS status;
+
 	if (lp_async_smb_echo_handler()) {
 		raw = 0;
 	} else {
@@ -88,7 +90,11 @@ static void reply_lanman1(struct smb_request *req, uint16_t choice)
 		SSVAL(req->outbuf,smb_vwv11, 8);
 	}
 
-	smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN1);
+	status = smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN1);
+	if (!NT_STATUS_IS_OK(status)) {
+		reply_nterror(req, status);
+		return;
+	}
 
 	/* Reply, SMBlockread, SMBwritelock supported. */
 	SCVAL(req->outbuf,smb_flg, FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
@@ -115,6 +121,8 @@ static void reply_lanman2(struct smb_request *req, uint16_t choice)
 	time_t t = time(NULL);
 	struct smbXsrv_connection *xconn = req->xconn;
 	uint16_t raw;
+	NTSTATUS status;
+
 	if (lp_async_smb_echo_handler()) {
 		raw = 0;
 	} else {
@@ -140,7 +148,11 @@ static void reply_lanman2(struct smb_request *req, uint16_t choice)
 		SSVAL(req->outbuf,smb_vwv11, 8);
 	}
 
-	smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN2);
+	status = smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN2);
+	if (!NT_STATUS_IS_OK(status)) {
+		reply_nterror(req, status);
+		return;
+	}
 
 	/* Reply, SMBlockread, SMBwritelock supported. */
 	SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
@@ -251,6 +263,7 @@ static void reply_nt1(struct smb_request *req, uint16_t choice)
 	struct smbXsrv_connection *xconn = req->xconn;
 	bool signing_desired = false;
 	bool signing_required = false;
+	NTSTATUS status;
 
 	xconn->smb1.negprot.encrypted_passwords = lp_encrypt_passwords();
 
@@ -328,7 +341,11 @@ static void reply_nt1(struct smb_request *req, uint16_t choice)
 	SSVAL(req->outbuf,smb_vwv0,choice);
 	SCVAL(req->outbuf,smb_vwv1,secword);
 
-	smbXsrv_connection_init_tables(xconn, PROTOCOL_NT1);
+	status = smbXsrv_connection_init_tables(xconn, PROTOCOL_NT1);
+	if (!NT_STATUS_IS_OK(status)) {
+		reply_nterror(req, status);
+		return;
+	}
 
 	SSVAL(req->outbuf,smb_vwv1+1, lp_max_mux()); /* maxmpx */
 	SSVAL(req->outbuf,smb_vwv2+1, 1); /* num vcs */
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index f64185d..add5908 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -391,12 +391,21 @@ static void smbd_notify_cancel_by_map(struct notify_mid_map *map)
 	NTSTATUS notify_status = NT_STATUS_CANCELLED;
 
 	if (smb2req != NULL) {
+		NTSTATUS sstatus;
+
 		if (smb2req->session == NULL) {
-			notify_status = STATUS_NOTIFY_CLEANUP;
-		} else if (!NT_STATUS_IS_OK(smb2req->session->status)) {
-			notify_status = STATUS_NOTIFY_CLEANUP;
+			sstatus = NT_STATUS_USER_SESSION_DELETED;
+		} else {
+			sstatus = smb2req->session->status;
 		}
-		if (smb2req->tcon == NULL) {
+
+		if (NT_STATUS_EQUAL(sstatus, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+			sstatus = NT_STATUS_OK;
+		}
+
+		if (!NT_STATUS_IS_OK(sstatus)) {
+			notify_status = STATUS_NOTIFY_CLEANUP;
+		} else if (smb2req->tcon == NULL) {
 			notify_status = STATUS_NOTIFY_CLEANUP;
 		} else if (!NT_STATUS_IS_OK(smb2req->tcon->status)) {
 			notify_status = STATUS_NOTIFY_CLEANUP;
diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c
index 2fcd359..45b833c 100644
--- a/source3/smbd/smb2_lock.c
+++ b/source3/smbd/smb2_lock.c
@@ -98,6 +98,23 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req)
 	in_locks[l].flags	= IVAL(lock_buffer, 0x10);
 	/* 0x14 - 4 reserved bytes */
 
+	status = req->session->status;
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+		/*
+		 * We need to catch NT_STATUS_NETWORK_SESSION_EXPIRED
+		 * for lock requests only.
+		 *
+		 * Unlock requests still need to be processed!
+		 *
+		 * This means smbd_smb2_request_check_session()
+		 * can't handle the difference and always
+		 * allows SMB2_OP_LOCK.
+		 */
+		if (in_locks[0].flags != SMB2_LOCK_FLAG_UNLOCK) {
+			return smbd_smb2_request_error(req, status);
+		}
+	}
+
 	lock_buffer = SMBD_SMB2_IN_DYN_PTR(req);
 
 	for (l=1; l < in_lock_count; l++) {
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index e6bc753..573f5f6 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -1885,6 +1885,25 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
 		case SMB2_OP_SESSSETUP:
 			status = NT_STATUS_OK;
 			break;
+		case SMB2_OP_LOGOFF:
+		case SMB2_OP_CLOSE:
+		case SMB2_OP_LOCK:
+		case SMB2_OP_CANCEL:
+		case SMB2_OP_KEEPALIVE:
+			/*
+			 * [MS-SMB2] 3.3.5.2.9 Verifying the Session
+			 * specifies that LOGOFF, CLOSE and (UN)LOCK
+			 * should always be processed even on expired sessions.
+			 *
+			 * Also see the logic in
+			 * smbd_smb2_request_process_lock().
+			 *
+			 * The smb2.session.expire2 test shows that
+			 * CANCEL and KEEPALIVE/ECHO should also
+			 * be processed.
+			 */
+			status = NT_STATUS_OK;
+			break;
 		default:
 			break;
 		}
@@ -2122,6 +2141,7 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
 	struct smbXsrv_connection *xconn = req->xconn;
 	const uint8_t *inhdr;
 	uint16_t channel_sequence;
+	uint8_t generation_wrap = 0;
 	uint32_t flags;
 	int cmp;
 	struct smbXsrv_open *op;
@@ -2148,6 +2168,14 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
 	channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE);
 
 	cmp = channel_sequence - op->global->channel_sequence;
+	if (cmp < 0) {
+		/*
+		 * csn wrap. We need to watch out for long-running
+		 * requests that are still sitting on a previously
+		 * used csn. SMB2_OP_NOTIFY can take VERY long.
+		 */
+		generation_wrap += 1;
+	}
 
 	if (abs(cmp) > INT16_MAX) {
 		/*
@@ -2184,7 +2212,7 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
 		 * a 16 bit overflow of the client-submitted sequence
 		 * number:
 		 *
-		 * If the stored channel squence number is more than
+		 * If the stored channel sequence number is more than
 		 * 0x7FFF larger than the one from the request, then
 		 * the client-provided sequence number has likely
 		 * overflown. We treat this case as valid instead
@@ -2195,33 +2223,36 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
 		cmp *= -1;
 	}
 
-	if (!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION)) {
-		if (cmp == 0) {
+	if (flags & SMB2_HDR_FLAG_REPLAY_OPERATION) {
+		if (cmp == 0 && op->pre_request_count == 0) {
 			op->request_count += 1;
 			req->request_counters_updated = true;
-		} else if (cmp > 0) {
+		} else if (cmp > 0 && op->pre_request_count == 0) {
 			op->pre_request_count += op->request_count;
 			op->request_count = 1;
 			op->global->channel_sequence = channel_sequence;
+			op->global->channel_generation += generation_wrap;
 			update_open = true;
 			req->request_counters_updated = true;
 		} else if (modify_call) {
 			return NT_STATUS_FILE_NOT_AVAILABLE;
 		}
 	} else {
-		if (cmp == 0 && op->pre_request_count == 0) {
+		if (cmp == 0) {
 			op->request_count += 1;
 			req->request_counters_updated = true;
-		} else if (cmp > 0 && op->pre_request_count == 0) {
+		} else if (cmp > 0) {
 			op->pre_request_count += op->request_count;
 			op->request_count = 1;
 			op->global->channel_sequence = channel_sequence;
+			op->global->channel_generation += generation_wrap;
 			update_open = true;
 			req->request_counters_updated = true;
 		} else if (modify_call) {
 			return NT_STATUS_FILE_NOT_AVAILABLE;
 		}
 	}
+	req->channel_generation = op->global->channel_generation;
 
 	if (update_open) {
 		status = smbXsrv_open_update(op);
@@ -2707,7 +2738,8 @@ static void smbd_smb2_request_reply_update_counts(struct smbd_smb2_request *req)
 	inhdr = SMBD_SMB2_IN_HDR_PTR(req);
 	channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE);
 
-	if (op->global->channel_sequence == channel_sequence) {
+	if ((op->global->channel_sequence == channel_sequence) &&
+	    (op->global->channel_generation == req->channel_generation)) {
 		SMB_ASSERT(op->request_count > 0);
 		op->request_count -= 1;
 	} else {
diff --git a/source4/libcli/smb2/keepalive.c b/source4/libcli/smb2/keepalive.c
index 402b063..71004aa14 100644
--- a/source4/libcli/smb2/keepalive.c
+++ b/source4/libcli/smb2/keepalive.c
@@ -26,7 +26,8 @@
 /*
   send a keepalive request
 */
-struct smb2_request *smb2_keepalive_send(struct smb2_transport *transport)
+struct smb2_request *smb2_keepalive_send(struct smb2_transport *transport,
+					 struct smb2_session *session)
 {
 	struct smb2_request *req;
 
@@ -35,6 +36,8 @@ struct smb2_request *smb2_keepalive_send(struct smb2_transport *transport)
 
 	SSVAL(req->out.body, 0x02, 0);
 
+	req->session = session;
+
 	smb2_transport_send(req);
 
 	return req;
@@ -60,6 +63,6 @@ NTSTATUS smb2_keepalive_recv(struct smb2_request *req)
 */
 NTSTATUS smb2_keepalive(struct smb2_transport *transport)
 {
-	struct smb2_request *req = smb2_keepalive_send(transport);
+	struct smb2_request *req = smb2_keepalive_send(transport, NULL);
 	return smb2_keepalive_recv(req);
 }
diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c
index 26b5583..109c04f 100644
--- a/source4/torture/smb2/replay.c
+++ b/source4/torture/smb2/replay.c
@@ -473,7 +473,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Test Durability V2 Create Replay Detection on Single Channel.
  */
 static bool test_replay_dhv2_oplock1(struct torture_context *tctx,
 				     struct smb2_tree *tree)
@@ -560,7 +560,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Test Durability V2 Create Replay Detection on Single Channel.
  * Hand in a different oplock level in the replay.
  * Server responds with the handed in oplock level and
  * corresponding durable status, but does not change the
@@ -697,7 +697,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Test Durability V2 Create Replay Detection on Single Channel.
  * Replay with a different share mode. The share mode of
  * the opened file is not changed by this.
  */
@@ -823,7 +823,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Single Channel.
+ * Test Durability V2 Create Replay Detection on Single Channel.
  * Create with an oplock, and replay with a lease.
  */
 static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx,
@@ -927,7 +927,7 @@ done:
 
 
 /**
- * Test durablity v2 create replay detection on single channel.
+ * Test durability v2 create replay detection on single channel.
  * Variant with leases instead of oplocks:
  * - open a file with a rh lease
  * - upgrade to a rwh lease with a second create
@@ -1065,7 +1065,7 @@ done:
 }
 
 /**
- * Test durablity v2 create replay detection on single channel.
+ * Test durability v2 create replay detection on single channel.
  * Variant with leases instead of oplocks, where the
  * replay does not specify the original lease level but
  * just a "R" lease. This still gives the upgraded lease
@@ -1216,7 +1216,7 @@ done:
 }
 
 /**
- * Test durablity v2 create replay detection on single channel.
+ * Test durability v2 create replay detection on single channel.
  * create with a lease, and replay with a different lease key
  */
 static bool test_replay_dhv2_lease3(struct torture_context *tctx,
@@ -1349,7 +1349,7 @@ done:
 }
 
 /**
- * Test durablity v2 create replay detection on single channel.
+ * Test durability v2 create replay detection on single channel.
  * Do the original create with a lease, and do the replay
  * with an oplock.
  */
@@ -1758,7 +1758,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Create Replay Detection on Multi Channel
+ * Test Durability V2 Create Replay Detection on Multi Channel
  */
 static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
 {
@@ -2164,7 +2164,7 @@ done:
 }
 
 /**
- * Test Durablity V2 Persistent Create Replay on a Single Channel
+ * Test Durability V2 Persistent Create Replay on a Single Channel
  */
 static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
 {
@@ -2427,6 +2427,102 @@ done:
 	return ret;
 }
 
+static bool test_replay7(struct torture_context *tctx, struct smb2_tree *tree)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_transport *transport = tree->session->transport;
+	NTSTATUS status;
+	struct smb2_handle _dh;
+	struct smb2_handle *dh = NULL;
+	struct smb2_notify notify;
+	struct smb2_request *req;
+	union smb_fileinfo qfinfo;
+	bool ret = false;
+
+	if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "SMB 3.X Dialect family required for "
+				   "replay tests\n");
+	}
+
+	torture_comment(tctx, "Notify across increment/decrement of csn\n");
+
+	smbXcli_conn_set_force_channel_sequence(transport->conn, true);
+
+	status = torture_smb2_testdir(tree, BASEDIR, &_dh);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	dh = &_dh;
+
+	notify.in.recursive		= 0x0000;
+	notify.in.buffer_size	= 0xffff;
+	notify.in.file.handle	= _dh;
+	notify.in.completion_filter	= FILE_NOTIFY_CHANGE_FILE_NAME;
+	notify.in.unknown		= 0x00000000;
+
+	/*
+	 * This posts a long-running request with csn==0 to "dh". Now
+	 * op->request_count==1 in smb2_server.c.
+	 */
+	smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);


-- 
Samba Shared Repository



More information about the samba-cvs mailing list