[Pkg-samba-maint] Bug#1051594: bookworm-pu: package samba/2:4.17.11+dfsg-0+deb12u1

Michael Tokarev mjt at tls.msk.ru
Sun Sep 10 11:11:19 BST 2023


Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org at packages.debian.org
Usertags: pu
X-Debbugs-Cc: samba at packages.debian.org, pkg-samba-maint at lists.alioth.debian.org
Control: affects -1 + src:samba

[ Reason ]
There's a next upstream stable/bugfix release of samba series 4.17,
with a next share of bugfixes.  This is the last regular stable release,
4.17 switched to security-only bugfix mode once 4.19 is out.  

Every change in there is worth having in debian stable, as it fixes
some bug.  Generally I think it is better to follow upstream stable
in case of samba as they tend to pick only important fixes for their
stable series.

[ Tests ]
Usual upstream testsuite is obviously passed.  Additionally, I run
this debian release on a few our boxes, both AD-DC mode and stand-
alone server mode, for quite some time.

[ Risks ]
There's always a risk to break something.  As usual for samba stable
releases though, this risk is minimal.

[ Checklist ]
  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in (old)stable
  [*] the issue is verified as fixed in unstable
    (unstable has next upstream major release from which
     all commits were picked up)

[ Changes ]

Here's the changelog entry in qeustion.  For the upstream
release, it links each change to a bug report at the
upstream bug tracker.  Additionally, there are 2 minor
debian-specific changes - it is the switch to bookworm
branch in the git packaging (Vcs-Git link, specific to
bookworm, not in sid), and a slight rewording of description
of samba-common-bin package (comes from sid).

samba (2:4.17.11+dfsg-0+deb12u1) bookworm; urgency=medium

  * new upstream stable/bugfix release 4.17.11, including:
   o https://bugzilla.samba.org/show_bug.cgi?id=9959
     Windows client join fails if a second container CN=System exists somewhere
   o https://bugzilla.samba.org/show_bug.cgi?id=15342
     Spotlight sometimes returns no results on latest macOS
   o https://bugzilla.samba.org/show_bug.cgi?id=15346
     2-3min delays at reconnect with smb2_validate_sequence_number:
     bad message_id 2
   o https://bugzilla.samba.org/show_bug.cgi?id=15384
     net ads lookup (with unspecified realm) fails
   o https://bugzilla.samba.org/show_bug.cgi?id=15401
     Improve GetNChanges to address some (but not all "Azure AD Connect")
     syncronisation tool looping during the initial user sync phase
   o https://bugzilla.samba.org/show_bug.cgi?id=15407
     Samba replication logs show (null) DN
   o https://bugzilla.samba.org/show_bug.cgi?id=15417
     Renaming results in NT_STATUS_SHARING_VIOLATION
     if previously attempted to remove the destination
   o https://bugzilla.samba.org/show_bug.cgi?id=15419
     Weird filename can cause assert to fail in openat_pathref_fsp_nosymlink()
   o https://bugzilla.samba.org/show_bug.cgi?id=15420
     reply_sesssetup_and_X() can dereference uninitialized tmp pointer
   o https://bugzilla.samba.org/show_bug.cgi?id=15427
     Spotlight results return wrong date in result list
   o https://bugzilla.samba.org/show_bug.cgi?id=15430
     Missing return in reply_exit_done()
   o https://bugzilla.samba.org/show_bug.cgi?id=15432
     TREE_CONNECT without SETUP causes smbd to use uninitialized pointer
   o https://bugzilla.samba.org/show_bug.cgi?id=15435
     Regression DFS not working with widelinks = true
   o https://bugzilla.samba.org/show_bug.cgi?id=15441
     samba-tool ntacl get segfault if aio_pthread appended
   o https://bugzilla.samba.org/show_bug.cgi?id=15446
     DCERPC_PKT_CO_CANCEL and DCERPC_PKT_ORPHANED can't be parsed
   o https://bugzilla.samba.org/show_bug.cgi?id=15449
     mdssvc: Do an early talloc_free() in _mdssvc_open()
   o https://bugzilla.samba.org/show_bug.cgi?id=15451
     ctdb_killtcp fails to work with --enable-pcap and libpcap ≥ 1.9.1
   o https://bugzilla.samba.org/show_bug.cgi?id=15453
     File doesn't show when user doesn't have permission
     if aio_pthread is loaded
   o https://bugzilla.samba.org/show_bug.cgi?id=15463
     macOS mdfind returns only 50 results
  * d/control: indicate the git branch in Vcs-Git URL (-b bookworm)
  * d/control: fix description of samba-common-bin (samba-client)

 -- Michael Tokarev <mjt at tls.msk.ru>  Sun, 10 Sep 2023 12:48:29 +0300

[ Other info ]

As usual, it is easier to review actual changes as git history,
not as single raw diff (what is being produced by debdiff).
https://salsa.debian.org/samba-team/samba/-/commits/upstream/4.17.11+dfsg
mirrors upstream git branch with all the upstream commits outlined above.

debdiff between 4.17.10+dfsg-0+deb12u1 and 4.17.11+dfsg-0+deb12u1 follows.

Thanks,

/mjt

diff -Nru samba-4.17.10+dfsg/debian/changelog samba-4.17.11+dfsg/debian/changelog
--- samba-4.17.10+dfsg/debian/changelog	2023-07-19 17:55:58.000000000 +0300
+++ samba-4.17.11+dfsg/debian/changelog	2023-09-10 12:48:29.000000000 +0300
@@ -1,3 +1,53 @@
+samba (2:4.17.11+dfsg-0+deb12u1) bookworm; urgency=medium
+
+  * new upstream stable/bugfix release 4.17.11, including:
+   o https://bugzilla.samba.org/show_bug.cgi?id=9959
+     Windows client join fails if a second container CN=System exists somewhere
+   o https://bugzilla.samba.org/show_bug.cgi?id=15342
+     Spotlight sometimes returns no results on latest macOS
+   o https://bugzilla.samba.org/show_bug.cgi?id=15346
+     2-3min delays at reconnect with smb2_validate_sequence_number:
+     bad message_id 2
+   o https://bugzilla.samba.org/show_bug.cgi?id=15384
+     net ads lookup (with unspecified realm) fails
+   o https://bugzilla.samba.org/show_bug.cgi?id=15401
+     Improve GetNChanges to address some (but not all "Azure AD Connect")
+     syncronisation tool looping during the initial user sync phase
+   o https://bugzilla.samba.org/show_bug.cgi?id=15407
+     Samba replication logs show (null) DN
+   o https://bugzilla.samba.org/show_bug.cgi?id=15417
+     Renaming results in NT_STATUS_SHARING_VIOLATION
+     if previously attempted to remove the destination
+   o https://bugzilla.samba.org/show_bug.cgi?id=15419
+     Weird filename can cause assert to fail in openat_pathref_fsp_nosymlink()
+   o https://bugzilla.samba.org/show_bug.cgi?id=15420
+     reply_sesssetup_and_X() can dereference uninitialized tmp pointer
+   o https://bugzilla.samba.org/show_bug.cgi?id=15427
+     Spotlight results return wrong date in result list
+   o https://bugzilla.samba.org/show_bug.cgi?id=15430
+     Missing return in reply_exit_done()
+   o https://bugzilla.samba.org/show_bug.cgi?id=15432
+     TREE_CONNECT without SETUP causes smbd to use uninitialized pointer
+   o https://bugzilla.samba.org/show_bug.cgi?id=15435
+     Regression DFS not working with widelinks = true
+   o https://bugzilla.samba.org/show_bug.cgi?id=15441
+     samba-tool ntacl get segfault if aio_pthread appended
+   o https://bugzilla.samba.org/show_bug.cgi?id=15446
+     DCERPC_PKT_CO_CANCEL and DCERPC_PKT_ORPHANED can't be parsed
+   o https://bugzilla.samba.org/show_bug.cgi?id=15449
+     mdssvc: Do an early talloc_free() in _mdssvc_open()
+   o https://bugzilla.samba.org/show_bug.cgi?id=15451
+     ctdb_killtcp fails to work with --enable-pcap and libpcap ≥ 1.9.1
+   o https://bugzilla.samba.org/show_bug.cgi?id=15453
+     File doesn't show when user doesn't have permission
+     if aio_pthread is loaded
+   o https://bugzilla.samba.org/show_bug.cgi?id=15463
+     macOS mdfind returns only 50 results
+  * d/control: indicate the git branch in Vcs-Git URL (-b bookworm)
+  * d/control: fix description of samba-common-bin (samba-client)
+
+ -- Michael Tokarev <mjt at tls.msk.ru>  Sun, 10 Sep 2023 12:48:29 +0300
+
 samba (2:4.17.10+dfsg-0+deb12u1) bookworm-security; urgency=medium
 
   * new upstream stable/security release 4.17.10, including:
diff -Nru samba-4.17.10+dfsg/debian/control samba-4.17.11+dfsg/debian/control
--- samba-4.17.10+dfsg/debian/control	2023-07-19 17:55:58.000000000 +0300
+++ samba-4.17.11+dfsg/debian/control	2023-09-10 12:48:20.000000000 +0300
@@ -76,7 +76,7 @@
 #	tdb-tools <!nocheck>,
 Rules-Requires-Root: binary-targets
 Vcs-Browser: https://salsa.debian.org/samba-team/samba
-Vcs-Git: https://salsa.debian.org/samba-team/samba.git
+Vcs-Git: https://salsa.debian.org/samba-team/samba.git -b bookworm
 
 Package: samba
 Architecture: any
@@ -183,8 +183,8 @@
  or member server in Active Directory or NT4-style domains.
  .
  This package contains the common files that are used by both the server
- (provided in the samba package) and the client (provided in the samba-clients
- package).
+ (provided in the samba package) and the client (provided in the smbclient
+ libsmbclient packages).
 
 Package: samba-ad-dc
 Architecture: all
diff -Nru samba-4.17.10+dfsg/ctdb/common/system_socket.c samba-4.17.11+dfsg/ctdb/common/system_socket.c
--- samba-4.17.10+dfsg/ctdb/common/system_socket.c	2022-08-08 17:15:38.916188700 +0300
+++ samba-4.17.11+dfsg/ctdb/common/system_socket.c	2023-09-07 11:59:49.025451000 +0300
@@ -747,13 +747,6 @@
 	return 0;
 }
 
-/*
- * Packet capture
- *
- * If AF_PACKET is available then use a raw socket otherwise use pcap.
- * wscript has checked to make sure that pcap is available if needed.
- */
-
 static int tcp4_extract(const uint8_t *ip_pkt,
 			size_t pktlen,
 			struct sockaddr_in *src,
@@ -864,8 +857,14 @@
 	return 0;
 }
 
+/*
+ * Packet capture
+ *
+ * If AF_PACKET is available then use a raw socket otherwise use pcap.
+ * wscript has checked to make sure that pcap is available if needed.
+ */
 
-#ifdef HAVE_AF_PACKET
+#if defined(HAVE_AF_PACKET) && !defined(ENABLE_PCAP)
 
 /*
  * This function is used to open a raw socket to capture from
@@ -881,7 +880,7 @@
 		return -1;
 	}
 
-	DBG_DEBUG("Created RAW SOCKET FD:%d for tcp tickle\n", s);
+	DBG_DEBUG("Opened raw socket for TCP tickle capture (fd=%d)\n", s);
 
 	ret = set_blocking(s, false);
 	if (ret != 0) {
@@ -964,22 +963,92 @@
 	return ENOMSG;
 }
 
-#else /* HAVE_AF_PACKET */
+#else /* defined(HAVE_AF_PACKET) && !defined(ENABLE_PCAP) */
 
 #include <pcap.h>
 
+/*
+ * Assume this exists if pcap.h exists - it has been around for a
+ * while
+ */
+#include <pcap/sll.h>
+
 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
 {
+	char errbuf[PCAP_ERRBUF_SIZE];
 	pcap_t *pt;
+	int pcap_packet_type;
+	const char *t = NULL;
+	int fd;
+	int ret;
 
-	pt=pcap_open_live(iface, 100, 0, 0, NULL);
+	pt = pcap_create(iface, errbuf);
 	if (pt == NULL) {
-		DBG_ERR("Failed to open capture device %s\n", iface);
+		DBG_ERR("Failed to open pcap capture device %s (%s)\n",
+			iface,
+			errbuf);
 		return -1;
 	}
+	/*
+	 * pcap isn't very clear about defaults...
+	 */
+	ret = pcap_set_snaplen(pt, 100);
+	if (ret < 0) {
+		DBG_ERR("Failed to set snaplen for pcap capture\n");
+		goto fail;
+	}
+	ret = pcap_set_promisc(pt, 0);
+	if (ret < 0) {
+		DBG_ERR("Failed to unset promiscuous mode for pcap capture\n");
+		goto fail;
+	}
+	ret = pcap_set_timeout(pt, 0);
+	if (ret < 0) {
+		DBG_ERR("Failed to set timeout for pcap capture\n");
+		goto fail;
+	}
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+	ret = pcap_set_immediate_mode(pt, 1);
+	if (ret < 0) {
+		DBG_ERR("Failed to set immediate mode for pcap capture\n");
+		goto fail;
+	}
+#endif
+	ret = pcap_activate(pt);
+	if (ret < 0) {
+		DBG_ERR("Failed to activate pcap capture\n");
+		goto fail;
+	}
+
+	pcap_packet_type = pcap_datalink(pt);
+	switch (pcap_packet_type) {
+	case DLT_EN10MB:
+		t = "DLT_EN10MB";
+		break;
+	case DLT_LINUX_SLL:
+		t = "DLT_LINUX_SLL";
+		break;
+#ifdef DLT_LINUX_SLL2
+	case DLT_LINUX_SLL2:
+		t = "DLT_LINUX_SLL2";
+		break;
+#endif /* DLT_LINUX_SLL2 */
+	default:
+		DBG_ERR("Unknown pcap packet type %d\n", pcap_packet_type);
+		goto fail;
+	}
+
+	fd = pcap_get_selectable_fd(pt);
+	DBG_DEBUG("Opened pcap capture for TCP tickle (type=%s, fd=%d)\n",
+		  t,
+		  fd);
+
 	*((pcap_t **)private_data) = pt;
+	return fd;
 
-	return pcap_fileno(pt);
+fail:
+	pcap_close(pt);
+	return -1;
 }
 
 int ctdb_sys_close_capture_socket(void *private_data)
