[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1051594: marked as done (bookworm-pu: package samba/2:4.17.11+dfsg-0+deb12u1)



Your message dated Sat, 07 Oct 2023 09:59:42 +0000
with message-id <E1qp462-00A4Gk-6X@coccia.debian.org>
and subject line Released with 12.2
has caused the Debian Bug report #1051594,
regarding bookworm-pu: package samba/2:4.17.11+dfsg-0+deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1051594: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1051594
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: samba@packages.debian.org, pkg-samba-maint@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@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@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@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@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@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@samba.org>
+   * BUG 15346: 2-3min delays at reconnect with smb2_validate_sequence_number:
+     bad message_id 2.
+
+o  Stefan Metzmacher <metze@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@qnap.com>
+   * BUG 15453: File doesn't show when user doesn't have permission if
+     aio_pthread is loaded.
+
+o  Noel Power <noel.power@suse.com>
+   * BUG 15384: net ads lookup (with unspecified realm) fails
+   * BUG 15435: Regression DFS not working with widelinks = true.
+
+o  Arvid Requate <requate@univention.de>
+   * BUG 9959: Windows client join fails if a second container CN=System exists
+    somewhere.
+
+o  Martin Schwenke <mschwenke@ddn.com>
+   * BUG 15451: ctdb_killtcp fails to work with --enable-pcap and libpcap ≥
+     1.9.1.
+
+o  Jones Syue <jonessyue@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

--- End Message ---
--- Begin Message ---
Version: 12.2

The upload requested in this bug has been released as part of 12.2.

--- End Message ---

Reply to: