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