@@ -999,10 +1068,12 @@
 			     uint16_t *window)
 {
 	int ret;
-	struct ether_header *eth;
 	struct pcap_pkthdr pkthdr;
 	const u_char *buffer;
 	pcap_t *pt = (pcap_t *)private_data;
+	int pcap_packet_type;
+	uint16_t ether_type;
+	size_t ll_hdr_len;
 
 	buffer=pcap_next(pt, &pkthdr);
 	if (buffer==NULL) {
@@ -1012,36 +1083,86 @@
 	ZERO_STRUCTP(src);
 	ZERO_STRUCTP(dst);
 
-	/* Ethernet */
-	eth = (struct ether_header *)buffer;
-
-	/* we want either IPv4 or IPv6 */
-	if (eth->ether_type == htons(ETHERTYPE_IP)) {
-		ret = tcp4_extract(buffer + sizeof(struct ether_header),
-				   (size_t)(pkthdr.caplen -
-					    sizeof(struct ether_header)),
+	pcap_packet_type = pcap_datalink(pt);
+	switch (pcap_packet_type) {
+	case DLT_EN10MB: {
+		const struct ether_header *eth =
+			(const struct ether_header *)buffer;
+		ether_type = ntohs(eth->ether_type);
+		ll_hdr_len = sizeof(struct ether_header);
+		break;
+	}
+	case DLT_LINUX_SLL: {
+		const struct sll_header *sll =
+			(const struct sll_header *)buffer;
+		uint16_t arphrd_type = ntohs(sll->sll_hatype);
+		switch (arphrd_type) {
+		case ARPHRD_ETHER:
+		case ARPHRD_INFINIBAND:
+			break;
+		default:
+			DBG_DEBUG("SLL: Unknown arphrd_type %"PRIu16"\n",
+				  arphrd_type);
+			return EPROTONOSUPPORT;
+		}
+		ether_type = ntohs(sll->sll_protocol);
+		ll_hdr_len = SLL_HDR_LEN;
+		break;
+	}
+#ifdef DLT_LINUX_SLL2
+	case DLT_LINUX_SLL2: {
+		const struct sll2_header *sll2 =
+			(const struct sll2_header *)buffer;
+		uint16_t arphrd_type = ntohs(sll2->sll2_hatype);
+		switch (arphrd_type) {
+		case ARPHRD_ETHER:
+		case ARPHRD_INFINIBAND:
+			break;
+		default:
+			DBG_DEBUG("SLL2: Unknown arphrd_type %"PRIu16"\n",
+				  arphrd_type);
+			return EPROTONOSUPPORT;
+		}
+		ether_type = ntohs(sll2->sll2_protocol);
+		ll_hdr_len = SLL2_HDR_LEN;
+		break;
+	}
+#endif /* DLT_LINUX_SLL2 */
+	default:
+		DBG_DEBUG("Unknown pcap packet type %d\n", pcap_packet_type);
+		return EPROTONOSUPPORT;
+	}
+
+	switch (ether_type) {
+	case ETHERTYPE_IP:
+		ret = tcp4_extract(buffer + ll_hdr_len,
+				   (size_t)pkthdr.caplen - ll_hdr_len,
 				   &src->ip,
 				   &dst->ip,
 				   ack_seq,
 				   seq,
 				   rst,
 				   window);
-		return ret;
-
-	} else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
-		ret = tcp6_extract(buffer + sizeof(struct ether_header),
-				   (size_t)(pkthdr.caplen -
-					    sizeof(struct ether_header)),
+		break;
+	case ETHERTYPE_IP6:
+		ret = tcp6_extract(buffer + ll_hdr_len,
+				   (size_t)pkthdr.caplen - ll_hdr_len,
 				   &src->ip6,
 				   &dst->ip6,
 				   ack_seq,
 				   seq,
 				   rst,
 				   window);
-		return ret;
+		break;
+	case ETHERTYPE_ARP:
+		/* Silently ignore ARP packets */
+		return EPROTO;
+	default:
+		DBG_DEBUG("Unknown ether type %"PRIu16"\n", ether_type);
+		return EPROTO;
 	}
 
-	return ENOMSG;
+	return ret;
 }
 
-#endif /* HAVE_AF_PACKET */
+#endif /* defined(HAVE_AF_PACKET) && !defined(ENABLE_PCAP) */
diff -Nru samba-4.17.10+dfsg/ctdb/config/functions samba-4.17.11+dfsg/ctdb/config/functions
--- samba-4.17.10+dfsg/ctdb/config/functions	2022-08-08 17:15:38.920188700 +0300
+++ samba-4.17.11+dfsg/ctdb/config/functions	2023-09-07 11:59:49.025451000 +0300
@@ -452,8 +452,14 @@
 	    return
 	fi
 
+	if [ -n "$CTDB_KILLTCP_DEBUGLEVEL" ]; then
+		_debuglevel="$CTDB_KILLTCP_DEBUGLEVEL"
+	else
+		_debuglevel="$CTDB_DEBUGLEVEL"
+	fi
 	echo "$_connections" | \
-		"${CTDB_HELPER_BINDIR}/ctdb_killtcp" "$_iface" || {
+		CTDB_DEBUGLEVEL="$_debuglevel" \
+			"${CTDB_HELPER_BINDIR}/ctdb_killtcp" "$_iface" || {
 		echo "Failed to kill TCP connections"
 		return
 	}
diff -Nru samba-4.17.10+dfsg/ctdb/tools/ctdb_killtcp.c samba-4.17.11+dfsg/ctdb/tools/ctdb_killtcp.c
--- samba-4.17.10+dfsg/ctdb/tools/ctdb_killtcp.c	2022-08-08 17:15:38.992189200 +0300
+++ samba-4.17.11+dfsg/ctdb/tools/ctdb_killtcp.c	2023-09-07 11:59:49.025451000 +0300
@@ -169,17 +169,18 @@
 				       &conn.server, &conn.client,
 				       &ack_seq, &seq, &rst, &window);
 	if (ret != 0) {
-		/* probably a non-tcp ACK packet */
+		/* Not a TCP-ACK?  Unexpected protocol? */
+		DBG_DEBUG("Failed to parse packet, errno=%d\n", ret);
 		return;
 	}
 
 	if (window == htons(1234) && (rst || seq == 0)) {
 		/* Ignore packets that we sent! */
-		D_DEBUG("Ignoring packet: %s, "
-			"seq=%"PRIu32", ack_seq=%"PRIu32", "
-			"rst=%d, window=%"PRIu16"\n",
-			ctdb_connection_to_string(state, &conn, false),
-			seq, ack_seq, rst, ntohs(window));
+		DBG_DEBUG("Ignoring sent packet: %s, "
+			  "seq=%"PRIu32", ack_seq=%"PRIu32", "
+			  "rst=%d, window=%"PRIu16"\n",
+			  ctdb_connection_to_string(state, &conn, false),
+			  seq, ack_seq, rst, ntohs(window));
 		return;
 	}
 
diff -Nru samba-4.17.10+dfsg/ctdb/wscript samba-4.17.11+dfsg/ctdb/wscript
--- samba-4.17.10+dfsg/ctdb/wscript	2022-08-08 17:29:11.345506700 +0300
+++ samba-4.17.11+dfsg/ctdb/wscript	2023-09-07 11:59:49.025451000 +0300
@@ -98,6 +98,9 @@
     opt.add_option('--enable-etcd-reclock',
                    help=("Enable etcd recovery lock helper (default=no)"),
                    action="store_true", dest='ctdb_etcd_reclock', default=False)
+    opt.add_option('--enable-pcap',
+                   help=("Use pcap for packet capture (default=no)"),
+                   action="store_true", dest='ctdb_pcap', default=False)
 
     opt.add_option('--with-libcephfs',
                    help=("Directory under which libcephfs is installed"),
@@ -201,15 +204,24 @@
     if not conf.CHECK_VARIABLE('ETIME', headers='errno.h'):
         conf.DEFINE('ETIME', 'ETIMEDOUT')
 
-    if sys.platform.startswith('linux'):
+    if Options.options.ctdb_pcap or not sys.platform.startswith('linux'):
+        conf.DEFINE('ENABLE_PCAP', 1)
+    if not conf.env.ENABLE_PCAP:
         conf.SET_TARGET_TYPE('pcap', 'EMPTY')
     else:
+        conf.find_program('pcap-config', var='PCAP_CONFIG')
+        if conf.env.PCAP_CONFIG:
+            conf.CHECK_CFG(path=conf.env.PCAP_CONFIG,
+                           args="--cflags --libs",
+                           package="",
+                           uselib_store="PCAP")
         if not conf.CHECK_HEADERS('pcap.h'):
             Logs.error('Need libpcap')
             sys.exit(1)
         if not conf.CHECK_FUNCS_IN('pcap_open_live', 'pcap', headers='pcap.h'):
             Logs.error('Need libpcap')
             sys.exit(1)
+        conf.CHECK_FUNCS_IN('pcap_set_immediate_mode', 'pcap', headers='pcap.h')
 
     if not conf.CHECK_FUNCS_IN('backtrace backtrace_symbols', 'execinfo',
                                checklibc=True, headers='execinfo.h'):
diff -Nru samba-4.17.10+dfsg/libcli/smb/smbXcli_base.c samba-4.17.11+dfsg/libcli/smb/smbXcli_base.c
--- samba-4.17.10+dfsg/libcli/smb/smbXcli_base.c	2023-05-11 10:07:19.570420700 +0300
+++ samba-4.17.11+dfsg/libcli/smb/smbXcli_base.c	2023-09-07 11:59:49.025451000 +0300
@@ -4220,6 +4220,8 @@
 struct smbXcli_negprot_state {
 	struct smbXcli_conn *conn;
 	struct tevent_context *ev;
+	struct smb2_negotiate_contexts *in_ctx;
+	struct smb2_negotiate_contexts *out_ctx;
 	uint32_t timeout_msec;
 
 	struct {
@@ -4242,7 +4244,8 @@
 					uint32_t timeout_msec,
 					enum protocol_types min_protocol,
 					enum protocol_types max_protocol,
-					uint16_t max_credits)
+					uint16_t max_credits,
+					struct smb2_negotiate_contexts *in_ctx)
 {
 	struct tevent_req *req, *subreq;
 	struct smbXcli_negprot_state *state;
@@ -4254,6 +4257,7 @@
 	}
 	state->conn = conn;
 	state->ev = ev;
+	state->in_ctx = in_ctx;
 	state->timeout_msec = timeout_msec;
 
 	if (min_protocol == PROTOCOL_NONE) {
@@ -4934,6 +4938,25 @@
 			return NULL;
 		}
 
+		if (state->in_ctx != NULL) {
+			struct smb2_negotiate_contexts *ctxs = state->in_ctx;
+
+			for (i=0; i<ctxs->num_contexts; i++) {
+				struct smb2_negotiate_context *ctx =
+					&ctxs->contexts[i];
+
+				status = smb2_negotiate_context_add(
+					state,
+					&c,
+					ctx->type,
+					ctx->data.data,
+					ctx->data.length);
+				if (!NT_STATUS_IS_OK(status)) {
+					return NULL;
+				}
+			}
+		}
+
 		status = smb2_negotiate_context_push(state, &b, c);
 		if (!NT_STATUS_IS_OK(status)) {
 			return NULL;
@@ -4988,7 +5011,6 @@
 	uint8_t *body;
 	size_t i;
 	uint16_t dialect_revision;
-	struct smb2_negotiate_contexts c = { .num_contexts = 0, };
 	uint32_t negotiate_context_offset = 0;
 	uint16_t negotiate_context_count = 0;
 	DATA_BLOB negotiate_context_blob = data_blob_null;
@@ -5195,10 +5217,15 @@
 	negotiate_context_blob.data += ctx_ofs;
 	negotiate_context_blob.length -= ctx_ofs;
 
-	status = smb2_negotiate_context_parse(state,
+	state->out_ctx = talloc_zero(state, struct smb2_negotiate_contexts);
+	if (tevent_req_nomem(state->out_ctx, req)) {
+		return;
+	}
+
+	status = smb2_negotiate_context_parse(state->out_ctx,
 					      negotiate_context_blob,
 					      negotiate_context_count,
-					      &c);
+					      state->out_ctx);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
 	}
@@ -5206,8 +5233,8 @@
 		return;
 	}
 
-	preauth = smb2_negotiate_context_find(&c,
-					SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
+	preauth = smb2_negotiate_context_find(
+		state->out_ctx, SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
 	if (preauth == NULL) {
 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
@@ -5237,7 +5264,8 @@
 		return;
 	}
 
-	sign_algo = smb2_negotiate_context_find(&c, SMB2_SIGNING_CAPABILITIES);
+	sign_algo = smb2_negotiate_context_find(
+		state->out_ctx, SMB2_SIGNING_CAPABILITIES);
 	if (sign_algo != NULL) {
 		const struct smb3_signing_capabilities *client_sign_algos =
 			&state->conn->smb2.client.smb3_capabilities.signing;
@@ -5296,7 +5324,8 @@
 		conn->smb2.server.sign_algo = sign_algo_selected;
 	}
 
-	cipher = smb2_negotiate_context_find(&c, SMB2_ENCRYPTION_CAPABILITIES);
+	cipher = smb2_negotiate_context_find(
+		state->out_ctx, SMB2_ENCRYPTION_CAPABILITIES);
 	if (cipher != NULL) {
 		const struct smb3_encryption_capabilities *client_ciphers =
 			&state->conn->smb2.client.smb3_capabilities.encryption;
@@ -5516,9 +5545,26 @@
 	return NT_STATUS_INVALID_NETWORK_RESPONSE;
 }
 
-NTSTATUS smbXcli_negprot_recv(struct tevent_req *req)
+NTSTATUS smbXcli_negprot_recv(
+	struct tevent_req *req,
+	TALLOC_CTX *mem_ctx,
+	struct smb2_negotiate_contexts **out_ctx)
 {
-	return tevent_req_simple_recv_ntstatus(req);
+	struct smbXcli_negprot_state *state = tevent_req_data(
+		req, struct smbXcli_negprot_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
+		return status;
+	}
+
+	if (out_ctx != NULL) {
+		*out_ctx = talloc_move(mem_ctx, &state->out_ctx);
+	}
+
+	tevent_req_received(req);
+	return NT_STATUS_OK;
 }
 
 NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
@@ -5543,9 +5589,15 @@
 	if (ev == NULL) {
 		goto fail;
 	}
-	req = smbXcli_negprot_send(frame, ev, conn, timeout_msec,
-				   min_protocol, max_protocol,
-				   WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
+	req = smbXcli_negprot_send(
+		frame,
+		ev,
+		conn,
+		timeout_msec,
+		min_protocol,
+		max_protocol,
+		WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK,
+		NULL);
 	if (req == NULL) {
 		goto fail;
 	}
@@ -5553,7 +5605,7 @@
 	if (!ok) {
 		goto fail;
 	}
-	status = smbXcli_negprot_recv(req);
+	status = smbXcli_negprot_recv(req, NULL, NULL);
  fail:
 	TALLOC_FREE(frame);
 	return status;
diff -Nru samba-4.17.10+dfsg/libcli/smb/smbXcli_base.h samba-4.17.11+dfsg/libcli/smb/smbXcli_base.h
--- samba-4.17.10+dfsg/libcli/smb/smbXcli_base.h	2022-08-08 17:15:39.192190600 +0300
+++ samba-4.17.11+dfsg/libcli/smb/smbXcli_base.h	2023-09-07 11:59:49.029451100 +0300
@@ -457,14 +457,19 @@
 NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req,
 				  struct iovec *sent_iov);
 
+struct smb2_negotiate_contexts;
 struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct smbXcli_conn *conn,
 					uint32_t timeout_msec,
 					enum protocol_types min_protocol,
 					enum protocol_types max_protocol,
-					uint16_t max_credits);
-NTSTATUS smbXcli_negprot_recv(struct tevent_req *req);
+					uint16_t max_credits,
+					struct smb2_negotiate_contexts *in_ctx);
+NTSTATUS smbXcli_negprot_recv(
+	struct tevent_req *req,
+	TALLOC_CTX *mem_ctx,
+	struct smb2_negotiate_contexts **out_ctx);
 NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
 			 uint32_t timeout_msec,
 			 enum protocol_types min_protocol,
diff -Nru samba-4.17.10+dfsg/librpc/idl/dcerpc.idl samba-4.17.11+dfsg/librpc/idl/dcerpc.idl
--- samba-4.17.10+dfsg/librpc/idl/dcerpc.idl	2022-08-08 17:15:39.212190900 +0300
+++ samba-4.17.11+dfsg/librpc/idl/dcerpc.idl	2023-09-07 11:59:49.029451100 +0300
@@ -276,12 +276,10 @@
 	} dcerpc_auth3;
 
 	typedef [public] struct {
-		[value(0)]	      uint32    _pad;
 		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
 	} dcerpc_orphaned;
 
 	typedef [public] struct {
-		[value(0)]	      uint32    _pad;
 		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
 	} dcerpc_co_cancel;
 
diff -Nru samba-4.17.10+dfsg/librpc/rpc/dcerpc_util.c samba-4.17.11+dfsg/librpc/rpc/dcerpc_util.c
--- samba-4.17.10+dfsg/librpc/rpc/dcerpc_util.c	2022-08-08 17:15:39.232191000 +0300
+++ samba-4.17.11+dfsg/librpc/rpc/dcerpc_util.c	2023-09-07 11:59:49.029451100 +0300
@@ -565,9 +565,14 @@
 
 		ofs = state->buffer.length;
 
-		if (frag_len < ofs) {
+		if (frag_len <= ofs) {
 			/*
-			 * something is wrong, let the caller deal with it
+			 * With frag_len == ofs, we are done, this is likely
+			 * a DCERPC_PKT_CO_CANCEL and DCERPC_PKT_ORPHANED
+			 * without any payload.
+			 *
+			 * Otherwise it's a broken packet and we
+			 * let the caller deal with it.
 			 */
 			*_vector = NULL;
 			*_count = 0;
diff -Nru samba-4.17.10+dfsg/python/samba/tests/blackbox/mdsearch.py samba-4.17.11+dfsg/python/samba/tests/blackbox/mdsearch.py
--- samba-4.17.10+dfsg/python/samba/tests/blackbox/mdsearch.py	2023-07-14 16:15:01.033234400 +0300
+++ samba-4.17.11+dfsg/python/samba/tests/blackbox/mdsearch.py	2023-09-07 11:59:49.029451100 +0300
@@ -100,7 +100,7 @@
         config = os.environ["SMB_CONF_PATH"]
 
         json_in = r'''{
-          "from": 0, "size": 100, "_source": ["path.real"],
+          "from": 0, "size": 50, "_source": ["path.real"],
           "query": {
             "query_string": {
               "query": "(samba*) AND path.real.fulltext:\"%BASEPATH%\""
diff -Nru samba-4.17.10+dfsg/python/samba/tests/dcerpc/mdssvc.py samba-4.17.11+dfsg/python/samba/tests/dcerpc/mdssvc.py
--- samba-4.17.10+dfsg/python/samba/tests/dcerpc/mdssvc.py	2023-07-14 16:15:01.033234400 +0300
+++ samba-4.17.11+dfsg/python/samba/tests/dcerpc/mdssvc.py	2023-09-07 11:59:49.029451100 +0300
@@ -125,7 +125,7 @@
 
     def test_mdscli_search(self):
         exp_json_query = r'''{
-          "from": 0, "size": 100, "_source": ["path.real"],
+          "from": 0, "size": 50, "_source": ["path.real"],
           "query": {
             "query_string": {
               "query": "(samba*) AND path.real.fulltext:\"%BASEPATH%\""
@@ -157,7 +157,7 @@
             r'kMDItemFSName=="x\\x"'
         )
         exp_json_query = r'''{
-          "from": 0, "size": 100, "_source": ["path.real"],
+          "from": 0, "size": 50, "_source": ["path.real"],
           "query": {
             "query_string": {
               "query": "(file.filename:x\\+x OR file.filename:x\\*x OR file.filename:x=x OR file.filename:x'x OR file.filename:x\\?x OR file.filename:x\\ x OR file.filename:x\\(x OR file.filename:x\\\"x OR file.filename:x\\\\x) AND path.real.fulltext:\"%BASEPATH%\""
@@ -166,7 +166,7 @@
         }'''
         fake_json_response = r'''{
           "hits" : {
-            "total" : {"value" : 2},
+            "total" : {"value" : 9},
             "hits" : [
               {"_source" : {"path" : {"real" : "%BASEPATH%/x+x"}}},
               {"_source" : {"path" : {"real" : "%BASEPATH%/x*x"}}},
diff -Nru samba-4.17.10+dfsg/selftest/knownfail.d/getncchanges samba-4.17.11+dfsg/selftest/knownfail.d/getncchanges
--- samba-4.17.10+dfsg/selftest/knownfail.d/getncchanges	2022-08-08 17:15:39.308191500 +0300
+++ samba-4.17.11+dfsg/selftest/knownfail.d/getncchanges	2023-09-07 11:59:49.029451100 +0300
@@ -4,3 +4,5 @@
 samba4.drs.getncchanges.python\(promoted_dc\).getncchanges.DrsReplicaSyncIntegrityTestCase.test_repl_get_tgt_chain\(promoted_dc\)
 samba4.drs.getncchanges.python\(promoted_dc\).getncchanges.DrsReplicaSyncIntegrityTestCase.test_repl_get_tgt_and_anc\(promoted_dc\)
 samba4.drs.getncchanges.python\(promoted_dc\).getncchanges.DrsReplicaSyncIntegrityTestCase.test_repl_get_tgt_multivalued_links\(promoted_dc\)
+# Samba chooses to always increment the USN for the NC root at the point where it would otherwise show up.
+samba4.drs.getncchanges.python\(.*\).getncchanges.DrsReplicaSyncIntegrityTestCase.test_repl_nc_is_first_nc_change_only\(
diff -Nru samba-4.17.10+dfsg/selftest/target/Samba3.pm samba-4.17.11+dfsg/selftest/target/Samba3.pm
--- samba-4.17.10+dfsg/selftest/target/Samba3.pm	2023-07-14 16:15:04.449269500 +0300
+++ samba-4.17.11+dfsg/selftest/target/Samba3.pm	2023-09-07 11:59:49.029451100 +0300
@@ -3023,6 +3023,11 @@
 	msdfs root = yes
 	msdfs shuffle referrals = yes
 	guest ok = yes
+[msdfs-share-wl]
+	path = $msdfs_shrdir
+	msdfs root = yes
+	wide links = yes
+	guest ok = yes
 [msdfs-share2]
 	path = $msdfs_shrdir2
 	msdfs root = yes
diff -Nru samba-4.17.10+dfsg/source3/libsmb/cliconnect.c samba-4.17.11+dfsg/source3/libsmb/cliconnect.c
--- samba-4.17.10+dfsg/source3/libsmb/cliconnect.c	2022-08-08 17:15:39.376192000 +0300
+++ samba-4.17.11+dfsg/source3/libsmb/cliconnect.c	2023-09-07 11:59:49.029451100 +0300
@@ -2850,11 +2850,15 @@
 		return;
 	}
 
-	subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
-				      state->cli->timeout,
-				      state->min_protocol,
-				      state->max_protocol,
-				      WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
+	subreq = smbXcli_negprot_send(
+		state,
+		state->ev,
+		state->cli->conn,
+		state->cli->timeout,
+		state->min_protocol,
+		state->max_protocol,
+		WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK,
+		NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -2869,7 +2873,7 @@
 		req, struct cli_start_connection_state);
 	NTSTATUS status;
 
-	status = smbXcli_negprot_recv(subreq);
+	status = smbXcli_negprot_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
diff -Nru samba-4.17.10+dfsg/source3/modules/vfs_aio_pthread.c samba-4.17.11+dfsg/source3/modules/vfs_aio_pthread.c
--- samba-4.17.10+dfsg/source3/modules/vfs_aio_pthread.c	2022-08-08 17:29:11.353506600 +0300
+++ samba-4.17.11+dfsg/source3/modules/vfs_aio_pthread.c	2023-09-07 11:59:49.033451300 +0300
@@ -468,35 +468,43 @@
 		return -1;
 	}
 
-	if (fsp->conn->sconn->client->server_multi_channel_enabled) {
+	if (fsp->conn->sconn->pool == NULL) {
+		/*
+		 * a threadpool is required for async support
+		 */
+		aio_allow_open = false;
+	}
+
+	if (fsp->conn->sconn->client != NULL &&
+	    fsp->conn->sconn->client->server_multi_channel_enabled) {
 		/*
 		 * This module is not compatible with multi channel yet.
 		 */
 		aio_allow_open = false;
 	}
 
-	if (!aio_allow_open) {
-		/* aio opens turned off. */
-		return openat(fsp_get_pathref_fd(dirfsp),
-			      smb_fname->base_name,
-			      how->flags,
-			      how->mode);
+	if (fsp->fsp_flags.is_pathref) {
+		/* Use SMB_VFS_NEXT_OPENAT() to call openat() with O_PATH. */
+		aio_allow_open = false;
 	}
 
 	if (!(how->flags & O_CREAT)) {
 		/* Only creates matter. */
-		return openat(fsp_get_pathref_fd(dirfsp),
-			      smb_fname->base_name,
-			      how->flags,
-			      how->mode);
+		aio_allow_open = false;
 	}
 
 	if (!(how->flags & O_EXCL)) {
 		/* Only creates with O_EXCL matter. */
-		return openat(fsp_get_pathref_fd(dirfsp),
-			      smb_fname->base_name,
-			      how->flags,
-			      how->mode);
+		aio_allow_open = false;
+	}
+
+	if (!aio_allow_open) {
+		/* aio opens turned off. */
+		return SMB_VFS_NEXT_OPENAT(handle,
+			      dirfsp,
+			      smb_fname,
+			      fsp,
+			      how);
 	}
 
 	/*
diff -Nru samba-4.17.10+dfsg/source3/modules/vfs_widelinks.c samba-4.17.11+dfsg/source3/modules/vfs_widelinks.c
--- samba-4.17.10+dfsg/source3/modules/vfs_widelinks.c	2022-08-08 17:29:11.361506700 +0300
+++ samba-4.17.11+dfsg/source3/modules/vfs_widelinks.c	2023-09-07 11:59:49.033451300 +0300
@@ -106,6 +106,7 @@
 
 struct widelinks_config {
 	bool active;
+	bool is_dfs_share;
 	char *cwd;
 };
 
@@ -134,7 +135,8 @@
 		DBG_ERR("vfs_widelinks module loaded with "
 			"widelinks = no\n");
 	}
-
+	config->is_dfs_share =
+		(lp_host_msdfs() && lp_msdfs_root(SNUM(handle->conn)));
         SMB_VFS_HANDLE_SET_DATA(handle,
 				config,
 				NULL, /* free_fn */
@@ -346,7 +348,7 @@
 {
 	struct vfs_open_how how = *_how;
 	struct widelinks_config *config = NULL;
-
+	int ret;
 	SMB_VFS_HANDLE_GET_DATA(handle,
 				config,
 				struct widelinks_config,
@@ -363,11 +365,33 @@
 		how.flags = (how.flags & ~O_NOFOLLOW);
 	}
 
-	return SMB_VFS_NEXT_OPENAT(handle,
+	ret = SMB_VFS_NEXT_OPENAT(handle,
 				   dirfsp,
 				   smb_fname,
 				   fsp,
 				   &how);
+	if (config->is_dfs_share && ret == -1 && errno == ENOENT) {
+		struct smb_filename *full_fname = NULL;
+		int lstat_ret;
+
+		full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+				dirfsp,
+				smb_fname);
+		if (full_fname == NULL) {
+			errno = ENOMEM;
+			return -1;
+		}
+		lstat_ret = SMB_VFS_NEXT_LSTAT(handle,
+				full_fname);
+		if (lstat_ret != -1 &&
+		    VALID_STAT(full_fname->st) &&
+		    S_ISLNK(full_fname->st.st_ex_mode)) {
+			fsp->fsp_name->st = full_fname->st;
+		}
+		TALLOC_FREE(full_fname);
+		errno = ENOENT;
+	}
+	return ret;
 }
 
 static struct dirent *widelinks_readdir(vfs_handle_struct *handle,
diff -Nru samba-4.17.10+dfsg/source3/passdb/pdb_samba_dsdb.c samba-4.17.11+dfsg/source3/passdb/pdb_samba_dsdb.c
--- samba-4.17.10+dfsg/source3/passdb/pdb_samba_dsdb.c	2022-08-08 17:15:39.424192400 +0300
+++ samba-4.17.11+dfsg/source3/passdb/pdb_samba_dsdb.c	2023-09-07 11:59:49.033451300 +0300
@@ -3305,9 +3305,13 @@
 		goto out;
 	}
 
-	msg->dn = ldb_dn_copy(tmp_ctx, base_dn);
+	msg->dn = samdb_system_container_dn(state->ldb, tmp_ctx);
+	if (msg->dn == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
 
-	ok = ldb_dn_add_child_fmt(msg->dn, "cn=%s,cn=System", td->domain_name);
+	ok = ldb_dn_add_child_fmt(msg->dn, "cn=%s", td->domain_name);
 	if (!ok) {
 		status = NT_STATUS_NO_MEMORY;
 		goto out;
@@ -3532,13 +3536,13 @@
 		return NT_STATUS_OK;
 	}
 
-	tdo_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+	tdo_dn = samdb_system_container_dn(state->ldb, tmp_ctx);
 	if (tdo_dn == NULL) {
 		status = NT_STATUS_NO_MEMORY;
 		goto out;
 	}
 
-	ok = ldb_dn_add_child_fmt(tdo_dn, "cn=%s,cn=System", domain);
+	ok = ldb_dn_add_child_fmt(tdo_dn, "cn=%s", domain);
 	if (!ok) {
 		TALLOC_FREE(tmp_ctx);
 		status = NT_STATUS_NO_MEMORY;
diff -Nru samba-4.17.10+dfsg/source3/rpc_server/mdssvc/marshalling.c samba-4.17.11+dfsg/source3/rpc_server/mdssvc/marshalling.c
--- samba-4.17.10+dfsg/source3/rpc_server/mdssvc/marshalling.c	2023-07-14 16:15:01.013234100 +0300
+++ samba-4.17.11+dfsg/source3/rpc_server/mdssvc/marshalling.c	2023-09-07 11:59:49.033451300 +0300
@@ -43,8 +43,8 @@
  * RPC data marshalling and unmarshalling
  ******************************************************************************/
 
-/* Spotlight epoch is UNIX epoch minus SPOTLIGHT_TIME_DELTA */
-#define SPOTLIGHT_TIME_DELTA 280878921600ULL
+/* Spotlight epoch is 1.1.2001 00:00 UTC */
+#define SPOTLIGHT_TIME_DELTA 978307200 /* Diff from UNIX epoch to Spotlight epoch */
 
 #define SQ_TYPE_NULL    0x0000
 #define SQ_TYPE_COMPLEX 0x0200
@@ -253,6 +253,10 @@
 {
 	uint64_t data;
 	uint64_t tag;
+	union {
+		double d;
+		uint64_t w;
+	} ieee_fp_union;
 
 	tag = sl_pack_tag(SQ_TYPE_DATE, 2, 1);
 	offset = sl_push_uint64_val(buf, offset, bufsize, tag);
@@ -260,7 +264,10 @@
 		return -1;
 	}
 
-	data = (t.tv_sec + SPOTLIGHT_TIME_DELTA) << 24;
+	ieee_fp_union.d = (double)(t.tv_sec - SPOTLIGHT_TIME_DELTA);
+	ieee_fp_union.d += (double)t.tv_usec / 1000000;
+
+	data = ieee_fp_union.w;
 	offset = sl_push_uint64_val(buf, offset, bufsize, data);
 	if (offset == -1) {
 		return -1;
@@ -723,6 +730,11 @@
 	int i, result;
 	struct sl_tag tag;
 	uint64_t query_data64;
+	union {
+		double d;
+		uint64_t w;
+	} ieee_fp_union;
+	double fraction;
 	sl_time_t t;
 
 	offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
@@ -735,9 +747,14 @@
 		if (offset == -1) {
 			return -1;
 		}
-		query_data64 = query_data64 >> 24;
-		t.tv_sec = query_data64 - SPOTLIGHT_TIME_DELTA;
-		t.tv_usec = 0;
+		ieee_fp_union.w = query_data64;
+		fraction = ieee_fp_union.d - (uint64_t)ieee_fp_union.d;
+
+		t = (sl_time_t) {
+			.tv_sec = ieee_fp_union.d + SPOTLIGHT_TIME_DELTA,
+			.tv_usec = fraction * 1000000
+		};
+
 		result = dalloc_add_copy(query, &t, sl_time_t);
 		if (result != 0) {
 			return -1;
diff -Nru samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc.c samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc.c
--- samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc.c	2023-07-14 16:15:01.053234600 +0300
+++ samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc.c	2023-09-07 11:59:49.033451300 +0300
@@ -188,8 +188,10 @@
 			if (result != 0) {
 				return false;
 			}
-		} else if (strcmp(attribute, "kMDItemFSContentChangeDate") == 0) {
-			sl_time.tv_sec = sp->st_ex_mtime.tv_sec;
+		} else if (strcmp(attribute, "kMDItemFSContentChangeDate") == 0 ||
+			strcmp(attribute, "kMDItemContentModificationDate") == 0)
+		{
+			sl_time = convert_timespec_to_timeval(sp->st_ex_mtime);
 			result = dalloc_add_copy(meta, &sl_time, sl_time_t);
 			if (result != 0) {
 				return false;
@@ -306,10 +308,21 @@
 static bool add_results(sl_array_t *array, struct sl_query *slq)
 {
 	sl_filemeta_t *fm;
-	uint64_t status = 0;
+	uint64_t status;
 	int result;
 	bool ok;
 
+	/*
+	 * Taken from network traces against a macOS SMB Spotlight server: if
+	 * the search is not finished yet in the backend macOS returns 0x23,
+	 * otherwise 0x0.
+	 */
+	if (slq->state >= SLQ_STATE_DONE) {
+		status = 0;
+	} else {
+		status = 0x23;
+	}
+
 	/* FileMeta */
 	fm = dalloc_zero(array, sl_filemeta_t);
 	if (fm == NULL) {
@@ -1126,7 +1139,7 @@
 			goto error;
 		}
 		if (slq->state == SLQ_STATE_FULL) {
-			slq->state = SLQ_STATE_RESULTS;
+			slq->state = SLQ_STATE_RUNNING;
 			slq->mds_ctx->backend->search_cont(slq);
 		}
 		break;
diff -Nru samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc_es.c samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc_es.c
--- samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc_es.c	2022-08-08 17:29:11.361506700 +0300
+++ samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc_es.c	2023-09-07 11:59:49.033451300 +0300
@@ -398,7 +398,7 @@
 		.ev = mds_es_ctx->mdssvc_es_ctx->mdssvc_ctx->ev_ctx,
 		.mds_es_ctx = mds_es_ctx,
 		.slq = slq,
-		.size = MAX_SL_RESULTS,
+		.size = SL_PAGESIZE,
 	};
 
 	/* 0 would mean no limit */
@@ -502,7 +502,7 @@
 		goto trigger;
 	}
 
-	if (slq->query_results->num_results >= MAX_SL_RESULTS) {
+	if (slq->query_results->num_results >= SL_PAGESIZE) {
 		slq->state = SLQ_STATE_FULL;
 		goto trigger;
 	}
@@ -693,7 +693,7 @@
 	subreq = http_read_response_send(state,
 					 state->ev,
 					 state->s->mds_es_ctx->http_conn,
-					 MAX_SL_RESULTS * 8192);
+					 SL_PAGESIZE * 8192);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -800,7 +800,7 @@
 	}
 	DBG_DEBUG("Hits: %zu\n", hits);
 
-	for (i = 0; i < hits; i++) {
+	for (i = 0; i < hits && s->from + i < s->max; i++) {
 		const char *path = NULL;
 
 		match = json_array_get(matches, i);
diff -Nru samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc.h samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc.h
--- samba-4.17.10+dfsg/source3/rpc_server/mdssvc/mdssvc.h	2023-07-14 16:15:01.053234600 +0300
+++ samba-4.17.11+dfsg/source3/rpc_server/mdssvc/mdssvc.h	2023-09-07 11:59:49.033451300 +0300
@@ -36,6 +36,7 @@
 
 #define MAX_SL_FRAGMENT_SIZE 0xFFFFF
 #define MAX_SL_RESULTS 100
+#define SL_PAGESIZE 50
 #define MAX_SL_RUNTIME 30
 #define MDS_TRACKER_ASYNC_TIMEOUT_MS 250
 
diff -Nru samba-4.17.10+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c samba-4.17.11+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c
--- samba-4.17.10+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c	2023-07-14 16:15:01.053234600 +0300
+++ samba-4.17.11+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c	2023-09-07 11:59:49.033451300 +0300
@@ -135,6 +135,7 @@
 	}
 
 	strlcpy(outpath, fake_path, 1024);
+	talloc_free(path);
 	talloc_free(fake_path);
 	return;
 }
diff -Nru samba-4.17.10+dfsg/source3/script/tests/test_bug15435_widelink_dfs.sh samba-4.17.11+dfsg/source3/script/tests/test_bug15435_widelink_dfs.sh
--- samba-4.17.10+dfsg/source3/script/tests/test_bug15435_widelink_dfs.sh	1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.11+dfsg/source3/script/tests/test_bug15435_widelink_dfs.sh	2023-09-07 11:59:49.033451300 +0300
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# regression test for dfs access with wide links enabled on dfs share
+
+if [ $# -lt 5 ]; then
+	cat <<EOF
+Usage: test_smbclient_basic.sh SERVER SERVER_IP DOMAIN USERNAME PASSWORD SMBCLIENT <smbclient arguments>
+EOF
+	exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+USERNAME="$3"
+PASSWORD="$4"
+smbclient="$5"
+CONFIGURATION="$6"
+shift 6
+ADDARGS="$@"
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+# TEST
+test_smbclient "smbclient as $DOMAIN\\$USERNAME" 'ls' "//$SERVER/msdfs-share-wl" -U$DOMAIN\\$USERNAME%$PASSWORD $ADDARGS -c 'cd msdfs-src1' || failed=$(expr $failed + 1)
+
+exit $failed
diff -Nru samba-4.17.10+dfsg/source3/selftest/tests.py samba-4.17.11+dfsg/source3/selftest/tests.py
--- samba-4.17.10+dfsg/source3/selftest/tests.py	2023-07-14 16:15:04.453269700 +0300
+++ samba-4.17.11+dfsg/source3/selftest/tests.py	2023-09-07 11:59:49.037451500 +0300
@@ -203,6 +203,39 @@
                "",
                "-l $LOCAL_PATH"])
 
+plantestsuite("samba3.smbtorture_s3.smb1.SMB1-TRUNCATED-SESSSETUP",
+                "fileserver_smb1",
+                [os.path.join(samba3srcdir,
+                              "script/tests/test_smbtorture_s3.sh"),
+                'SMB1-TRUNCATED-SESSSETUP',
+                '//$SERVER_IP/tmp',
+                '$USERNAME',
+                '$PASSWORD',
+                smbtorture3,
+                "-mNT1"])
+
+plantestsuite("samba3.smbtorture_s3.smb1.SMB1-NEGOTIATE-EXIT",
+                "fileserver_smb1",
+                [os.path.join(samba3srcdir,
+                              "script/tests/test_smbtorture_s3.sh"),
+                'SMB1-NEGOTIATE-EXIT',
+                '//$SERVER_IP/tmp',
+                '$USERNAME',
+                '$PASSWORD',
+                smbtorture3,
+                "-mNT1"])
+
+plantestsuite("samba3.smbtorture_s3.smb1.SMB1-NEGOTIATE-TCON",
+                "fileserver_smb1",
+                [os.path.join(samba3srcdir,
+                              "script/tests/test_smbtorture_s3.sh"),
+                'SMB1-NEGOTIATE-TCON',
+                '//$SERVER_IP/tmp',
+                '$USERNAME',
+                '$PASSWORD',
+                smbtorture3,
+                "-mNT1"])
+
 #
 # MSDFS attribute tests.
 #
@@ -1515,6 +1548,16 @@
      "",
      "-b $PREFIX/clusteredmember/unclists/tmp.txt -N 5 -o 10"])
 
+plantestsuite("samba3.blackbox.smbclient-bug15435",
+              "fileserver",
+              [os.path.join(samba3srcdir, "script/tests/test_bug15435_widelink_dfs.sh"),
+               "$SERVER",
+               "$SERVER_IP",
+               "$USERNAME",
+               "$PASSWORD",
+               smbclient3,
+               configuration])
+
 plantestsuite(
     "samba3.net_machine_account",
     "clusteredmember",
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb1_ipc.c samba-4.17.11+dfsg/source3/smbd/smb1_ipc.c
--- samba-4.17.10+dfsg/source3/smbd/smb1_ipc.c	2022-08-08 17:15:39.480193000 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb1_ipc.c	2023-09-07 11:59:49.037451500 +0300
@@ -688,7 +688,7 @@
 		return;
 	}
 
-	if ((state = talloc(conn, struct trans_state)) == NULL) {
+	if ((state = talloc_zero(conn, struct trans_state)) == NULL) {
 		DEBUG(0, ("talloc failed\n"));
 		reply_nterror(req, NT_STATUS_NO_MEMORY);
 		END_PROFILE(SMBtrans);
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb1_message.c samba-4.17.11+dfsg/source3/smbd/smb1_message.c
--- samba-4.17.10+dfsg/source3/smbd/smb1_message.c	2022-08-08 17:15:39.484192800 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb1_message.c	2023-09-07 11:59:49.037451500 +0300
@@ -161,7 +161,7 @@
 		return;
 	}
 
-	state = talloc(talloc_tos(), struct msg_state);
+	state = talloc_zero(talloc_tos(), struct msg_state);
 
 	p = req->buf + 1;
 	p += srvstr_pull_req_talloc(
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb1_reply.c samba-4.17.11+dfsg/source3/smbd/smb1_reply.c
--- samba-4.17.10+dfsg/source3/smbd/smb1_reply.c	2022-08-08 17:29:11.369506800 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb1_reply.c	2023-09-07 11:59:49.037451500 +0300
@@ -4661,6 +4661,7 @@
 		reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
 		smb_request_done(smb1req);
 		END_PROFILE(SMBexit);
+		return;
 	}
 
 	/*
@@ -4700,6 +4701,7 @@
 			reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
 			smb_request_done(smb1req);
 			END_PROFILE(SMBexit);
+			return;
 		}
 		close_file_free(NULL, &fsp, SHUTDOWN_CLOSE);
 	}
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb1_sesssetup.c samba-4.17.11+dfsg/source3/smbd/smb1_sesssetup.c
--- samba-4.17.10+dfsg/source3/smbd/smb1_sesssetup.c	2022-08-08 17:15:39.484192800 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb1_sesssetup.c	2023-09-07 11:59:49.037451500 +0300
@@ -86,7 +86,7 @@
 	DATA_BLOB in_blob;
 	DATA_BLOB out_blob = data_blob_null;
 	size_t bufrem;
-	char *tmp;
+	char *tmp = NULL;
 	const char *native_os;
 	const char *native_lanman;
 	const char *primary_domain;
@@ -581,7 +581,7 @@
 	struct reply_sesssetup_and_X_state *state = NULL;
 	uint64_t sess_vuid;
 	uint16_t smb_bufsize;
-	char *tmp;
+	char *tmp = NULL;
 	fstring sub_user; /* Sanitised username for substitution */
 	const char *native_os;
 	const char *native_lanman;
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb2_close.c samba-4.17.11+dfsg/source3/smbd/smb2_close.c
--- samba-4.17.10+dfsg/source3/smbd/smb2_close.c	2022-08-08 17:15:39.488193000 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb2_close.c	2023-09-07 11:59:49.037451500 +0300
@@ -225,6 +225,8 @@
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
 			 smb_fname_str_dbg(smb_fname), nt_errstr(status)));
+		file_free(smbreq, fsp);
+		*_fsp = fsp = NULL;
 		return status;
 	}
 
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb2_process.c samba-4.17.11+dfsg/source3/smbd/smb2_process.c
--- samba-4.17.10+dfsg/source3/smbd/smb2_process.c	2022-08-08 17:15:39.488193000 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb2_process.c	2023-09-07 11:59:49.041451700 +0300
@@ -764,6 +764,8 @@
 		return false;
 	}
 
+	*req = (struct smb_request) { .cmd = 0};
+
 	req->request_time = timeval_current();
 	now = timeval_to_nttime(&req->request_time);
 
@@ -782,16 +784,12 @@
 	req->encrypted = encrypted;
 	req->sconn = sconn;
 	req->xconn = xconn;
-	req->conn = NULL;
 	if (xconn != NULL) {
 		status = smb1srv_tcon_lookup(xconn, req->tid, now, &tcon);
 		if (NT_STATUS_IS_OK(status)) {
 			req->conn = tcon->compat;
 		}
 	}
-	req->chain_fsp = NULL;
-	req->smb2req = NULL;
-	req->chain = NULL;
 	req->posix_pathnames = lp_posix_pathnames();
 	smb_init_perfcount_data(&req->pcd);
 
@@ -812,7 +810,6 @@
 		return false;
 	}
 
-	req->outbuf = NULL;
 	return true;
 }
 
diff -Nru samba-4.17.10+dfsg/source3/smbd/smb2_reply.c samba-4.17.11+dfsg/source3/smbd/smb2_reply.c
--- samba-4.17.10+dfsg/source3/smbd/smb2_reply.c	2022-08-16 23:15:21.296624400 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smb2_reply.c	2023-09-07 11:59:49.041451700 +0300
@@ -335,6 +335,7 @@
 		char *share = NULL;
 		char *remaining_path = NULL;
 		char path_sep = 0;
+		char *p = NULL;
 
 		if (posix_pathnames && (dst[0] == '/')) {
 			path_sep = dst[0];
@@ -386,6 +387,16 @@
 			goto local_path;
 		}
 		/*
+		 * Ensure the server name does not contain
+		 * any possible path components by converting
+		 * them to _'s.
+		 */
+		for (p = server + 1; p < share; p++) {
+			if (*p == '/' || *p == '\\') {
+				*p = '_';
+			}
+		}
+		/*
 		 * It's a well formed DFS path with
 		 * at least server and share components.
 		 * Replace the slashes with '/' and
@@ -400,12 +411,32 @@
 		remaining_path = strchr(share+1, path_sep);
 		if (remaining_path == NULL) {
 			/*
+			 * Ensure the share name does not contain
+			 * any possible path components by converting
+			 * them to _'s.
+			 */
+			for (p = share + 1; *p; p++) {
+				if (*p == '/' || *p == '\\') {
+					*p = '_';
+				}
+			}
+			/*
 			 * If no remaining path this was
 			 * a bare /server/share path. Just return.
 			 */
 			*err = NT_STATUS_OK;
 			return ret;
 		}
+		/*
+		 * Ensure the share name does not contain
+		 * any possible path components by converting
+		 * them to _'s.
+		 */
+		for (p = share + 1; p < remaining_path; p++) {
+			if (*p == '/' || *p == '\\') {
+				*p = '_';
+			}
+		}
 		*remaining_path = '/';
 		dst = remaining_path + 1;
 		/* dst now points at any following components. */
@@ -517,6 +548,7 @@
 	ssize_t bufrem = smbreq_bufrem(req, src);
 
 	if (bufrem == 0) {
+		*dest = NULL;
 		return 0;
 	}
 
diff -Nru samba-4.17.10+dfsg/source3/smbd/smbXsrv_client.c samba-4.17.11+dfsg/source3/smbd/smbXsrv_client.c
--- samba-4.17.10+dfsg/source3/smbd/smbXsrv_client.c	2022-10-19 15:14:56.032195800 +0300
+++ samba-4.17.11+dfsg/source3/smbd/smbXsrv_client.c	2023-09-07 11:59:49.041451700 +0300
@@ -487,6 +487,7 @@
 	struct tevent_context *ev;
 	struct smbd_smb2_request *smb2req;
 	struct db_record *db_rec;
+	struct server_id sent_server_id;
 	uint64_t watch_instance;
 	uint32_t last_seqnum;
 	struct tevent_req *filter_subreq;
@@ -529,6 +530,8 @@
 
 	tevent_req_set_cleanup_fn(req, smb2srv_client_mc_negprot_cleanup);
 
+	server_id_set_disconnected(&state->sent_server_id);
+
 	smb2srv_client_mc_negprot_next(req);
 
 	if (!tevent_req_is_in_progress(req)) {
@@ -554,7 +557,6 @@
 	uint32_t seqnum = 0;
 	struct server_id last_server_id = { .pid = 0, };
 
-	TALLOC_FREE(state->filter_subreq);
 	SMB_ASSERT(state->db_rec == NULL);
 	state->db_rec = smbXsrv_client_global_fetch_locked(table->global.db_ctx,
 							   &client_guid,
@@ -625,6 +627,30 @@
 		return;
 	}
 
+	if (server_id_equal(&state->sent_server_id, &global->server_id)) {
+		/*
+		 * We hit a race with other concurrent connections,
+		 * which have woken us.
+		 *
+		 * We already sent the pass or drop message to
+		 * the process, so we need to wait for a
+		 * response and not pass the connection
+		 * again! Otherwise the process would
+		 * receive the same tcp connection via
+		 * more than one file descriptor and
+		 * create more than one smbXsrv_connection
+		 * structure for the same tcp connection,
+		 * which means the client would see more
+		 * than one SMB2 negprot response to its
+		 * single SMB2 netprot request and we
+		 * as server get the session keys and
+		 * message id validation wrong
+		 */
+		goto watch_again;
+	}
+
+	server_id_set_disconnected(&state->sent_server_id);
+
 	/*
 	 * If last_server_id is set, we expect
 	 * smbXsrv_client_global_verify_record()
@@ -635,6 +661,7 @@
 	SMB_ASSERT(last_server_id.pid == 0);
 	last_server_id = global->server_id;
 
+	TALLOC_FREE(state->filter_subreq);
 	if (procid_is_local(&global->server_id)) {
 		subreq = messaging_filtered_read_send(state,
 						      state->ev,
@@ -659,6 +686,7 @@
 			 */
 			goto verify_again;
 		}
+		state->sent_server_id = global->server_id;
 		if (tevent_req_nterror(req, status)) {
 			return;
 		}
@@ -673,11 +701,14 @@
 			 */
 			goto verify_again;
 		}
+		state->sent_server_id = global->server_id;
 		if (tevent_req_nterror(req, status)) {
 			return;
 		}
 	}
 
+watch_again:
+
 	/*
 	 * If the record changed, but we are not happy with the change yet,
 	 * we better remove ourself from the waiter list
diff -Nru samba-4.17.10+dfsg/source3/torture/torture.c samba-4.17.11+dfsg/source3/torture/torture.c
--- samba-4.17.10+dfsg/source3/torture/torture.c	2023-03-09 12:18:38.357810700 +0300
+++ samba-4.17.11+dfsg/source3/torture/torture.c	2023-09-07 11:59:49.045451900 +0300
@@ -3953,8 +3953,15 @@
 	for (i=0;i<50000;i++) {
 		struct tevent_req *req;
 
-		req = smbXcli_negprot_send(ev, ev, cli->conn, cli->timeout,
-					   PROTOCOL_CORE, PROTOCOL_NT1, 0);
+		req = smbXcli_negprot_send(
+			ev,
+			ev,
+			cli->conn,
+			cli->timeout,
+			PROTOCOL_CORE,
+			PROTOCOL_NT1,
+			0,
+			NULL);
 		if (req == NULL) {
 			TALLOC_FREE(ev);
 			return false;
@@ -14638,6 +14645,395 @@
 	}
 	return true;
 }
+struct session_setup_nt1_truncated_state {
+	uint16_t vwv[13];
+	uint8_t bytes[20];
+};
+
+static void smb1_session_setup_nt1_truncated_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb1_session_setup_nt1_truncated_send(
+		TALLOC_CTX *mem_ctx,
+		struct tevent_context *ev,
+		struct smbXcli_conn *conn)
+{
+	uint16_t *vwv = NULL;
+	uint8_t *bytes = NULL;
+	const char *pass = "12345678";
+	const char *uname = "z";
+	struct session_setup_nt1_truncated_state *state = NULL;
+	struct tevent_req *req = NULL;
+	struct tevent_req *subreq = NULL;
+
+	req = tevent_req_create(mem_ctx,
+				&state,
+				struct session_setup_nt1_truncated_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	vwv = &state->vwv[0];
+	bytes = &state->bytes[0];
+
+	SCVAL(vwv+0,  0, 0xff);
+	SCVAL(vwv+0,  1, 0);
+	SSVAL(vwv+1,  0, 0);
+	SSVAL(vwv+2,  0, 8192);
+	SSVAL(vwv+3,  0, 2);
+	SSVAL(vwv+4,  0, 1);
+	SIVAL(vwv+5,  0, 0);
+	SSVAL(vwv+7,  0, strlen(pass)); /* OEMPasswordLen */
+	SSVAL(vwv+8,  0, 0); /* UnicodePasswordLen */
+	SSVAL(vwv+9,  0, 0); /* reserved */
+	SSVAL(vwv+10, 0, 0); /* reserved */
+	SIVAL(vwv+11, 0, CAP_STATUS32);
+
+	memcpy(bytes, pass, strlen(pass));
+	bytes += strlen(pass);
+	memcpy(bytes, uname, strlen(uname)+1);
+
+	subreq = smb1cli_req_send(state, ev, conn,
+				  SMBsesssetupX,
+				  0, /*  additional_flags */
+				  0, /*  clear_flags */
+				  0, /*  additional_flags2 */
+				  0, /*  clear_flags2 */
+				  10000, /* timeout_msec */
+				  getpid(),
+				  NULL, /* tcon */
+				  NULL, /* session */
+				  13, /* wct */
+				  state->vwv,
+				  strlen(pass), /* Truncate length at password. */
+				  state->bytes);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				smb1_session_setup_nt1_truncated_done,
+				req);
+	return req;
+}
+
+static void smb1_session_setup_nt1_truncated_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct session_setup_nt1_truncated_state *state =
+		tevent_req_data(req,
+		struct session_setup_nt1_truncated_state);
+	NTSTATUS status;
+	struct smb1cli_req_expected_response expected[] = {
+	{
+		.status = NT_STATUS_OK,
+		.wct    = 3,
+	},
+	};
+
+	status = smb1cli_req_recv(subreq, state,
+				  NULL,
+				  NULL,
+				  NULL,
+				  NULL,
+				  NULL, /* pvwv_offset */
+				  NULL,
+				  NULL,
+				  NULL, /* pbytes_offset */
+				  NULL,
+				  expected, ARRAY_SIZE(expected));
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static NTSTATUS smb1_session_setup_nt1_truncated_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool run_smb1_truncated_sesssetup(int dummy)
+{
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	struct smbXcli_conn *conn;
+	struct sockaddr_storage ss;
+	NTSTATUS status;
+	int fd;
+	bool ok;
+
+	printf("Starting send truncated SMB1 sesssetup.\n");
+
+	ok = resolve_name(host, &ss, 0x20, true);
+	if (!ok) {
+		d_fprintf(stderr, "Could not resolve name %s\n", host);
+		return false;
+	}
+
+	status = open_socket_out(&ss, 445, 10000, &fd);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "open_socket_out failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	conn = smbXcli_conn_create(talloc_tos(), fd, host, SMB_SIGNING_OFF, 0,
+				   NULL, 0, NULL);
+	if (conn == NULL) {
+		d_fprintf(stderr, "smbXcli_conn_create failed\n");
+		return false;
+	}
+
+	status = smbXcli_negprot(conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "smbXcli_negprot failed!\n");
+		return false;
+	}
+
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		d_fprintf(stderr, "samba_tevent_context_init failed\n");
+		return false;
+	}
+
+	req = smb1_session_setup_nt1_truncated_send(ev, ev, conn);
+	if (req == NULL) {
+		d_fprintf(stderr, "smb1_session_setup_nt1_truncated_send failed\n");
+		return false;
+	}
+
+	ok = tevent_req_poll_ntstatus(req, ev, &status);
+	if (!ok) {
+		d_fprintf(stderr, "tevent_req_poll failed with status %s\n",
+			nt_errstr(status));
+		return false;
+	}
+
+	status = smb1_session_setup_nt1_truncated_recv(req);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "smb1_session_setup_nt1_truncated_recv returned "
+			  "%s, expected NT_STATUS_OK\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	TALLOC_FREE(conn);
+	return true;
+}
+
+struct smb1_negotiate_exit_state {
+	int dummy;
+};
+
+static void smb1_negotiate_exit_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb1_negotiate_exit_send(
+		TALLOC_CTX *mem_ctx,
+		struct tevent_context *ev,
+		struct smbXcli_conn *conn)
+{
+	struct smb1_negotiate_exit_state *state = NULL;
+	struct tevent_req *req = NULL;
+	struct tevent_req *subreq = NULL;
+
+	req = tevent_req_create(mem_ctx,
+				&state,
+				struct smb1_negotiate_exit_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	subreq = smb1cli_req_send(state, ev, conn,
+				  SMBexit,
+				  0, /*  additional_flags */
+				  0, /*  clear_flags */
+				  0, /*  additional_flags2 */
+				  0, /*  clear_flags2 */
+				  10000, /* timeout_msec */
+				  getpid(),
+				  NULL, /* tcon */
+				  NULL, /* session */
+				  0, /* wct */
+				  NULL,
+				  0,
+				  NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				smb1_negotiate_exit_done,
+				req);
+	return req;
+}
+
+static void smb1_negotiate_exit_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct smb1_negotiate_exit_state *state =
+		tevent_req_data(req,
+		struct smb1_negotiate_exit_state);
+	NTSTATUS status;
+	struct smb1cli_req_expected_response expected[] = {
+	{
+		.status = NT_STATUS_OK,
+		.wct    = 0,
+	},
+	};
+
+	status = smb1cli_req_recv(subreq, state,
+				  NULL,
+				  NULL,
+				  NULL,
+				  NULL,
+				  NULL, /* pvwv_offset */
+				  NULL,
+				  NULL,
+				  NULL, /* pbytes_offset */
+				  NULL,
+				  expected, ARRAY_SIZE(expected));
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static NTSTATUS smb1_negotiate_exit_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool do_smb1_exit(TALLOC_CTX *mem_ctx,
+			 struct tevent_context *ev,
+			 struct smbXcli_conn *conn)
+{
+	struct tevent_req *req;
+	bool ok;
+	NTSTATUS status;
+	NTSTATUS expected_status = NT_STATUS_DOS(ERRSRV, ERRinvnid);;
+
+	req = smb1_negotiate_exit_send(ev, ev, conn);
+	if (req == NULL) {
+		d_fprintf(stderr, "smb1_negotiate_exit_send failed\n");
+		return false;
+	}
+
+	ok = tevent_req_poll_ntstatus(req, ev, &status);
+	if (!ok) {
+		d_fprintf(stderr, "tevent_req_poll failed with status %s\n",
+			nt_errstr(status));
+		return false;
+	}
+
+	status = smb1_negotiate_exit_recv(req);
+	if (!NT_STATUS_EQUAL(status, expected_status)) {
+		d_fprintf(stderr, "smb1_negotiate_exit_recv returned "
+			  "%s, expected ERRSRV, ERRinvnid\n",
+			  nt_errstr(status));
+		return false;
+	}
+	return true;
+}
+
+static bool run_smb1_negotiate_exit(int dummy)
+{
+	struct tevent_context *ev;
+	struct smbXcli_conn *conn;
+	struct sockaddr_storage ss;
+	NTSTATUS status;
+	int fd;
+	bool ok;
+
+	printf("Starting send SMB1 negotiate+exit.\n");
+
+	ok = resolve_name(host, &ss, 0x20, true);
+	if (!ok) {
+		d_fprintf(stderr, "Could not resolve name %s\n", host);
+		return false;
+	}
+
+	status = open_socket_out(&ss, 445, 10000, &fd);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "open_socket_out failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	conn = smbXcli_conn_create(talloc_tos(), fd, host, SMB_SIGNING_OFF, 0,
+				   NULL, 0, NULL);
+	if (conn == NULL) {
+		d_fprintf(stderr, "smbXcli_conn_create failed\n");
+		return false;
+	}
+
+	status = smbXcli_negprot(conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "smbXcli_negprot failed!\n");
+		return false;
+	}
+
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		d_fprintf(stderr, "samba_tevent_context_init failed\n");
+		return false;
+	}
+
+	/*
+	 * Call do_smb1_exit twice to catch a server crash, the
+	 * server sends the first return code then crashes.
+	 */
+	ok = do_smb1_exit(ev, ev, conn);
+	if (!ok) {
+		d_fprintf(stderr, "do_smb1_exit (1) failed\n");
+		return false;
+	}
+	ok = do_smb1_exit(ev, ev, conn);
+	if (!ok) {
+		d_fprintf(stderr, "do_smb1_exit (2) failed\n");
+		return false;
+	}
+
+	TALLOC_FREE(conn);
+	return true;
+}
+
+static bool run_smb1_negotiate_tcon(int dummy)
+{
+	struct cli_state *cli = NULL;
+	uint16_t cnum = 0;
+	uint16_t max_xmit = 0;
+	NTSTATUS status;
+
+	printf("Starting send SMB1 negotiate+tcon.\n");
+	cli = open_nbt_connection();
+	if (cli == NULL) {
+		d_fprintf(stderr, "open_nbt_connection failed!\n");
+		return false;
+	}
+	smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+	status = smbXcli_negprot(cli->conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr, "smbXcli_negprot failed %s!\n",
+			nt_errstr(status));
+		return false;
+	}
+        status = cli_raw_tcon(cli,
+			      share,
+			      "",
+			      "?????",
+			      &max_xmit,
+			      &cnum);
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		d_fprintf(stderr, "cli_raw_tcon failed - got %s "
+			"(should get NT_STATUS_ACCESS_DENIED)!\n",
+			nt_errstr(status));
+		return false;
+	}
+	return true;
+}
 
 static bool run_ign_bad_negprot(int dummy)
 {
@@ -14714,6 +15110,7 @@
 	return true;
 }
 
+
 static double create_procs(bool (*fn)(int), bool *result)
 {
 	int i, status;
@@ -15367,6 +15764,18 @@
 		.fn    = run_oplock_cancel,
 	},
 	{
+		.name  = "SMB1-TRUNCATED-SESSSETUP",
+		.fn    = run_smb1_truncated_sesssetup,
+	},
+	{
+		.name  = "SMB1-NEGOTIATE-EXIT",
+		.fn    = run_smb1_negotiate_exit,
+	},
+	{
+		.name  = "SMB1-NEGOTIATE-TCON",
+		.fn    = run_smb1_negotiate_tcon,
+	},
+	{
 		.name  = "PIDHIGH",
 		.fn    = run_pidhigh,
 	},
diff -Nru samba-4.17.10+dfsg/source3/utils/net_ads.c samba-4.17.11+dfsg/source3/utils/net_ads.c
--- samba-4.17.10+dfsg/source3/utils/net_ads.c	2023-05-11 10:07:19.602421000 +0300
+++ samba-4.17.11+dfsg/source3/utils/net_ads.c	2023-09-07 11:59:49.045451900 +0300
@@ -713,10 +713,12 @@
 	} else if (ads->auth.realm == NULL) {
 		const char *c_realm = cli_credentials_get_realm(c->creds);
 
-		ads->auth.realm = talloc_strdup(ads, c_realm);
-		if (ads->auth.realm == NULL) {
-			TALLOC_FREE(ads);
-			return ADS_ERROR(LDAP_NO_MEMORY);
+		if (c_realm != NULL) {
+			ads->auth.realm = talloc_strdup(ads, c_realm);
+			if (ads->auth.realm == NULL) {
+				TALLOC_FREE(ads);
+				return ADS_ERROR(LDAP_NO_MEMORY);
+			}
 		}
 	}
 
diff -Nru samba-4.17.10+dfsg/source4/dsdb/common/dsdb_dn.c samba-4.17.11+dfsg/source4/dsdb/common/dsdb_dn.c
--- samba-4.17.10+dfsg/source4/dsdb/common/dsdb_dn.c	2023-03-09 12:18:38.361810200 +0300
+++ samba-4.17.11+dfsg/source4/dsdb/common/dsdb_dn.c	2023-09-07 11:59:49.045451900 +0300
@@ -554,6 +554,18 @@
 						 new_dn,
 						 normalised_dn,
 						 nc_root);
+	if (ret != LDB_SUCCESS) {
+		/*
+		 * dsdb_normalise_dn_and_find_nc_root() sets LDB error
+		 * strings, and the functions it calls do also
+		 */
+		DBG_NOTICE("Failed to find DN \"%s\" -> \"%s\" for normalisation: %s (%s)\n",
+			   drs_ObjectIdentifier_to_debug_string(mem_ctx, nc),
+			   ldb_dn_get_extended_linearized(mem_ctx, new_dn, 1),
+			   ldb_errstring(ldb),
+			   ldb_strerror(ret));
+	}
+
 	TALLOC_FREE(new_dn);
 	return ret;
 }
diff -Nru samba-4.17.10+dfsg/source4/dsdb/common/util.c samba-4.17.11+dfsg/source4/dsdb/common/util.c
--- samba-4.17.10+dfsg/source4/dsdb/common/util.c	2023-03-29 17:28:07.068394400 +0300
+++ samba-4.17.11+dfsg/source4/dsdb/common/util.c	2023-09-07 11:59:49.049452000 +0300
@@ -1241,6 +1241,25 @@
        return new_dn;
 }
 
+struct ldb_dn *samdb_system_container_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
+{
+	struct ldb_dn *new_dn = NULL;
+	bool ok;
+
+	new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
+	if (new_dn == NULL) {
+		return NULL;
+	}
+
+	ok = ldb_dn_add_child_fmt(new_dn, "CN=System");
+	if (!ok) {
+		TALLOC_FREE(new_dn);
+		return NULL;
+	}
+
+	return new_dn;
+}
+
 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
 {
 	struct ldb_dn *new_dn;
diff -Nru samba-4.17.10+dfsg/source4/dsdb/common/util_trusts.c samba-4.17.11+dfsg/source4/dsdb/common/util_trusts.c
--- samba-4.17.10+dfsg/source4/dsdb/common/util_trusts.c	2022-08-08 17:15:39.544193300 +0300
+++ samba-4.17.11+dfsg/source4/dsdb/common/util_trusts.c	2023-09-07 11:59:49.049452000 +0300
@@ -2459,17 +2459,12 @@
 		return NT_STATUS_INVALID_PARAMETER_MIX;
 	}
 
-	system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
+	system_dn = samdb_system_container_dn(sam_ctx, frame);
 	if (system_dn == NULL) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_NO_MEMORY;
-	}
-
 	if (netbios != NULL) {
 		netbios_encoded = ldb_binary_encode_string(frame, netbios);
 		if (netbios_encoded == NULL) {
@@ -2617,17 +2612,12 @@
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
+	system_dn = samdb_system_container_dn(sam_ctx, frame);
 	if (system_dn == NULL) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_NO_MEMORY;
-	}
-
 	filter = talloc_asprintf(frame,
 				"(&"
 				  "(objectClass=trustedDomain)"
@@ -2794,16 +2784,11 @@
 
 	*res = NULL;
 
-	system_dn = ldb_dn_copy(frame, ldb_get_default_basedn(sam_ctx));
+	system_dn = samdb_system_container_dn(sam_ctx, frame);
 	if (system_dn == NULL) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
-
-	if (!ldb_dn_add_child_fmt(system_dn, "CN=System")) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_NO_MEMORY;
-	}
 
 	if (exclude != NULL) {
 		exclude_encoded = ldb_binary_encode_string(frame, exclude);
diff -Nru samba-4.17.10+dfsg/source4/dsdb/samdb/ldb_modules/operational.c samba-4.17.11+dfsg/source4/dsdb/samdb/ldb_modules/operational.c
--- samba-4.17.10+dfsg/source4/dsdb/samdb/ldb_modules/operational.c	2022-08-08 17:15:39.552193400 +0300
+++ samba-4.17.11+dfsg/source4/dsdb/samdb/ldb_modules/operational.c	2023-09-07 11:59:49.049452000 +0300
@@ -998,19 +998,20 @@
 {
 	static const char * const attrs[] = { NULL };
 	int ret;
-	struct ldb_dn *domain_dn = NULL;
 	struct ldb_dn *psc_dn = NULL;
 	struct ldb_result *res = NULL;
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
+	bool psc_ok;
 
 	*pso_count = 0;
-	domain_dn = ldb_get_default_basedn(ldb);
-	psc_dn = ldb_dn_new_fmt(mem_ctx, ldb,
-			        "CN=Password Settings Container,CN=System,%s",
-				ldb_dn_get_linearized(domain_dn));
+	psc_dn = samdb_system_container_dn(ldb, mem_ctx);
 	if (psc_dn == NULL) {
 		return ldb_oom(ldb);
 	}
+	psc_ok = ldb_dn_add_child_fmt(psc_dn, "CN=Password Settings Container");
+	if (psc_ok == false) {
+		return ldb_oom(ldb);
+	}
 
 	/* get the number of PSO children */
 	ret = dsdb_module_search(module, mem_ctx, &res, psc_dn,
@@ -1077,8 +1078,8 @@
 	int i;
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
 	char *sid_filter = NULL;
-	struct ldb_dn *domain_dn = NULL;
 	struct ldb_dn *psc_dn = NULL;
+	bool psc_ok;
 	const char *attrs[] = {
 		"msDS-PasswordSettingsPrecedence",
 		"objectGUID",
@@ -1104,13 +1105,14 @@
 	}
 
 	/* only PSOs located in the Password Settings Container are valid */
-	domain_dn = ldb_get_default_basedn(ldb);
-	psc_dn = ldb_dn_new_fmt(mem_ctx, ldb,
-			        "CN=Password Settings Container,CN=System,%s",
-				ldb_dn_get_linearized(domain_dn));
+	psc_dn = samdb_system_container_dn(ldb, mem_ctx);
 	if (psc_dn == NULL) {
 		return ldb_oom(ldb);
 	}
+	psc_ok = ldb_dn_add_child_fmt(psc_dn, "CN=Password Settings Container");
+	if (psc_ok == false) {
+		return ldb_oom(ldb);
+	}
 
 	ret = dsdb_module_search(module, mem_ctx, result, psc_dn,
 				 LDB_SCOPE_ONELEVEL, attrs,
diff -Nru samba-4.17.10+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c samba-4.17.11+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c
--- samba-4.17.10+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c	2022-08-08 17:15:39.560193500 +0300
+++ samba-4.17.11+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c	2023-09-07 11:59:49.049452000 +0300
@@ -5390,14 +5390,9 @@
 
 	/* Objects under CN=System */
 
-	dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
+	dn1 = samdb_system_container_dn(ldb, ac);
 	if (dn1 == NULL) return ldb_oom(ldb);
 
-	if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
-		talloc_free(dn1);
-		return LDB_ERR_OPERATIONS_ERROR;
-	}
-
 	if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
 	    (ldb_dn_compare_base(dn1, newdn) != 0)) {
 		talloc_free(dn1);
diff -Nru samba-4.17.10+dfsg/source4/libcli/raw/rawnegotiate.c samba-4.17.11+dfsg/source4/libcli/raw/rawnegotiate.c
--- samba-4.17.10+dfsg/source4/libcli/raw/rawnegotiate.c	2022-08-08 17:15:39.604194000 +0300
+++ samba-4.17.11+dfsg/source4/libcli/raw/rawnegotiate.c	2023-09-07 11:59:49.053452300 +0300
@@ -106,7 +106,8 @@
 				      timeout_msec,
 				      minprotocol,
 				      maxprotocol,
-				      transport->options.max_credits);
+				      transport->options.max_credits,
+				      NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -125,7 +126,7 @@
 		struct smb_raw_negotiate_state);
 	NTSTATUS status;
 
-	status = smbXcli_negprot_recv(subreq);
+	status = smbXcli_negprot_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
diff -Nru samba-4.17.10+dfsg/source4/libcli/smb2/connect.c samba-4.17.11+dfsg/source4/libcli/smb2/connect.c
--- samba-4.17.10+dfsg/source4/libcli/smb2/connect.c	2022-08-08 17:15:39.608193900 +0300
+++ samba-4.17.11+dfsg/source4/libcli/smb2/connect.c	2023-09-07 11:59:49.053452300 +0300
@@ -187,7 +187,8 @@
 				      state->transport->conn, timeout_msec,
 				      min_protocol,
 				      state->transport->options.max_protocol,
-				      state->transport->options.max_credits);
+				      state->transport->options.max_credits,
+				      NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -203,7 +204,7 @@
 		struct tevent_req);
 	NTSTATUS status;
 
-	status = smbXcli_negprot_recv(subreq);
+	status = smbXcli_negprot_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
@@ -404,6 +405,7 @@
 			  const char *share,
 			  struct resolve_context *resolve_ctx,
 			  struct cli_credentials *credentials,
+			  struct smbXcli_conn **existing_conn,
 			  uint64_t previous_session_id,
 			  struct smb2_tree **tree,
 			  struct tevent_context *ev,
@@ -428,7 +430,7 @@
 				   resolve_ctx,
 				   credentials,
 				   false, /* fallback_to_anonymous */
-				   NULL, /* existing_conn */
+				   existing_conn,
 				   previous_session_id,
 				   options,
 				   socket_options,
@@ -472,6 +474,7 @@
 
 	status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
 				  credentials,
+				  NULL, /* existing_conn */
 				  0, /* previous_session_id */
 				  tree, ev, options, socket_options,
 				  gensec_settings);
diff -Nru samba-4.17.10+dfsg/source4/libcli/smb_composite/connect_nego.c samba-4.17.11+dfsg/source4/libcli/smb_composite/connect_nego.c
--- samba-4.17.10+dfsg/source4/libcli/smb_composite/connect_nego.c	2022-08-08 17:15:39.608193900 +0300
+++ samba-4.17.11+dfsg/source4/libcli/smb_composite/connect_nego.c	2023-09-07 11:59:49.053452300 +0300
@@ -167,7 +167,8 @@
 				      timeout_msec,
 				      state->options.min_protocol,
 				      state->options.max_protocol,
-				      state->options.max_credits);
+				      state->options.max_credits,
+				      NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		return;
 	}
@@ -181,7 +182,7 @@
 		struct tevent_req);
 	NTSTATUS status;
 
-	status = smbXcli_negprot_recv(subreq);
+	status = smbXcli_negprot_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
diff -Nru samba-4.17.10+dfsg/source4/rpc_server/backupkey/dcesrv_backupkey.c samba-4.17.11+dfsg/source4/rpc_server/backupkey/dcesrv_backupkey.c
--- samba-4.17.10+dfsg/source4/rpc_server/backupkey/dcesrv_backupkey.c	2022-08-08 17:15:39.632194000 +0300
+++ samba-4.17.11+dfsg/source4/rpc_server/backupkey/dcesrv_backupkey.c	2023-09-07 11:59:49.053452300 +0300
@@ -59,10 +59,10 @@
 			       const char *name,
 			       const DATA_BLOB *lsa_secret)
 {
+	TALLOC_CTX *frame = talloc_stackframe();
 	struct ldb_message *msg;
 	struct ldb_result *res;
-	struct ldb_dn *domain_dn;
-	struct ldb_dn *system_dn;
+	struct ldb_dn *system_dn = NULL;
 	struct ldb_val val;
 	int ret;
 	char *name2;
@@ -72,13 +72,9 @@
 		NULL
 	};
 
-	domain_dn = ldb_get_default_basedn(ldb);
-	if (!domain_dn) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	msg = ldb_msg_new(mem_ctx);
+	msg = ldb_msg_new(frame);
 	if (msg == NULL) {
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -92,15 +88,15 @@
 	 * * taillor the function to the particular needs of backup protocol
 	 */
 
-	system_dn = samdb_search_dn(ldb, msg, domain_dn, "(&(objectClass=container)(cn=System))");
+	system_dn = samdb_system_container_dn(ldb, frame);
 	if (system_dn == NULL) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
 	name2 = talloc_asprintf(msg, "%s Secret", name);
 	if (name2 == NULL) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -110,7 +106,7 @@
 
 	if (ret != LDB_SUCCESS ||  res->count != 0 ) {
 		DEBUG(2, ("Secret %s already exists !\n", name2));
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_OBJECT_NAME_COLLISION;
 	}
 
@@ -119,41 +115,41 @@
 	 * here only if the key didn't exists before
 	 */
 
-	msg->dn = ldb_dn_copy(mem_ctx, system_dn);
+	msg->dn = ldb_dn_copy(frame, system_dn);
 	if (msg->dn == NULL) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 	if (!ldb_dn_add_child_fmt(msg->dn, "cn=%s", name2)) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
 	ret = ldb_msg_add_string(msg, "cn", name2);
 	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 	ret = ldb_msg_add_string(msg, "objectClass", "secret");
 	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
-	ret = samdb_msg_add_uint64(ldb, mem_ctx, msg, "priorSetTime", nt_now);
+	ret = samdb_msg_add_uint64(ldb, frame, msg, "priorSetTime", nt_now);
 	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 	val.data = lsa_secret->data;
 	val.length = lsa_secret->length;
 	ret = ldb_msg_add_value(msg, "currentValue", &val, NULL);
 	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
-	ret = samdb_msg_add_uint64(ldb, mem_ctx, msg, "lastSetTime", nt_now);
+	ret = samdb_msg_add_uint64(ldb, frame, msg, "lastSetTime", nt_now);
 	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -167,11 +163,11 @@
 		DEBUG(2,("Failed to create secret record %s: %s\n",
 			ldb_dn_get_linearized(msg->dn),
 			ldb_errstring(ldb)));
-		talloc_free(msg);
+		talloc_free(frame);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
-	talloc_free(msg);
+	talloc_free(frame);
 	return NT_STATUS_OK;
 }
 
@@ -183,8 +179,7 @@
 {
 	TALLOC_CTX *tmp_mem;
 	struct ldb_result *res;
-	struct ldb_dn *domain_dn;
-	struct ldb_dn *system_dn;
+	struct ldb_dn *system_dn = NULL;
 	const struct ldb_val *val;
 	uint8_t *data;
 	const char *attrs[] = {
@@ -196,17 +191,12 @@
 	lsa_secret->data = NULL;
 	lsa_secret->length = 0;
 
-	domain_dn = ldb_get_default_basedn(ldb);
-	if (!domain_dn) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
 	tmp_mem = talloc_new(mem_ctx);
 	if (tmp_mem == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	system_dn = samdb_search_dn(ldb, tmp_mem, domain_dn, "(&(objectClass=container)(cn=System))");
+	system_dn = samdb_system_container_dn(ldb, tmp_mem);
 	if (system_dn == NULL) {
 		talloc_free(tmp_mem);
 		return NT_STATUS_NO_MEMORY;
diff -Nru samba-4.17.10+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.h samba-4.17.11+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.h
--- samba-4.17.10+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.h	2022-08-08 17:15:39.636194000 +0300
+++ samba-4.17.11+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.h	2023-09-07 11:59:49.053452300 +0300
@@ -35,7 +35,7 @@
 	struct GUID remote_bind_guid;
 	struct drsuapi_DsBindInfoCtr *remote_info;
 	struct drsuapi_DsBindInfoCtr *local_info;
-	struct drsuapi_getncchanges_state *getncchanges_state;
+	struct drsuapi_getncchanges_state *getncchanges_full_repl_state;
 };
 
 
diff -Nru samba-4.17.10+dfsg/source4/rpc_server/drsuapi/getncchanges.c samba-4.17.11+dfsg/source4/rpc_server/drsuapi/getncchanges.c
--- samba-4.17.10+dfsg/source4/rpc_server/drsuapi/getncchanges.c	2023-03-09 12:18:38.365809700 +0300
+++ samba-4.17.11+dfsg/source4/rpc_server/drsuapi/getncchanges.c	2023-09-07 11:59:49.053452300 +0300
@@ -62,6 +62,7 @@
 	bool is_get_anc;
 	bool broken_samba_4_5_get_anc_emulation;
 	bool is_get_tgt;
+	bool send_nc_root_first;
 	uint64_t min_usn;
 	uint64_t max_usn;
 	struct drsuapi_DsReplicaHighWaterMark last_hwm;
@@ -1038,18 +1039,6 @@
 				  struct drsuapi_changed_objects *m2,
 				  struct drsuapi_getncchanges_state *getnc_state)
 {
-	int ret;
-
-	ret = ldb_dn_compare(getnc_state->ncRoot_dn, m1->dn);
-	if (ret == 0) {
-		return -1;
-	}
-
-	ret = ldb_dn_compare(getnc_state->ncRoot_dn, m2->dn);
-	if (ret == 0) {
-		return 1;
-	}
-
 	if (m1->usn == m2->usn) {
 		return ldb_dn_compare(m2->dn, m1->dn);
 	}
@@ -1711,6 +1700,7 @@
  */
 static WERROR getncchanges_collect_objects(struct drsuapi_bind_state *b_state,
 					   TALLOC_CTX *mem_ctx,
+					   struct drsuapi_getncchanges_state *getnc_state,
 					   struct drsuapi_DsGetNCChangesRequest10 *req10,
 					   struct ldb_dn *search_dn,
 					   const char *extra_filter,
@@ -1719,7 +1709,6 @@
 	int ret;
 	char* search_filter;
 	enum ldb_scope scope = LDB_SCOPE_SUBTREE;
-	struct drsuapi_getncchanges_state *getnc_state = b_state->getncchanges_state;
 	bool critical_only = false;
 
 	if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
@@ -1773,6 +1762,7 @@
  */
 static WERROR getncchanges_collect_objects_exop(struct drsuapi_bind_state *b_state,
 						TALLOC_CTX *mem_ctx,
+						struct drsuapi_getncchanges_state *getnc_state,
 						struct drsuapi_DsGetNCChangesRequest10 *req10,
 						struct drsuapi_DsGetNCChangesCtr6 *ctr6,
 						struct ldb_dn *search_dn,
@@ -1932,7 +1922,13 @@
 		/* TODO: implement extended op specific collection
 		 * of objects. Right now we just normal procedure
 		 * for collecting objects */
-		return getncchanges_collect_objects(b_state, mem_ctx, req10, search_dn, extra_filter, search_res);
+		return getncchanges_collect_objects(b_state,
+						    mem_ctx,
+						    getnc_state,
+						    req10,
+						    search_dn,
+						    extra_filter,
+						    search_res);
 	}
 }
 
@@ -2117,7 +2113,7 @@
  * @param new_objs if parents are added, this gets updated to point to a chain
  * of parent objects (with the parents first and the child last)
  */
-static WERROR getncchanges_add_ancestors(struct drsuapi_DsReplicaObjectListItemEx *child_obj,
+static WERROR getncchanges_add_ancestors(const struct GUID *parent_object_guid,
 					 struct ldb_dn *child_dn,
 					 TALLOC_CTX *mem_ctx,
 					 struct ldb_context *sam_ctx,
@@ -2140,7 +2136,7 @@
 					    DSDB_SECRET_ATTRIBUTES,
 					    NULL };
 
-	next_anc_guid = child_obj->parent_object_guid;
+	next_anc_guid = parent_object_guid;
 
 	while (next_anc_guid != NULL) {
 		struct drsuapi_DsReplicaObjectListItemEx *anc_obj = NULL;
@@ -2149,19 +2145,24 @@
 		struct ldb_dn *anc_dn = NULL;
 
 		/*
-		 * Don't send an object twice. (If we've sent the object, then
-		 * we've also sent all its parents as well)
+		 * For the GET_ANC case (but not the 'send NC root
+		 * first' case), don't send an object twice.
+		 *
+		 * (If we've sent the object, then we've also sent all
+		 * its parents as well)
 		 */
-		werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
-						       next_anc_guid);
-		if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
-			return WERR_OK;
-		}
-		if (W_ERROR_IS_OK(werr)) {
-			return WERR_INTERNAL_ERROR;
-		}
-		if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
-			return werr;
+		if (getnc_state->obj_cache) {
+			werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
+							       next_anc_guid);
+			if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
+				return WERR_OK;
+			}
+			if (W_ERROR_IS_OK(werr)) {
+				return WERR_INTERNAL_ERROR;
+			}
+			if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
+				return werr;
+			}
 		}
 
 		anc_obj = talloc_zero(mem_ctx,
@@ -2215,11 +2216,18 @@
 		/*
 		 * Regardless of whether we actually use it or not,
 		 * we add it to the cache so we don't look at it again
-		 */
-		werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
-						    next_anc_guid);
-		if (!W_ERROR_IS_OK(werr)) {
-			return werr;
+		 *
+		 * The only time we are here without
+		 * getnc_state->obj_cache is for the forced addition
+		 * of the NC root to the start of the reply, this we
+		 * want to add each and every call..
+		 */
+		if (getnc_state->obj_cache) {
+			werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
+							    next_anc_guid);
+			if (!W_ERROR_IS_OK(werr)) {
+				return werr;
+			}
 		}
 
 		/*
@@ -2348,7 +2356,8 @@
 	 */
 	if (getnc_state->is_get_anc
 	    && !getnc_state->broken_samba_4_5_get_anc_emulation) {
-		werr = getncchanges_add_ancestors(obj, msg->dn, mem_ctx,
+		werr = getncchanges_add_ancestors(obj->parent_object_guid,
+						  msg->dn, mem_ctx,
 						  sam_ctx, getnc_state,
 						  schema, session_key,
 						  req10, local_pas,
@@ -2701,7 +2710,7 @@
 		dcesrv_call_session_info(dce_call);
 	struct imessaging_context *imsg_ctx =
 		dcesrv_imessaging_context(dce_call->conn);
-	struct drsuapi_DsReplicaObjectIdentifier *ncRoot;
+	struct drsuapi_DsReplicaObjectIdentifier *untrusted_ncRoot;
 	int ret;
 	uint32_t i, k;
 	struct dsdb_schema *schema;
@@ -2712,7 +2721,7 @@
 	WERROR werr;
 	struct dcesrv_handle *h;
 	struct drsuapi_bind_state *b_state;
-	struct drsuapi_getncchanges_state *getnc_state;
+	struct drsuapi_getncchanges_state *getnc_state = NULL;
 	struct drsuapi_DsGetNCChangesRequest10 *req10;
 	uint32_t options;
 	uint32_t link_count = 0;
@@ -2823,8 +2832,8 @@
 	}
 
 	/* Perform access checks. */
-	ncRoot = req10->naming_context;
-	if (ncRoot == NULL) {
+	untrusted_ncRoot = req10->naming_context;
+	if (untrusted_ncRoot == NULL) {
 		DEBUG(0,(__location__ ": Request for DsGetNCChanges with no NC\n"));
 		return WERR_DS_DRA_INVALID_PARAMETER;
 	}
@@ -2962,23 +2971,50 @@
 		ZERO_STRUCT(req10->highwatermark);
 	}
 
-	getnc_state = b_state->getncchanges_state;
+	/*
+	 * An extended operation is "special single-response cycle"
+	 * per MS-DRSR 4.1.10.1.1 "Start and Finish" so we don't need
+	 * to guess if this is a continuation of any long-term
+	 * state.
+	 *
+	 * Otherwise, maintain (including marking as stale, which is
+	 * what the below is for) the replication state.
+	 *
+	 * Note that point 5 "The server implementation MAY declare
+	 * the supplied values ... as too stale to use."  would allow
+	 * resetting the state at almost any point, Microsoft Azure AD
+	 * Connect will switch back and forth between a REPL_OBJ and a
+	 * full replication, so we must not reset the statue during
+	 * extended operations.
+	 */
+	if (req10->extended_op == DRSUAPI_EXOP_NONE &&
+	    b_state->getncchanges_full_repl_state != NULL) {
+		/*
+		 * Knowing that this is not an extended operation, we
+		 * can access (and validate) the full replication
+		 * state
+		 */
+		getnc_state = b_state->getncchanges_full_repl_state;
+	}
 
 	/* see if a previous replication has been abandoned */
-	if (getnc_state) {
+	if (getnc_state != NULL) {
 		struct ldb_dn *new_dn;
 		ret = drs_ObjectIdentifier_to_dn_and_nc_root(getnc_state,
 							     sam_ctx,
-							     ncRoot,
+							     untrusted_ncRoot,
 							     &new_dn,
 							     NULL);
 		if (ret != LDB_SUCCESS) {
 			/*
 			 * This can't fail as we have done this above
-			 * implicitly but not got the DN out
+			 * implicitly but not got the DN out, but
+			 * print a good error message regardless just
+			 * in case.
 			 */
-			DBG_ERR("Bad DN '%s'\n",
-				drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot));
+			DBG_ERR("Bad DN '%s' as Naming Context for GetNCChanges: %s\n",
+				drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
+				ldb_strerror(ret));
 			return WERR_DS_DRA_INVALID_PARAMETER;
 		}
 		if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
@@ -2987,11 +3023,11 @@
 				 ldb_dn_get_linearized(getnc_state->ncRoot_dn),
 				 ldb_dn_get_linearized(getnc_state->last_dn)));
 			TALLOC_FREE(getnc_state);
-			b_state->getncchanges_state = NULL;
+			b_state->getncchanges_full_repl_state = NULL;
 		}
 	}
 
-	if (getnc_state) {
+	if (getnc_state != NULL) {
 		ret = drsuapi_DsReplicaHighWaterMark_cmp(&getnc_state->last_hwm,
 							 &req10->highwatermark);
 		if (ret != 0) {
@@ -3001,10 +3037,15 @@
 				 (ret > 0) ? "older" : "newer",
 				 ldb_dn_get_linearized(getnc_state->last_dn)));
 			TALLOC_FREE(getnc_state);
-			b_state->getncchanges_state = NULL;
+			b_state->getncchanges_full_repl_state = NULL;
 		}
 	}
 
+	 /*
+	  * This is either a new replication cycle, or an extended
+	  * operation.  A new cycle is triggered above by the
+	  * TALLOC_FREE() which sets getnc_state to NULL.
+	  */
 	if (getnc_state == NULL) {
 		struct ldb_result *res = NULL;
 		const char *attrs[] = {
@@ -3017,10 +3058,13 @@
 
 		ret = drs_ObjectIdentifier_to_dn_and_nc_root(mem_ctx,
 							     sam_ctx,
-							     ncRoot,
+							     untrusted_ncRoot,
 							     &ncRoot_dn,
 							     NULL);
 		if (ret != LDB_SUCCESS) {
+			DBG_ERR("Bad DN '%s' as Naming Context or EXOP DN for GetNCChanges: %s\n",
+				drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
+				ldb_strerror(ret));
 			return WERR_DS_DRA_BAD_DN;
 		}
 
@@ -3110,19 +3154,39 @@
 			return WERR_DS_DRA_NOT_SUPPORTED;
 		}
 
-		/* Initialize the state we'll store over the replication cycle */
-		getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
+		/*
+		 * Initialize the state, initially for the remainder
+		 * of this call (EXOPs)
+		 *
+		 * An extended operation is a "special single-response
+		 * cycle" per MS-DRSR 4.1.10.1.1 "Start and Finish"
+		 *
+		 */
+		getnc_state = talloc_zero(mem_ctx, struct drsuapi_getncchanges_state);
 		if (getnc_state == NULL) {
 			return WERR_NOT_ENOUGH_MEMORY;
 		}
-		b_state->getncchanges_state = getnc_state;
+
+		if (req10->extended_op == DRSUAPI_EXOP_NONE) {
+			/*
+			 * Promote the memory to being a store of
+			 * long-term state that we will use over the
+			 * replication cycle for full replication
+			 * requests
+			 *
+			 * Store the state in a clearly named location
+			 * for pulling back only during full
+			 * replications
+			 */
+			b_state->getncchanges_full_repl_state
+				= talloc_steal(b_state, getnc_state);
+		}
 
 		getnc_state->ncRoot_dn = ncRoot_dn;
 		talloc_steal(getnc_state, ncRoot_dn);
 
 		getnc_state->ncRoot_guid = samdb_result_guid(res->msgs[0],
 							     "objectGUID");
-		ncRoot->guid = getnc_state->ncRoot_guid;
 
 		/* find out if we are to replicate Schema NC */
 		ret = ldb_dn_compare_base(ldb_get_schema_basedn(sam_ctx),
@@ -3132,15 +3196,6 @@
 		TALLOC_FREE(res);
 	}
 
-	if (!ldb_dn_validate(getnc_state->ncRoot_dn) ||
-	    ldb_dn_is_null(getnc_state->ncRoot_dn)) {
-		DEBUG(0,(__location__ ": Bad DN '%s'\n",
-			 drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot)));
-		return WERR_DS_DRA_INVALID_PARAMETER;
-	}
-
-	ncRoot->guid = getnc_state->ncRoot_guid;
-
 	/* we need the session key for encrypting password attributes */
 	status = dcesrv_auth_session_key(dce_call, &session_key);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3203,11 +3258,13 @@
 		}
 
 		if (req10->extended_op == DRSUAPI_EXOP_NONE) {
-			werr = getncchanges_collect_objects(b_state, mem_ctx, req10,
+			werr = getncchanges_collect_objects(b_state, mem_ctx,
+							    getnc_state, req10,
 							    search_dn, extra_filter,
 							    &search_res);
 		} else {
-			werr = getncchanges_collect_objects_exop(b_state, mem_ctx, req10,
+			werr = getncchanges_collect_objects_exop(b_state, mem_ctx,
+								 getnc_state, req10,
 								 &r->out.ctr->ctr6,
 								 search_dn, extra_filter,
 								 &search_res);
@@ -3232,6 +3289,12 @@
 			if (changes[i].usn > getnc_state->max_usn) {
 				getnc_state->max_usn = changes[i].usn;
 			}
+
+			if (req10->extended_op == DRSUAPI_EXOP_NONE &&
+			    GUID_equal(&changes[i].guid, &getnc_state->ncRoot_guid))
+			{
+				getnc_state->send_nc_root_first = true;
+			}
 		}
 
 		if (req10->extended_op == DRSUAPI_EXOP_NONE) {
@@ -3320,11 +3383,19 @@
 	if (r->out.ctr->ctr6.naming_context == NULL) {
 		return WERR_NOT_ENOUGH_MEMORY;
 	}
-	*r->out.ctr->ctr6.naming_context = *ncRoot;
+
+	/*
+	 * Match Windows and echo back the original values from the request, even if
+	 * they say DummyDN for the string NC
+	 */
+	*r->out.ctr->ctr6.naming_context = *untrusted_ncRoot;
 
 	/* find the SID if there is one */
 	dsdb_find_sid_by_dn(sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
 
+	/* Set GUID */
+	r->out.ctr->ctr6.naming_context->guid = getnc_state->ncRoot_guid;
+
 	dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, &ctr);
 	r->out.ctr->ctr6.mapping_ctr = *ctr;
 
@@ -3365,6 +3436,36 @@
 	}
 
 	/*
+	 * If we have the NC root in this replication, send it
+	 * first regardless.  However, don't bump the USN now,
+	 * treat it as if it was sent early due to GET_ANC
+	 *
+	 * This is triggered for each call, so every page of responses
+	 * gets the NC root as the first object, up to the point where
+	 * it naturally occurs in the replication.
+	 */
+
+	if (getnc_state->send_nc_root_first) {
+		struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
+
+		werr = getncchanges_add_ancestors(&getnc_state->ncRoot_guid,
+						  NULL, mem_ctx,
+						  sam_ctx, getnc_state,
+						  schema, &session_key,
+						  req10, local_pas,
+						  machine_dn, &new_objs);
+
+		if (!W_ERROR_IS_OK(werr)) {
+			return werr;
+		}
+
+		getncchanges_chunk_add_objects(repl_chunk, new_objs);
+
+		DEBUG(8,(__location__ ": replicating NC root %s\n",
+			 ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
+	}
+
+	/*
 	 * Check in case we're still processing the links from an object in the
 	 * previous chunk. We want to send the links (and any targets needed)
 	 * before moving on to the next object.
@@ -3402,6 +3503,23 @@
 		TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 		uint32_t old_la_index;
 
+		/*
+		 * Once we get to the 'natural' place to send the NC
+		 * root, stop sending it at the front of each reply
+		 * and make sure to suppress sending it now
+		 *
+		 * We don't just 'continue' here as we must send links
+		 * and unlike Windows we want to update the
+		 * tmp_highest_usn
+		 */
+
+		if (getnc_state->send_nc_root_first &&
+		    GUID_equal(&getnc_state->guids[i], &getnc_state->ncRoot_guid))
+		{
+			getnc_state->send_nc_root_first = false;
+			obj_already_sent = true;
+		}
+
 		msg_dn = ldb_dn_new_fmt(tmp_ctx, sam_ctx, "<GUID=%s>",
 					GUID_string(tmp_ctx, &getnc_state->guids[i]));
 		W_ERROR_HAVE_NO_MEMORY(msg_dn);
@@ -3504,12 +3622,21 @@
 			getncchanges_chunk_add_objects(repl_chunk, new_objs);
 
 			talloc_free(getnc_state->last_dn);
-			getnc_state->last_dn = talloc_move(getnc_state, &msg->dn);
+			/*
+			 * talloc_steal() as we still need msg->dn to
+			 * be a valid pointer for the log on the next
+			 * line.
+			 *
+			 * msg only remains in scope for the next 25
+			 * lines or so anyway.
+			 */
+			getnc_state->last_dn = talloc_steal(getnc_state, msg->dn);
 		}
 
-		DEBUG(8,(__location__ ": %s object %s\n",
+		DEBUG(8,(__location__ ": %s object %s new tmp_highest_usn=%" PRIu64 "\n",
 			 new_objs ? "replicating" : "skipping send of",
-			 ldb_dn_get_linearized(msg->dn)));
+			 ldb_dn_get_linearized(msg->dn),
+			 r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn));
 
 		getnc_state->total_links += (getnc_state->la_count - old_la_index);
 
@@ -3551,7 +3678,15 @@
 		struct drsuapi_DsReplicaUpdateRefsRequest1 ureq;
 		DEBUG(3,("UpdateRefs on getncchanges for %s\n",
 			 GUID_string(mem_ctx, &req10->destination_dsa_guid)));
-		ureq.naming_context = ncRoot;
+
+		/*
+		 * We pass the pre-validation NC root here as
+		 * drsuapi_UpdateRefs() has to check its own input
+		 * values due to being called from
+		 * dcesrv_drsuapi_DsReplicaUpdateRefs()
+		 */
+
+		ureq.naming_context = untrusted_ncRoot;
 		ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(sam_ctx, mem_ctx,
 								   &req10->destination_dsa_guid);
 		if (!ureq.dest_dsa_dns_name) {
@@ -3574,7 +3709,7 @@
 					  &ureq);
 		if (!W_ERROR_IS_OK(werr)) {
 			DEBUG(0,(__location__ ": Failed UpdateRefs on %s for %s in DsGetNCChanges - %s\n",
-				 drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot),
+				 drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
 				 ureq.dest_dsa_dns_name,
 				 win_errstr(werr)));
 		}
@@ -3658,21 +3793,29 @@
 		r->out.ctr->ctr6.nc_linked_attributes_count = getnc_state->total_links;
 	}
 
-	if (!r->out.ctr->ctr6.more_data) {
+	if (req10->extended_op != DRSUAPI_EXOP_NONE) {
+		r->out.ctr->ctr6.uptodateness_vector = NULL;
+		r->out.ctr->ctr6.nc_object_count = 0;
+		ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
+	} else if (!r->out.ctr->ctr6.more_data) {
 
 		/* this is the last response in the replication cycle */
 		r->out.ctr->ctr6.new_highwatermark = getnc_state->final_hwm;
 		r->out.ctr->ctr6.uptodateness_vector = talloc_move(mem_ctx,
-							&getnc_state->final_udv);
+								   &getnc_state->final_udv);
 
 		/*
 		 * Free the state info stored for the replication cycle. Note
 		 * that the RPC message we're sending contains links stored in
 		 * getnc_state. mem_ctx is local to this RPC call, so the memory
 		 * will get freed after the RPC message is sent on the wire.
+		 *
+		 * We must not do this for an EXOP, as that should not
+		 * end the replication state, which is why that is
+		 * checked first above.
 		 */
 		talloc_steal(mem_ctx, getnc_state);
-		b_state->getncchanges_state = NULL;
+		b_state->getncchanges_full_repl_state = NULL;
 	} else {
 		ret = drsuapi_DsReplicaHighWaterMark_cmp(&r->out.ctr->ctr6.old_highwatermark,
 							 &r->out.ctr->ctr6.new_highwatermark);
@@ -3694,19 +3837,13 @@
 		getnc_state->last_hwm = r->out.ctr->ctr6.new_highwatermark;
 	}
 
-	if (req10->extended_op != DRSUAPI_EXOP_NONE) {
-		r->out.ctr->ctr6.uptodateness_vector = NULL;
-		r->out.ctr->ctr6.nc_object_count = 0;
-		ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
-	}
-
 	TALLOC_FREE(repl_chunk);
 
 	DEBUG(r->out.ctr->ctr6.more_data?4:2,
 	      ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %u/%u) %u links (done %u/%u (as %s))\n",
 	       (unsigned long long)(req10->highwatermark.highest_usn+1),
 	       req10->replica_flags,
-	       drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot),
+	       drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
 	       r->out.ctr->ctr6.object_count,
 	       i, r->out.ctr->ctr6.more_data?getnc_state->num_records:i,
 	       r->out.ctr->ctr6.linked_attributes_count,
diff -Nru samba-4.17.10+dfsg/source4/rpc_server/lsa/lsa_init.c samba-4.17.11+dfsg/source4/rpc_server/lsa/lsa_init.c
--- samba-4.17.10+dfsg/source4/rpc_server/lsa/lsa_init.c	2022-08-08 17:15:39.636194000 +0300
+++ samba-4.17.11+dfsg/source4/rpc_server/lsa/lsa_init.c	2023-09-07 11:59:49.053452300 +0300
@@ -146,10 +146,9 @@
 
 	/* work out the system_dn - useful for so many calls its worth
 	   fetching here */
-	state->system_dn = samdb_search_dn(state->sam_ldb, state,
-					   state->domain_dn, "(&(objectClass=container)(cn=System))");
-	if (!state->system_dn) {
-		return NT_STATUS_NO_SUCH_DOMAIN;		
+	state->system_dn = samdb_system_container_dn(state->sam_ldb, state);
+	if (state->system_dn == NULL) {
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN);
diff -Nru samba-4.17.10+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c samba-4.17.11+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c
--- samba-4.17.10+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c	2023-07-17 11:28:30.146744000 +0300
+++ samba-4.17.11+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c	2023-09-07 11:59:49.057452400 +0300
@@ -3911,11 +3911,9 @@
 		return WERR_INVALID_FLAGS;
 	}
 
-	system_dn = samdb_search_dn(sam_ctx, mem_ctx,
-				    ldb_get_default_basedn(sam_ctx),
-				    "(&(objectClass=container)(cn=System))");
-	if (!system_dn) {
-		return WERR_GEN_FAILURE;
+	system_dn = samdb_system_container_dn(sam_ctx, mem_ctx);
+	if (system_dn == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
 	}
 
 	ret = gendb_search(sam_ctx, mem_ctx, system_dn,
diff -Nru samba-4.17.10+dfsg/source4/torture/drs/python/getncchanges.py samba-4.17.11+dfsg/source4/torture/drs/python/getncchanges.py
--- samba-4.17.10+dfsg/source4/torture/drs/python/getncchanges.py	2023-03-09 12:18:38.369809400 +0300
+++ samba-4.17.11+dfsg/source4/torture/drs/python/getncchanges.py	2023-09-07 11:59:49.057452400 +0300
@@ -49,22 +49,15 @@
         self.set_test_ldb_dc(self.ldb_dc2)
 
         self.ou = str(samba.tests.create_test_ou(self.test_ldb_dc,
-                                                 "getncchanges"))
+                                                 "getncchanges." + self.id().rsplit(".", 1)[1]))
+
+        self.addCleanup(self.ldb_dc2.delete, self.ou, ["tree_delete:1"])
+
         self.base_dn = self.test_ldb_dc.get_default_basedn()
 
         self.default_conn = DcConnection(self, self.ldb_dc2, self.dnsname_dc2)
         self.set_dc_connection(self.default_conn)
 
-    def tearDown(self):
-        super(DrsReplicaSyncIntegrityTestCase, self).tearDown()
-        # tidyup groups and users
-        try:
-            self.ldb_dc2.delete(self.ou, ["tree_delete:1"])
-        except ldb.LdbError as e:
-            (enum, string) = e.args
-            if enum == ldb.ERR_NO_SUCH_OBJECT:
-                pass
-
     def init_test_state(self):
         self.rxd_dn_list = []
         self.rxd_links = []
@@ -1220,6 +1213,208 @@
         # The NC should be the first object returned due to GET_ANC
         self.assertEqual(ctr.first_object.object.identifier.guid, guid)
 
+    def _test_do_full_repl_no_overlap(self, mix=True, get_anc=False):
+        self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+
+        # We set get_anc=True so we can assert the BASE DN will be the
+        # first object
+        ctr6 = self._repl_send_request(get_anc=get_anc)
+        guid_list_1 = self._get_ctr6_object_guids(ctr6)
+
+        if mix:
+            dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+            req8 = self._exop_req8(dest_dsa=None,
+                                   invocation_id=dc_guid_1,
+                                   nc_dn_str=self.ldb_dc1.get_default_basedn(),
+                                   exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+            (level, ctr_repl_obj) = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
+
+            self.assertEqual(ctr_repl_obj.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+
+            repl_obj_guid_list = self._get_ctr6_object_guids(ctr_repl_obj)
+
+            self.assertEqual(len(repl_obj_guid_list), 1)
+
+            # This should be the first object in the main replication due
+            # to get_anc=True above in one case, and a rule that the NC must be first regardless otherwise
+            self.assertEqual(repl_obj_guid_list[0], guid_list_1[0])
+
+        self.last_ctr = ctr6
+        ctr6 = self._repl_send_request(get_anc=True)
+        guid_list_2 = self._get_ctr6_object_guids(ctr6)
+
+        self.assertNotEqual(guid_list_1, guid_list_2)
+
+    def test_do_full_repl_no_overlap_get_anc(self):
+        """
+        Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+        """
+        self._test_do_full_repl_no_overlap(mix=False, get_anc=True)
+
+    def test_do_full_repl_no_overlap(self):
+        """
+        Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+        """
+        self._test_do_full_repl_no_overlap(mix=False)
+
+    def test_do_full_repl_mix_no_overlap(self):
+        """
+        Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+
+        Assert this is true even if we do a REPL_OBJ in between the replications
+
+        """
+        self._test_do_full_repl_no_overlap(mix=True)
+
+    def nc_change(self):
+        old_base_msg = self.default_conn.ldb_dc.search(base=self.base_dn,
+                                                       scope=SCOPE_BASE,
+                                                       attrs=["oEMInformation"])
+        rec_cleanup = {"dn": self.base_dn,
+                       "oEMInformation": old_base_msg[0]["oEMInformation"][0]}
+        m_cleanup = ldb.Message.from_dict(self.default_conn.ldb_dc,
+                                          rec_cleanup,
+                                          ldb.FLAG_MOD_REPLACE)
+
+        self.addCleanup(self.default_conn.ldb_dc.modify, m_cleanup)
+
+        rec = {"dn": self.base_dn,
+               "oEMInformation": f"Tortured by Samba's getncchanges.py {self.id()} against {self.default_conn.dnsname_dc}"}
+        m = ldb.Message.from_dict(self.default_conn.ldb_dc, rec, ldb.FLAG_MOD_REPLACE)
+        self.default_conn.ldb_dc.modify(m)
+
+    def _test_repl_nc_is_first(self, start_at_zero=True, nc_change=True, ou_change=True, mid_change=False):
+        """Tests that the NC is always replicated first, but does not move the
+           tmp_highest_usn at that point, just like 'early' GET_ANC objects.
+        """
+
+        # create objects, twice more than the page size of 133
+        objs = self.create_object_range(0, 300, prefix="obj")
+
+        if nc_change:
+            self.nc_change()
+
+        if mid_change:
+            # create even moire objects
+            objs = self.create_object_range(301, 450, prefix="obj2")
+
+        base_msg = self.default_conn.ldb_dc.search(base=self.base_dn,
+                                                   scope=SCOPE_BASE,
+                                                   attrs=["uSNChanged",
+                                                          "objectGUID"])
+
+        base_guid = misc.GUID(base_msg[0]["objectGUID"][0])
+        base_usn = int(base_msg[0]["uSNChanged"][0])
+
+        if ou_change:
+            # Make one more modification.  We want to assert we have
+            # caught up to the base DN, but Windows both promotes the NC
+            # to the front and skips including it in the tmp_highest_usn,
+            # so we make a later modification that will be to show we get
+            # this change.
+            rec = {"dn": self.ou,
+                   "postalCode": "0"}
+            m = ldb.Message.from_dict(self.default_conn.ldb_dc, rec, ldb.FLAG_MOD_REPLACE)
+            self.default_conn.ldb_dc.modify(m)
+
+        ou_msg = self.default_conn.ldb_dc.search(base=self.ou,
+                                                   scope=SCOPE_BASE,
+                                                   attrs=["uSNChanged",
+                                                          "objectGUID"])
+
+        ou_guid = misc.GUID(ou_msg[0]["objectGUID"][0])
+        ou_usn = int(ou_msg[0]["uSNChanged"][0])
+
+        # Check some predicates about USN ordering that the below tests will rely on
+        if ou_change and nc_change:
+            self.assertGreater(ou_usn, base_usn);
+        elif not ou_change and nc_change:
+            self.assertGreater(base_usn, ou_usn);
+
+        ctr6 = self.repl_get_next()
+
+        guid_list_1 = self._get_ctr6_object_guids(ctr6)
+        if nc_change or start_at_zero:
+            self.assertEqual(base_guid, misc.GUID(guid_list_1[0]))
+            self.assertIn(str(base_guid), guid_list_1)
+            self.assertNotIn(str(base_guid), guid_list_1[1:])
+        else:
+            self.assertNotEqual(base_guid, misc.GUID(guid_list_1[0]))
+            self.assertNotIn(str(base_guid), guid_list_1)
+
+        self.assertTrue(ctr6.more_data)
+
+        if not ou_change and nc_change:
+            self.assertLess(ctr6.new_highwatermark.tmp_highest_usn, base_usn)
+
+        i = 0
+        while not self.replication_complete():
+            i = i + 1
+            last_tmp_highest_usn = ctr6.new_highwatermark.tmp_highest_usn
+            ctr6 = self.repl_get_next()
+            guid_list_2 = self._get_ctr6_object_guids(ctr6)
+            if len(guid_list_2) > 0:
+                self.assertNotEqual(last_tmp_highest_usn, ctr6.new_highwatermark.tmp_highest_usn)
+
+            if (nc_change or start_at_zero) and base_usn > last_tmp_highest_usn:
+                self.assertEqual(base_guid, misc.GUID(guid_list_2[0]),
+                                 f"pass={i} more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+                self.assertIn(str(base_guid), guid_list_2,
+                                 f"pass {i}·more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+            else:
+                self.assertNotIn(str(base_guid), guid_list_2,
+                                 f"pass {i}·more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+
+        if ou_change:
+            # The modification to the base OU should be in the final chunk
+            self.assertIn(str(ou_guid), guid_list_2)
+            self.assertGreaterEqual(ctr6.new_highwatermark.highest_usn,
+                                    ou_usn)
+        else:
+            # Show that the NC root change does not show up in the
+            # highest_usn.  We either get the change before or after
+            # it.
+            self.assertNotEqual(ctr6.new_highwatermark.highest_usn,
+                                base_usn)
+        self.assertEqual(ctr6.new_highwatermark.highest_usn,
+                          ctr6.new_highwatermark.tmp_highest_usn)
+
+        self.assertFalse(ctr6.more_data)
+
+    def test_repl_nc_is_first_start_zero_nc_change(self):
+        self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+        self._test_repl_nc_is_first(start_at_zero=True, nc_change=True, ou_change=True)
+
+    def test_repl_nc_is_first_start_zero(self):
+        # Get the NC change in the middle of the replication stream, certainly not at the start or end
+        self.nc_change()
+        self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+        self._test_repl_nc_is_first(start_at_zero=True, nc_change=False, ou_change=False)
+
+    def test_repl_nc_is_first_mid(self):
+        # This is a modification of the next test, that Samba
+        # will pass as it will always include the NC in the
+        # tmp_highest_usn at the point where it belongs
+        self._test_repl_nc_is_first(start_at_zero=False,
+                                    nc_change=True,
+                                    ou_change=True,
+                                    mid_change=True)
+
+    def test_repl_nc_is_first(self):
+        # This is a modification of the next test, that Samba
+        # will pass as it will always include the NC in the
+        # tmp_highest_usn at the point where it belongs
+        self._test_repl_nc_is_first(start_at_zero=False, nc_change=True, ou_change=True)
+
+    def test_repl_nc_is_first_nc_change_only(self):
+        # This shows that the NC change is not reflected in the tmp_highest_usn
+        self._test_repl_nc_is_first(start_at_zero=False, nc_change=True, ou_change=False)
+
+    def test_repl_nc_is_first_no_change(self):
+        # The NC should not be present in this replication
+        self._test_repl_nc_is_first(start_at_zero=False, nc_change=False, ou_change=False)
 
 class DcConnection:
     """Helper class to track a connection to another DC"""
@@ -1229,3 +1424,4 @@
         (self.drs, self.drs_handle) = drs_base._ds_bind(dnsname_dc)
         (self.default_hwm, utdv) = drs_base._get_highest_hwm_utdv(ldb_dc)
         self.default_utdv = utdv
+        self.dnsname_dc = dnsname_dc
diff -Nru samba-4.17.10+dfsg/source4/torture/drs/python/getnc_exop.py samba-4.17.11+dfsg/source4/torture/drs/python/getnc_exop.py
--- samba-4.17.10+dfsg/source4/torture/drs/python/getnc_exop.py	2023-03-09 12:18:38.369809400 +0300
+++ samba-4.17.11+dfsg/source4/torture/drs/python/getnc_exop.py	2023-09-07 11:59:49.057452400 +0300
@@ -295,6 +295,29 @@
             (enum, estr) = e1.args
             self.assertEqual(enum, werror.WERR_DS_DRA_BAD_NC)
 
+    def test_valid_GUID_only_REPL_OBJ(self):
+        dc_guid_1 = self.ldb_dc1.get_invocation_id()
+        drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+        res = self.ldb_dc1.search(base=self.ou, scope=SCOPE_BASE,
+                                  attrs=["objectGUID"])
+
+        guid = misc.GUID(res[0]["objectGUID"][0])
+
+        req8 = self._exop_req8(dest_dsa=None,
+                               invocation_id=dc_guid_1,
+                               nc_dn_str="",
+                               nc_guid=guid,
+                               exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+        try:
+            (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+        except WERRORError as e1:
+            (enum, estr) = e1.args
+            self.fail(f"Failed to call GetNCChanges with EXOP_REPL_OBJ and a GUID: {estr}")
+
+        self.assertEqual(ctr.first_object.object.identifier.guid, guid)
+
     def test_DummyDN_valid_GUID_REPL_OBJ(self):
         dc_guid_1 = self.ldb_dc1.get_invocation_id()
         drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
@@ -314,7 +337,7 @@
             (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
         except WERRORError as e1:
             (enum, estr) = e1.args
-            self.fail(f"Failed to call GetNCChanges with EXOP_REPL_OBJ and a GUID: {estr}")
+            self.fail(f"Failed to call GetNCChanges with EXOP_REPL_OBJ, DummyDN and a GUID: {estr}")
 
         self.assertEqual(ctr.first_object.object.identifier.guid, guid)
 
diff -Nru samba-4.17.10+dfsg/source4/torture/ndr/dcerpc.c samba-4.17.11+dfsg/source4/torture/ndr/dcerpc.c
--- samba-4.17.10+dfsg/source4/torture/ndr/dcerpc.c	1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.11+dfsg/source4/torture/ndr/dcerpc.c	2023-09-07 11:59:49.057452400 +0300
@@ -0,0 +1,148 @@
+/*
+   Unix SMB/CIFS implementation.
+   test suite for dcerpc ndr operations
+
+   Copyright (C) Stefan Metzmacher 2023
+
+   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 "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "torture/ndr/proto.h"
+
+/*
+ *  ncacn_packet: struct ncacn_packet
+ *      rpc_vers                 : 0x05 (5)
+ *      rpc_vers_minor           : 0x00 (0)
+ *      ptype                    : DCERPC_PKT_CO_CANCEL (18)
+ *      pfc_flags                : 0x06 (6)
+ *             0: DCERPC_PFC_FLAG_FIRST
+ *             1: DCERPC_PFC_FLAG_LAST
+ *             1: DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING
+ *             0: DCERPC_PFC_FLAG_CONC_MPX
+ *             0: DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ *             0: DCERPC_PFC_FLAG_MAYBE
+ *             0: DCERPC_PFC_FLAG_OBJECT_UUID
+ *      drep: ARRAY(4)
+ *          [0]                      : 0x10 (16)
+ *          [1]                      : 0x00 (0)
+ *          [2]                      : 0x00 (0)
+ *          [3]                      : 0x00 (0)
+ *      frag_length              : 0x0010 (16)
+ *      auth_length              : 0x0000 (0)
+ *      call_id                  : 0x00000001 (1)
+ *      u                        : union dcerpc_payload(case 18)
+ *      co_cancel: struct dcerpc_co_cancel
+ *          auth_info                : DATA_BLOB length=0
+ */
+static const uint8_t ncacn_packet_co_cancel_data[] = {
+	0x05, 0x00, 0x12, 0x06, 0x10, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+};
+
+static bool ncacn_packet_co_cancel_check(struct torture_context *tctx,
+					 struct ncacn_packet *pkt)
+{
+	torture_assert_int_equal(tctx, pkt->rpc_vers, 5, "rpc_vers");
+	torture_assert_int_equal(tctx, pkt->rpc_vers_minor, 0, "rpc_vers_minor");
+	torture_assert_int_equal(tctx, pkt->ptype, DCERPC_PKT_CO_CANCEL, "ptype");
+	torture_assert_int_equal(tctx, pkt->pfc_flags,
+				 DCERPC_PFC_FLAG_LAST |
+				 DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING,
+				 "pfc_flags");
+	torture_assert_int_equal(tctx, pkt->drep[0], DCERPC_DREP_LE, "drep[0]");
+	torture_assert_int_equal(tctx, pkt->drep[1], 0, "drep[1]");
+	torture_assert_int_equal(tctx, pkt->drep[2], 0, "drep[2]");
+	torture_assert_int_equal(tctx, pkt->drep[3], 0, "drep[3]");
+	torture_assert_int_equal(tctx, pkt->frag_length, 16, "frag_length");
+	torture_assert_int_equal(tctx, pkt->auth_length, 0, "auth_length");
+	torture_assert_int_equal(tctx, pkt->call_id, 1, "call_id");
+	torture_assert_int_equal(tctx, pkt->u.co_cancel.auth_info.length, 0,
+				 "co_cancel.auth_info.length");
+	return true;
+}
+
+/*
+ *  ncacn_packet: struct ncacn_packet
+ *      rpc_vers                 : 0x05 (5)
+ *      rpc_vers_minor           : 0x00 (0)
+ *      ptype                    : DCERPC_PKT_ORPHANED (19)
+ *      pfc_flags                : 0x03 (3)
+ *             1: DCERPC_PFC_FLAG_FIRST
+ *             1: DCERPC_PFC_FLAG_LAST
+ *             0: DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING
+ *             0: DCERPC_PFC_FLAG_CONC_MPX
+ *             0: DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ *             0: DCERPC_PFC_FLAG_MAYBE
+ *             0: DCERPC_PFC_FLAG_OBJECT_UUID
+ *      drep: ARRAY(4)
+ *          [0]                      : 0x10 (16)
+ *          [1]                      : 0x00 (0)
+ *          [2]                      : 0x00 (0)
+ *          [3]                      : 0x00 (0)
+ *      frag_length              : 0x0010 (16)
+ *      auth_length              : 0x0000 (0)
+ *      call_id                  : 0x00000008 (8)
+ *      u                        : union dcerpc_payload(case 19)
+ *      orphaned: struct dcerpc_orphaned
+ *          auth_info                : DATA_BLOB length=0
+ */
+static const uint8_t ncacn_packet_orphaned_data[] = {
+	0x05, 0x00, 0x13, 0x03, 0x10, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+};
+
+static bool ncacn_packet_orphaned_check(struct torture_context *tctx,
+					struct ncacn_packet *pkt)
+{
+	torture_assert_int_equal(tctx, pkt->rpc_vers, 5, "rpc_vers");
+	torture_assert_int_equal(tctx, pkt->rpc_vers_minor, 0, "rpc_vers_minor");
+	torture_assert_int_equal(tctx, pkt->ptype, DCERPC_PKT_ORPHANED, "ptype");
+	torture_assert_int_equal(tctx, pkt->pfc_flags,
+				 DCERPC_PFC_FLAG_FIRST|DCERPC_PFC_FLAG_LAST,
+				 "pfc_flags");
+	torture_assert_int_equal(tctx, pkt->drep[0], DCERPC_DREP_LE, "drep[0]");
+	torture_assert_int_equal(tctx, pkt->drep[1], 0, "drep[1]");
+	torture_assert_int_equal(tctx, pkt->drep[2], 0, "drep[2]");
+	torture_assert_int_equal(tctx, pkt->drep[3], 0, "drep[3]");
+	torture_assert_int_equal(tctx, pkt->frag_length, 16, "frag_length");
+	torture_assert_int_equal(tctx, pkt->auth_length, 0, "auth_length");
+	torture_assert_int_equal(tctx, pkt->call_id, 8, "call_id");
+	torture_assert_int_equal(tctx, pkt->u.orphaned.auth_info.length, 0,
+				 "orphaned.auth_info.length");
+	return true;
+}
+
+struct torture_suite *ndr_dcerpc_suite(TALLOC_CTX *ctx)
+{
+	struct torture_suite *suite = torture_suite_create(ctx, "dcerpc");
+	struct torture_suite *co_cancel = torture_suite_create(ctx, "co_cancel");
+	struct torture_suite *orphaned = torture_suite_create(ctx, "orphaned");
+
+	torture_suite_add_suite(suite, co_cancel);
+	torture_suite_add_ndr_pull_validate_test(co_cancel,
+					ncacn_packet,
+					ncacn_packet_co_cancel_data,
+					ncacn_packet_co_cancel_check);
+
+	torture_suite_add_suite(suite, orphaned);
+	torture_suite_add_ndr_pull_validate_test(orphaned,
+					ncacn_packet,
+					ncacn_packet_orphaned_data,
+					ncacn_packet_orphaned_check);
+
+	return suite;
+}
diff -Nru samba-4.17.10+dfsg/source4/torture/ndr/ndr.c samba-4.17.11+dfsg/source4/torture/ndr/ndr.c
--- samba-4.17.10+dfsg/source4/torture/ndr/ndr.c	2022-08-08 17:15:40.456200100 +0300
+++ samba-4.17.11+dfsg/source4/torture/ndr/ndr.c	2023-09-07 11:59:49.057452400 +0300
@@ -759,6 +759,7 @@
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "ndr");
 
+	torture_suite_add_suite(suite, ndr_dcerpc_suite(suite));
 	torture_suite_add_suite(suite, ndr_winreg_suite(suite));
 	torture_suite_add_suite(suite, ndr_atsvc_suite(suite));
 	torture_suite_add_suite(suite, ndr_lsa_suite(suite));
diff -Nru samba-4.17.10+dfsg/source4/torture/smb2/acls.c samba-4.17.11+dfsg/source4/torture/smb2/acls.c
--- samba-4.17.10+dfsg/source4/torture/smb2/acls.c	2022-08-08 17:15:40.480200300 +0300
+++ samba-4.17.11+dfsg/source4/torture/smb2/acls.c	2023-09-07 11:59:49.057452400 +0300
@@ -2139,40 +2139,6 @@
 }
 #endif
 
-/**
- * SMB2 connect with explicit share
- **/
-static bool torture_smb2_con_share(struct torture_context *tctx,
-                           const char *share,
-                           struct smb2_tree **tree)
-{
-        struct smbcli_options options;
-        NTSTATUS status;
-        const char *host = torture_setting_string(tctx, "host", NULL);
-
-        lpcfg_smbcli_options(tctx->lp_ctx, &options);
-
-        status = smb2_connect_ext(tctx,
-                                  host,
-                                  lpcfg_smb_ports(tctx->lp_ctx),
-                                  share,
-                                  lpcfg_resolve_context(tctx->lp_ctx),
-                                  samba_cmdline_get_creds(),
-                                  0,
-                                  tree,
-                                  tctx->ev,
-                                  &options,
-                                  lpcfg_socket_options(tctx->lp_ctx),
-                                  lpcfg_gensec_settings(tctx, tctx->lp_ctx)
-                                  );
-        if (!NT_STATUS_IS_OK(status)) {
-		torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
-			host, share, nt_errstr(status));
-                return false;
-        }
-        return true;
-}
-
 static bool test_access_based(struct torture_context *tctx,
 				struct smb2_tree *tree)
 {
diff -Nru samba-4.17.10+dfsg/source4/torture/smb2/multichannel.c samba-4.17.11+dfsg/source4/torture/smb2/multichannel.c
--- samba-4.17.10+dfsg/source4/torture/smb2/multichannel.c	2022-08-08 17:15:40.488200400 +0300
+++ samba-4.17.11+dfsg/source4/torture/smb2/multichannel.c	2023-09-07 11:59:49.057452400 +0300
@@ -31,6 +31,7 @@
 #include "lib/cmdline/cmdline.h"
 #include "libcli/security/security.h"
 #include "libcli/resolve/resolve.h"
+#include "lib/socket/socket.h"
 #include "lib/param/param.h"
 #include "lib/events/events.h"
 #include "oplock_break_handler.h"
@@ -2345,6 +2346,315 @@
 	return ret;
 }
 
+/*
+ * Test channel merging race
+ * This is a regression test for
+ * https://bugzilla.samba.org/show_bug.cgi?id=15346
+ */
+struct test_multichannel_bug_15346_conn;
+
+struct test_multichannel_bug_15346_state {
+	struct torture_context *tctx;
+	struct test_multichannel_bug_15346_conn *conns;
+	size_t num_conns;
+	size_t num_ready;
+	bool asserted;
+	bool looping;
+};
+
+struct test_multichannel_bug_15346_conn {
+	struct test_multichannel_bug_15346_state *state;
+	size_t idx;
+	struct smbXcli_conn *smbXcli;
+	struct tevent_req *nreq;
+	struct tevent_req *ereq;
+};
+
+static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq);
+static void test_multichannel_bug_15346_edone(struct tevent_req *subreq);
+
+static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq)
+{
+	struct test_multichannel_bug_15346_conn *conn =
+		(struct test_multichannel_bug_15346_conn *)
+		tevent_req_callback_data_void(subreq);
+	struct test_multichannel_bug_15346_state *state = conn->state;
+	struct torture_context *tctx = state->tctx;
+	NTSTATUS status;
+	bool ok = false;
+
+	SMB_ASSERT(conn->nreq == subreq);
+	conn->nreq = NULL;
+
+	status = smbXcli_negprot_recv(subreq, NULL, NULL);
+	TALLOC_FREE(subreq);
+	torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
+					"smbXcli_negprot_recv failed");
+
+	torture_comment(tctx, "conn[%zu]: negprot done\n", conn->idx);
+
+	conn->ereq = smb2cli_echo_send(conn->smbXcli,
+				       tctx->ev,
+				       conn->smbXcli,
+				       state->num_conns * 2 * 1000);
+	torture_assert_goto(tctx, conn->ereq != NULL, ok, asserted,
+			    "smb2cli_echo_send");
+	tevent_req_set_callback(conn->ereq,
+				test_multichannel_bug_15346_edone,
+				conn);
+
+	return;
+
+asserted:
+	SMB_ASSERT(!ok);
+	state->asserted = true;
+	state->looping = false;
+	return;
+}
+
+static void test_multichannel_bug_15346_edone(struct tevent_req *subreq)
+{
+	struct test_multichannel_bug_15346_conn *conn =
+		(struct test_multichannel_bug_15346_conn *)
+		tevent_req_callback_data_void(subreq);
+	struct test_multichannel_bug_15346_state *state = conn->state;
+	struct torture_context *tctx = state->tctx;
+	NTSTATUS status;
+	bool ok = false;
+
+	SMB_ASSERT(conn->ereq == subreq);
+	conn->ereq = NULL;
+
+	status = smb2cli_echo_recv(subreq);
+	TALLOC_FREE(subreq);
+	torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
+					"smb2cli_echo_recv failed");
+
+	torture_comment(tctx, "conn[%zu]: echo done\n", conn->idx);
+
+	state->num_ready += 1;
+	if (state->num_ready < state->num_conns) {
+		return;
+	}
+
+	state->looping = false;
+	return;
+
+asserted:
+	SMB_ASSERT(!ok);
+	state->asserted = true;
+	state->looping = false;
+	return;
+}
+
+static bool test_multichannel_bug_15346(struct torture_context *tctx,
+					struct smb2_tree *tree1)
+{
+	const char *host = torture_setting_string(tctx, "host", NULL);
+	const char *share = torture_setting_string(tctx, "share", NULL);
+	struct resolve_context *resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
+	const char *socket_options = lpcfg_socket_options(tctx->lp_ctx);
+	struct gensec_settings *gsettings = NULL;
+	bool ret = true;
+	NTSTATUS status;
+	struct smb2_transport *transport1 = tree1->session->transport;
+	struct test_multichannel_bug_15346_state *state = NULL;
+	uint32_t server_capabilities;
+	struct smb2_handle root_handle = {{0}};
+	size_t i;
+
+	if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+		torture_fail(tctx,
+			     "SMB 3.X Dialect family required for Multichannel"
+			     " tests\n");
+	}
+
+	server_capabilities = smb2cli_conn_server_capabilities(
+					tree1->session->transport->conn);
+	if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+		torture_fail(tctx,
+			     "Server does not support multichannel.");
+	}
+
+	torture_comment(tctx, "Testing for BUG 15346\n");
+
+	state = talloc_zero(tctx, struct test_multichannel_bug_15346_state);
+	torture_assert_goto(tctx, state != NULL, ret, done,
+			    "talloc_zero");
+	state->tctx = tctx;
+
+	gsettings = lpcfg_gensec_settings(state, tctx->lp_ctx);
+	torture_assert_goto(tctx, gsettings != NULL, ret, done,
+			    "lpcfg_gensec_settings");
+
+	/*
+	 * 32 is the W2K12R2 and W2K16 limit
+	 * add 31 additional connections
+	 */
+	state->num_conns = 31;
+	state->conns = talloc_zero_array(state,
+				  struct test_multichannel_bug_15346_conn,
+				  state->num_conns);
+	torture_assert_goto(tctx, state->conns != NULL, ret, done,
+			    "talloc_zero_array");
+
+	/*
+	 * First we open additional the tcp connections
+	 */
+
+	for (i = 0; i < state->num_conns; i++) {
+		struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+		struct socket_context *sock = NULL;
+		uint16_t port = 445;
+		struct smbcli_options options = transport1->options;
+
+		conn->state = state;
+		conn->idx = i;
+
+		status = socket_connect_multi(state->conns,
+					      host,
+					      1, &port,
+					      resolve_ctx,
+					      tctx->ev,
+					      &sock,
+					      &port);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"socket_connect_multi failed");
+
+		conn->smbXcli = smbXcli_conn_create(state->conns,
+					sock->fd,
+					host,
+					SMB_SIGNING_OFF,
+					0,
+					&options.client_guid,
+					options.smb2_capabilities,
+					&options.smb3_capabilities);
+		torture_assert_goto(tctx, conn->smbXcli != NULL, ret, done,
+				    "smbXcli_conn_create failed");
+		sock->fd = -1;
+		TALLOC_FREE(sock);
+	}
+
+	/*
+	 * Now prepare the async SMB2 Negotiate requests
+	 */
+	for (i = 0; i < state->num_conns; i++) {
+		struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+
+		conn->nreq = smbXcli_negprot_send(conn->smbXcli,
+						  tctx->ev,
+						  conn->smbXcli,
+						  state->num_conns * 2 * 1000,
+						  smbXcli_conn_protocol(transport1->conn),
+						  smbXcli_conn_protocol(transport1->conn),
+						  33, /* max_credits */
+						  NULL);
+		torture_assert_goto(tctx, conn->nreq != NULL, ret, done, "smbXcli_negprot_send");
+		tevent_req_set_callback(conn->nreq,
+					test_multichannel_bug_15346_ndone,
+					conn);
+	}
+
+	/*
+	 * now we loop until all negprot and the first round
+	 * of echos are done.
+	 */
+	state->looping = true;
+	while (state->looping) {
+		torture_assert_goto(tctx, tevent_loop_once(tctx->ev) == 0,
+				    ret, done, "tevent_loop_once");
+	}
+
+	if (state->asserted) {
+		ret = false;
+		goto done;
+	}
+
+	/*
+	 * No we check that the connections are still usable
+	 */
+	for (i = 0; i < state->num_conns; i++) {
+		struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+
+		torture_comment(tctx, "conn[%zu]: checking echo again1\n", conn->idx);
+
+		status = smb2cli_echo(conn->smbXcli, 1000);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"smb2cli_echo failed");
+	}
+
+	status = smb2_util_roothandle(tree1, &root_handle);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_roothandle failed");
+
+	/*
+	 * No we check that the connections are still usable
+	 */
+	for (i = 0; i < state->num_conns; i++) {
+		struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+		struct smbcli_options options = transport1->options;
+		struct smb2_session *session = NULL;
+		struct smb2_tree *tree = NULL;
+		union smb_fileinfo io;
+
+		torture_comment(tctx, "conn[%zu]: checking session bind\n", conn->idx);
+
+		/*
+		 * Prepare smb2_{tree,session,transport} structures
+		 * for the existing connection.
+		 */
+		options.only_negprot = true;
+		status = smb2_connect_ext(state->conns,
+					  host,
+					  NULL, /* ports */
+					  share,
+					  resolve_ctx,
+					  samba_cmdline_get_creds(),
+					  &conn->smbXcli,
+					  0, /* previous_session_id */
+					  &tree,
+					  tctx->ev,
+					  &options,
+					  socket_options,
+					  gsettings);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"smb2_connect_ext failed");
+		conn->smbXcli = tree->session->transport->conn;
+
+		session = smb2_session_channel(tree->session->transport,
+					       lpcfg_gensec_settings(tree, tctx->lp_ctx),
+					       tree,
+					       tree1->session);
+		torture_assert_goto(tctx, session != NULL, ret, done,
+				    "smb2_session_channel failed");
+
+		status = smb2_session_setup_spnego(session,
+						   samba_cmdline_get_creds(),
+						   0 /* previous_session_id */);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"smb2_session_setup_spnego failed");
+
+		/*
+		 * Fix up the bound smb2_tree
+		 */
+		tree->session = session;
+		tree->smbXcli = tree1->smbXcli;
+
+		ZERO_STRUCT(io);
+		io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+		io.generic.in.file.handle = root_handle;
+
+		status = smb2_getinfo_file(tree, tree, &io);
+		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+						"smb2_getinfo_file failed");
+	}
+
+ done:
+	talloc_free(state);
+
+	return ret;
+}
+
 struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
@@ -2354,10 +2664,13 @@
 								   "oplocks");
 	struct torture_suite *suite_leases = torture_suite_create(ctx,
 								  "leases");
+	struct torture_suite *suite_bugs = torture_suite_create(ctx,
+								"bugs");
 
 	torture_suite_add_suite(suite, suite_generic);
 	torture_suite_add_suite(suite, suite_oplocks);
 	torture_suite_add_suite(suite, suite_leases);
+	torture_suite_add_suite(suite, suite_bugs);
 
 	torture_suite_add_1smb2_test(suite_generic, "interface_info",
 				     test_multichannel_interface_info);
@@ -2379,6 +2692,8 @@
 				     test_multichannel_lease_break_test3);
 	torture_suite_add_1smb2_test(suite_leases, "test4",
 				     test_multichannel_lease_break_test4);
+	torture_suite_add_1smb2_test(suite_bugs, "bug_15346",
+				     test_multichannel_bug_15346);
 
 	suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
 
diff -Nru samba-4.17.10+dfsg/source4/torture/smb2/util.c samba-4.17.11+dfsg/source4/torture/smb2/util.c
--- samba-4.17.10+dfsg/source4/torture/smb2/util.c	2022-08-08 17:15:40.492200400 +0300
+++ samba-4.17.11+dfsg/source4/torture/smb2/util.c	2023-09-07 11:59:49.057452400 +0300
@@ -426,6 +426,7 @@
 				  share,
 				  lpcfg_resolve_context(tctx->lp_ctx),
 				  samba_cmdline_get_creds(),
+				  NULL, /* existing_conn */
 				  previous_session_id,
 				  tree,
 				  tctx->ev,
@@ -459,35 +460,28 @@
 /**
  * SMB2 connect with share from soption
  **/
-bool torture_smb2_con_sopt(struct torture_context *tctx,
-			   const char *soption,
-			   struct smb2_tree **tree)
+bool torture_smb2_con_share(struct torture_context *tctx,
+			    const char *share,
+			    struct smb2_tree **tree)
 {
 	struct smbcli_options options;
 	NTSTATUS status;
 	const char *host = torture_setting_string(tctx, "host", NULL);
-	const char *share = torture_setting_string(tctx, soption, NULL);
 
 	lpcfg_smbcli_options(tctx->lp_ctx, &options);
 
-	if (share == NULL) {
-		torture_comment(tctx, "No share for option %s\n", soption);
-		return false;
-	}
-
-	status = smb2_connect_ext(tctx,
-				  host,
-				  lpcfg_smb_ports(tctx->lp_ctx),
-				  share,
-				  lpcfg_resolve_context(tctx->lp_ctx),
-				  samba_cmdline_get_creds(),
-				  0,
-				  tree,
-				  tctx->ev,
-				  &options,
-				  lpcfg_socket_options(tctx->lp_ctx),
-				  lpcfg_gensec_settings(tctx, tctx->lp_ctx)
-				  );
+	status = smb2_connect(tctx,
+			      host,
+			      lpcfg_smb_ports(tctx->lp_ctx),
+			      share,
+			      lpcfg_resolve_context(tctx->lp_ctx),
+			      samba_cmdline_get_creds(),
+			      tree,
+			      tctx->ev,
+			      &options,
+			      lpcfg_socket_options(tctx->lp_ctx),
+			      lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+			      );
 	if (!NT_STATUS_IS_OK(status)) {
 		torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
 		       host, share, nt_errstr(status));
@@ -496,6 +490,23 @@
 	return true;
 }
 
+/**
+ * SMB2 connect with share from soption
+ **/
+bool torture_smb2_con_sopt(struct torture_context *tctx,
+			   const char *soption,
+			   struct smb2_tree **tree)
+{
+	const char *share = torture_setting_string(tctx, soption, NULL);
+
+	if (share == NULL) {
+		torture_comment(tctx, "No share for option %s\n", soption);
+		return false;
+	}
+
+	return torture_smb2_con_share(tctx, share, tree);
+}
+
 /*
   create and return a handle to a test file
   with a specific access mask
diff -Nru samba-4.17.10+dfsg/source4/torture/vfs/acl_xattr.c samba-4.17.11+dfsg/source4/torture/vfs/acl_xattr.c
--- samba-4.17.10+dfsg/source4/torture/vfs/acl_xattr.c	2022-08-08 17:15:40.492200400 +0300
+++ samba-4.17.11+dfsg/source4/torture/vfs/acl_xattr.c	2023-09-07 11:59:49.057452400 +0300
@@ -47,40 +47,6 @@
 	} \
 } while (0)
 
-/**
- * SMB2 connect with explicit share
- **/
-static bool torture_smb2_con_share(struct torture_context *tctx,
-                           const char *share,
-                           struct smb2_tree **tree)
-{
-        struct smbcli_options options;
-        NTSTATUS status;
-        const char *host = torture_setting_string(tctx, "host", NULL);
-
-        lpcfg_smbcli_options(tctx->lp_ctx, &options);
-
-        status = smb2_connect_ext(tctx,
-                                  host,
-                                  lpcfg_smb_ports(tctx->lp_ctx),
-                                  share,
-                                  lpcfg_resolve_context(tctx->lp_ctx),
-                                  samba_cmdline_get_creds(),
-                                  0,
-                                  tree,
-                                  tctx->ev,
-                                  &options,
-                                  lpcfg_socket_options(tctx->lp_ctx),
-                                  lpcfg_gensec_settings(tctx, tctx->lp_ctx)
-                                  );
-        if (!NT_STATUS_IS_OK(status)) {
-                printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
-                       host, share, nt_errstr(status));
-                return false;
-        }
-        return true;
-}
-
 static bool test_default_acl_posix(struct torture_context *tctx,
 				   struct smb2_tree *tree_unused)
 {
diff -Nru samba-4.17.10+dfsg/source4/torture/wscript_build samba-4.17.11+dfsg/source4/torture/wscript_build
--- samba-4.17.10+dfsg/source4/torture/wscript_build	2022-08-08 17:15:40.496200600 +0300
+++ samba-4.17.11+dfsg/source4/torture/wscript_build	2023-09-07 11:59:49.057452400 +0300
@@ -47,6 +47,7 @@
 
 bld.SAMBA_SUBSYSTEM('TORTURE_NDR',
         source='''ndr/ndr.c
+                  ndr/dcerpc.c
                   ndr/winreg.c
                   ndr/atsvc.c
                   ndr/lsa.c
diff -Nru samba-4.17.10+dfsg/VERSION samba-4.17.11+dfsg/VERSION
--- samba-4.17.10+dfsg/VERSION	2023-07-17 23:19:16.862757200 +0300
+++ samba-4.17.11+dfsg/VERSION	2023-09-07 11:59:49.021451000 +0300
@@ -25,7 +25,7 @@
 ########################################################
 SAMBA_VERSION_MAJOR=4
 SAMBA_VERSION_MINOR=17
-SAMBA_VERSION_RELEASE=10
+SAMBA_VERSION_RELEASE=11
 
 ########################################################
 # If a official release has a serious bug              #
diff -Nru samba-4.17.10+dfsg/WHATSNEW.txt samba-4.17.11+dfsg/WHATSNEW.txt
--- samba-4.17.10+dfsg/WHATSNEW.txt	2023-07-17 23:19:16.842757700 +0300
+++ samba-4.17.11+dfsg/WHATSNEW.txt	2023-09-07 11:59:49.021451000 +0300
@@ -1,4 +1,93 @@
                    ===============================
+                   Release Notes for Samba 4.17.11
+                         September 07, 2023
+                   ===============================
+
+
+This is the latest stable release of the Samba 4.17 release series.
+
+
+Changes since 4.17.10
+---------------------
+
+o  Jeremy Allison <jra at samba.org>
+   * BUG 15419: Weird filename can cause assert to fail in
+     openat_pathref_fsp_nosymlink().
+   * BUG 15420: reply_sesssetup_and_X() can dereference uninitialized tmp
+     pointer.
+   * BUG 15430: Missing return in reply_exit_done().
+   * BUG 15432: TREE_CONNECT without SETUP causes smbd to use uninitialized
+     pointer.
+
+o  Andrew Bartlett <abartlet at samba.org>
+   * BUG 15401: Improve GetNChanges to address some (but not all "Azure AD
+     Connect") syncronisation tool looping during the initial user sync phase.
+   * BUG 15407: Samba replication logs show (null) DN.
+   * BUG 9959: Windows client join fails if a second container CN=System exists
+    somewhere.
+
+o  Ralph Boehme <slow at samba.org>
+   * BUG 15342: Spotlight sometimes returns no results on latest macOS.
+   * BUG 15417: Renaming results in NT_STATUS_SHARING_VIOLATION if previously
+     attempted to remove the destination.
+   * BUG 15427: Spotlight results return wrong date in result list.
+   * BUG 15463: macOS mdfind returns only 50 results.
+
+o  Volker Lendecke <vl at samba.org>
+   * BUG 15346: 2-3min delays at reconnect with smb2_validate_sequence_number:
+     bad message_id 2.
+
+o  Stefan Metzmacher <metze at samba.org>
+   * BUG 15346: 2-3min delays at reconnect with smb2_validate_sequence_number:
+     bad message_id 2.
+   * BUG 15441: samba-tool ntacl get segfault if aio_pthread appended.
+   * BUG 15446: DCERPC_PKT_CO_CANCEL and DCERPC_PKT_ORPHANED can't be parsed.
+
+o  MikeLiu <mikeliu at qnap.com>
+   * BUG 15453: File doesn't show when user doesn't have permission if
+     aio_pthread is loaded.
+
+o  Noel Power <noel.power at suse.com>
+   * BUG 15384: net ads lookup (with unspecified realm) fails
+   * BUG 15435: Regression DFS not working with widelinks = true.
+
+o  Arvid Requate <requate at univention.de>
+   * BUG 9959: Windows client join fails if a second container CN=System exists
+    somewhere.
+
+o  Martin Schwenke <mschwenke at ddn.com>
+   * BUG 15451: ctdb_killtcp fails to work with --enable-pcap and libpcap ≥
+     1.9.1.
+
+o  Jones Syue <jonessyue at qnap.com>
+   * BUG 15441: samba-tool ntacl get segfault if aio_pthread appended.
+   * BUG 15449: mdssvc: Do an early talloc_free() in _mdssvc_open().
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical:matrix.org matrix room, or
+#samba-technical IRC channel on irc.libera.chat.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored.  All bug reports should
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+                   ===============================
                    Release Notes for Samba 4.17.10
                             July 19, 2023
                    ===============================
@@ -70,8 +159,7 @@
 ======================================================================
 
 
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
                    ==============================
                    Release Notes for Samba 4.17.9
                            July 06, 2023


More information about the Pkg-samba-maint mailing list