From 550ece56400dc7391296943cf93ce0a4e54f9843 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 12:05:51 -0800
Subject: [PATCH 08/99] CVE-2021-44141: s4: libcli: Add smbcli_unlink_wcard().

We will use this in place of smbcli_unlink() when we
know we are using a wildcard pattern. If can be used
to generally replace smbcli_unlink() as it calls down
to smbcli_unlink() is no wildcard is detected.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/libcli/clifile.c | 96 ++++++++++++++++++++++++++++++++++++++++
 source4/libcli/libcli.h  |  5 +++
 2 files changed, 101 insertions(+)

diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c
index 19288247c44..f013a5653bb 100644
--- a/source4/libcli/clifile.c
+++ b/source4/libcli/clifile.c
@@ -23,6 +23,7 @@
 #include "system/filesys.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/libcli.h"
+#include "system/dir.h"
 
 /****************************************************************************
  Hard/Symlink a file (UNIX extensions).
@@ -148,6 +149,101 @@ NTSTATUS smbcli_unlink(struct smbcli_tree *tree, const char *fname)
 	return smb_raw_unlink(tree, &parms);
 }
 
+struct wcard_delete_state {
+	struct smbcli_tree *tree;
+	NTSTATUS status;
+	char *error_name; /* To help debugging. */
+};
+
+static void del_fn(struct clilist_file_info *finfo,
+			const char *pattern,
+			void *priv)
+{
+	NTSTATUS status;
+	union smb_unlink parms;
+	char *filename = NULL;
+	char *dirname = NULL;
+	char *p = NULL;
+	struct wcard_delete_state *state = (struct wcard_delete_state *)priv;
+
+	if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
+		return;
+	}
+	dirname = talloc_strdup(state, pattern);
+	if (dirname == NULL) {
+		TALLOC_FREE(state->error_name);
+		state->status = NT_STATUS_NO_MEMORY;
+		return;
+	}
+	p = strrchr_m(dirname, '\\');
+	if (p != NULL) {
+		/* Remove the terminating '\' */
+		*p = '\0';
+	}
+	if (dirname[0] != '\0') {
+		filename = talloc_asprintf(dirname,
+					   "%s\\%s",
+					   dirname,
+					   finfo->name);
+	} else {
+		filename = talloc_asprintf(dirname,
+					   "%s",
+					   finfo->name);
+	}
+	if (filename == NULL) {
+		TALLOC_FREE(dirname);
+		TALLOC_FREE(state->error_name);
+		state->status = NT_STATUS_NO_MEMORY;
+		return;
+	}
+	parms.unlink.in.pattern = filename;
+	parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM |
+				 FILE_ATTRIBUTE_HIDDEN;
+	status = smb_raw_unlink(state->tree, &parms);
+	if (NT_STATUS_IS_OK(state->status)) {
+		state->status = status;
+		if (!NT_STATUS_IS_OK(status)) {
+			/*
+			 * Save off the name we failed to
+			 * delete to help debugging.
+			 */
+			state->error_name = talloc_move(state, &filename);
+		}
+	}
+	TALLOC_FREE(dirname);
+}
+
+/****************************************************************************
+ Delete a file, possibly with a wildcard pattern.
+****************************************************************************/
+NTSTATUS smbcli_unlink_wcard(struct smbcli_tree *tree, const char *pattern)
+{
+	NTSTATUS status;
+	int ret;
+	struct wcard_delete_state *state = NULL;
+
+	if (strchr(pattern, '*') == NULL) {
+		/* No wildcard, just call smbcli_unlink(). */
+		return smbcli_unlink(tree, pattern);
+	}
+	state = talloc_zero(tree, struct wcard_delete_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	state->tree = tree;
+	ret = smbcli_list(tree,
+			  pattern,
+			  FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+			  del_fn,
+			  state);
+	status = state->status;
+	TALLOC_FREE(state);
+	if (ret < 0) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	return status;
+}
+
 /****************************************************************************
  Create a directory.
 ****************************************************************************/
diff --git a/source4/libcli/libcli.h b/source4/libcli/libcli.h
index 652a9f5d182..9d2a3240483 100644
--- a/source4/libcli/libcli.h
+++ b/source4/libcli/libcli.h
@@ -158,6 +158,11 @@ NTSTATUS smbcli_rename(struct smbcli_tree *tree, const char *fname_src,
 ****************************************************************************/
 NTSTATUS smbcli_unlink(struct smbcli_tree *tree, const char *fname);
 
+/****************************************************************************
+ Delete a wildcard pattern of files.
+****************************************************************************/
+NTSTATUS smbcli_unlink_wcard(struct smbcli_tree *tree, const char *fname);
+
 /****************************************************************************
  Create a directory.
 ****************************************************************************/
-- 
2.25.1


From cf661f306afaf66feeea11bb2d9e7f7e3c988914 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 12:10:14 -0800
Subject: [PATCH 09/99] CVE-2021-44141: s4: libcli: In smbcli_deltree() use
 smbcli_unlink_wcard() in place of smbcli_unlink().

We know we have a wildcard mask here.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/libcli/clideltree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/libcli/clideltree.c b/source4/libcli/clideltree.c
index 01b33313213..3e4f9fb834f 100644
--- a/source4/libcli/clideltree.c
+++ b/source4/libcli/clideltree.c
@@ -119,7 +119,7 @@ int smbcli_deltree(struct smbcli_tree *tree, const char *dname)
 	if (asprintf(&mask, "%s\\*", dname) < 0) {
 		return -1;
 	}
-	smbcli_unlink(dstate.tree, mask);
+	smbcli_unlink_wcard(dstate.tree, mask);
 	smbcli_list(dstate.tree, mask, 
 		 FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 
 		 delete_fn, &dstate);
-- 
2.25.1


From a0fd6cd62f3d773371fa5f460306a562e524e6eb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 12:08:49 -0800
Subject: [PATCH 10/99] CVE-2021-44141: s4: torture: In raw.notify test use
 smbcli_unlink_wcard() in place of smbcli_unlink().

We know we have a wildcard mask here.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/raw/notify.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/raw/notify.c b/source4/torture/raw/notify.c
index 881ad6b71cc..f3c38068780 100644
--- a/source4/torture/raw/notify.c
+++ b/source4/torture/raw/notify.c
@@ -254,7 +254,7 @@ static bool test_notify_dir(struct torture_context *tctx,
 
 	torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
 	/* (2nd unlink) do a wildcard unlink */
-	status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
+	status = smbcli_unlink_wcard(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
 	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
 					"smb_raw_changenotify_recv");
 
-- 
2.25.1


From 6f9580493e250a00d100a3f96253d00bd4294b55 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 17:52:37 -0800
Subject: [PATCH 11/99] CVE-2021-44141: s4: torture: Use smbcli_unlink_wcard()
 to remove wildcards in base.chkpath test.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/basic/base.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c
index e91fef1d6c2..232ba9c5cb3 100644
--- a/source4/torture/basic/base.c
+++ b/source4/torture/basic/base.c
@@ -1461,7 +1461,7 @@ static bool torture_chkpath_test(struct torture_context *tctx,
 
 	/* cleanup from an old run */
 	smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
-	smbcli_unlink(cli->tree, "\\chkpath.dir\\*");
+	smbcli_unlink_wcard(cli->tree, "\\chkpath.dir\\*");
 	smbcli_rmdir(cli->tree, "\\chkpath.dir");
 
 	if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\chkpath.dir"))) {
@@ -1516,7 +1516,7 @@ static bool torture_chkpath_test(struct torture_context *tctx,
 	}
 
 	smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
-	smbcli_unlink(cli->tree, "\\chkpath.dir\\*");
+	smbcli_unlink_wcard(cli->tree, "\\chkpath.dir\\*");
 	smbcli_rmdir(cli->tree, "\\chkpath.dir");
 
 	return ret;
-- 
2.25.1


From 745d08fe10a824ef1fe1fcf57fadfd6c8b6ae216 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 17:58:58 -0800
Subject: [PATCH 12/99] CVE-2021-44141: s4: torture: Use smbcli_unlink_wcard()
 to cleanup in base.mangle test.

Avoid using smbcli_unlink() calls with wildcard names.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/basic/mangle_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/basic/mangle_test.c b/source4/torture/basic/mangle_test.c
index 0c3ccd54bf9..9bd3cf55dfb 100644
--- a/source4/torture/basic/mangle_test.c
+++ b/source4/torture/basic/mangle_test.c
@@ -195,7 +195,7 @@ bool torture_mangle(struct torture_context *torture,
 		}
 	}
 
-	smbcli_unlink(cli->tree, "\\mangle_test\\*");
+	smbcli_unlink_wcard(cli->tree, "\\mangle_test\\*");
 	if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, "\\mangle_test"))) {
 		printf("ERROR: Failed to remove directory\n");
 		return false;
-- 
2.25.1


From ee3a5f2ee00cbd78446cff2e815f6cf3600e17a8 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 18:03:57 -0800
Subject: [PATCH 13/99] CVE-2021-44141: s4: torture: Use smbcli_unlink_wcard()
 in base.casetable test.

Avoid smbcli_unlink() calls with a wildcard path.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/basic/utable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/basic/utable.c b/source4/torture/basic/utable.c
index da2fe2e0b37..a3ddf1a7621 100644
--- a/source4/torture/basic/utable.c
+++ b/source4/torture/basic/utable.c
@@ -195,7 +195,7 @@ bool torture_casetable(struct torture_context *tctx,
 		smbcli_close(cli->tree, fnum);
 	}
 
-	smbcli_unlink(cli->tree, "\\utable\\*");
+	smbcli_unlink_wcard(cli->tree, "\\utable\\*");
 	smbcli_rmdir(cli->tree, "\\utable");
 
 	return true;
-- 
2.25.1


From 2cfbfd3e0a6fd012944cad4e0fe7fe2a8688b7cc Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 18:08:32 -0800
Subject: [PATCH 14/99] CVE-2021-44141: s4: torture: Use smbcli_unlink_wcard()
 to setup and cleanup in masktest.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/masktest.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/masktest.c b/source4/torture/masktest.c
index 5b2457a92e9..e311769a43d 100644
--- a/source4/torture/masktest.c
+++ b/source4/torture/masktest.c
@@ -225,7 +225,7 @@ static void test_mask(int argc, char *argv[],
 
 	smbcli_mkdir(cli->tree, "\\masktest");
 
-	smbcli_unlink(cli->tree, "\\masktest\\*");
+	smbcli_unlink_wcard(cli->tree, "\\masktest\\*");
 
 	if (argc >= 2) {
 		while (argc >= 2) {
-- 
2.25.1


From db095ee5f039dc079200f1791c62c168ec57f2aa Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:23:10 -0800
Subject: [PATCH 15/99] CVE-2021-44141: s4: libcli: smbcli_unlink() is no
 longer used with wildcard patterns.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/libcli/clifile.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c
index f013a5653bb..c6a5cd5a5e7 100644
--- a/source4/libcli/clifile.c
+++ b/source4/libcli/clifile.c
@@ -140,11 +140,7 @@ NTSTATUS smbcli_unlink(struct smbcli_tree *tree, const char *fname)
 	union smb_unlink parms;
 
 	parms.unlink.in.pattern = fname;
-	if (strchr(fname, '*')) {
-		parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
-	} else {
-		parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
-	}
+	parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
 
 	return smb_raw_unlink(tree, &parms);
 }
-- 
2.25.1


From 57fbf7564c7a0bea68ec80f774deb2fba22f3afb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 13:47:07 -0800
Subject: [PATCH 16/99] CVE-2021-44141: s3: torture: Add torture_deltree() for
 setup and teardown.

Not yet used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/proto.h   |   1 +
 source3/torture/torture.c | 127 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 128 insertions(+)

diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 65fa17523d8..d4db60f9dde 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -74,6 +74,7 @@ bool torture_ioctl_test(int dummy);
 bool torture_chkpath_test(int dummy);
 NTSTATUS torture_setup_unix_extensions(struct cli_state *cli);
 void torture_conn_set_sockopt(struct cli_state *cli);
+void torture_deltree(struct cli_state *cli, const char *dname);
 
 /* The following definitions come from torture/utable.c  */
 
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 4a886614ae1..a995b54df9c 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -458,6 +458,133 @@ void torture_conn_set_sockopt(struct cli_state *cli)
 	smbXcli_conn_set_sockopt(cli->conn, sockops);
 }
 
+static NTSTATUS torture_delete_fn(struct file_info *finfo,
+				  const char *pattern,
+				  void *state)
+{
+	NTSTATUS status;
+	char *filename = NULL;
+	char *dirname = NULL;
+	char *p = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct cli_state *cli = (struct cli_state *)state;
+
+	if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_OK;
+	}
+
+	dirname = talloc_strdup(frame, pattern);
+	if (dirname == NULL) {
+		TALLOC_FREE(frame);
+                return NT_STATUS_NO_MEMORY;
+        }
+        p = strrchr_m(dirname, '\\');
+        if (p != NULL) {
+                /* Remove the terminating '\' */
+                *p = '\0';
+        }
+        if (dirname[0] != '\0') {
+                filename = talloc_asprintf(frame,
+                                           "%s\\%s",
+                                           dirname,
+                                           finfo->name);
+        } else {
+                filename = talloc_asprintf(frame,
+                                           "%s",
+                                           finfo->name);
+        }
+        if (filename == NULL) {
+                TALLOC_FREE(frame);
+                return NT_STATUS_NO_MEMORY;
+        }
+	if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
+		char *subdirname = talloc_asprintf(frame,
+						   "%s\\*",
+						   filename);
+		if (subdirname == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+		status = cli_list(cli,
+				  subdirname,
+				  FILE_ATTRIBUTE_DIRECTORY |
+					  FILE_ATTRIBUTE_HIDDEN |
+					  FILE_ATTRIBUTE_SYSTEM,
+				  torture_delete_fn,
+				  cli);
+		if (NT_STATUS_IS_OK(status)) {
+			printf("torture_delete_fn: cli_list "
+				"of %s failed (%s)\n",
+				subdirname,
+				nt_errstr(status));
+			TALLOC_FREE(frame);
+			return status;
+		}
+		status = cli_rmdir(cli, filename);
+	} else {
+		status = cli_unlink(cli,
+				    filename,
+				    FILE_ATTRIBUTE_SYSTEM |
+					FILE_ATTRIBUTE_HIDDEN);
+	}
+	if (!NT_STATUS_IS_OK(status)) {
+		if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
+			printf("torture_delete_fn: cli_rmdir"
+				" of %s failed (%s)\n",
+				filename,
+				nt_errstr(status));
+		} else {
+			printf("torture_delete_fn: cli_unlink"
+				" of %s failed (%s)\n",
+				filename,
+				nt_errstr(status));
+		}
+	}
+	TALLOC_FREE(frame);
+	return status;
+}
+
+void torture_deltree(struct cli_state *cli, const char *dname)
+{
+	char *mask = NULL;
+	NTSTATUS status;
+
+	/* It might be a file */
+	(void)cli_unlink(cli,
+			 dname,
+			 FILE_ATTRIBUTE_SYSTEM |
+				FILE_ATTRIBUTE_HIDDEN);
+
+	mask = talloc_asprintf(cli,
+			       "%s\\*",
+			       dname);
+	if (mask == NULL) {
+		printf("torture_deltree: talloc_asprintf failed\n");
+		return;
+	}
+
+	status = cli_list(cli,
+			mask,
+			FILE_ATTRIBUTE_DIRECTORY |
+				FILE_ATTRIBUTE_HIDDEN|
+				FILE_ATTRIBUTE_SYSTEM,
+			torture_delete_fn,
+			cli);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("torture_deltree: cli_list of %s failed (%s)\n",
+			mask,
+			nt_errstr(status));
+	}
+	TALLOC_FREE(mask);
+	status = cli_rmdir(cli, dname);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("torture_deltree: cli_rmdir of %s failed (%s)\n",
+			dname,
+			nt_errstr(status));
+	}
+}
+
 /* check if the server produced the expected dos or nt error code */
 static bool check_both_error(int line, NTSTATUS status,
 			     uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
-- 
2.25.1


From 74fe15a05ad913112c4a76431b9e280e17ab2ee4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:51:54 -0800
Subject: [PATCH 17/99] CVE-2021-44141: s3: torture: In
 run_smb1_wild_mangle_unlink_test() use torture_deltree() for setup and
 cleanup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/torture.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index a995b54df9c..cb11524446a 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -12814,10 +12814,7 @@ static bool run_smb1_wild_mangle_unlink_test(int dummy)
 	}
 
 	/* Start fresh. */
-	cli_unlink(cli,
-		star_name,
-		FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, dname);
+	torture_deltree(cli, dname);
 
 	/*
 	 * Create two files - 'a' and '*'.
@@ -12927,10 +12924,7 @@ static bool run_smb1_wild_mangle_unlink_test(int dummy)
 	TALLOC_FREE(mangled_name);
 
 	if (cli != NULL) {
-		cli_unlink(cli,
-			star_name,
-			FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-		cli_rmdir(cli, dname);
+		torture_deltree(cli, dname);
 		torture_close_connection(cli);
 	}
 
-- 
2.25.1


From 919b3c8d3fb9c5248a79ff01e096353cab3fd9f0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 13:51:12 -0800
Subject: [PATCH 18/99] CVE-2021-44141: s3: torture: In
 run_smb1_wild_mangle_rename_test() use torture_deltree() for setup and
 cleanup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/torture.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index cb11524446a..5b5b5287d55 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -12972,10 +12972,7 @@ static bool run_smb1_wild_mangle_rename_test(int dummy)
 	smbXcli_conn_set_sockopt(cli->conn, sockops);
 
 	/* Ensure we start from fresh. */
-	cli_unlink(cli,
-		wild_name,
-		FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_posix_rmdir(cli_posix, dname);
+	torture_deltree(cli, dname);
 
 	/*
 	 * Create two files - 'foo' and 'fo*'.
@@ -13094,13 +13091,10 @@ static bool run_smb1_wild_mangle_rename_test(int dummy)
 	TALLOC_FREE(windows_rename_src);
 
 	if (cli != NULL) {
-		cli_unlink(cli,
-			wild_name,
-			FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+		torture_deltree(cli, dname);
 		torture_close_connection(cli);
 	}
 
-	cli_posix_rmdir(cli_posix, dname);
 	torture_close_connection(cli_posix);
 
 	return correct;
-- 
2.25.1


From 04304b9f92cb6b17fa368ed039f84f3a75cf9016 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:13:41 -0800
Subject: [PATCH 19/99] CVE-2021-44141: s3: torture: In torture_utable(), use
 torture_deltree() for setup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/utable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/torture/utable.c b/source3/torture/utable.c
index a912c4cb3b0..01f6b2e51e9 100644
--- a/source3/torture/utable.c
+++ b/source3/torture/utable.c
@@ -43,8 +43,8 @@ bool torture_utable(int dummy)
 
 	memset(valid, 0, sizeof(valid));
 
+	torture_deltree(cli, "\\utable");
 	cli_mkdir(cli, "\\utable");
-	cli_unlink(cli, "\\utable\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
 
 	for (c=1; c < 0x10000; c++) {
 		size_t size = 0;
-- 
2.25.1


From 18ac36f7aed4e46f2c029d67c0e97ce4c32e9bbe Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:14:53 -0800
Subject: [PATCH 20/99] CVE-2021-44141: s3: torture: In torture_casetable(),
 use torture_deltree() for setup and cleanup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/utable.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/source3/torture/utable.c b/source3/torture/utable.c
index 01f6b2e51e9..059cae9edd1 100644
--- a/source3/torture/utable.c
+++ b/source3/torture/utable.c
@@ -146,8 +146,7 @@ bool torture_casetable(int dummy)
 
 	memset(equiv, 0, sizeof(equiv));
 
-	cli_unlink(cli, "\\utable\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, "\\utable");
+	torture_deltree(cli, "\\utable");
 	if (!NT_STATUS_IS_OK(cli_mkdir(cli, "\\utable"))) {
 		printf("Failed to create utable directory!\n");
 		return False;
@@ -205,8 +204,7 @@ bool torture_casetable(int dummy)
 		cli_close(cli, fnum);
 	}
 
-	cli_unlink(cli, "\\utable\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, "\\utable");
+	torture_deltree(cli, "\\utable");
 
 	return True;
 }
-- 
2.25.1


From ff64b0f32d0f0b41926badff7aab53c32759bc94 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:16:38 -0800
Subject: [PATCH 21/99] CVE-2021-44141: s3: torture: In torture_chkpath_test(),
 use torture_deltree() for setup and cleanup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/torture.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 5b5b5287d55..e4343cf3050 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -9933,9 +9933,7 @@ bool torture_chkpath_test(int dummy)
 	printf("starting chkpath test\n");
 
 	/* cleanup from an old run */
-	cli_rmdir(cli, "\\chkpath.dir\\dir2");
-	cli_unlink(cli, "\\chkpath.dir\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, "\\chkpath.dir");
+	torture_deltree(cli, "\\chkpath.dir");
 
 	status = cli_mkdir(cli, "\\chkpath.dir");
 	if (!NT_STATUS_IS_OK(status)) {
@@ -9996,9 +9994,7 @@ bool torture_chkpath_test(int dummy)
 		ret = False;
 	}
 
-	cli_rmdir(cli, "\\chkpath.dir\\dir2");
-	cli_unlink(cli, "\\chkpath.dir\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, "\\chkpath.dir");
+	torture_deltree(cli, "\\chkpath.dir");
 
 	if (!torture_close_connection(cli)) {
 		return False;
-- 
2.25.1


From 8349c57f76fcd53810620fc79d6b892ed2141ae6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:18:56 -0800
Subject: [PATCH 22/99] CVE-2021-44141: s3: torture: In run_streamerror(), use
 torture_deltree() for setup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/torture.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index e4343cf3050..9ad0f2120e5 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -12464,8 +12464,7 @@ static bool run_streamerror(int dummy)
 		return false;
 	}
 
-	cli_unlink(cli, "\\testdir_streamerror\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, dname);
+	torture_deltree(cli, dname);
 
 	status = cli_mkdir(cli, dname);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
2.25.1


From cf109e26b7ae918833cb4610dbcba8dc9f7c5bc0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:20:07 -0800
Subject: [PATCH 23/99] CVE-2021-44141: s3: torture: In test_mask(), use
 torture_deltree() for setup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/masktest.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c
index ebd156167cd..d7485cfb5eb 100644
--- a/source3/torture/masktest.c
+++ b/source3/torture/masktest.c
@@ -355,10 +355,9 @@ static void test_mask(int argc, char *argv[],
 	int fc_len = strlen(filechars);
 	TALLOC_CTX *ctx = talloc_tos();
 
+	torture_deltree(cli, "\\masktest");
 	cli_mkdir(cli, "\\masktest");
 
-	cli_unlink(cli, "\\masktest\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-
 	if (argc >= 2) {
 		while (argc >= 2) {
 			mask = talloc_asprintf(ctx,
-- 
2.25.1


From c249f1d09d60fb637a118c0ade7714cc3fcb1866 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:21:47 -0800
Subject: [PATCH 24/99] CVE-2021-44141: s3: torture: In torture_mangle(), use
 torture_deltree() for setup and cleanup.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/mangle_test.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/source3/torture/mangle_test.c b/source3/torture/mangle_test.c
index 5832a92cdda..92754b9eeb6 100644
--- a/source3/torture/mangle_test.c
+++ b/source3/torture/mangle_test.c
@@ -188,8 +188,7 @@ bool torture_mangle(int dummy)
 		return False;
 	}
 
-	cli_unlink(cli, "\\mangle_test\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	cli_rmdir(cli, "\\mangle_test");
+	torture_deltree(cli, "\\mangle_test");
 
 	if (!NT_STATUS_IS_OK(cli_mkdir(cli, "\\mangle_test"))) {
 		printf("ERROR: Failed to make directory\n");
@@ -212,11 +211,7 @@ bool torture_mangle(int dummy)
 		}
 	}
 
-	cli_unlink(cli, "\\mangle_test\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-	if (!NT_STATUS_IS_OK(cli_rmdir(cli, "\\mangle_test"))) {
-		printf("ERROR: Failed to remove directory\n");
-		return False;
-	}
+	torture_deltree(cli, "\\mangle_test");
 
 	printf("\nTotal collisions %u/%u  - %.2f%%   (%u failures)\n",
 	       collisions, total, (100.0*collisions) / total, failures);
-- 
2.25.1


From 6c40cda03e7011fe6ad7df2170a11bcfcce38e40 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 14:10:41 -0800
Subject: [PATCH 25/99] CVE-2021-44141: s3: torture: In
 run_smb1_wild_mangle_unlink_test() use a valid pathname for rename target.

The server will not be supporting wildcard rename soon.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/torture/torture.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 9ad0f2120e5..b80a1113a5f 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -12941,7 +12941,7 @@ static bool run_smb1_wild_mangle_rename_test(int dummy)
 	const char *foostar_name = "smb1_wild_mangle_rename/fo*";
 	const char *wild_name = "smb1_wild_mangle_rename/*";
 	char *windows_rename_src = NULL;
-	const char *windows_rename_dst = "smb1_wild_mangle_rename\\ba*";
+	const char *windows_rename_dst = "smb1_wild_mangle_rename\\bar";
 	char *mangled_name = NULL;
 	NTSTATUS status;
 
-- 
2.25.1


From b39ba559c078b371a3b212a4c26e589fae811417 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:05:20 -0800
Subject: [PATCH 26/99] CVE-2021-44141: s4: torture: Remove the wildcard unlink
 test code.

This is pre WindowXP SMB1 functionality, and we
need to remove this from the server in order to
move towards SMB2-only, so the test must go.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/raw/unlink.c | 72 ------------------------------------
 1 file changed, 72 deletions(-)

diff --git a/source4/torture/raw/unlink.c b/source4/torture/raw/unlink.c
index 4f198fa2759..53059aa576a 100644
--- a/source4/torture/raw/unlink.c
+++ b/source4/torture/raw/unlink.c
@@ -112,78 +112,6 @@ static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
 	status = smb_raw_unlink(cli->tree, &io);
 	CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
 
-	printf("Trying wildcards\n");
-	smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
-	io.unlink.in.pattern = BASEDIR "\\t*.t";
-	io.unlink.in.attrib = 0;
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-
-	io.unlink.in.pattern = BASEDIR "\\z*";
-	io.unlink.in.attrib = 0;
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-
-	io.unlink.in.pattern = BASEDIR "\\z*";
-	io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
-	status = smb_raw_unlink(cli->tree, &io);
-
-	if (torture_setting_bool(tctx, "samba3", false)) {
-		/*
-		 * In Samba3 we gave up upon getting the error codes in
-		 * wildcard unlink correct. Trying gentest showed that this is
-		 * irregular beyond our capabilities. So for
-		 * FILE_ATTRIBUTE_DIRECTORY we always return NAME_INVALID.
-		 * Tried by jra and vl. If others feel like solving this
-		 * puzzle, please tell us :-)
-		 */
-		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
-	}
-	else {
-		CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-	}
-
-	io.unlink.in.pattern = BASEDIR "\\*";
-	io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
-
-	io.unlink.in.pattern = BASEDIR "\\?";
-	io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
-
-	io.unlink.in.pattern = BASEDIR "\\t*";
-	io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
-	status = smb_raw_unlink(cli->tree, &io);
-	if (torture_setting_bool(tctx, "samba3", false)) {
-		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
-	}
-	else {
-		CHECK_STATUS(status, NT_STATUS_OK);
-	}
-
-	smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
-
-	io.unlink.in.pattern = BASEDIR "\\*.dat";
-	io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
-	status = smb_raw_unlink(cli->tree, &io);
-	if (torture_setting_bool(tctx, "samba3", false)) {
-		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
-	}
-	else {
-		CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-	}
-
-	io.unlink.in.pattern = BASEDIR "\\*.tx?";
-	io.unlink.in.attrib = 0;
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
-	status = smb_raw_unlink(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-
-
 done:
 	smb_raw_exit(cli->session);
 	smbcli_deltree(cli->tree, BASEDIR);
-- 
2.25.1


From 05d2d29964ef5ef0e519b9621002138423d99bf9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 13:22:39 -0800
Subject: [PATCH 27/99] CVE-2021-44141: s4: torture: Remove the wildcard rename
 test code.

This is pre WindowXP SMB1 functionality, and we
need to remove this from the server in order to
move towards SMB2-only, so the test must go.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source4/torture/raw/rename.c | 33 ---------------------------------
 1 file changed, 33 deletions(-)

diff --git a/source4/torture/raw/rename.c b/source4/torture/raw/rename.c
index 63e13c0546f..5f48c055984 100644
--- a/source4/torture/raw/rename.c
+++ b/source4/torture/raw/rename.c
@@ -146,39 +146,6 @@ static bool test_mv(struct torture_context *tctx,
 	status = smb_raw_rename(cli->tree, &io);
 	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 
-
-	torture_comment(tctx, "trying wildcard rename\n");
-	io.rename.in.pattern1 = BASEDIR "\\*.txt";
-	io.rename.in.pattern2 = fname1;
-	
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
-	torture_comment(tctx, "and again\n");
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
-	torture_comment(tctx, "Trying extension change\n");
-	io.rename.in.pattern1 = BASEDIR "\\*.txt";
-	io.rename.in.pattern2 = BASEDIR "\\*.bak";
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-
-	torture_comment(tctx, "Checking attrib handling\n");
-	torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN);
-	io.rename.in.pattern1 = BASEDIR "\\test1.bak";
-	io.rename.in.pattern2 = BASEDIR "\\*.txt";
-	io.rename.in.attrib = 0;
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
-
-	io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
-	status = smb_raw_rename(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_OK);
-
 done:
 	smbcli_close(cli->tree, fnum);
 	smb_raw_exit(cli->session);
-- 
2.25.1


From 80d8a557dda29441f4091ec76bed86d23fd3f223 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:18:35 -0800
Subject: [PATCH 28/99] CVE-2021-44141: s3: torture: Remove the wildcard unlink
 test code.

This is pre WindowXP SMB1 functionality, and we
need to remove this from the server in order to
move towards SMB2-only, so the test must go.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 selftest/todo_smb2_tests_to_port.list |  2 -
 source3/selftest/tests.py             |  2 +-
 source3/torture/torture.c             | 69 ---------------------------
 3 files changed, 1 insertion(+), 72 deletions(-)

diff --git a/selftest/todo_smb2_tests_to_port.list b/selftest/todo_smb2_tests_to_port.list
index a9d7b8b48c5..dc1df963918 100644
--- a/selftest/todo_smb2_tests_to_port.list
+++ b/selftest/todo_smb2_tests_to_port.list
@@ -242,7 +242,6 @@ samba3.smbtorture_s3.crypt_client.TRANS2(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt_client.UID-REGRESSION-TEST(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt_client.UNLINK(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt_client.W2K(nt4_dc_smb1)
-samba3.smbtorture_s3.crypt_client.WILDDELETE(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt_client.XCOPY(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt.POSIX-ACL-OPLOCK(nt4_dc_smb1)
 samba3.smbtorture_s3.crypt.POSIX-ACL-SHAREROOT(nt4_dc_smb1)
@@ -327,7 +326,6 @@ samba3.smbtorture_s3.plain.TRANS2(fileserver_smb1)
 samba3.smbtorture_s3.plain.UID-REGRESSION-TEST(fileserver_smb1)
 samba3.smbtorture_s3.plain.UNLINK(fileserver_smb1)
 samba3.smbtorture_s3.plain.W2K(fileserver_smb1)
-samba3.smbtorture_s3.plain.WILDDELETE(fileserver_smb1)
 samba3.smbtorture_s3.plain.WINDOWS-BAD-SYMLINK(nt4_dc_smb1)
 samba3.smbtorture_s3.plain.XCOPY(fileserver_smb1)
 samba3.smbtorture_s3.vfs_aio_fork(fileserver_smb1).RW1(fileserver_smb1)
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 0654d8b0495..4751e4437aa 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -113,7 +113,7 @@ fileserver_tests = [
          "UNLINK", "BROWSE", "ATTR", "TRANS2", "TORTURE",
          "OPLOCK1", "OPLOCK2", "OPLOCK4", "STREAMERROR",
          "DIR", "DIR1", "DIR-CREATETIME", "TCON", "TCONDEV", "RW1", "RW2", "RW3", "LARGE_READX", "RW-SIGNING",
-         "OPEN", "XCOPY", "RENAME", "DELETE", "DELETE-LN", "WILDDELETE", "PROPERTIES", "W2K",
+         "OPEN", "XCOPY", "RENAME", "DELETE", "DELETE-LN", "PROPERTIES", "W2K",
          "TCON2", "IOCTL", "CHKPATH", "FDSESS", "CHAIN1", "CHAIN2", "OWNER-RIGHTS",
          "CHAIN3", "PIDHIGH", "CLI_SPLICE",
          "UID-REGRESSION-TEST", "SHORTNAME-TEST",
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index b80a1113a5f..0d3b01326b1 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -6121,71 +6121,6 @@ static bool run_delete_print_test(int dummy)
 	return correct;
 }
 
-/*
-  Test wildcard delete.
- */
-static bool run_wild_deletetest(int dummy)
-{
-	struct cli_state *cli = NULL;
-	const char *dname = "\\WTEST";
-	const char *fname = "\\WTEST\\A";
-	const char *wunlink_name = "\\WTEST\\*";
-	uint16_t fnum1 = (uint16_t)-1;
-	bool correct = false;
-	NTSTATUS status;
-
-	printf("starting wildcard delete test\n");
-
-	if (!torture_open_connection(&cli, 0)) {
-		return false;
-	}
-
-	smbXcli_conn_set_sockopt(cli->conn, sockops);
-
-	cli_unlink(cli, fname, 0);
-	cli_rmdir(cli, dname);
-	status = cli_mkdir(cli, dname);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("mkdir of %s failed %s!\n", dname, nt_errstr(status));
-		goto fail;
-	}
-	status = cli_openx(cli, fname, O_CREAT|O_RDONLY, DENY_NONE, &fnum1);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("open of %s failed %s!\n", fname, nt_errstr(status));
-		goto fail;
-	}
-	status = cli_close(cli, fnum1);
-	fnum1 = -1;
-
-	/*
-	 * Note the unlink attribute-type of zero. This should
-	 * map into FILE_ATTRIBUTE_NORMAL at the server even
-	 * on a wildcard delete.
-	 */
-
-	status = cli_unlink(cli, wunlink_name, 0);
-	if (!NT_STATUS_IS_OK(status)) {
-		printf("unlink of %s failed %s!\n",
-			wunlink_name, nt_errstr(status));
-		goto fail;
-	}
-
-	printf("finished wildcard delete test\n");
-
-	correct = true;
-
-  fail:
-
-	if (fnum1 != (uint16_t)-1) cli_close(cli, fnum1);
-	cli_unlink(cli, fname, 0);
-	cli_rmdir(cli, dname);
-
-	if (cli && !torture_close_connection(cli)) {
-		correct = false;
-	}
-	return correct;
-}
-
 static bool run_deletetest_ln(int dummy)
 {
 	struct cli_state *cli;
@@ -15148,10 +15083,6 @@ static struct {
 		.name  = "DELETE-PRINT",
 		.fn    = run_delete_print_test,
 	},
-	{
-		.name  = "WILDDELETE",
-		.fn    = run_wild_deletetest,
-	},
 	{
 		.name  = "DELETE-LN",
 		.fn    = run_deletetest_ln,
-- 
2.25.1


From d57802650f48391ef906283963c86e31466702c4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:24:07 -0800
Subject: [PATCH 29/99] CVE-2021-44141: s3: smbd: Remove support for SMBcopy
 SMB_COM_COPY (0x29)

It's not used in our client code or tested.

From MS-CIFS.

This command was introduced in the LAN Manager 1.0 dialect
It was rendered obsolete in the NT LAN Manager dialect.
This command was used to perform server-side file copies, but
is no longer used. Clients SHOULD
NOT send requests using this command code.
Servers receiving requests with this command code
SHOULD return STATUS_NOT_IMPLEMENTED (ERRDOS/ERRbadfunc).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 416 ++-----------------------------------------
 1 file changed, 11 insertions(+), 405 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index f85d1122a07..faef4b23a3c 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -8766,416 +8766,22 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
 
 /****************************************************************************
  Reply to a file copy.
+
+ From MS-CIFS.
+
+ This command was introduced in the LAN Manager 1.0 dialect
+ It was rendered obsolete in the NT LAN Manager dialect.
+ This command was used to perform server-side file copies, but
+ is no longer used. Clients SHOULD
+ NOT send requests using this command code.
+ Servers receiving requests with this command code
+ SHOULD return STATUS_NOT_IMPLEMENTED (ERRDOS/ERRbadfunc).
 ****************************************************************************/
 
 void reply_copy(struct smb_request *req)
 {
-	connection_struct *conn = req->conn;
-	struct smb_filename *smb_fname_src = NULL;
-	struct smb_filename *smb_fname_src_dir = NULL;
-	struct smb_filename *smb_fname_dst = NULL;
-	char *fname_src = NULL;
-	char *fname_dst = NULL;
-	char *fname_src_mask = NULL;
-	char *fname_src_dir = NULL;
-	const char *p;
-	int count=0;
-	int error = ERRnoaccess;
-	int tid2;
-	int ofun;
-	int flags;
-	bool target_is_directory=False;
-	bool source_has_wild = False;
-	bool dest_has_wild = False;
-	NTSTATUS status;
-	uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-		ucf_flags_from_smb_request(req);
-	uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-		ucf_flags_from_smb_request(req);
-	TALLOC_CTX *ctx = talloc_tos();
-
 	START_PROFILE(SMBcopy);
-
-	if (req->wct < 3) {
-		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-		goto out;
-	}
-
-	tid2 = SVAL(req->vwv+0, 0);
-	ofun = SVAL(req->vwv+1, 0);
-	flags = SVAL(req->vwv+2, 0);
-
-	p = (const char *)req->buf;
-	p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
-				       &status);
-	if (!NT_STATUS_IS_OK(status)) {
-		reply_nterror(req, status);
-		goto out;
-	}
-	p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
-				       &status);
-	if (!NT_STATUS_IS_OK(status)) {
-		reply_nterror(req, status);
-		goto out;
-	}
-
-	DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
-
-	if (tid2 != conn->cnum) {
-		/* can't currently handle inter share copies XXXX */
-		DEBUG(3,("Rejecting inter-share copy\n"));
-		reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
-		goto out;
-	}
-
-	status = filename_convert(ctx, conn,
-				  fname_src,
-				  ucf_flags_src,
-				  0,
-				  &smb_fname_src);
-	if (!NT_STATUS_IS_OK(status)) {
-		if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
-			reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
-					ERRSRV, ERRbadpath);
-			goto out;
-		}
-		reply_nterror(req, status);
-		goto out;
-	}
-
-	status = filename_convert(ctx, conn,
-				  fname_dst,
-				  ucf_flags_dst,
-				  0,
-				  &smb_fname_dst);
-	if (!NT_STATUS_IS_OK(status)) {
-		if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
-			reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
-					ERRSRV, ERRbadpath);
-			goto out;
-		}
-		reply_nterror(req, status);
-		goto out;
-	}
-
-	target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
-
-	if ((flags&1) && target_is_directory) {
-		reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
-		goto out;
-	}
-
-	if ((flags&2) && !target_is_directory) {
-		reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
-		goto out;
-	}
-
-	if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
-		/* wants a tree copy! XXXX */
-		DEBUG(3,("Rejecting tree copy\n"));
-		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-		goto out;
-	}
-
-	/* Split up the directory from the filename/mask. */
-	status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
-				      &fname_src_dir, &fname_src_mask);
-	if (!NT_STATUS_IS_OK(status)) {
-		reply_nterror(req, NT_STATUS_NO_MEMORY);
-		goto out;
-	}
-
-	if (!req->posix_pathnames) {
-		char *orig_src_lcomp = NULL;
-		char *orig_dst_lcomp = NULL;
-		/*
-		 * Check the wildcard mask *before*
-		 * unmangling. As mangling is done
-		 * for names that can't be returned
-		 * to Windows the unmangled name may
-		 * contain Windows wildcard characters.
-		 */
-		orig_src_lcomp = get_original_lcomp(ctx,
-					conn,
-					fname_src,
-					ucf_flags_src);
-		if (orig_src_lcomp == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-		orig_dst_lcomp = get_original_lcomp(ctx,
-					conn,
-					fname_dst,
-					ucf_flags_dst);
-		if (orig_dst_lcomp == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-		source_has_wild = ms_has_wild(orig_src_lcomp);
-		dest_has_wild = ms_has_wild(orig_dst_lcomp);
-		TALLOC_FREE(orig_src_lcomp);
-		TALLOC_FREE(orig_dst_lcomp);
-	}
-
-	/*
-	 * We should only check the mangled cache
-	 * here if unix_convert failed. This means
-	 * that the path in 'mask' doesn't exist
-	 * on the file system and so we need to look
-	 * for a possible mangle. This patch from
-	 * Tine Smukavec <valentin.smukavec@hermes.si>.
-	 */
-	if (!VALID_STAT(smb_fname_src->st) &&
-	    mangle_is_mangled(fname_src_mask, conn->params)) {
-		char *new_mask = NULL;
-		mangle_lookup_name_from_8_3(ctx, fname_src_mask,
-					    &new_mask, conn->params);
-
-		/* Use demangled name if one was successfully found. */
-		if (new_mask) {
-			TALLOC_FREE(fname_src_mask);
-			fname_src_mask = new_mask;
-		}
-	}
-
-	if (!source_has_wild) {
-
-		/*
-		 * Only one file needs to be copied. Append the mask back onto
-		 * the directory.
-		 */
-		TALLOC_FREE(smb_fname_src->base_name);
-		if (ISDOT(fname_src_dir)) {
-			/* Ensure we use canonical names on open. */
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s",
-							fname_src_mask);
-		} else {
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s/%s",
-							fname_src_dir,
-							fname_src_mask);
-		}
-		if (!smb_fname_src->base_name) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-
-		if (dest_has_wild) {
-			char *fname_dst_mod = NULL;
-			if (!resolve_wildcards(smb_fname_dst,
-					       smb_fname_src->base_name,
-					       smb_fname_dst->base_name,
-					       &fname_dst_mod)) {
-				reply_nterror(req, NT_STATUS_NO_MEMORY);
-				goto out;
-			}
-			TALLOC_FREE(smb_fname_dst->base_name);
-			smb_fname_dst->base_name = fname_dst_mod;
-		}
-
-		status = check_name(conn, smb_fname_src);
-		if (!NT_STATUS_IS_OK(status)) {
-			reply_nterror(req, status);
-			goto out;
-		}
-
-		status = check_name(conn, smb_fname_dst);
-		if (!NT_STATUS_IS_OK(status)) {
-			reply_nterror(req, status);
-			goto out;
-		}
-
-		status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
-				   ofun, count, target_is_directory);
-
-		if(!NT_STATUS_IS_OK(status)) {
-			reply_nterror(req, status);
-			goto out;
-		} else {
-			count++;
-		}
-	} else {
-		struct smb_Dir *dir_hnd = NULL;
-		const char *dname = NULL;
-		char *talloced = NULL;
-		long offset = 0;
-
-		/*
-		 * There is a wildcard that requires us to actually read the
-		 * src dir and copy each file matching the mask to the dst.
-		 * Right now streams won't be copied, but this could
-		 * presumably be added with a nested loop for reach dir entry.
-		 */
-		SMB_ASSERT(!smb_fname_src->stream_name);
-		SMB_ASSERT(!smb_fname_dst->stream_name);
-
-		smb_fname_src->stream_name = NULL;
-		smb_fname_dst->stream_name = NULL;
-
-		if (strequal(fname_src_mask,"????????.???")) {
-			TALLOC_FREE(fname_src_mask);
-			fname_src_mask = talloc_strdup(ctx, "*");
-			if (!fname_src_mask) {
-				reply_nterror(req, NT_STATUS_NO_MEMORY);
-				goto out;
-			}
-		}
-
-		smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
-					fname_src_dir,
-					NULL,
-					NULL,
-					smb_fname_src->twrp,
-					smb_fname_src->flags);
-		if (smb_fname_src_dir == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-
-		status = check_name(conn, smb_fname_src_dir);
-		if (!NT_STATUS_IS_OK(status)) {
-			reply_nterror(req, status);
-			goto out;
-		}
-
-		dir_hnd = OpenDir(ctx,
-				conn,
-				smb_fname_src_dir,
-				fname_src_mask,
-				0);
-		if (dir_hnd == NULL) {
-			status = map_nt_error_from_unix(errno);
-			reply_nterror(req, status);
-			goto out;
-		}
-
-		error = ERRbadfile;
-
-		/* Iterate over the src dir copying each entry to the dst. */
-		while ((dname = ReadDirName(dir_hnd, &offset,
-					    &smb_fname_src->st, &talloced))) {
-			char *destname = NULL;
-
-			if (ISDOT(dname) || ISDOTDOT(dname)) {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			if (IS_VETO_PATH(conn, dname)) {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			if(!mask_match(dname, fname_src_mask,
-				       conn->case_sensitive)) {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			error = ERRnoaccess;
-
-			/* Get the src smb_fname struct setup. */
-			TALLOC_FREE(smb_fname_src->base_name);
-			if (ISDOT(fname_src_dir)) {
-				/* Ensure we use canonical names on open. */
-				smb_fname_src->base_name =
-					talloc_asprintf(smb_fname_src, "%s",
-						dname);
-			} else {
-				smb_fname_src->base_name =
-					talloc_asprintf(smb_fname_src, "%s/%s",
-						fname_src_dir, dname);
-			}
-
-			if (!smb_fname_src->base_name) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(talloced);
-				reply_nterror(req, NT_STATUS_NO_MEMORY);
-				goto out;
-			}
-
-			if (!resolve_wildcards(ctx, smb_fname_src->base_name,
-					       smb_fname_dst->base_name,
-					       &destname)) {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-			if (!destname) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(talloced);
-				reply_nterror(req, NT_STATUS_NO_MEMORY);
-				goto out;
-			}
-
-			TALLOC_FREE(smb_fname_dst->base_name);
-			smb_fname_dst->base_name = destname;
-
-			ZERO_STRUCT(smb_fname_src->st);
-			vfs_stat(conn, smb_fname_src);
-
-			status = openat_pathref_fsp(conn->cwd_fsp,
-						    smb_fname_src);
-			if (!NT_STATUS_IS_OK(status)) {
-				DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
-					smb_fname_str_dbg(smb_fname_src),
-					nt_errstr(status));
-				break;
-			}
-
-			if (!is_visible_fsp(smb_fname_src->fsp)) {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			status = check_name(conn, smb_fname_src);
-			if (!NT_STATUS_IS_OK(status)) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(talloced);
-				reply_nterror(req, status);
-				goto out;
-			}
-
-			status = check_name(conn, smb_fname_dst);
-			if (!NT_STATUS_IS_OK(status)) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(talloced);
-				reply_nterror(req, status);
-				goto out;
-			}
-
-			DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
-				smb_fname_src->base_name,
-				smb_fname_dst->base_name));
-
-			status = copy_file(ctx, conn, smb_fname_src,
-					   smb_fname_dst, ofun,	count,
-					   target_is_directory);
-			if (NT_STATUS_IS_OK(status)) {
-				count++;
-			}
-
-			TALLOC_FREE(talloced);
-		}
-		TALLOC_FREE(dir_hnd);
-	}
-
-	if (count == 0) {
-		reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
-		goto out;
-	}
-
-	reply_outbuf(req, 1, 0);
-	SSVAL(req->outbuf,smb_vwv0,count);
- out:
-	TALLOC_FREE(smb_fname_src);
-	TALLOC_FREE(smb_fname_src_dir);
-	TALLOC_FREE(smb_fname_dst);
-	TALLOC_FREE(fname_src);
-	TALLOC_FREE(fname_dst);
-	TALLOC_FREE(fname_src_mask);
-	TALLOC_FREE(fname_src_dir);
-
+	reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
 	END_PROFILE(SMBcopy);
 	return;
 }
-- 
2.25.1


From 79ae11f3cb464ffe381c62451ad38125f1872156 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:31:44 -0800
Subject: [PATCH 30/99] CVE-2021-44141: s3: smbd: In reply_unlink() remove the
 possibility of receiving a wildcard name.

This was the only user of "has_wild=true" passed to
unlink_internals().

Next commit will remove this functionality from unlink_internals().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index faef4b23a3c..dd8c536ffac 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3537,10 +3537,8 @@ void reply_unlink(struct smb_request *req)
 	struct smb_filename *smb_fname = NULL;
 	uint32_t dirtype;
 	NTSTATUS status;
-	uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-			ucf_flags_from_smb_request(req);
+	uint32_t ucf_flags = ucf_flags_from_smb_request(req);
 	TALLOC_CTX *ctx = talloc_tos();
-	bool has_wild = false;
 
 	START_PROFILE(SMBunlink);
 
@@ -3573,22 +3571,9 @@ void reply_unlink(struct smb_request *req)
 		goto out;
 	}
 
-	if (!req->posix_pathnames) {
-		char *lcomp = get_original_lcomp(ctx,
-					conn,
-					name,
-					ucf_flags);
-		if (lcomp == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-		has_wild = ms_has_wild(lcomp);
-		TALLOC_FREE(lcomp);
-	}
-
 	DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
 
-	status = unlink_internals(conn, req, dirtype, smb_fname, has_wild);
+	status = unlink_internals(conn, req, dirtype, smb_fname, false);
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
 			/* We have re-scheduled this call. */
-- 
2.25.1


From e4c3d31854fa1969d946bd6a7cfcf25db5d21d7b Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 12:53:29 -0800
Subject: [PATCH 31/99] CVE-2021-44141: s3: smbd: Change unlink_internals() to
 ignore has_wild parameter.

It's always passed as false now so we can remove the (horrible)
enumeration code for unlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 226 +++++--------------------------------------
 1 file changed, 26 insertions(+), 200 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index dd8c536ffac..abdf5f01fd8 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3283,11 +3283,9 @@ NTSTATUS unlink_internals(connection_struct *conn,
 {
 	char *fname_dir = NULL;
 	char *fname_mask = NULL;
-	int count=0;
 	NTSTATUS status = NT_STATUS_OK;
 	struct smb_filename *smb_fname_dir = NULL;
 	TALLOC_CTX *ctx = talloc_tos();
-	int ret;
 
 	/* Split up the directory from the filename/mask. */
 	status = split_fname_dir_mask(ctx, smb_fname->base_name,
@@ -3316,209 +3314,37 @@ NTSTATUS unlink_internals(connection_struct *conn,
 		}
 	}
 
-	if (!has_wild) {
-
-		/*
-		 * Only one file needs to be unlinked. Append the mask back
-		 * onto the directory.
-		 */
-		TALLOC_FREE(smb_fname->base_name);
-		if (ISDOT(fname_dir)) {
-			/* Ensure we use canonical names on open. */
-			smb_fname->base_name = talloc_asprintf(smb_fname,
-							"%s",
-							fname_mask);
-		} else {
-			smb_fname->base_name = talloc_asprintf(smb_fname,
-							"%s/%s",
-							fname_dir,
-							fname_mask);
-		}
-		if (!smb_fname->base_name) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-		if (dirtype == 0) {
-			dirtype = FILE_ATTRIBUTE_NORMAL;
-		}
-
-		status = check_name(conn, smb_fname);
-		if (!NT_STATUS_IS_OK(status)) {
-			goto out;
-		}
-
-		status = do_unlink(conn, req, smb_fname, dirtype);
-		if (!NT_STATUS_IS_OK(status)) {
-			goto out;
-		}
-
-		count++;
+	/*
+	 * Only one file needs to be unlinked. Append the mask back
+	 * onto the directory.
+	 */
+	TALLOC_FREE(smb_fname->base_name);
+	if (ISDOT(fname_dir)) {
+		/* Ensure we use canonical names on open. */
+		smb_fname->base_name = talloc_asprintf(smb_fname,
+						"%s",
+						fname_mask);
 	} else {
-		struct smb_Dir *dir_hnd = NULL;
-		long offset = 0;
-		const char *dname = NULL;
-		char *talloced = NULL;
-
-		if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
-			status = NT_STATUS_OBJECT_NAME_INVALID;
-			goto out;
-		}
-		if (dirtype == 0) {
-			dirtype = FILE_ATTRIBUTE_NORMAL;
-		}
-
-		if (strequal(fname_mask,"????????.???")) {
-			TALLOC_FREE(fname_mask);
-			fname_mask = talloc_strdup(ctx, "*");
-			if (!fname_mask) {
-				status = NT_STATUS_NO_MEMORY;
-				goto out;
-			}
-		}
-
-		smb_fname_dir = synthetic_smb_fname(talloc_tos(),
-					fname_dir,
-					NULL,
-					NULL,
-					smb_fname->twrp,
-					smb_fname->flags);
-		if (smb_fname_dir == NULL) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-
-		status = check_name(conn, smb_fname_dir);
-		if (!NT_STATUS_IS_OK(status)) {
-			goto out;
-		}
-
-		dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
-				  dirtype);
-		if (dir_hnd == NULL) {
-			status = map_nt_error_from_unix(errno);
-			goto out;
-		}
-
-		/* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
-		   the pattern matches against the long name, otherwise the short name 
-		   We don't implement this yet XXXX
-		*/
-
-		status = NT_STATUS_NO_SUCH_FILE;
-
-		while ((dname = ReadDirName(dir_hnd, &offset,
-					    &smb_fname->st, &talloced))) {
-			TALLOC_CTX *frame = talloc_stackframe();
-			char *p = NULL;
-			struct smb_filename *f = NULL;
-
-			/* Quick check for "." and ".." */
-			if (ISDOT(dname) || ISDOTDOT(dname)) {
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			if (IS_VETO_PATH(conn, dname)) {
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			if(!mask_match(dname, fname_mask,
-				       conn->case_sensitive)) {
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			if (ISDOT(fname_dir)) {
-				/* Ensure we use canonical names on open. */
-				p = talloc_asprintf(smb_fname, "%s", dname);
-			} else {
-				p = talloc_asprintf(smb_fname, "%s/%s",
-						    fname_dir, dname);
-			}
-			if (p == NULL) {
-				TALLOC_FREE(dir_hnd);
-				status = NT_STATUS_NO_MEMORY;
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-			f = synthetic_smb_fname(frame,
-						p,
-						NULL,
-						&smb_fname->st,
-						smb_fname->twrp,
-						smb_fname->flags);
-			if (f == NULL) {
-				TALLOC_FREE(dir_hnd);
-				status = NT_STATUS_NO_MEMORY;
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-
-			ret = vfs_stat(conn, f);
-			if (ret != 0) {
-				status = map_nt_error_from_unix(errno);
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-
-			status = openat_pathref_fsp(conn->cwd_fsp, f);
-			if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
-			    (f->flags & SMB_FILENAME_POSIX_PATH) &&
-			    S_ISLNK(f->st.st_ex_mode))
-			{
-				status = NT_STATUS_OK;
-			}
-			if (!NT_STATUS_IS_OK(status)) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-
-			if (!is_visible_fsp(f->fsp)) {
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				continue;
-			}
-
-			status = check_name(conn, f);
-			if (!NT_STATUS_IS_OK(status)) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-
-			status = do_unlink(conn, req, f, dirtype);
-			if (!NT_STATUS_IS_OK(status)) {
-				TALLOC_FREE(dir_hnd);
-				TALLOC_FREE(frame);
-				TALLOC_FREE(talloced);
-				goto out;
-			}
-
-			count++;
-			DBG_DEBUG("successful unlink [%s]\n",
-				  smb_fname_str_dbg(f));
-
-			TALLOC_FREE(frame);
-			TALLOC_FREE(talloced);
-		}
-		TALLOC_FREE(dir_hnd);
+		smb_fname->base_name = talloc_asprintf(smb_fname,
+						"%s/%s",
+						fname_dir,
+						fname_mask);
+	}
+	if (!smb_fname->base_name) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
+	if (dirtype == 0) {
+		dirtype = FILE_ATTRIBUTE_NORMAL;
 	}
 
-	if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
-		status = map_nt_error_from_unix(errno);
+	status = check_name(conn, smb_fname);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto out;
 	}
 
+	status = do_unlink(conn, req, smb_fname, dirtype);
+
  out:
 	TALLOC_FREE(smb_fname_dir);
 	TALLOC_FREE(fname_dir);
-- 
2.25.1


From 945c9264243c811346d28ce0aeb740bdbe1083dc Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 13:03:03 -0800
Subject: [PATCH 32/99] CVE-2021-44141: s3: smbd: Remove 'bool has_wild'
 parameter from unlink_internals().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/printing/nt_printing.c | 2 +-
 source3/smbd/proto.h           | 3 +--
 source3/smbd/reply.c           | 5 ++---
 source3/smbd/trans2.c          | 3 +--
 4 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index b172ed92c6e..a47afda4a84 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -2042,7 +2042,7 @@ static NTSTATUS driver_unlink_internals(connection_struct *conn,
 		goto err_out;
 	}
 
-	status = unlink_internals(conn, NULL, 0, smb_fname, false);
+	status = unlink_internals(conn, NULL, 0, smb_fname);
 err_out:
 	talloc_free(tmp_ctx);
 	return status;
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index bf7401f5191..9454d44968b 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -995,8 +995,7 @@ void reply_ctemp(struct smb_request *req);
 NTSTATUS unlink_internals(connection_struct *conn,
 			struct smb_request *req,
 			uint32_t dirtype,
-			struct smb_filename *smb_fname,
-			bool has_wcard);
+			struct smb_filename *smb_fname);
 void reply_unlink(struct smb_request *req);
 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
 		      off_t startpos, size_t nread);
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index abdf5f01fd8..e996b809243 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3278,8 +3278,7 @@ static NTSTATUS do_unlink(connection_struct *conn,
 NTSTATUS unlink_internals(connection_struct *conn,
 			struct smb_request *req,
 			uint32_t dirtype,
-			struct smb_filename *smb_fname,
-			bool has_wild)
+			struct smb_filename *smb_fname)
 {
 	char *fname_dir = NULL;
 	char *fname_mask = NULL;
@@ -3399,7 +3398,7 @@ void reply_unlink(struct smb_request *req)
 
 	DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
 
-	status = unlink_internals(conn, req, dirtype, smb_fname, false);
+	status = unlink_internals(conn, req, dirtype, smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
 			/* We have re-scheduled this call. */
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 4f6d92955cf..c455b68725e 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -6514,8 +6514,7 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
 			status = unlink_internals(conn,
 						req,
 						FILE_ATTRIBUTE_NORMAL,
-						smb_fname_new,
-						false);
+						smb_fname_new);
 			if (!NT_STATUS_IS_OK(status)) {
 				goto out;
 			}
-- 
2.25.1


From 410126c7fb939c3bebee318376602e5084a93e12 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 13:56:31 -0800
Subject: [PATCH 33/99] CVE-2021-44141: s3: smbd: Remove
 UCF_ALWAYS_ALLOW_WCARD_LCOMP flag from pathname processing in reply_mv().

We are no longer supporting wildcard rename via SMBmv (0x7)
as WindowsXP SMB1 and above do not use it.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index e996b809243..0bc3db4c9ca 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -8242,10 +8242,8 @@ void reply_mv(struct smb_request *req)
 	const char *src_original_lcomp = NULL;
 	struct smb_filename *smb_fname_dst = NULL;
 	const char *dst_original_lcomp = NULL;
-	uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
-		(!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
-	uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
-		(!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
+	uint32_t src_ucf_flags = ucf_flags_from_smb_request(req);
+	uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req);
 	bool stream_rename = false;
 
 	START_PROFILE(SMBmv);
-- 
2.25.1


From 7b0eba7ff03aa79400c4dbac224122209c8e8995 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:07:07 -0800
Subject: [PATCH 34/99] CVE-2021-44141: s3: smbd: In
 smb_file_rename_information() (SMB_FILE_RENAME_INFORMATION info level)
 prevent destination wildcards.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/trans2.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index c455b68725e..1eac9b0d2db 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -7438,8 +7438,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
 		 * the newname instead.
 		 */
 		char *base_name = NULL;
-		uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP|
-				ucf_flags_from_smb_request(req);
+		uint32_t ucf_flags = ucf_flags_from_smb_request(req);
 
 		/* newname must *not* be a stream name. */
 		if (newname[0] == ':') {
-- 
2.25.1


From 07b47529426d4623270c2541b840bf71cfca9d59 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:08:13 -0800
Subject: [PATCH 35/99] CVE-2021-44141: s3: smbd: In SMBntrename (0xa5) prevent
 wildcards in destination name.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/nttrans.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index ffff822e221..5e6163f0433 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1771,6 +1771,11 @@ void reply_ntrename(struct smb_request *req)
 		goto out;
 	}
 
+	if (!req->posix_pathnames && ms_has_wild(newname)) {
+		reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+		goto out;
+	}
+
 	if (!req->posix_pathnames) {
 		/* The newname must begin with a ':' if the
 		   oldname contains a ':'. */
-- 
2.25.1


From 9d0c2fd42fc77de7a9748ef2ecd7d284b5105e37 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:12:46 -0800
Subject: [PATCH 36/99] CVE-2021-44141: s3: smbd: In reply_ntrename() remove
 the UCF_ALWAYS_ALLOW_WCARD_LCOMP flag for destination lookups.

We know the destination will never be a wildcard.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/nttrans.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 5e6163f0433..e25a59a7cb9 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1788,14 +1788,6 @@ void reply_ntrename(struct smb_request *req)
 		}
 	}
 
-	/*
-	 * If this is a rename operation, allow wildcards and save the
-	 * destination's last component.
-	 */
-	if (rename_type == RENAME_FLAG_RENAME) {
-		ucf_flags_dst |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
-	}
-
 	/* rename_internals() calls unix_convert(), so don't call it here. */
 	status = filename_convert(ctx, conn,
 				  oldname,
-- 
2.25.1


From c7678425514417b524800e65098bc8608849c457 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:14:57 -0800
Subject: [PATCH 37/99] CVE-2021-44141: s3: smbd: In reply_ntrename(), never
 set dest_has_wcard.

It can never be true.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/nttrans.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index e25a59a7cb9..f5cb82024c8 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1816,10 +1816,6 @@ void reply_ntrename(struct smb_request *req)
 		goto out;
 	}
 
-	if (!req->posix_pathnames) {
-		dest_has_wcard = ms_has_wild(dst_original_lcomp);
-	}
-
 	status = filename_convert(ctx, conn,
 				  newname,
 				  ucf_flags_dst,
-- 
2.25.1


From 992864a49f099052c452eb5e1da733f39294d94a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:17:51 -0800
Subject: [PATCH 38/99] CVE-2021-44141: s3: smbd: In reply_ntrename() remove
 'bool dest_has_wcard' and all uses.

It's always false now.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/nttrans.c | 32 ++++++++++++--------------------
 1 file changed, 12 insertions(+), 20 deletions(-)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index f5cb82024c8..b0f55ade267 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1732,7 +1732,6 @@ void reply_ntrename(struct smb_request *req)
 	const char *dst_original_lcomp = NULL;
 	const char *p;
 	NTSTATUS status;
-	bool dest_has_wcard = False;
 	uint32_t attrs;
 	uint32_t ucf_flags_src = ucf_flags_from_smb_request(req);
 	uint32_t ucf_flags_dst = ucf_flags_from_smb_request(req);
@@ -1862,27 +1861,20 @@ void reply_ntrename(struct smb_request *req)
 						DELETE_ACCESS);
 			break;
 		case RENAME_FLAG_HARD_LINK:
-			if (dest_has_wcard) {
-				/* No wildcards. */
-				status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
-			} else {
-				status = hardlink_internals(ctx, conn,
-							    req,
-							    false,
-							    smb_fname_old,
-							    smb_fname_new);
-			}
+			status = hardlink_internals(ctx,
+						    conn,
+						    req,
+						    false,
+						    smb_fname_old,
+						    smb_fname_new);
 			break;
 		case RENAME_FLAG_COPY:
-			if (dest_has_wcard) {
-				/* No wildcards. */
-				status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
-			} else {
-				status = copy_internals(ctx, conn, req,
-							smb_fname_old,
-							smb_fname_new,
-							attrs);
-			}
+			status = copy_internals(ctx,
+						conn,
+						req,
+						smb_fname_old,
+						smb_fname_new,
+						attrs);
 			break;
 		case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
 			status = NT_STATUS_INVALID_PARAMETER;
-- 
2.25.1


From 848b891d978d928dc3199f7f1e146bfc0b7ab988 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:25:03 -0800
Subject: [PATCH 39/99] CVE-2021-44141: s3: smbd: Prepare to remove wildcard
 matching from rename_internals().

src_has_wild and dest_has_wild can never be true.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 0bc3db4c9ca..3eaadb33861 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7860,20 +7860,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 		goto out;
 	}
 
-	if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
-		/*
-		 * Check the wildcard mask *before*
-		 * unmangling. As mangling is done
-		 * for names that can't be returned
-		 * to Windows the unmangled name may
-		 * contain Windows wildcard characters.
-		 */
-		if (src_original_lcomp != NULL) {
-			src_has_wild = ms_has_wild(src_original_lcomp);
-		}
-		dest_has_wild = ms_has_wild(dst_original_lcomp);
-	}
-
 	/*
 	 * We should only check the mangled cache
 	 * here if unix_convert failed. This means
-- 
2.25.1


From ece00d51a7b28ec96c0a173ca40feb61aaf5dbe3 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:26:28 -0800
Subject: [PATCH 40/99] CVE-2021-44141: s3: smbd: Remove dest_has_wild and all
 associated code from rename_internals()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 3eaadb33861..21f40cf123e 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7841,7 +7841,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 	struct smb2_create_blobs *posx = NULL;
 	int rc;
 	bool src_has_wild = false;
-	bool dest_has_wild = false;
 
 	/*
 	 * Split the old name into directory and last component
@@ -7923,24 +7922,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			  smb_fname_str_dbg(smb_fname_dst),
 			  dst_original_lcomp));
 
-		/* The dest name still may have wildcards. */
-		if (dest_has_wild) {
-			char *fname_dst_mod = NULL;
-			if (!resolve_wildcards(smb_fname_dst,
-					       smb_fname_src->base_name,
-					       smb_fname_dst->base_name,
-					       &fname_dst_mod)) {
-				DEBUG(6, ("rename_internals: resolve_wildcards "
-					  "%s %s failed\n",
-					  smb_fname_src->base_name,
-					  smb_fname_dst->base_name));
-				status = NT_STATUS_NO_MEMORY;
-				goto out;
-			}
-			TALLOC_FREE(smb_fname_dst->base_name);
-			smb_fname_dst->base_name = fname_dst_mod;
-		}
-
 		ZERO_STRUCT(smb_fname_src->st);
 
 		rc = vfs_stat(conn, smb_fname_src);
-- 
2.25.1


From cafca2b7a0eca282d24d8f3571bc14ef725f30e4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:29:43 -0800
Subject: [PATCH 41/99] CVE-2021-44141: s3: smbd: Remove all wildcard code from
 rename_internals().

We no longer use resolve_wildcards() so comment it out
for later removal. Keep the '{ ... }' block around the
singleton rename for now, to keep the diff small.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 201 +------------------------------------------
 1 file changed, 4 insertions(+), 197 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 21f40cf123e..a0e61546323 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7059,6 +7059,7 @@ void reply_rmdir(struct smb_request *req)
 	return;
 }
 
+#if 0
 /*******************************************************************
  Resolve wildcards in a filename rename.
 ********************************************************************/
@@ -7185,6 +7186,7 @@ static bool resolve_wildcards(TALLOC_CTX *ctx,
 
 	return True;
 }
+#endif
 
 /****************************************************************************
  Ensure open files have their names updated. Updated to notify other smbd's
@@ -7831,24 +7833,18 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 	char *fname_src_dir = NULL;
 	struct smb_filename *smb_fname_src_dir = NULL;
 	char *fname_src_mask = NULL;
-	int count=0;
 	NTSTATUS status = NT_STATUS_OK;
-	struct smb_Dir *dir_hnd = NULL;
-	const char *dname = NULL;
 	char *talloced = NULL;
-	long offset = 0;
 	int create_options = 0;
 	struct smb2_create_blobs *posx = NULL;
 	int rc;
-	bool src_has_wild = false;
 
 	/*
 	 * Split the old name into directory and last component
 	 * strings. Note that unix_convert may have stripped off a
 	 * leading ./ from both name and newname if the rename is
 	 * at the root of the share. We need to make sure either both
-	 * name and newname contain a / character or neither of them do
-	 * as this is checked in resolve_wildcards().
+	 * name and newname contain a / character or neither of them do.
 	 */
 
 	/* Split up the directory from the filename/mask. */
@@ -7888,7 +7884,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 		}
 	}
 
-	if (!src_has_wild) {
+	{
 		files_struct *fsp;
 
 		/*
@@ -7992,195 +7988,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			  nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
 			  smb_fname_str_dbg(smb_fname_dst)));
 
-		goto out;
-	}
-
-	/*
-	 * Wildcards - process each file that matches.
-	 */
-	if (strequal(fname_src_mask, "????????.???")) {
-		TALLOC_FREE(fname_src_mask);
-		fname_src_mask = talloc_strdup(ctx, "*");
-		if (!fname_src_mask) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-	}
-
-	smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
-				fname_src_dir,
-				NULL,
-				NULL,
-				smb_fname_src->twrp,
-				smb_fname_src->flags);
-	if (smb_fname_src_dir == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto out;
-	}
-
-	status = check_name(conn, smb_fname_src_dir);
-	if (!NT_STATUS_IS_OK(status)) {
-		goto out;
-	}
-
-	dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
-			  attrs);
-	if (dir_hnd == NULL) {
-		status = map_nt_error_from_unix(errno);
-		goto out;
-	}
-
-	status = NT_STATUS_NO_SUCH_FILE;
-	/*
-	 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-	 * - gentest fix. JRA
-	 */
-
-	while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
-				    &talloced))) {
-		files_struct *fsp = NULL;
-		char *destname = NULL;
-		bool sysdir_entry = False;
-
-		/* Quick check for "." and ".." */
-		if (ISDOT(dname) || ISDOTDOT(dname)) {
-			if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
-				sysdir_entry = True;
-			} else {
-				TALLOC_FREE(talloced);
-				continue;
-			}
-		}
-
-		if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
-			TALLOC_FREE(talloced);
-			continue;
-		}
-
-		if (sysdir_entry) {
-			status = NT_STATUS_OBJECT_NAME_INVALID;
-			break;
-		}
-
-		TALLOC_FREE(smb_fname_src->base_name);
-		if (ISDOT(fname_src_dir)) {
-			/* Ensure we use canonical names on open. */
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s",
-							dname);
-		} else {
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s/%s",
-							fname_src_dir,
-							dname);
-		}
-		if (!smb_fname_src->base_name) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-
-		if (!resolve_wildcards(ctx, smb_fname_src->base_name,
-				       smb_fname_dst->base_name,
-				       &destname)) {
-			DEBUG(6, ("resolve_wildcards %s %s failed\n",
-				  smb_fname_src->base_name, destname));
-			TALLOC_FREE(talloced);
-			continue;
-		}
-		if (!destname) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-
-		TALLOC_FREE(smb_fname_dst->base_name);
-		smb_fname_dst->base_name = destname;
-
-		ZERO_STRUCT(smb_fname_src->st);
-		vfs_stat(conn, smb_fname_src);
-
-		status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
-		if (!NT_STATUS_IS_OK(status)) {
-			DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
-				 smb_fname_str_dbg(smb_fname_src),
-				 nt_errstr(status));
-			break;
-		}
-
-		if (!is_visible_fsp(smb_fname_src->fsp)) {
-			TALLOC_FREE(talloced);
-			continue;
-		}
-
-		create_options = 0;
-
-		if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
-			create_options |= FILE_DIRECTORY_FILE;
-		}
-
-		status = SMB_VFS_CREATE_FILE(
-			conn,				/* conn */
-			req,				/* req */
-			smb_fname_src,			/* fname */
-			access_mask,			/* access_mask */
-			(FILE_SHARE_READ |		/* share_access */
-			    FILE_SHARE_WRITE),
-			FILE_OPEN,			/* create_disposition*/
-			create_options,			/* create_options */
-			0,				/* file_attributes */
-			0,				/* oplock_request */
-			NULL,				/* lease */
-			0,				/* allocation_size */
-			0,				/* private_flags */
-			NULL,				/* sd */
-			NULL,				/* ea_list */
-			&fsp,				/* result */
-			NULL,				/* pinfo */
-			posx,				/* in_context_blobs */
-			NULL);				/* out_context_blobs */
-
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
-				 "returned %s rename %s -> %s\n",
-				 nt_errstr(status),
-				 smb_fname_str_dbg(smb_fname_src),
-				 smb_fname_str_dbg(smb_fname_dst)));
-			break;
-		}
-
-		dst_original_lcomp = talloc_strdup(smb_fname_dst, dname);
-		if (dst_original_lcomp == NULL) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
-
-		status = rename_internals_fsp(conn,
-					fsp,
-					smb_fname_dst,
-					dst_original_lcomp,
-					attrs,
-					replace_if_exists);
-
-		close_file(req, fsp, NORMAL_CLOSE);
-
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(3, ("rename_internals_fsp returned %s for "
-				  "rename %s -> %s\n", nt_errstr(status),
-				  smb_fname_str_dbg(smb_fname_src),
-				  smb_fname_str_dbg(smb_fname_dst)));
-			break;
-		}
-
-		count++;
-
-		DEBUG(3,("rename_internals: doing rename on %s -> "
-			 "%s\n", smb_fname_str_dbg(smb_fname_src),
-			 smb_fname_str_dbg(smb_fname_src)));
-		TALLOC_FREE(talloced);
-	}
-	TALLOC_FREE(dir_hnd);
-
-	if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
-		status = map_nt_error_from_unix(errno);
 	}
 
  out:
-- 
2.25.1


From be70e606c61cd2da8f27718f5a227728494793e3 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:31:36 -0800
Subject: [PATCH 42/99] CVE-2021-44141: s3: smbd: Remove the commented out
 resolve_wildcards().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 129 -------------------------------------------
 1 file changed, 129 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index a0e61546323..aec0892c81a 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7059,135 +7059,6 @@ void reply_rmdir(struct smb_request *req)
 	return;
 }
 
-#if 0
-/*******************************************************************
- Resolve wildcards in a filename rename.
-********************************************************************/
-
-static bool resolve_wildcards(TALLOC_CTX *ctx,
-				const char *name1,
-				const char *name2,
-				char **pp_newname)
-{
-	char *name2_copy = NULL;
-	char *root1 = NULL;
-	char *root2 = NULL;
-	char *ext1 = NULL;
-	char *ext2 = NULL;
-	char *p,*p2, *pname1, *pname2;
-
-	name2_copy = talloc_strdup(ctx, name2);
-	if (!name2_copy) {
-		return False;
-	}
-
-	pname1 = strrchr_m(name1,'/');
-	pname2 = strrchr_m(name2_copy,'/');
-
-	if (!pname1 || !pname2) {
-		return False;
-	}
-
-	/* Truncate the copy of name2 at the last '/' */
-	*pname2 = '\0';
-
-	/* Now go past the '/' */
-	pname1++;
-	pname2++;
-
-	root1 = talloc_strdup(ctx, pname1);
-	root2 = talloc_strdup(ctx, pname2);
-
-	if (!root1 || !root2) {
-		return False;
-	}
-
-	p = strrchr_m(root1,'.');
-	if (p) {
-		*p = 0;
-		ext1 = talloc_strdup(ctx, p+1);
-	} else {
-		ext1 = talloc_strdup(ctx, "");
-	}
-	p = strrchr_m(root2,'.');
-	if (p) {
-		*p = 0;
-		ext2 = talloc_strdup(ctx, p+1);
-	} else {
-		ext2 = talloc_strdup(ctx, "");
-	}
-
-	if (!ext1 || !ext2) {
-		return False;
-	}
-
-	p = root1;
-	p2 = root2;
-	while (*p2) {
-		if (*p2 == '?') {
-			/* Hmmm. Should this be mb-aware ? */
-			*p2 = *p;
-			p2++;
-		} else if (*p2 == '*') {
-			*p2 = '\0';
-			root2 = talloc_asprintf(ctx, "%s%s",
-						root2,
-						p);
-			if (!root2) {
-				return False;
-			}
-			break;
-		} else {
-			p2++;
-		}
-		if (*p) {
-			p++;
-		}
-	}
-
-	p = ext1;
-	p2 = ext2;
-	while (*p2) {
-		if (*p2 == '?') {
-			/* Hmmm. Should this be mb-aware ? */
-			*p2 = *p;
-			p2++;
-		} else if (*p2 == '*') {
-			*p2 = '\0';
-			ext2 = talloc_asprintf(ctx, "%s%s",
-						ext2,
-						p);
-			if (!ext2) {
-				return False;
-			}
-			break;
-		} else {
-			p2++;
-		}
-		if (*p) {
-			p++;
-		}
-	}
-
-	if (*ext2) {
-		*pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
-				name2_copy,
-				root2,
-				ext2);
-	} else {
-		*pp_newname = talloc_asprintf(ctx, "%s/%s",
-				name2_copy,
-				root2);
-	}
-
-	if (!*pp_newname) {
-		return False;
-	}
-
-	return True;
-}
-#endif
-
 /****************************************************************************
  Ensure open files have their names updated. Updated to notify other smbd's
  asynchronously.
-- 
2.25.1


From cf2de328ea36011d9f4594bac84fce0b8db0889e Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:35:54 -0800
Subject: [PATCH 43/99] CVE-2021-44141: s3: smbd: Inside rename_internals()
 remove '{ ... }' block around singleton rename code.

Best viewed with 'git show -b'

As we're touching the DEBUG() code, change it to modern DBG_NOTICE().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 132 +++++++++++++++++++++----------------------
 1 file changed, 64 insertions(+), 68 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index aec0892c81a..e9814037b1e 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7708,6 +7708,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 	char *talloced = NULL;
 	int create_options = 0;
 	struct smb2_create_blobs *posx = NULL;
+	struct files_struct *fsp = NULL;
 	int rc;
 
 	/*
@@ -7755,70 +7756,67 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 		}
 	}
 
-	{
-		files_struct *fsp;
+	/*
+	 * Only one file needs to be renamed. Append the mask back
+	 * onto the directory.
+	 */
+	TALLOC_FREE(smb_fname_src->base_name);
+	if (ISDOT(fname_src_dir)) {
+		/* Ensure we use canonical names on open. */
+		smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
+						"%s",
+						fname_src_mask);
+	} else {
+		smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
+						"%s/%s",
+						fname_src_dir,
+						fname_src_mask);
+	}
+	if (!smb_fname_src->base_name) {
+		status = NT_STATUS_NO_MEMORY;
+		goto out;
+	}
 
-		/*
-		 * Only one file needs to be renamed. Append the mask back
-		 * onto the directory.
-		 */
-		TALLOC_FREE(smb_fname_src->base_name);
-		if (ISDOT(fname_src_dir)) {
-			/* Ensure we use canonical names on open. */
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s",
-							fname_src_mask);
-		} else {
-			smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-							"%s/%s",
-							fname_src_dir,
-							fname_src_mask);
-		}
-		if (!smb_fname_src->base_name) {
-			status = NT_STATUS_NO_MEMORY;
-			goto out;
-		}
+	DBG_NOTICE("case_sensitive = %d, "
+		  "case_preserve = %d, short case preserve = %d, "
+		  "directory = %s, newname = %s, "
+		  "last_component_dest = %s\n",
+		  conn->case_sensitive, conn->case_preserve,
+		  conn->short_case_preserve,
+		  smb_fname_str_dbg(smb_fname_src),
+		  smb_fname_str_dbg(smb_fname_dst),
+		  dst_original_lcomp);
 
-		DEBUG(3, ("rename_internals: case_sensitive = %d, "
-			  "case_preserve = %d, short case preserve = %d, "
-			  "directory = %s, newname = %s, "
-			  "last_component_dest = %s\n",
-			  conn->case_sensitive, conn->case_preserve,
-			  conn->short_case_preserve,
-			  smb_fname_str_dbg(smb_fname_src),
-			  smb_fname_str_dbg(smb_fname_dst),
-			  dst_original_lcomp));
+	ZERO_STRUCT(smb_fname_src->st);
 
-		ZERO_STRUCT(smb_fname_src->st);
+	rc = vfs_stat(conn, smb_fname_src);
+	if (rc == -1) {
+		status = map_nt_error_from_unix_common(errno);
+		goto out;
+	}
 
-		rc = vfs_stat(conn, smb_fname_src);
-		if (rc == -1) {
-			status = map_nt_error_from_unix_common(errno);
+	status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
+	if (!NT_STATUS_IS_OK(status)) {
+		if (!NT_STATUS_EQUAL(status,
+				NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 			goto out;
 		}
-
-		status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
-		if (!NT_STATUS_IS_OK(status)) {
-			if (!NT_STATUS_EQUAL(status,
-					NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-				goto out;
-			}
-			/*
-			 * Possible symlink src.
-			 */
-			if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
-				goto out;
-			}
-			if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
-				goto out;
-			}
+		/*
+		 * Possible symlink src.
+		 */
+		if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
+			goto out;
 		}
-
-		if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
-			create_options |= FILE_DIRECTORY_FILE;
+		if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
+			goto out;
 		}
+	}
 
-		status = SMB_VFS_CREATE_FILE(
+	if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
+		create_options |= FILE_DIRECTORY_FILE;
+	}
+
+	status = SMB_VFS_CREATE_FILE(
 			conn,				/* conn */
 			req,				/* req */
 			smb_fname_src,			/* fname */
@@ -7839,27 +7837,25 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			posx,				/* in_context_blobs */
 			NULL);				/* out_context_blobs */
 
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(3, ("Could not open rename source %s: %s\n",
-				  smb_fname_str_dbg(smb_fname_src),
-				  nt_errstr(status)));
-			goto out;
-		}
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_NOTICE("Could not open rename source %s: %s\n",
+			  smb_fname_str_dbg(smb_fname_src),
+			  nt_errstr(status));
+		goto out;
+	}
 
-		status = rename_internals_fsp(conn,
+	status = rename_internals_fsp(conn,
 					fsp,
 					smb_fname_dst,
 					dst_original_lcomp,
 					attrs,
 					replace_if_exists);
 
-		close_file(req, fsp, NORMAL_CLOSE);
+	close_file(req, fsp, NORMAL_CLOSE);
 
-		DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
-			  nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
-			  smb_fname_str_dbg(smb_fname_dst)));
-
-	}
+	DBG_NOTICE("Error %s rename %s -> %s\n",
+		  nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
+		  smb_fname_str_dbg(smb_fname_dst));
 
  out:
 	TALLOC_FREE(posx);
-- 
2.25.1


From fc80b553dc6c6a17fa496e1347174ffb802c3ffb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:39:42 -0800
Subject: [PATCH 44/99] CVE-2021-44141: s3: smbd: Remove 'const char
 *src_original_lcomp' parameter from rename_internals().

No longer used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/nttrans.c | 1 -
 source3/smbd/proto.h   | 1 -
 source3/smbd/reply.c   | 2 --
 source3/smbd/trans2.c  | 1 -
 4 files changed, 5 deletions(-)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index b0f55ade267..2b742411071 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1853,7 +1853,6 @@ void reply_ntrename(struct smb_request *req)
 						conn,
 						req,
 						smb_fname_old,
-						NULL,
 						smb_fname_new,
 						dst_original_lcomp,
 						attrs,
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 9454d44968b..fa26d58bfde 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1041,7 +1041,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			connection_struct *conn,
 			struct smb_request *req,
 			struct smb_filename *smb_fname_src,
-			const char *src_original_lcomp,
 			struct smb_filename *smb_fname_dst,
 			const char *dst_original_lcomp,
 			uint32_t attrs,
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index e9814037b1e..8fc943375b4 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7694,7 +7694,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			connection_struct *conn,
 			struct smb_request *req,
 			struct smb_filename *smb_fname_src,
-			const char *src_original_lcomp,
 			struct smb_filename *smb_fname_dst,
 			const char *dst_original_lcomp,
 			uint32_t attrs,
@@ -7996,7 +7995,6 @@ void reply_mv(struct smb_request *req)
 				conn,
 				req,
 				smb_fname_src,
-				src_original_lcomp,
 				smb_fname_dst,
 				dst_original_lcomp,
 				attrs,
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 1eac9b0d2db..2b2643b6325 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -7527,7 +7527,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
 					conn,
 					req,
 					smb_fname_src,
-					NULL,
 					smb_fname_dst,
 					dst_original_lcomp,
 					0,
-- 
2.25.1


From 8c1a9ccb546e7677dc05e98bd6aa77681e0d7510 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 1 Dec 2021 16:40:55 -0800
Subject: [PATCH 45/99] CVE-2021-44141: s3: smbd: Remove 'const char
 *src_original_lcomp' from reply_mv().

No longer used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
 source3/smbd/reply.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 8fc943375b4..079c8da7e3c 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7879,7 +7879,6 @@ void reply_mv(struct smb_request *req)
 	NTSTATUS status;
 	TALLOC_CTX *ctx = talloc_tos();
 	struct smb_filename *smb_fname_src = NULL;
-	const char *src_original_lcomp = NULL;
 	struct smb_filename *smb_fname_dst = NULL;
 	const char *dst_original_lcomp = NULL;
 	uint32_t src_ucf_flags = ucf_flags_from_smb_request(req);
@@ -7939,16 +7938,6 @@ void reply_mv(struct smb_request *req)
 		goto out;
 	}
 
-	/* Get the last component of the source for rename_internals(). */
-	src_original_lcomp = get_original_lcomp(ctx,
-					conn,
-					name,
-					dst_ucf_flags);
-	if (src_original_lcomp == NULL) {
-		reply_nterror(req, NT_STATUS_NO_MEMORY);
-		goto out;
-	}
-
 	status = filename_convert(ctx,
 				  conn,
 				  newname,
-- 
2.25.1


From 9907c8af089a6263349566f002747d84edf926d3 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:08:07 -0800
Subject: [PATCH 46/99] CVE-2021-44141: s3: smbd: Move setting of dirtype if
 FILE_ATTRIBUTE_NORMAL to do_unlink().

Now we don't use wildcards when calling in unlink_internals()
the logic inside it serves no purpose and can be replaced with
a direct call to do_unlink() (which we will rename to unlink_internals()).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 079c8da7e3c..b709dc65c47 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3142,6 +3142,10 @@ static NTSTATUS do_unlink(connection_struct *conn,
 	int ret;
 	struct smb2_create_blobs *posx = NULL;
 
+	if (dirtype == 0) {
+		dirtype = FILE_ATTRIBUTE_NORMAL;
+	}
+
 	DEBUG(10,("do_unlink: %s, dirtype = %d\n",
 		  smb_fname_str_dbg(smb_fname),
 		  dirtype));
@@ -3333,9 +3337,6 @@ NTSTATUS unlink_internals(connection_struct *conn,
 		status = NT_STATUS_NO_MEMORY;
 		goto out;
 	}
-	if (dirtype == 0) {
-		dirtype = FILE_ATTRIBUTE_NORMAL;
-	}
 
 	status = check_name(conn, smb_fname);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
2.25.1


From 9fb1d11b2edafe0b2e8fb8cfbe34e1da046b3d97 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:11:20 -0800
Subject: [PATCH 47/99] CVE-2021-44141: s3: smbd: Move to modern debug calls
 inside do_unlink().

We will be changing its name next.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index b709dc65c47..71d7454e58f 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3146,9 +3146,9 @@ static NTSTATUS do_unlink(connection_struct *conn,
 		dirtype = FILE_ATTRIBUTE_NORMAL;
 	}
 
-	DEBUG(10,("do_unlink: %s, dirtype = %d\n",
+	DBG_DEBUG("%s, dirtype = %d\n",
 		  smb_fname_str_dbg(smb_fname),
-		  dirtype));
+		  dirtype);
 
 	if (!CAN_WRITE(conn)) {
 		return NT_STATUS_MEDIA_WRITE_PROTECTED;
@@ -3248,17 +3248,17 @@ static NTSTATUS do_unlink(connection_struct *conn,
 	TALLOC_FREE(posx);
 
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
-			   nt_errstr(status)));
+		DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
+			   nt_errstr(status));
 		return status;
 	}
 
 	status = can_set_delete_on_close(fsp, fattr);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
+		DBG_DEBUG("can_set_delete_on_close for file %s - "
 			"(%s)\n",
 			smb_fname_str_dbg(smb_fname),
-			nt_errstr(status)));
+			nt_errstr(status));
 		close_file(req, fsp, NORMAL_CLOSE);
 		return status;
 	}
-- 
2.25.1


From a88596028eac6facd644afa7eb5bf9ed34915c30 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:14:40 -0800
Subject: [PATCH 48/99] CVE-2021-44141: s3: smbd: Comment out the old
 unlink_internals(). Rename do_unlink() -> unlink_internals().

One parameter needs changing position. The logic inside unlink_internals()
is no longer needed if it doesn't accept wildcards. filename_convert()
already handles mangled names just fine, so we don't need this logic.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 71d7454e58f..01de8f0c03f 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3130,10 +3130,10 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
  * unlink a file with all relevant access checks
  *******************************************************************/
 
-static NTSTATUS do_unlink(connection_struct *conn,
+NTSTATUS unlink_internals(connection_struct *conn,
 			struct smb_request *req,
-			struct smb_filename *smb_fname,
-			uint32_t dirtype)
+			uint32_t dirtype,
+			struct smb_filename *smb_fname)
 {
 	uint32_t fattr;
 	files_struct *fsp;
@@ -3274,6 +3274,7 @@ static NTSTATUS do_unlink(connection_struct *conn,
 	return close_file(req, fsp, NORMAL_CLOSE);
 }
 
+#if 0
 /****************************************************************************
  The guts of the unlink command, split out so it may be called by the NT SMB
  code.
@@ -3351,6 +3352,7 @@ NTSTATUS unlink_internals(connection_struct *conn,
 	TALLOC_FREE(fname_mask);
 	return status;
 }
+#endif
 
 /****************************************************************************
  Reply to a unlink
-- 
2.25.1


From fad0039acabd43eaf6853af60e5d245a2691a664 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:16:52 -0800
Subject: [PATCH 49/99] CVE-2021-44141: s3: smbd: Remove the old
 unlink_internals() implementation.

No longer used. filename_convert() already handles mangled
names just fine, so we don't need this logic.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 80 --------------------------------------------
 1 file changed, 80 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 01de8f0c03f..26049b2b62b 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3274,86 +3274,6 @@ NTSTATUS unlink_internals(connection_struct *conn,
 	return close_file(req, fsp, NORMAL_CLOSE);
 }
 
-#if 0
-/****************************************************************************
- The guts of the unlink command, split out so it may be called by the NT SMB
- code.
-****************************************************************************/
-
-NTSTATUS unlink_internals(connection_struct *conn,
-			struct smb_request *req,
-			uint32_t dirtype,
-			struct smb_filename *smb_fname)
-{
-	char *fname_dir = NULL;
-	char *fname_mask = NULL;
-	NTSTATUS status = NT_STATUS_OK;
-	struct smb_filename *smb_fname_dir = NULL;
-	TALLOC_CTX *ctx = talloc_tos();
-
-	/* Split up the directory from the filename/mask. */
-	status = split_fname_dir_mask(ctx, smb_fname->base_name,
-				      &fname_dir, &fname_mask);
-	if (!NT_STATUS_IS_OK(status)) {
-		goto out;
-	}
-
-	/*
-	 * We should only check the mangled cache
-	 * here if unix_convert failed. This means
-	 * that the path in 'mask' doesn't exist
-	 * on the file system and so we need to look
-	 * for a possible mangle. This patch from
-	 * Tine Smukavec <valentin.smukavec@hermes.si>.
-	 */
-
-	if (!VALID_STAT(smb_fname->st) &&
-	    mangle_is_mangled(fname_mask, conn->params)) {
-		char *new_mask = NULL;
-		mangle_lookup_name_from_8_3(ctx, fname_mask,
-					    &new_mask, conn->params);
-		if (new_mask) {
-			TALLOC_FREE(fname_mask);
-			fname_mask = new_mask;
-		}
-	}
-
-	/*
-	 * Only one file needs to be unlinked. Append the mask back
-	 * onto the directory.
-	 */
-	TALLOC_FREE(smb_fname->base_name);
-	if (ISDOT(fname_dir)) {
-		/* Ensure we use canonical names on open. */
-		smb_fname->base_name = talloc_asprintf(smb_fname,
-						"%s",
-						fname_mask);
-	} else {
-		smb_fname->base_name = talloc_asprintf(smb_fname,
-						"%s/%s",
-						fname_dir,
-						fname_mask);
-	}
-	if (!smb_fname->base_name) {
-		status = NT_STATUS_NO_MEMORY;
-		goto out;
-	}
-
-	status = check_name(conn, smb_fname);
-	if (!NT_STATUS_IS_OK(status)) {
-		goto out;
-	}
-
-	status = do_unlink(conn, req, smb_fname, dirtype);
-
- out:
-	TALLOC_FREE(smb_fname_dir);
-	TALLOC_FREE(fname_dir);
-	TALLOC_FREE(fname_mask);
-	return status;
-}
-#endif
-
 /****************************************************************************
  Reply to a unlink
 ****************************************************************************/
-- 
2.25.1


From 26ecf18b426eb3f2db9d60f02ece2af5e6fa057e Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:35:17 -0800
Subject: [PATCH 50/99] CVE-2021-44141: s3: smbd: Handling
 SMB_FILE_RENAME_INFORMATION, the destination name is a single component.

No errors should be allowed from filename_convert().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/trans2.c | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 2b2643b6325..95a7cc63970 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -7477,25 +7477,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
 					  0,
 					  &smb_fname_dst);
 
-		/* If an error we expect this to be
-		 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
-
 		if (!NT_STATUS_IS_OK(status)) {
-			if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
-					    status)) {
-				goto out;
-			}
-			/* Create an smb_fname to call rename_internals_fsp() */
-			smb_fname_dst = synthetic_smb_fname(ctx,
-						base_name,
-						NULL,
-						NULL,
-						smb_fname_src->twrp,
-						smb_fname_src->flags);
-			if (smb_fname_dst == NULL) {
-				status = NT_STATUS_NO_MEMORY;
-				goto out;
-			}
+			goto out;
 		}
 		dst_original_lcomp = get_original_lcomp(smb_fname_dst,
 					conn,
-- 
2.25.1


From 838985e439df0c1b741516ff141da02ecbf5656f Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:45:13 -0800
Subject: [PATCH 51/99] CVE-2021-44141: s3: smbd: In rename_internals_fsp(),
 remove unneeded call to check_name().

All callers have gone through filename_convert(), which has
already called check_name() on the destination.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 26049b2b62b..b9f1bd6b9c2 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7185,11 +7185,6 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 	bool dst_exists, old_is_stream, new_is_stream;
 	int ret;
 
-	status = check_name(conn, smb_fname_dst_in);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
 	status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
-- 
2.25.1


From 43a9866c46b9a82af34693e5c17c0c627169cb76 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:47:13 -0800
Subject: [PATCH 52/99] CVE-2021-44141: s3: smbd: check_name() is now static to
 filename.c

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 2 +-
 source3/smbd/proto.h    | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 11022dca703..44f9aebf068 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1430,7 +1430,7 @@ static NTSTATUS check_veto_path(connection_struct *conn,
  a valid one for the user to access.
 ****************************************************************************/
 
-NTSTATUS check_name(connection_struct *conn,
+static NTSTATUS check_name(connection_struct *conn,
 			const struct smb_filename *smb_fname)
 {
 	NTSTATUS status = check_veto_path(conn, smb_fname);
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index fa26d58bfde..e6a0d6c3d51 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -358,8 +358,6 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		      NTTIME twrp,
 		      struct smb_filename **smb_fname,
 		      uint32_t ucf_flags);
-NTSTATUS check_name(connection_struct *conn,
-			const struct smb_filename *smb_fname);
 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
 				    uint32_t ucf_flags,
 				    NTTIME twrp);
-- 
2.25.1


From 68ee550a0dd41e31fd6ffdd1aeda8adb3595a8cf Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:49:46 -0800
Subject: [PATCH 53/99] CVE-2021-44141: s3: smbd: In rename_internals(), remove
 the name spliting and re-combining code.

filename_convert() handles mangled names just fine, so we don't
need to split the last component and check for mangle.

Now we don't take wildcard names this is not needed. This was the
last caller of split_fname_dir_mask(), so ifdef it out.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 67 ++------------------------------------------
 1 file changed, 2 insertions(+), 65 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index b9f1bd6b9c2..7b0eb18d744 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1624,6 +1624,7 @@ void reply_dskattr(struct smb_request *req)
 	return;
 }
 
+#if 0
 /*
  * Utility function to split the filename from the directory.
  */
@@ -1655,6 +1656,7 @@ static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
 	*fname_mask_out = fname_mask;
 	return NT_STATUS_OK;
 }
+#endif
 
 /****************************************************************************
  Make a dir struct.
@@ -7618,52 +7620,12 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			bool replace_if_exists,
 			uint32_t access_mask)
 {
-	char *fname_src_dir = NULL;
-	struct smb_filename *smb_fname_src_dir = NULL;
-	char *fname_src_mask = NULL;
 	NTSTATUS status = NT_STATUS_OK;
-	char *talloced = NULL;
 	int create_options = 0;
 	struct smb2_create_blobs *posx = NULL;
 	struct files_struct *fsp = NULL;
 	int rc;
 
-	/*
-	 * Split the old name into directory and last component
-	 * strings. Note that unix_convert may have stripped off a
-	 * leading ./ from both name and newname if the rename is
-	 * at the root of the share. We need to make sure either both
-	 * name and newname contain a / character or neither of them do.
-	 */
-
-	/* Split up the directory from the filename/mask. */
-	status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
-				      &fname_src_dir, &fname_src_mask);
-	if (!NT_STATUS_IS_OK(status)) {
-		status = NT_STATUS_NO_MEMORY;
-		goto out;
-	}
-
-	/*
-	 * We should only check the mangled cache
-	 * here if unix_convert failed. This means
-	 * that the path in 'mask' doesn't exist
-	 * on the file system and so we need to look
-	 * for a possible mangle. This patch from
-	 * Tine Smukavec <valentin.smukavec@hermes.si>.
-	 */
-
-	if (!VALID_STAT(smb_fname_src->st) &&
-	    mangle_is_mangled(fname_src_mask, conn->params)) {
-		char *new_mask = NULL;
-		mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
-					    conn->params);
-		if (new_mask) {
-			TALLOC_FREE(fname_src_mask);
-			fname_src_mask = new_mask;
-		}
-	}
-
 	if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
 		status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -7673,27 +7635,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 		}
 	}
 
-	/*
-	 * Only one file needs to be renamed. Append the mask back
-	 * onto the directory.
-	 */
-	TALLOC_FREE(smb_fname_src->base_name);
-	if (ISDOT(fname_src_dir)) {
-		/* Ensure we use canonical names on open. */
-		smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-						"%s",
-						fname_src_mask);
-	} else {
-		smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
-						"%s/%s",
-						fname_src_dir,
-						fname_src_mask);
-	}
-	if (!smb_fname_src->base_name) {
-		status = NT_STATUS_NO_MEMORY;
-		goto out;
-	}
-
 	DBG_NOTICE("case_sensitive = %d, "
 		  "case_preserve = %d, short case preserve = %d, "
 		  "directory = %s, newname = %s, "
@@ -7776,10 +7717,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 
  out:
 	TALLOC_FREE(posx);
-	TALLOC_FREE(talloced);
-	TALLOC_FREE(smb_fname_src_dir);
-	TALLOC_FREE(fname_src_dir);
-	TALLOC_FREE(fname_src_mask);
 	return status;
 }
 
-- 
2.25.1


From 0163d21c31ad978182adba73bae8f0ee48c69e53 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 9 Dec 2021 16:51:45 -0800
Subject: [PATCH 54/99] CVE-2021-44141: s3: smbd: Remove
 split_fname_dir_mask().

No longer used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 34 ----------------------------------
 1 file changed, 34 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 7b0eb18d744..d2048856cff 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1624,40 +1624,6 @@ void reply_dskattr(struct smb_request *req)
 	return;
 }
 
-#if 0
-/*
- * Utility function to split the filename from the directory.
- */
-static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
-				     char **fname_dir_out,
-				     char **fname_mask_out)
-{
-	const char *p = NULL;
-	char *fname_dir = NULL;
-	char *fname_mask = NULL;
-
-	p = strrchr_m(fname_in, '/');
-	if (!p) {
-		fname_dir = talloc_strdup(ctx, ".");
-		fname_mask = talloc_strdup(ctx, fname_in);
-	} else {
-		fname_dir = talloc_strndup(ctx, fname_in,
-		    PTR_DIFF(p, fname_in));
-		fname_mask = talloc_strdup(ctx, p+1);
-	}
-
-	if (!fname_dir || !fname_mask) {
-		TALLOC_FREE(fname_dir);
-		TALLOC_FREE(fname_mask);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	*fname_dir_out = fname_dir;
-	*fname_mask_out = fname_mask;
-	return NT_STATUS_OK;
-}
-#endif
-
 /****************************************************************************
  Make a dir struct.
 ****************************************************************************/
-- 
2.25.1


From 1c1c7ed99466ace89eb61d4783903b8b8a718e27 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 17:51:42 -0800
Subject: [PATCH 55/99] CVE-2021-44141: s3: smbd: In call_trans2findfirst() we
 don't need filename_convert_with_privilege() anymore.

It was extra-paranoid code now not needed as the new VFS
version of filename_convert() does the same job.

There are now no remaining callers of filename_convert_with_privilege().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/trans2.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 95a7cc63970..4612221dbfe 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2757,19 +2757,12 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 	if (backup_priv) {
 		become_root();
 		as_root = true;
-		ntstatus = filename_convert_with_privilege(talloc_tos(),
-				conn,
-				req,
-				directory,
-				ucf_flags,
-				&smb_dname);
-	} else {
-		ntstatus = filename_convert(talloc_tos(), conn,
+	}
+	ntstatus = filename_convert(talloc_tos(), conn,
 				    directory,
 				    ucf_flags,
 				    0,
 				    &smb_dname);
-	}
 
 	if (!NT_STATUS_IS_OK(ntstatus)) {
 		if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
-- 
2.25.1


From 46ec23c244bc001a5bb1105a2d1e23ebfdd78ca4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 2 Dec 2021 17:55:26 -0800
Subject: [PATCH 56/99] CVE-2021-44141: s3: smbd: Remove
 filename_convert_with_privilege(). No longer used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 21 ---------------------
 source3/smbd/proto.h    |  6 ------
 2 files changed, 27 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 44f9aebf068..3d0f350c3dc 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -2078,27 +2078,6 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 					pp_smb_fname);
 }
 
-/*
- * Go through all the steps to validate a filename.
- * root (privileged) version.
- */
-
-NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
-                                connection_struct *conn,
-				struct smb_request *smbreq,
-                                const char *name_in,
-                                uint32_t ucf_flags,
-                                struct smb_filename **pp_smb_fname)
-{
-	return filename_convert_internal(ctx,
-					conn,
-					smbreq,
-					name_in,
-					ucf_flags,
-					0,
-					pp_smb_fname);
-}
-
 /*
  * Build the full path from a dirfsp and dirfsp relative name
  */
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index e6a0d6c3d51..58b32c6908b 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -382,12 +382,6 @@ NTSTATUS filename_convert(TALLOC_CTX *mem_ctx,
 			uint32_t ucf_flags,
 			NTTIME twrp,
 			struct smb_filename **pp_smb_fname);
-NTSTATUS filename_convert_with_privilege(TALLOC_CTX *mem_ctx,
-			connection_struct *conn,
-			struct smb_request *smbreq,
-			const char *name_in,
-			uint32_t ucf_flags,
-			struct smb_filename **pp_smb_fname);
 
 /* The following definitions come from smbd/files.c  */
 
-- 
2.25.1


From 733e66aa31da219f7bc54cd380451d380d6ca3a1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 10:10:45 -0800
Subject: [PATCH 57/99] CVE-2021-44141: s3: smbd: In
 filename_convert_internal(), remove call to check_name_with_privilege().

We now always pass NULL as struct smb_request *smbreq,
so this code path can never be taken.

Comment out check_name_with_privilege() as it's now
no longer used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 3d0f350c3dc..882f41ec400 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1452,6 +1452,7 @@ static NTSTATUS check_name(connection_struct *conn,
 	return NT_STATUS_OK;
 }
 
+#if 0
 /****************************************************************************
  Must be called as root. Creates the struct privilege_paths
  attached to the struct smb_request if this call is successful.
@@ -1470,6 +1471,7 @@ static NTSTATUS check_name_with_privilege(connection_struct *conn,
 			smb_fname,
 			smbreq);
 }
+#endif
 
 /****************************************************************************
  Check if two filenames are equal.
@@ -1999,11 +2001,8 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
 			TALLOC_FREE(smb_fname);
 			return status;
 		}
-	} else if (!smbreq) {
-		status = check_name(conn, smb_fname);
 	} else {
-		status = check_name_with_privilege(conn, smbreq,
-				smb_fname);
+		status = check_name(conn, smb_fname);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3,("filename_convert_internal: check_name failed "
-- 
2.25.1


From 3f60b452049e4c10cec414a7da8709f2ceb3f929 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 10:13:13 -0800
Subject: [PATCH 58/99] CVE-2021-44141: s3: smbd: Remove unused
 check_name_with_privilege().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 882f41ec400..297f48496e8 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1452,27 +1452,6 @@ static NTSTATUS check_name(connection_struct *conn,
 	return NT_STATUS_OK;
 }
 
-#if 0
-/****************************************************************************
- Must be called as root. Creates the struct privilege_paths
- attached to the struct smb_request if this call is successful.
-****************************************************************************/
-
-static NTSTATUS check_name_with_privilege(connection_struct *conn,
-		struct smb_request *smbreq,
-		const struct smb_filename *smb_fname)
-{
-	NTSTATUS status = check_veto_path(conn, smb_fname);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-	return check_reduced_name_with_privilege(conn,
-			smb_fname,
-			smbreq);
-}
-#endif
-
 /****************************************************************************
  Check if two filenames are equal.
  This needs to be careful about whether we are case sensitive.
-- 
2.25.1


From 51c024a1b029c0ca66594336d5474b8cc64c4452 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 10:14:03 -0800
Subject: [PATCH 59/99] CVE-2021-44141: s3: smbd: Remove now unused
 check_reduced_name_with_privilege().

We now only have one function that does this check (check_reduced_name()),
used everywhere.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/proto.h |   3 -
 source3/smbd/vfs.c   | 173 -------------------------------------------
 2 files changed, 176 deletions(-)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 58b32c6908b..5e7bc392b87 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1300,9 +1300,6 @@ struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn);
 NTSTATUS check_reduced_name(connection_struct *conn,
 			const struct smb_filename *cwd_fname,
 			const struct smb_filename *smb_fname);
-NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
-			const struct smb_filename *smb_fname,
-			struct smb_request *smbreq);
 int vfs_stat(struct connection_struct *conn,
 	     struct smb_filename *smb_fname);
 int vfs_stat_smb_basename(struct connection_struct *conn,
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 34831385e09..d8b7b1283fb 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1122,179 +1122,6 @@ struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 	return result;
 }
 
-/*******************************************************************
- Reduce a file name, removing .. elements and checking that
- it is below dir in the hierarchy. This uses realpath.
- This function must run as root, and will return names
- and valid stat structs that can be checked on open.
-********************************************************************/
-
-NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
-			const struct smb_filename *smb_fname,
-			struct smb_request *smbreq)
-{
-	NTSTATUS status;
-	TALLOC_CTX *ctx = talloc_tos();
-	const char *conn_rootdir;
-	size_t rootdir_len;
-	char *resolved_name = NULL;
-	struct smb_filename *resolved_fname = NULL;
-	struct smb_filename *saved_dir_fname = NULL;
-	struct smb_filename *smb_fname_cwd = NULL;
-	int ret;
-	struct smb_filename *parent_name = NULL;
-	struct smb_filename *file_name = NULL;
-
-	DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
-			smb_fname->base_name,
-			conn->connectpath));
-
-	status = SMB_VFS_PARENT_PATHNAME(conn,
-					 ctx,
-					 smb_fname,
-					 &parent_name,
-					 &file_name);
-	if (!NT_STATUS_IS_OK(status)) {
-		goto err;
-	}
-
-	if (SMB_VFS_STAT(conn, parent_name) != 0) {
-		status = map_nt_error_from_unix(errno);
-		goto err;
-	}
-	/* Remember where we were. */
-	saved_dir_fname = vfs_GetWd(ctx, conn);
-	if (!saved_dir_fname) {
-		status = map_nt_error_from_unix(errno);
-		goto err;
-	}
-
-	if (vfs_ChDir(conn, parent_name) == -1) {
-		status = map_nt_error_from_unix(errno);
-		goto err;
-	}
-
-	smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
-					    ".",
-					    NULL,
-					    NULL,
-					    parent_name->twrp,
-					    0);
-	if (smb_fname_cwd == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto err;
-	}
-
-	/* Get the absolute path of the parent directory. */
-	resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
-	if (resolved_fname == NULL) {
-		status = map_nt_error_from_unix(errno);
-		goto err;
-	}
-	resolved_name = resolved_fname->base_name;
-
-	if (*resolved_name != '/') {
-		DEBUG(0,("check_reduced_name_with_privilege: realpath "
-			"doesn't return absolute paths !\n"));
-		status = NT_STATUS_OBJECT_NAME_INVALID;
-		goto err;
-	}
-
-	DBG_DEBUG("realpath [%s] -> [%s]\n",
-		  smb_fname_str_dbg(parent_name),
-		  resolved_name);
-
-	/* Now check the stat value is the same. */
-	if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
-		status = map_nt_error_from_unix(errno);
-		goto err;
-	}
-
-	/* Ensure we're pointing at the same place. */
-	if (!check_same_stat(&smb_fname_cwd->st, &parent_name->st)) {
-		DBG_ERR("device/inode/uid/gid on directory %s changed. "
-			"Denying access !\n",
-			smb_fname_str_dbg(parent_name));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto err;
-	}
-
-	/* Ensure we're below the connect path. */
-
-	conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
-	if (conn_rootdir == NULL) {
-		DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
-			"conn_rootdir\n"));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto err;
-	}
-
-	rootdir_len = strlen(conn_rootdir);
-
-	/*
-	 * In the case of rootdir_len == 1, we know that conn_rootdir is
-	 * "/", and we also know that resolved_name starts with a slash.
-	 * So, in this corner case, resolved_name is automatically a
-	 * sub-directory of the conn_rootdir. Thus we can skip the string
-	 * comparison and the next character checks (which are even
-	 * wrong in this case).
-	 */
-	if (rootdir_len != 1) {
-		bool matched;
-
-		matched = (strncmp(conn_rootdir, resolved_name,
-				rootdir_len) == 0);
-
-		if (!matched || (resolved_name[rootdir_len] != '/' &&
-				 resolved_name[rootdir_len] != '\0')) {
-			DBG_WARNING("%s is a symlink outside the "
-				    "share path\n",
-				    smb_fname_str_dbg(parent_name));
-			DEBUGADD(1, ("conn_rootdir =%s\n", conn_rootdir));
-			DEBUGADD(1, ("resolved_name=%s\n", resolved_name));
-			status = NT_STATUS_ACCESS_DENIED;
-			goto err;
-		}
-	}
-
-	/* Now ensure that the last component either doesn't
-	   exist, or is *NOT* a symlink. */
-
-	ret = SMB_VFS_LSTAT(conn, file_name);
-	if (ret == -1) {
-		/* Errno must be ENOENT for this be ok. */
-		if (errno != ENOENT) {
-			status = map_nt_error_from_unix(errno);
-			DBG_WARNING("LSTAT on %s failed with %s\n",
-				    smb_fname_str_dbg(file_name),
-				    nt_errstr(status));
-			goto err;
-		}
-	}
-
-	if (VALID_STAT(file_name->st) &&
-	    S_ISLNK(file_name->st.st_ex_mode))
-	{
-		DBG_WARNING("Last component %s is a symlink. Denying"
-			    "access.\n",
-			    smb_fname_str_dbg(file_name));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto err;
-	}
-
-	status = NT_STATUS_OK;
-
-  err:
-
-	if (saved_dir_fname != NULL) {
-		vfs_ChDir(conn, saved_dir_fname);
-		TALLOC_FREE(saved_dir_fname);
-	}
-	TALLOC_FREE(resolved_fname);
-	TALLOC_FREE(parent_name);
-	return status;
-}
-
 /*******************************************************************
  Reduce a file name, removing .. elements and checking that
  it is below dir in the hierarchy. This uses realpath.
-- 
2.25.1


From f8ecb37606ef65a53fbf45c7a4305454de1e53af Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 10:19:38 -0800
Subject: [PATCH 60/99] CVE-2021-44141: s3: smbd: filename_convert() is now a
 one-to-one wrapper around filename_convert_internal().

Remove filename_convert() and rename filename_convert_internal() -> filename_convert().
Move the old DEBUG(..) statements to DBG_XXX() so they don't print the wrong name.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 46 +++++++++++------------------------------
 1 file changed, 12 insertions(+), 34 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 297f48496e8..2c4fa5506ff 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1913,13 +1913,12 @@ char *get_original_lcomp(TALLOC_CTX *ctx,
  * @return NT_STATUS_OK if all operations completed successfully, appropriate
  * 	   error otherwise.
  */
-static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
-				connection_struct *conn,
-				struct smb_request *smbreq,
-				const char *name_in,
-				uint32_t ucf_flags,
-				NTTIME twrp,
-				struct smb_filename **_smb_fname)
+NTSTATUS filename_convert(TALLOC_CTX *ctx,
+			  connection_struct *conn,
+			  const char *name_in,
+			  uint32_t ucf_flags,
+			  NTTIME twrp,
+			  struct smb_filename **_smb_fname)
 {
 	struct smb_filename *smb_fname = NULL;
 	bool has_wild;
@@ -1935,10 +1934,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
 				!conn->sconn->using_smb2,
 				&fname);
 		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(10,("filename_convert_internal: dfs_redirect "
+			DBG_DEBUG("dfs_redirect "
 				"failed for name %s with %s\n",
 				name_in,
-				nt_errstr(status) ));
+				nt_errstr(status));
 			return status;
 		}
 		name_in = fname;
@@ -1964,10 +1963,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
 
 	status = unix_convert(ctx, conn, name_in, twrp, &smb_fname, ucf_flags);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10,("filename_convert_internal: unix_convert failed "
+		DBG_DEBUG("unix_convert failed "
 			"for name %s with %s\n",
 			name_in,
-			nt_errstr(status) ));
+			nt_errstr(status));
 		return status;
 	}
 
@@ -1984,10 +1983,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
 		status = check_name(conn, smb_fname);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(3,("filename_convert_internal: check_name failed "
+		DBG_NOTICE("check_name failed "
 			"for name %s with %s\n",
 			smb_fname_str_dbg(smb_fname),
-			nt_errstr(status) ));
+			nt_errstr(status));
 		TALLOC_FREE(smb_fname);
 		return status;
 	}
@@ -2035,27 +2034,6 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
 	return status;
 }
 
-/*
- * Go through all the steps to validate a filename.
- * Non-root version.
- */
-
-NTSTATUS filename_convert(TALLOC_CTX *ctx,
-				connection_struct *conn,
-				const char *name_in,
-				uint32_t ucf_flags,
-				NTTIME twrp,
-				struct smb_filename **pp_smb_fname)
-{
-	return filename_convert_internal(ctx,
-					conn,
-					NULL,
-					name_in,
-					ucf_flags,
-					twrp,
-					pp_smb_fname);
-}
-
 /*
  * Build the full path from a dirfsp and dirfsp relative name
  */
-- 
2.25.1


From 3490db2a38981b10ad165d9815ff026ad1b8513d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 16:00:26 -0800
Subject: [PATCH 61/99] CVE-2021-44141: s3: smbd: In dfs_path_lookup(). If we
 have a DFS path including a @GMT-token, don't throw away the twrp value when
 parsing the path.

Not yet used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/msdfs.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index fd002e98071..86ca79a994b 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -697,6 +697,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 		const struct dfs_path *pdp, /* Parsed out
 					       server+share+extrapath. */
 		uint32_t ucf_flags,
+		NTTIME *_twrp,
 		int *consumedcntp,
 		struct referral **ppreflist,
 		size_t *preferral_count)
@@ -867,6 +868,10 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 		}
 	}
 
+	if ((ucf_flags & UCF_GMT_PATHNAME) && _twrp != NULL) {
+		*_twrp = smb_fname->twrp;
+	}
+
 	status = NT_STATUS_OK;
  out:
 
@@ -965,6 +970,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
 				path_in,
 				pdp,
 				ucf_flags,
+				NULL, /* twrp. */
 				NULL, /* int *consumedcntp */
 				NULL, /* struct referral **ppreflist */
 				NULL); /* size_t *preferral_count */
@@ -1189,6 +1195,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
 				dfs_path,
 				pdp,
 				0, /* ucf_flags */
+				NULL,
 				consumedcntp,
 				&jucn->referral_list,
 				&jucn->referral_count);
-- 
2.25.1


From 5c55cd93e5bd1481e88edd4fa0c76f4679bdfcc6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 16:14:08 -0800
Subject: [PATCH 62/99] CVE-2021-44141: s3: smbd: Allow dfs_redirect() to
 return a TWRP token it got from a parsed pathname.

This one is subtle. If an SMB1 request has both a DFS path and a @GMT token,
the unix_convert() inside the DFS path processing will remove the @GMT
token, not allowing the subsequent unix_convert() inside filename_convert()
to see it. By returning it from dfs_redirect() we can ensure it's correctly
added to the smb_filename returned from filename_convert().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 11 +++++++++--
 source3/smbd/msdfs.c    |  3 ++-
 source3/smbd/proto.h    |  1 +
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 2c4fa5506ff..bcbe9f70015 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1824,6 +1824,7 @@ char *get_original_lcomp(TALLOC_CTX *ctx,
 	char *last_slash = NULL;
 	char *orig_lcomp;
 	char *fname = NULL;
+	NTTIME twrp = 0;
 	NTSTATUS status;
 
 	if (ucf_flags & UCF_DFS_PATHNAME) {
@@ -1832,6 +1833,7 @@ char *get_original_lcomp(TALLOC_CTX *ctx,
 				filename_in,
 				ucf_flags,
 				!conn->sconn->using_smb2,
+				&twrp,
 				&fname);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_DEBUG("dfs_redirect "
@@ -1860,7 +1862,7 @@ char *get_original_lcomp(TALLOC_CTX *ctx,
 					filename_in,
 					NULL,
 					NULL,
-					0,
+					twrp,
 					0);
 		if (smb_fname == NULL) {
 			TALLOC_FREE(fname);
@@ -1868,7 +1870,7 @@ char *get_original_lcomp(TALLOC_CTX *ctx,
 		}
 		status = canonicalize_snapshot_path(smb_fname,
 						    ucf_flags,
-						    0);
+						    twrp);
 		if (!NT_STATUS_IS_OK(status)) {
 			TALLOC_FREE(fname);
 			TALLOC_FREE(smb_fname);
@@ -1928,10 +1930,12 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 
 	if (ucf_flags & UCF_DFS_PATHNAME) {
 		char *fname = NULL;
+		NTTIME dfs_twrp = 0;
 		status = dfs_redirect(ctx, conn,
 				name_in,
 				ucf_flags,
 				!conn->sconn->using_smb2,
+				&dfs_twrp,
 				&fname);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_DEBUG("dfs_redirect "
@@ -1942,6 +1946,9 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 		}
 		name_in = fname;
 		ucf_flags &= ~UCF_DFS_PATHNAME;
+		if (twrp == 0 && dfs_twrp != 0) {
+			twrp = dfs_twrp;
+		}
 	}
 
 	if (is_fake_file_path(name_in)) {
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 86ca79a994b..07636592016 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -901,6 +901,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
 			const char *path_in,
 			uint32_t ucf_flags,
 			bool allow_broken_path,
+			NTTIME *_twrp,
 			char **pp_path_out)
 {
 	const struct loadparm_substitution *lp_sub =
@@ -970,7 +971,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
 				path_in,
 				pdp,
 				ucf_flags,
-				NULL, /* twrp. */
+				_twrp, /* twrp. */
 				NULL, /* int *consumedcntp */
 				NULL, /* struct referral **ppreflist */
 				NULL); /* size_t *preferral_count */
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 5e7bc392b87..c1db119633e 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -567,6 +567,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
 			const char *name_in,
 			uint32_t ucf_flags,
 			bool allow_broken_path,
+			NTTIME *twrp,
 			char **pp_name_out);
 struct connection_struct;
 struct smb_filename;
-- 
2.25.1


From e6d9ef3b1e8e19c1b02a3320a619464b1c319a51 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 10:35:09 -0800
Subject: [PATCH 63/99] CVE-2021-44141: s3: smbd: Add
 filename_convert_smb1_search_path() - deals with SMB1 search pathnames.

SMB1search and trans2 findfirst are unique in that
they are the only passed in pathnames that can contain
a terminal wildcard component.

Deal with these two special cases with this new function
that strips off the terminal wildcard and returns as
the mask, and pass the non-wildcard parent directory
component through the standard filename_convert().

Uses new helper function strip_gmt_from_raw_dfs().

When SMB1search and trans2 findfirst have been
converted to use this function, we can strip all
wildcard handling out of filename_convert() as
we now know it will only ever be given valid
pathnames.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 240 ++++++++++++++++++++++++++++++++++++++++
 source3/smbd/proto.h    |   6 +
 2 files changed, 246 insertions(+)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index bcbe9f70015..ab2a418a3a0 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -2041,6 +2041,246 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 	return status;
 }
 
+/*
+ * Strip a @GMT component from an SMB1-DFS path. Could be anywhere
+ * in the path.
+ */
+
+static char *strip_gmt_from_raw_dfs(TALLOC_CTX *ctx,
+				    const char *name_in,
+				    bool posix_pathnames,
+				    NTTIME *_twrp)
+{
+	NTSTATUS status;
+	struct smb_filename *smb_fname = NULL;
+	char *name_out = NULL;
+
+	smb_fname = synthetic_smb_fname(ctx,
+					name_in,
+					NULL,
+					NULL,
+					0,
+					0);
+	if (smb_fname == NULL) {
+		return NULL;
+	}
+	if (!posix_pathnames) {
+		/*
+		 * Raw DFS names are still '\\' separated.
+		 * canonicalize_snapshot_path() only works
+		 * on '/' separated paths. Convert.
+		 */
+		string_replace(smb_fname->base_name, '\\', '/');
+	}
+	status = canonicalize_snapshot_path(smb_fname,
+					    UCF_GMT_PATHNAME,
+					    0);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(smb_fname);
+		return NULL;
+	}
+	if (!posix_pathnames) {
+		/* Replace as raw DFS names. */
+		string_replace(smb_fname->base_name, '/', '\\');
+	}
+	name_out = talloc_strdup(ctx, smb_fname->base_name);
+	*_twrp = smb_fname->twrp;
+	TALLOC_FREE(smb_fname);
+	return name_out;
+}
+
+/*
+ * Deal with the SMB1 semantics of sending a pathname with a
+ * wildcard as the terminal component for a SMB1search or
+ * trans2 findfirst.
+ */
+
+NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
+					   connection_struct *conn,
+					   const char *name_in,
+					   uint32_t ucf_flags,
+					   struct smb_filename **_smb_fname_out,
+					   char **_mask_out)
+{
+	NTSTATUS status;
+	char *p = NULL;
+	char *mask = NULL;
+	struct smb_filename *smb_fname = NULL;
+	bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
+	NTTIME twrp = 0;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	*_smb_fname_out = NULL;
+	*_mask_out = NULL;
+
+	DBG_DEBUG("name_in: %s\n", name_in);
+
+	if (ucf_flags & UCF_DFS_PATHNAME) {
+		/*
+		 * We've been given a raw DFS pathname.
+		 * In Windows mode this is separated by '\\'
+		 * characters.
+		 *
+		 * We need to remove the last component
+		 * which must be a wildcard before passing
+		 * to dfs_redirect(). But the last component
+		 * may also be a @GMT- token so we have to
+		 * remove that first.
+		 */
+		char path_sep = posix_pathnames ? '/' : '\\';
+		char *fname = NULL;
+		char *name_in_copy = NULL;
+		char *last_component = NULL;
+
+		/* Work on a copy of name_in. */
+		if (ucf_flags & UCF_GMT_PATHNAME) {
+			name_in_copy = strip_gmt_from_raw_dfs(frame,
+							      name_in,
+							      posix_pathnames,
+							      &twrp);
+			ucf_flags &= ~UCF_GMT_PATHNAME;
+		} else {
+			name_in_copy = talloc_strdup(frame, name_in);
+		}
+		if (name_in_copy == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		/*
+		 * Now we know that the last component is the
+		 * wildcard. Copy it and truncate to remove it.
+		 */
+		p = strrchr_m(name_in_copy, path_sep);
+		if (p == NULL) {
+			last_component = talloc_strdup(frame, name_in_copy);
+			name_in_copy[0] = '\0';
+		} else {
+			last_component = talloc_strdup(frame, p+1);
+			*p = '\0';
+		}
+		if (last_component == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		DBG_DEBUG("name_in_copy: %s\n", name_in);
+
+		/*
+		 * Now we can call dfs_redirect()
+		 * on the name without wildcard.
+		 */
+		status = dfs_redirect(frame,
+				      conn,
+				      name_in_copy,
+				      ucf_flags,
+				      !conn->sconn->using_smb2,
+				      NULL,
+				      &fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_DEBUG("dfs_redirect "
+				"failed for name %s with %s\n",
+				name_in_copy,
+				nt_errstr(status));
+			TALLOC_FREE(frame);
+			return status;
+		}
+		/* Add the last component back. */
+		if (fname[0] == '\0') {
+			name_in = talloc_strdup(frame, last_component);
+		} else {
+			name_in = talloc_asprintf(frame,
+						  "%s%c%s",
+						  fname,
+						  path_sep,
+						  last_component);
+		}
+		if (name_in == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+		ucf_flags &= ~UCF_DFS_PATHNAME;
+
+		DBG_DEBUG("After DFS redirect name_in: %s\n", name_in);
+	}
+
+	smb_fname = synthetic_smb_fname(frame,
+					name_in,
+					NULL,
+					NULL,
+					twrp,
+					posix_pathnames ?
+						SMB_FILENAME_POSIX_PATH : 0);
+	if (smb_fname == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/* Canonicalize any @GMT- paths. */
+	status = canonicalize_snapshot_path(smb_fname, ucf_flags, twrp);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	/* Get the original lcomp. */
+	mask = get_original_lcomp(frame,
+				  conn,
+				  name_in,
+				  ucf_flags);
+	if (mask == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (mask[0] == '\0') {
+		/* Windows and OS/2 systems treat search on the root as * */
+		TALLOC_FREE(mask);
+		mask = talloc_strdup(frame, "*");
+		if (mask == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	DBG_DEBUG("mask = %s\n", mask);
+
+	/*
+	 * Remove the terminal component so
+	 * filename_convert never sees the mask.
+	 */
+	p = strrchr_m(smb_fname->base_name,'/');
+	if (p == NULL) {
+		/* filename_convert handles a '\0' base_name. */
+		smb_fname->base_name[0] = '\0';
+	} else {
+		*p = '\0';
+	}
+
+	DBG_DEBUG("For filename_convert: smb_fname = %s\n",
+		smb_fname_str_dbg(smb_fname));
+
+	/* Convert the parent directory path. */
+	status = filename_convert(frame,
+				  conn,
+				  smb_fname->base_name,
+				  ucf_flags,
+				  smb_fname->twrp,
+				  &smb_fname);
+
+	if (NT_STATUS_IS_OK(status)) {
+		*_smb_fname_out = talloc_move(ctx, &smb_fname);
+		*_mask_out = talloc_move(ctx, &mask);
+	} else {
+		DBG_DEBUG("filename_convert error for %s: %s\n",
+			smb_fname_str_dbg(smb_fname),
+			nt_errstr(status));
+	}
+
+	TALLOC_FREE(frame);
+	return status;
+}
+
 /*
  * Build the full path from a dirfsp and dirfsp relative name
  */
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index c1db119633e..46d3f2e5156 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -382,6 +382,12 @@ NTSTATUS filename_convert(TALLOC_CTX *mem_ctx,
 			uint32_t ucf_flags,
 			NTTIME twrp,
 			struct smb_filename **pp_smb_fname);
+NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
+					   connection_struct *conn,
+					   const char *name_in,
+					   uint32_t ucf_flags,
+					   struct smb_filename **_smb_fname_out,
+					   char **_mask_out);
 
 /* The following definitions come from smbd/files.c  */
 
-- 
2.25.1


From 0f1436ed031b702ab5853b6a21e476a1c47b243c Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:22:03 -0800
Subject: [PATCH 64/99] CVE-2021-44141: s3: smbd: Convert reply_search() to use
 filename_convert_smb1_search_path().

Cleans up this code path nicely !

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/reply.c | 71 ++++++++++----------------------------------
 1 file changed, 16 insertions(+), 55 deletions(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index d2048856cff..cc95bfa3af0 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1747,15 +1747,17 @@ void reply_search(struct smb_request *req)
 	/* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
 
 	if (status_len == 0) {
-		int ret;
+		const char *dirpath;
 		struct smb_filename *smb_dname = NULL;
-		uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-			ucf_flags_from_smb_request(req);
-		nt_status = filename_convert(ctx, conn,
-					     path,
-					     ucf_flags,
-					     0,
-					     &smb_fname);
+		uint32_t ucf_flags = ucf_flags_from_smb_request(req);
+
+		nt_status = filename_convert_smb1_search_path(ctx,
+					conn,
+					path,
+					ucf_flags,
+					&smb_dname,
+					&mask);
+
 		if (!NT_STATUS_IS_OK(nt_status)) {
 			if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
 				reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
@@ -1766,56 +1768,9 @@ void reply_search(struct smb_request *req)
 			goto out;
 		}
 
-		directory = smb_fname->base_name;
-
-		p = strrchr_m(directory,'/');
-		if ((p != NULL) && (*directory != '/')) {
-			mask = talloc_strdup(ctx, p + 1);
-			directory = talloc_strndup(ctx, directory,
-						   PTR_DIFF(p, directory));
-		} else {
-			mask = talloc_strdup(ctx, directory);
-			directory = talloc_strdup(ctx,".");
-		}
-
-		if (!directory) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-
 		memset((char *)status,'\0',21);
 		SCVAL(status,0,(dirtype & 0x1F));
 
-		smb_dname = synthetic_smb_fname(talloc_tos(),
-					directory,
-					NULL,
-					NULL,
-					smb_fname->twrp,
-					smb_fname->flags);
-		if (smb_dname == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-
-		/*
-		 * As we've cut off the last component from
-		 * smb_fname we need to re-stat smb_dname
-		 * so FILE_OPEN disposition knows the directory
-		 * exists.
-		 */
-		ret = vfs_stat(conn, smb_dname);
-		if (ret == -1) {
-			nt_status = map_nt_error_from_unix(errno);
-			reply_nterror(req, nt_status);
-			goto out;
-		}
-
-		nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
-		if (!NT_STATUS_IS_OK(nt_status)) {
-			reply_nterror(req, nt_status);
-			goto out;
-		}
-
 		/*
 		 * Open an fsp on this directory for the dptr.
 		 */
@@ -1872,6 +1827,12 @@ void reply_search(struct smb_request *req)
 		}
 
 		dptr_num = dptr_dnum(fsp->dptr);
+		dirpath = dptr_path(sconn, dptr_num);
+		directory = talloc_strdup(ctx, dirpath);
+		if (!directory) {
+			reply_nterror(req, NT_STATUS_NO_MEMORY);
+			goto out;
+		}
 
 	} else {
 		int status_dirtype;
-- 
2.25.1


From 12b44645fb92de451cf82de12b46a43fdc1c2cc1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:28:40 -0800
Subject: [PATCH 65/99] CVE-2021-44141: s3: smbd: Fix call_trans2findfirst() to
 use filename_convert_smb1_search_path().

filename_convert() no longer has to handle wildcards.
UCF_ALWAYS_ALLOW_WCARD_LCOMP is now unused.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/trans2.c | 99 ++++---------------------------------------
 1 file changed, 8 insertions(+), 91 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 4612221dbfe..3ba7011b989 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2665,14 +2665,12 @@ static void call_trans2findfirst(connection_struct *conn,
 	NTSTATUS ntstatus = NT_STATUS_OK;
 	bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
 	struct smbd_server_connection *sconn = req->sconn;
-	uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-			ucf_flags_from_smb_request(req);
+	uint32_t ucf_flags = ucf_flags_from_smb_request(req);
 	bool backup_priv = false;
 	bool as_root = false;
 	files_struct *fsp = NULL;
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
-	int ret;
 
 	if (total_params < 13) {
 		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2758,11 +2756,12 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 		become_root();
 		as_root = true;
 	}
-	ntstatus = filename_convert(talloc_tos(), conn,
-				    directory,
-				    ucf_flags,
-				    0,
-				    &smb_dname);
+	ntstatus = filename_convert_smb1_search_path(talloc_tos(),
+						     conn,
+						     directory,
+						     ucf_flags,
+						     &smb_dname,
+						     &mask);
 
 	if (!NT_STATUS_IS_OK(ntstatus)) {
 		if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2774,72 +2773,9 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 		goto out;
 	}
 
-	/*
-	 * The above call to filename_convert() is on the path from the client
-	 * including the search mask. Until the code that chops of the search
-	 * mask from the path below is moved before the call to
-	 * filename_convert(), we close a possible pathref fsp to ensure
-	 * SMB_VFS_CREATE_FILE() below will internally open a pathref fsp on the
-	 * correct path.
-	 */
-	if (smb_dname->fsp != NULL) {
-		ntstatus = fd_close(smb_dname->fsp);
-		if (!NT_STATUS_IS_OK(ntstatus)) {
-			reply_nterror(req, ntstatus);
-			goto out;
-		}
-		/*
-		 * The pathref fsp link destructor will set smb_dname->fsp to
-		 * NULL. Turning this into an assert to give a hint at readers
-		 * of the code trying to understand the mechanics.
-		 */
-		file_free(req, smb_dname->fsp);
-		SMB_ASSERT(smb_dname->fsp == NULL);
-	}
-
-	mask = get_original_lcomp(talloc_tos(),
-				conn,
-				directory,
-				ucf_flags);
-	if (mask == NULL) {
-		reply_nterror(req, NT_STATUS_NO_MEMORY);
-		goto out;
-	}
-
+	TALLOC_FREE(directory);
 	directory = smb_dname->base_name;
 
-	p = strrchr_m(directory,'/');
-	if(p == NULL) {
-		/* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
-		if((directory[0] == '.') && (directory[1] == '\0')) {
-			mask = talloc_strdup(talloc_tos(),"*");
-			if (!mask) {
-				reply_nterror(req, NT_STATUS_NO_MEMORY);
-				goto out;
-			}
-		}
-	} else {
-		*p = 0;
-	}
-
-	if (p == NULL || p == directory) {
-		struct smb_filename *old_name = smb_dname;
-
-		/* Ensure we don't have a directory name of "". */
-		smb_dname = synthetic_smb_fname(talloc_tos(),
-						".",
-						NULL,
-						&old_name->st,
-						old_name->twrp,
-						old_name->flags);
-		TALLOC_FREE(old_name);
-		if (smb_dname == NULL) {
-			reply_nterror(req, NT_STATUS_NO_MEMORY);
-			goto out;
-		}
-		directory = smb_dname->base_name;
-	}
-
 	DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
 
 	if (info_level == SMB_FIND_EA_LIST) {
@@ -2897,25 +2833,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 	}
 	params = *pparams;
 
-	/*
-	 * As we've cut off the last component from
-	 * smb_fname we need to re-stat smb_dname
-	 * so FILE_OPEN disposition knows the directory
-	 * exists.
-	 */
-	ret = vfs_stat(conn, smb_dname);
-	if (ret == -1) {
-		ntstatus = map_nt_error_from_unix(errno);
-		reply_nterror(req, ntstatus);
-		goto out;
-	}
-
-	ntstatus = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
-	if (!NT_STATUS_IS_OK(ntstatus)) {
-		reply_nterror(req, ntstatus);
-		goto out;
-	}
-
 	/*
 	 * Open an fsp on this directory for the dptr.
 	 */
-- 
2.25.1


From fc8e6669edb9e20fbc3a4f06dccccbb7ec676f70 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:31:40 -0800
Subject: [PATCH 66/99] CVE-2021-44141: s3: smbd: dfs_path_lookup() no longer
 deals with wildcards.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/msdfs.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 07636592016..6a3abd2f6eb 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -680,10 +680,6 @@ bool is_msdfs_link(struct files_struct *dirfsp,
  Used by other functions to decide if a dfs path is remote,
  and to get the list of referred locations for that remote path.
 
- search_flag: For findfirsts, dfs links themselves are not
- redirected, but paths beyond the links are. For normal smb calls,
- even dfs links need to be redirected.
-
  consumedcntp: how much of the dfs path is being redirected. the client
  should try the remaining path on the redirected server.
 
@@ -755,15 +751,6 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 		TALLOC_FREE(parent_fname);
 
 		if (NT_STATUS_IS_OK(status)) {
-			/* XX_ALLOW_WCARD_XXX is called from search functions.*/
-			if (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP) {
-				DBG_INFO("(FindFirst) No redirection "
-					 "for dfs link %s.\n",
-					 dfspath);
-				status = NT_STATUS_OK;
-				goto out;
-			}
-
 			DBG_INFO("%s resolves to a valid dfs link\n",
 				 dfspath);
 
-- 
2.25.1


From d91d4a17443ab833bd210c10ac68b3992cb97370 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:42:23 -0800
Subject: [PATCH 67/99] CVE-2021-44141: s3: smbd: Remove 'bool
 search_wcard_flag' from parse_dfs_path().

Never set.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/msdfs.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 6a3abd2f6eb..1feeec6fff2 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -894,14 +894,13 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
 	NTSTATUS status;
-	bool search_wcard_flag = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
 	struct dfs_path *pdp = talloc(ctx, struct dfs_path);
 
 	if (!pdp) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	status = parse_dfs_path(conn, path_in, search_wcard_flag,
+	status = parse_dfs_path(conn, path_in, false,
 				allow_broken_path, pdp);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(pdp);
-- 
2.25.1


From 6f2c67d9993925e45245c7c3f1aa947d72cd2573 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:48:23 -0800
Subject: [PATCH 68/99] CVE-2021-44141: s3: smbd: parse_dfs_path() can ignore
 wildcards.

If one is passed to filename_convert(), it will error out there
with NT_STATUS_OBJECT_NAME_INVALID.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/msdfs.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 1feeec6fff2..c003b442baa 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -215,12 +215,6 @@ static NTSTATUS parse_dfs_path(connection_struct *conn,
 	if (pdp->posix_path) {
 		status = check_path_syntax_posix(pdp->reqpath);
 	} else {
-		if (!allow_wcards) {
-			bool has_wcard = ms_has_wild(pdp->reqpath);
-			if (has_wcard) {
-				return NT_STATUS_INVALID_PARAMETER;
-			}
-		}
 		status = check_path_syntax(pdp->reqpath);
 	}
 
-- 
2.25.1


From b73be0c7a7c86943416cb83de387341ebfb169fd Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:30:42 -0800
Subject: [PATCH 69/99] CVE-2021-44141: s3: smbd: filename_convert() no longer
 deals with wildcards.

These are already errored out with NT_STATUS_OBJECT_NAME_INVALID
in the unix_convert() code.

Remove the check.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index ab2a418a3a0..dca5de31be6 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1923,7 +1923,6 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 			  struct smb_filename **_smb_fname)
 {
 	struct smb_filename *smb_fname = NULL;
-	bool has_wild;
 	NTSTATUS status;
 
 	*_smb_fname = NULL;
@@ -1998,14 +1997,6 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
 		return status;
 	}
 
-	has_wild = ms_has_wild(name_in);
-	if (has_wild) {
-		DBG_DEBUG("[%s] contains wildcard, skipping pathref fsp\n",
-			  name_in);
-		*_smb_fname = smb_fname;
-		return NT_STATUS_OK;
-	}
-
 	if (!VALID_STAT(smb_fname->st)) {
 		DBG_DEBUG("[%s] does not exist, skipping pathref fsp\n",
 			  smb_fname_str_dbg(smb_fname));
-- 
2.25.1


From 5e42ab3f6a09ec469ef882dca24f1372711646a0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 11:33:42 -0800
Subject: [PATCH 70/99] CVE-2021-44141: s3: smbd: Inside 'struct uc_state',
 remove allow_wcard_last_component.

This is never allowed.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index dca5de31be6..dc2a5a33824 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -524,7 +524,6 @@ struct uc_state {
 	bool component_was_mangled;
 	bool name_has_wildcard;
 	bool posix_pathnames;
-	bool allow_wcard_last_component;
 	bool done;
 };
 
@@ -870,7 +869,7 @@ static NTSTATUS unix_convert_step(struct uc_state *state)
 			return NT_STATUS_OBJECT_NAME_INVALID;
 		}
 		return determine_path_error(state->end+1,
-					    state->allow_wcard_last_component,
+					    false,
 					    state->posix_pathnames);
 	}
 
@@ -962,7 +961,6 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 		.orig_path = orig_path,
 		.ucf_flags = ucf_flags,
 		.posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES),
-		.allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP),
 	};
 
 	*smb_fname_out = NULL;
@@ -1038,7 +1036,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 			status = NT_STATUS_OBJECT_NAME_INVALID;
 		} else {
 			status =determine_path_error(&state->orig_path[2],
-			    state->allow_wcard_last_component,
+			    false,
 			    state->posix_pathnames);
 		}
 		goto err;
@@ -1163,7 +1161,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 	if (!state->posix_pathnames) {
 		/* POSIX pathnames have no wildcards. */
 		state->name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
-		if (state->name_has_wildcard && !state->allow_wcard_last_component) {
+		if (state->name_has_wildcard) {
 			/* Wildcard not valid anywhere. */
 			status = NT_STATUS_OBJECT_NAME_INVALID;
 			goto fail;
-- 
2.25.1


From b0fc0efbac5b1c4144769ec5a2855f4276b9c7a2 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 12:37:15 -0800
Subject: [PATCH 71/99] CVE-2021-44141: s3: smbd: We no longer need
 determine_path_error().

Now we don't have to consider wildcards just
return NT_STATUS_OBJECT_PATH_NOT_FOUND for
the cases we used to call it.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 47 ++---------------------------------------
 1 file changed, 2 insertions(+), 45 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index dc2a5a33824..09bf859bd2d 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -90,45 +90,6 @@ static bool mangled_equal(const char *name1,
 	return strequal(name1, mname);
 }
 
-/****************************************************************************
- Cope with the differing wildcard and non-wildcard error cases.
-****************************************************************************/
-
-static NTSTATUS determine_path_error(const char *name,
-			bool allow_wcard_last_component,
-			bool posix_pathnames)
-{
-	const char *p;
-	bool name_has_wild = false;
-
-	if (!allow_wcard_last_component) {
-		/* Error code within a pathname. */
-		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-	}
-
-	/* We're terminating here so we
-	 * can be a little slower and get
-	 * the error code right. Windows
-	 * treats the last part of the pathname
-	 * separately I think, so if the last
-	 * component is a wildcard then we treat
-	 * this ./ as "end of component" */
-
-	p = strchr(name, '/');
-
-	if (!posix_pathnames) {
-		name_has_wild = ms_has_wild(name);
-	}
-
-	if (!p && (name_has_wild || ISDOT(name))) {
-		/* Error code at the end of a pathname. */
-		return NT_STATUS_OBJECT_NAME_INVALID;
-	} else {
-		/* Error code within a pathname. */
-		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-	}
-}
-
 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
 {
 	/* Ensure we catch all names with in "/."
@@ -868,9 +829,7 @@ static NTSTATUS unix_convert_step(struct uc_state *state)
 			/* Error code at the end of a pathname. */
 			return NT_STATUS_OBJECT_NAME_INVALID;
 		}
-		return determine_path_error(state->end+1,
-					    false,
-					    state->posix_pathnames);
+		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
 	}
 
 	/* The name cannot have a wildcard if it's not
@@ -1035,9 +994,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 		if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') {
 			status = NT_STATUS_OBJECT_NAME_INVALID;
 		} else {
-			status =determine_path_error(&state->orig_path[2],
-			    false,
-			    state->posix_pathnames);
+			status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
 		}
 		goto err;
 	}
-- 
2.25.1


From d52dd78e9d8cecbc9e913c0b91f345cafe755dbd Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 12:40:43 -0800
Subject: [PATCH 72/99] CVE-2021-44141: s3: smbd: UCF_ALWAYS_ALLOW_WCARD_LCOMP
 0x00000002 is no longer used.

Hurrah !

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 3 ---
 source3/smbd/smbd.h     | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 09bf859bd2d..73a2f116915 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -459,9 +459,6 @@ Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
 didn't get any fatal errors that should immediately terminate the calling SMB
 processing whilst resolving.
 
-If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard
-should be allowed in the last component of the path only.
-
 If the orig_path was a stream, smb_filename->base_name will point to the base
 filename, and smb_filename->stream_name will point to the stream name.  If
 orig_path was not a stream, then smb_filename->stream_name will be NULL.
diff --git a/source3/smbd/smbd.h b/source3/smbd/smbd.h
index 84fcf033a71..88bff2830d9 100644
--- a/source3/smbd/smbd.h
+++ b/source3/smbd/smbd.h
@@ -61,7 +61,7 @@ struct trans_state {
  * unix_convert_flags
  */
 /* UCF_SAVE_LCOMP 0x00000001 is no longer used. */
-#define UCF_ALWAYS_ALLOW_WCARD_LCOMP	0x00000002
+/* UCF_ALWAYS_ALLOW_WCARD_LCOMP	0x00000002 is no longer used. */
 /* UCF_COND_ALLOW_WCARD_LCOMP 0x00000004 is no longer used. */
 #define UCF_POSIX_PATHNAMES		0x00000008
 /* #define UCF_UNIX_NAME_LOOKUP 0x00000010 is no longer used. */
-- 
2.25.1


From 3471f03816f8133f501288c8e468c36cdad8ae65 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 12:53:36 -0800
Subject: [PATCH 73/99] CVE-2021-44141: s3: smbd: Inside unix_convert(), never
 set state->name_is_wildcard.

We error out immediately if it's set anyway.
Preparing to remove 'state->name_is_wildcard' structure element.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 73a2f116915..2095c23aaf4 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1114,8 +1114,8 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 
 	if (!state->posix_pathnames) {
 		/* POSIX pathnames have no wildcards. */
-		state->name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
-		if (state->name_has_wildcard) {
+		bool name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
+		if (name_has_wildcard) {
 			/* Wildcard not valid anywhere. */
 			status = NT_STATUS_OBJECT_NAME_INVALID;
 			goto fail;
-- 
2.25.1


From 36f480c7c8ea88238a040415f677ad0a57fec60c Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 12:55:41 -0800
Subject: [PATCH 74/99] CVE-2021-44141: s3: smbd: In unix_convert(), remove all
 references to state->name_has_wildcard.

It is never set.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 25 ++-----------------------
 1 file changed, 2 insertions(+), 23 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 2095c23aaf4..01c0d9d7dbd 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1125,7 +1125,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 	DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
 		  state->smb_fname->base_name, state->dirpath, state->name);
 
-	if (!state->name_has_wildcard) {
+	{
 		int parent_stat_errno = 0;
 
 		/*
@@ -1239,27 +1239,6 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 				goto done;
 			}
 		}
-	} else {
-		/*
-		 * We have a wildcard in the pathname.
-		 *
-		 * Optimization for common case where the wildcard
-		 * is in the last component and the client already
-		 * sent the correct case.
-		 * NOTE : check_parent_exists() doesn't preserve errno.
-		 */
-		int saved_errno = errno;
-		status = check_parent_exists(state->mem_ctx,
-					state->conn,
-					state->posix_pathnames,
-					state->smb_fname,
-					&state->dirpath,
-					&state->name,
-					NULL);
-		errno = saved_errno;
-		if (!NT_STATUS_IS_OK(status)) {
-			goto fail;
-		}
 	}
 
 	/*
@@ -1299,7 +1278,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 	 * components as this can change the size.
 	 */
 
-	if(!state->component_was_mangled && !state->name_has_wildcard) {
+	if(!state->component_was_mangled) {
 		stat_cache_add(state->orig_path,
 			       state->smb_fname->base_name,
 			       state->smb_fname->twrp,
-- 
2.25.1


From 104499b56ded1960c0fa7f2dfd49eea4d0f76172 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 12:59:50 -0800
Subject: [PATCH 75/99] CVE-2021-44141: s3: smbd: In unix_convert() remove the
 now unneeded block indentation.

We removed the 'if (state->name_has_wildcard) {' clause, so
the block no longer needs indenting.

Best seen with git show -b.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 193 ++++++++++++++++++++--------------------
 1 file changed, 95 insertions(+), 98 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 01c0d9d7dbd..c8b3f1f5955 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -910,6 +910,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 	struct uc_state *state = &uc_state;
 	NTSTATUS status;
 	int ret = -1;
+	int parent_stat_errno = 0;
 
 	*state = (struct uc_state) {
 		.mem_ctx = mem_ctx,
@@ -1125,119 +1126,115 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
 	DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
 		  state->smb_fname->base_name, state->dirpath, state->name);
 
-	{
-		int parent_stat_errno = 0;
+	/*
+	 * stat the name - if it exists then we can add the stream back (if
+	 * there was one) and be done!
+	 */
 
-		/*
-		 * stat the name - if it exists then we can add the stream back (if
-		 * there was one) and be done!
-		 */
+	ret = vfs_stat(state->conn, state->smb_fname);
+	if (ret == 0) {
+		status = check_for_dot_component(state->smb_fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto fail;
+		}
+		/* Add the path (not including the stream) to the cache. */
+		stat_cache_add(state->orig_path,
+			       state->smb_fname->base_name,
+			       state->smb_fname->twrp,
+			       state->conn->case_sensitive);
+		DBG_DEBUG("Conversion of base_name finished "
+			  "[%s] -> [%s]\n",
+			  state->orig_path, state->smb_fname->base_name);
+		goto done;
+	}
 
-		ret = vfs_stat(state->conn, state->smb_fname);
-		if (ret == 0) {
-			status = check_for_dot_component(state->smb_fname);
-			if (!NT_STATUS_IS_OK(status)) {
-				goto fail;
-			}
-			/* Add the path (not including the stream) to the cache. */
-			stat_cache_add(state->orig_path,
-				       state->smb_fname->base_name,
-				       state->smb_fname->twrp,
-				       state->conn->case_sensitive);
-			DBG_DEBUG("Conversion of base_name finished "
-				  "[%s] -> [%s]\n",
-				  state->orig_path, state->smb_fname->base_name);
-			goto done;
+	/* Stat failed - ensure we don't use it. */
+	SET_STAT_INVALID(state->smb_fname->st);
+
+	/*
+	 * Note: we must continue processing a path if we get EACCES
+	 * from stat. With NFS4 permissions the file might be lacking
+	 * READ_ATTR, but if the parent has LIST permissions we can
+	 * resolve the path in the path traversal loop down below.
+	 */
+
+	if (errno == ENOENT) {
+		/* Optimization when creating a new file - only
+		   the last component doesn't exist.
+		   NOTE : check_parent_exists() doesn't preserve errno.
+		*/
+		int saved_errno = errno;
+		status = check_parent_exists(state->mem_ctx,
+					state->conn,
+					state->posix_pathnames,
+					state->smb_fname,
+					&state->dirpath,
+					&state->name,
+					&parent_stat_errno);
+		errno = saved_errno;
+		if (!NT_STATUS_IS_OK(status)) {
+			goto fail;
 		}
+	}
 
-		/* Stat failed - ensure we don't use it. */
-		SET_STAT_INVALID(state->smb_fname->st);
+	/*
+	 * A special case - if we don't have any wildcards or mangling chars and are case
+	 * sensitive or the underlying filesystem is case insensitive then searching
+	 * won't help.
+	 */
 
-		/*
-		 * Note: we must continue processing a path if we get EACCES
-		 * from stat. With NFS4 permissions the file might be lacking
-		 * READ_ATTR, but if the parent has LIST permissions we can
-		 * resolve the path in the path traversal loop down below.
-		 */
+	if ((state->conn->case_sensitive || !(state->conn->fs_capabilities &
+				FILE_CASE_SENSITIVE_SEARCH)) &&
+			!mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
 
-		if (errno == ENOENT) {
-			/* Optimization when creating a new file - only
-			   the last component doesn't exist.
-			   NOTE : check_parent_exists() doesn't preserve errno.
-			*/
-			int saved_errno = errno;
-			status = check_parent_exists(state->mem_ctx,
-						state->conn,
-						state->posix_pathnames,
-						state->smb_fname,
-						&state->dirpath,
-						&state->name,
-						&parent_stat_errno);
-			errno = saved_errno;
-			if (!NT_STATUS_IS_OK(status)) {
-				goto fail;
-			}
+		status = check_for_dot_component(state->smb_fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto fail;
 		}
 
 		/*
-		 * A special case - if we don't have any wildcards or mangling chars and are case
-		 * sensitive or the underlying filesystem is case insensitive then searching
-		 * won't help.
+		 * The stat failed. Could be ok as it could be
+		 * a new file.
 		 */
 
-		if ((state->conn->case_sensitive || !(state->conn->fs_capabilities &
-					FILE_CASE_SENSITIVE_SEARCH)) &&
-				!mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
-
-			status = check_for_dot_component(state->smb_fname);
-			if (!NT_STATUS_IS_OK(status)) {
-				goto fail;
-			}
-
+		if (errno == ENOTDIR || errno == ELOOP) {
+			status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			goto fail;
+		} else if (errno == ENOENT) {
 			/*
-			 * The stat failed. Could be ok as it could be
- 			 * a new file.
- 			 */
-
-			if (errno == ENOTDIR || errno == ELOOP) {
+			 * Was it a missing last component ?
+			 * or a missing intermediate component ?
+			 *
+			 * Optimization.
+			 *
+			 * For this code path we can guarantee that
+			 * we have gone through check_parent_exists()
+			 * and it returned NT_STATUS_OK.
+			 *
+			 * Either there was no parent component (".")
+			 * parent_stat_errno == 0 and we have a missing
+			 * last component here.
+			 *
+			 * OR check_parent_exists() called STAT/LSTAT
+			 * and if it failed parent_stat_errno has been
+			 * set telling us if the parent existed or not.
+			 *
+			 * Either way we can avoid another STAT/LSTAT
+			 * system call on the parent here.
+			 */
+			if (parent_stat_errno == ENOTDIR ||
+					parent_stat_errno == ENOENT ||
+					parent_stat_errno == ELOOP) {
 				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
 				goto fail;
-			} else if (errno == ENOENT) {
-				/*
-				 * Was it a missing last component ?
-				 * or a missing intermediate component ?
-				 *
-				 * Optimization.
-				 *
-				 * For this code path we can guarantee that
-				 * we have gone through check_parent_exists()
-				 * and it returned NT_STATUS_OK.
-				 *
-				 * Either there was no parent component (".")
-				 * parent_stat_errno == 0 and we have a missing
-				 * last component here.
-				 *
-				 * OR check_parent_exists() called STAT/LSTAT
-				 * and if it failed parent_stat_errno has been
-				 * set telling us if the parent existed or not.
-				 *
-				 * Either way we can avoid another STAT/LSTAT
-				 * system call on the parent here.
-				 */
-				if (parent_stat_errno == ENOTDIR ||
-						parent_stat_errno == ENOENT ||
-						parent_stat_errno == ELOOP) {
-					status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-					goto fail;
-				}
-
-				/*
-				 * Missing last component is ok - new file.
-				 * Also deal with permission denied elsewhere.
-				 * Just drop out to done.
-				 */
-				goto done;
 			}
+
+			/*
+			 * Missing last component is ok - new file.
+			 * Also deal with permission denied elsewhere.
+			 * Just drop out to done.
+			 */
+			goto done;
 		}
 	}
 
-- 
2.25.1


From e94d2bcbdc6d4899be71b74a2daf39e65474558c Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 13:03:47 -0800
Subject: [PATCH 76/99] CVE-2021-44141: s3: smbd: In unix_convert_step() remove
 all use of 'state->name_was_wildcard'

We know it is never true.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 23 ++---------------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index c8b3f1f5955..c582d24ec6b 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -829,25 +829,6 @@ static NTSTATUS unix_convert_step(struct uc_state *state)
 		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
 	}
 
-	/* The name cannot have a wildcard if it's not
-	   the last component. */
-
-	if (!state->posix_pathnames) {
-		state->name_has_wildcard = ms_has_wild(state->name);
-	}
-
-	/* Wildcards never valid within a pathname. */
-	if (state->name_has_wildcard && state->end != NULL) {
-		return NT_STATUS_OBJECT_NAME_INVALID;
-	}
-
-	/* Skip the stat call if it's a wildcard end. */
-	if (state->name_has_wildcard) {
-		DBG_DEBUG("Wildcard [%s]\n", state->name);
-		state->done = true;
-		return NT_STATUS_OK;
-	}
-
 	status = unix_convert_step_stat(state);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
@@ -880,9 +861,9 @@ static NTSTATUS unix_convert_step(struct uc_state *state)
 
 	/*
 	 * Cache the dirpath thus far. Don't cache a name with mangled
-	 * or wildcard components as this can change the size.
+	 * components as this can change the size.
 	 */
-	if(!state->component_was_mangled && !state->name_has_wildcard) {
+	if(!state->component_was_mangled) {
 		stat_cache_add(state->orig_path,
 			       state->dirpath,
 			       state->smb_fname->twrp,
-- 
2.25.1


From f77e56e2d1baff6f0ff78e10d6bbba49d106edd9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 13:05:55 -0800
Subject: [PATCH 77/99] CVE-2021-44141: s3: smbd: In unix_convert_step_stat()
 remove use of state->name_was_wildcard.

It can never be true.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index c582d24ec6b..8f7da13f034 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -662,8 +662,8 @@ static NTSTATUS unix_convert_step_stat(struct uc_state *state)
 	if (state->posix_pathnames) {
 		/*
 		 * For posix_pathnames, we're done.
-		 * Don't blunder into the name_has_wildcard OR
-		 * get_real_filename() codepaths as they may
+		 * Don't blunder into the
+		 * get_real_filename() codepath as they may
 		 * be doing case insensitive lookups. So when
 		 * creating a new POSIX directory Foo they might
 		 * match on name foo.
@@ -712,10 +712,6 @@ static NTSTATUS unix_convert_step_stat(struct uc_state *state)
 	 * Try to find this part of the path in the directory.
 	 */
 
-	if (state->name_has_wildcard) {
-		return unix_convert_step_search_fail(state);
-	}
-
 	dname = (struct smb_filename) {
 		.base_name = state->dirpath,
 		.twrp = state->smb_fname->twrp,
-- 
2.25.1


From f8698b1f797ddf2c6e418e683e6c68392ad3ef9e Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 3 Dec 2021 13:06:27 -0800
Subject: [PATCH 78/99] CVE-2021-44141: s3: smbd: Remove 'struct uc_state'
 name_has_wildcard element.

It is never set or looked at.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/smbd/filename.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 8f7da13f034..0d82085870c 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -480,7 +480,6 @@ struct uc_state {
 	char *dirpath;
 	char *stream;
 	bool component_was_mangled;
-	bool name_has_wildcard;
 	bool posix_pathnames;
 	bool done;
 };
-- 
2.25.1


From 10242faa0785ca277d584274c151467e78e787bf Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 12:54:47 -0800
Subject: [PATCH 79/99] CVE-2021-44141: s4: torture: Fix
 raw.search:test_one_file() to use torture_result() instead of printf.

I think this test pre-dates torture_result.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source4/torture/raw/search.c | 60 ++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 19 deletions(-)

diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index 14af01bffad..07285893f40 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -316,7 +316,11 @@ static bool test_one_file(struct torture_context *tctx,
 
 	fnum = create_complex_file(cli, tctx, fname);
 	if (fnum == -1) {
-		printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+		torture_result(tctx,
+			TORTURE_FAIL,
+			__location__"ERROR: open of %s failed (%s)\n",
+			fname,
+			smbcli_errstr(cli->tree));
 		ret = false;
 		goto done;
 	}
@@ -343,9 +347,11 @@ static bool test_one_file(struct torture_context *tctx,
 		}
 
 		if (!NT_STATUS_IS_OK(levels[i].status)) {
-			printf("search level %s(%d) failed - %s\n",
-			       levels[i].name, (int)levels[i].level, 
-			       nt_errstr(levels[i].status));
+			torture_result(tctx,
+				TORTURE_FAIL,
+				__location__"search level %s(%d) failed - %s\n",
+				levels[i].name, (int)levels[i].level,
+				nt_errstr(levels[i].status));
 			ret = false;
 			continue;
 		}
@@ -363,7 +369,9 @@ static bool test_one_file(struct torture_context *tctx,
 			expected_status = STATUS_NO_MORE_FILES;
 		}
 		if (!NT_STATUS_EQUAL(status, expected_status)) {
-			printf("search level %s(%d) should fail with %s - %s\n",
+			torture_result(tctx,
+				TORTURE_FAIL,
+				__location__"search level %s(%d) should fail with %s - %s\n",
 			       levels[i].name, (int)levels[i].level, 
 			       nt_errstr(expected_status),
 			       nt_errstr(status));
@@ -400,8 +408,10 @@ static bool test_one_file(struct torture_context *tctx,
 	s = find(name); \
 	if (s) { \
 		if ((s->sname1.field1) != (v.sname2.out.field2)) { \
-			printf("(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
+				__location__, \
 				#sname1, #field1, (int)s->sname1.field1, \
 				#sname2, #field2, (int)v.sname2.out.field2); \
 			ret = false; \
@@ -412,8 +422,10 @@ static bool test_one_file(struct torture_context *tctx,
 	s = find(name); \
 	if (s) { \
 		if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
-			printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s/%s [%s]\n", \
+				__location__, \
 				#sname1, #field1, timestring(tctx, s->sname1.field1), \
 				#sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
 			ret = false; \
@@ -424,8 +436,10 @@ static bool test_one_file(struct torture_context *tctx,
 	s = find(name); \
 	if (s) { \
 		if (s->sname1.field1 != v.sname2.out.field2) { \
-			printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s/%s [%s]\n", \
+				__location__, \
 				#sname1, #field1, nt_time_string(tctx, s->sname1.field1), \
 				#sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
 			ret = false; \
@@ -436,8 +450,10 @@ static bool test_one_file(struct torture_context *tctx,
 	s = find(name); \
 	if (s) { \
 		if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
-			printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s/%s [%s]\n", \
+				__location__, \
 				#sname1, #field1, s->sname1.field1, \
 				#sname2, #field2, v.sname2.out.field2.s); \
 			ret = false; \
@@ -450,8 +466,10 @@ static bool test_one_file(struct torture_context *tctx,
 		if (!s->sname1.field1.s || \
 		    strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \
 		    wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
-			printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s/%s [%s]\n", \
+				__location__, \
 				#sname1, #field1, s->sname1.field1.s, \
 				#sname2, #field2, v.sname2.out.field2.s); \
 			ret = false; \
@@ -464,8 +482,10 @@ static bool test_one_file(struct torture_context *tctx,
 		if (!s->sname1.field1.s || \
 		    strcmp(s->sname1.field1.s, fname) || \
 		    wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
-			printf("(%s) %s/%s [%s] != %s\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s\n", \
+				__location__, \
 				#sname1, #field1, s->sname1.field1.s, \
 				fname); \
 			ret = false; \
@@ -477,8 +497,10 @@ static bool test_one_file(struct torture_context *tctx,
 	if (s) { \
 		if (!s->sname1.field1 || \
 		    strcmp(s->sname1.field1, fname)) { \
-			printf("(%s) %s/%s [%s] != %s\n", \
-			       __location__, \
+			torture_result(tctx,\
+				TORTURE_FAIL,\
+				"(%s) %s/%s [%s] != %s\n", \
+				__location__, \
 				#sname1, #field1, s->sname1.field1, \
 				fname); \
 			ret = false; \
-- 
2.25.1


From 738c7080e78553b9f6eeef778522a1df9a88f977 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 14:18:47 -0800
Subject: [PATCH 80/99] CVE-2021-44141: s4: torture: In
 raw.search:test_one_file() remove the leading '\\' in the test filenames.

We'll soon be using this under SMB1+POSIX and neither Windows or POSIX
need a leading '\\' (and SMB1+POSIX sees the '\\' as part of the name).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source4/torture/raw/search.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index 07285893f40..9b140928689 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -305,8 +305,8 @@ static bool test_one_file(struct torture_context *tctx,
 {
 	bool ret = true;
 	int fnum;
-	const char *fname = "\\torture_search.txt";
-	const char *fname2 = "\\torture_search-NOTEXIST.txt";
+	const char *fname = "torture_search.txt";
+	const char *fname2 = "torture_search-NOTEXIST.txt";
 	NTSTATUS status;
 	int i;
 	union smb_fileinfo all_info, alt_info, name_info, internal_info;
@@ -581,20 +581,20 @@ static bool test_one_file(struct torture_context *tctx,
 		    short_name, alt_info, alt_name_info, fname, STR_UNICODE);
 	}
 
-	CHECK_NAME("STANDARD",            standard,            name, fname+1, 0);
-	CHECK_NAME("EA_SIZE",             ea_size,             name, fname+1, 0);
-	CHECK_NAME("DIRECTORY_INFO",      directory_info,      name, fname+1, STR_TERMINATE_ASCII);
-	CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII);
+	CHECK_NAME("STANDARD",            standard,            name, fname, 0);
+	CHECK_NAME("EA_SIZE",             ea_size,             name, fname, 0);
+	CHECK_NAME("DIRECTORY_INFO",      directory_info,      name, fname, STR_TERMINATE_ASCII);
+	CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname, STR_TERMINATE_ASCII);
 
 	if (name_info_supported) {
-		CHECK_NAME("NAME_INFO", name_info, name, fname+1,
+		CHECK_NAME("NAME_INFO", name_info, name, fname,
 		    STR_TERMINATE_ASCII);
 	}
 
-	CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII);
-	CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           name, fname+1, STR_TERMINATE_ASCII);
-	CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           name, fname+1, STR_TERMINATE_ASCII);
-	CHECK_UNIX_NAME("UNIX_INFO",           unix_info,           name, fname+1, STR_TERMINATE_ASCII);
+	CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname, STR_TERMINATE_ASCII);
+	CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info,           name, fname, STR_TERMINATE_ASCII);
+	CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,           name, fname, STR_TERMINATE_ASCII);
+	CHECK_UNIX_NAME("UNIX_INFO",           unix_info,           name, fname, STR_TERMINATE_ASCII);
 
 	if (internal_info_supported) {
 		CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,
-- 
2.25.1


From 4fc4bd4f20cdfcf1df63f76f2f9940808b286c72 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 18 Nov 2021 11:48:42 -0800
Subject: [PATCH 81/99] CVE-2021-44141: s3: smbd: Tighten up info level checks
 for SMB1+POSIX to make sure POSIX was negotiated first.

Add knownfail file

	knownfail.d/posix_infolevel_fails

for tests that don't currently negotiate
SMB1+POSIX before using SMB1+POSIX calls.

These are:

samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\)
samba3.blackbox.acl_xattr.NT1.nt_affects_posix.*
samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*
samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*
samba3.unix.info2.info2\(nt4_dc_smb1\)
samba3.unix.info2.info2\(ad_dc_smb1\)
samba3.raw.search.one\ file\ search.*

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails |  8 +++
 source3/smbd/trans2.c                      | 60 +++++++++++++++++++---
 2 files changed, 62 insertions(+), 6 deletions(-)
 create mode 100644 selftest/knownfail.d/posix_infolevel_fails

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
new file mode 100644
index 00000000000..78a6781684c
--- /dev/null
+++ b/selftest/knownfail.d/posix_infolevel_fails
@@ -0,0 +1,8 @@
+^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\)
+^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.*
+^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
+^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*
+^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*
+^samba3.unix.info2.info2\(nt4_dc_smb1\)
+^samba3.unix.info2.info2\(ad_dc_smb1\)
+^samba3.raw.search.one\ file\ search.*
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 3ba7011b989..33ba9da9f83 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2717,6 +2717,10 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
 				goto out;
 			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				goto out;
+			}
 			break;
 		default:
 			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
@@ -3183,6 +3187,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
 				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
 				return;
 			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
 			break;
 		default:
 			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
@@ -5144,8 +5152,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 	uint32_t access_mask = 0;
 	size_t len = 0;
 
-	if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
-		return NT_STATUS_INVALID_LEVEL;
+	if (INFO_LEVEL_IS_UNIX(info_level)) {
+		if (!lp_unix_extensions()) {
+			return NT_STATUS_INVALID_LEVEL;
+		}
+		if (!req->posix_pathnames) {
+			return NT_STATUS_INVALID_LEVEL;
+		}
 	}
 
 	DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
@@ -5958,9 +5971,15 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 
 		DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
 
-		if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
-			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-			return;
+		if (INFO_LEVEL_IS_UNIX(info_level)) {
+			if (!lp_unix_extensions()) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
 		}
 
 		/* Initial check for valid fsp ptr. */
@@ -6053,6 +6072,10 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
 				return;
 			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
 		}
 
 		if (req->posix_pathnames) {
@@ -9061,7 +9084,9 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
 		if (!lp_unix_extensions()) {
 			return NT_STATUS_INVALID_LEVEL;
 		}
-
+		if (!req->posix_pathnames) {
+			return NT_STATUS_INVALID_LEVEL;
+		}
 		status = smbd_do_posix_setfilepathinfo(conn,
 						       req,
 						       req,
@@ -9282,6 +9307,17 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 		}
 		info_level = SVAL(params,2);
 
+		if (INFO_LEVEL_IS_UNIX(info_level)) {
+			if (!lp_unix_extensions()) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
+		}
+
 		smb_fname = fsp->fsp_name;
 
 		if (fsp_get_pathref_fd(fsp) == -1) {
@@ -9360,6 +9396,18 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 		}
 
 		info_level = SVAL(params,0);
+
+		if (INFO_LEVEL_IS_UNIX(info_level)) {
+			if (!lp_unix_extensions()) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
+			if (!req->posix_pathnames) {
+				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+				return;
+			}
+		}
+
 		if (req->posix_pathnames) {
 			srvstr_get_path_posix(req,
 				params,
-- 
2.25.1


From c032a254bb5b703f510c42880ea5416982df9577 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Sat, 20 Nov 2021 20:17:11 -0800
Subject: [PATCH 82/99] CVE-2021-44141: s3: smbclient: Give a message if we try
 and use any POSIX command without negotiating POSIX first.

Ensure we only use a POSIX command if POSIX is set up.
Issue the message: Command "posix" must be issued before the "XXXX" command can be used.
After the parameter parsing has been done.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source3/client/client.c | 79 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/source3/client/client.c b/source3/client/client.c
index a8e11044b39..5ad6ee7b844 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -2839,6 +2839,11 @@ static int cmd_posix_open(void)
 		d_printf("posix_open <filename> 0<mode>\n");
 		return 1;
 	}
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"posix_open\" command can be used.\n");
+		return 1;
+	}
 	mode = (mode_t)strtol(buf, (char **)NULL, 8);
 
 	status = cli_resolve_path(ctx, "",
@@ -2900,6 +2905,11 @@ static int cmd_posix_mkdir(void)
 		d_printf("posix_mkdir <filename> 0<mode>\n");
 		return 1;
 	}
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"posix_mkdir\" command can be used.\n");
+		return 1;
+	}
 	mode = (mode_t)strtol(buf, (char **)NULL, 8);
 
 	status = cli_resolve_path(ctx, "",
@@ -2934,6 +2944,11 @@ static int cmd_posix_unlink(void)
 		d_printf("posix_unlink <filename>\n");
 		return 1;
 	}
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"posix_unlink\" command can be used.\n");
+		return 1;
+	}
 	mask = talloc_asprintf(ctx,
 			"%s%s",
 			client_get_cur_dir(),
@@ -2979,6 +2994,11 @@ static int cmd_posix_rmdir(void)
 		d_printf("posix_rmdir <filename>\n");
 		return 1;
 	}
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"posix_rmdir\" command can be used.\n");
+		return 1;
+	}
 	mask = talloc_asprintf(ctx,
 			"%s%s",
 			client_get_cur_dir(),
@@ -3178,6 +3198,12 @@ static int cmd_lock(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"lock\" command can be used.\n");
+		return 1;
+	}
+
 	len = (uint64_t)strtol(buf, (char **)NULL, 16);
 
 	status = cli_posix_lock(cli, fnum, start, len, true, lock_type);
@@ -3214,6 +3240,12 @@ static int cmd_unlock(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"unlock\" command can be used.\n");
+		return 1;
+	}
+
 	len = (uint64_t)strtol(buf, (char **)NULL, 16);
 
 	status = cli_posix_unlock(cli, fnum, start, len);
@@ -3237,6 +3269,12 @@ static int cmd_posix_whoami(void)
 	bool guest = false;
 	uint32_t i;
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			"the \"posix_whoami\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_whoami(cli,
 			ctx,
 			&uid,
@@ -3374,6 +3412,12 @@ static int cmd_link(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"link\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_hardlink(targetcli, targetname, newname);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s linking files (%s -> %s)\n",
@@ -3427,6 +3471,12 @@ static int cmd_readlink(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"readlink\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_readlink(targetcli, name, talloc_tos(), &linkname);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s readlink on file %s\n",
@@ -3466,6 +3516,11 @@ static int cmd_symlink(void)
 	link_target = buf;
 
 	if (SERVER_HAS_UNIX_CIFS(cli)) {
+		if (CLI_DIRSEP_CHAR != '/') {
+			d_printf("Command \"posix\" must be issued before "
+				"the \"symlink\" command can be used.\n");
+			return 1;
+		}
 		newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
 					  buf2);
 		if (!newname) {
@@ -3549,6 +3604,12 @@ static int cmd_chmod(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"chmod\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_chmod(targetcli, targetname, mode);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s chmod file %s 0%o\n",
@@ -3713,6 +3774,12 @@ static int cmd_getfacl(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"getfacl\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_unix_extensions_version(targetcli, &major, &minor,
 					     &caplow, &caphigh);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -4012,6 +4079,12 @@ static int cmd_stat(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"stat\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_stat(targetcli, targetname, &sbuf);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s stat file %s\n",
@@ -4126,6 +4199,12 @@ static int cmd_chown(void)
 		return 1;
 	}
 
+	if (CLI_DIRSEP_CHAR != '/') {
+		d_printf("Command \"posix\" must be issued before "
+			 "the \"chown\" command can be used.\n");
+		return 1;
+	}
+
 	status = cli_posix_chown(targetcli, targetname, uid, gid);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s chown file %s uid=%d, gid=%d\n",
-- 
2.25.1


From bfcf165b29b30dd1f8037ab0f9a9e03731d2642f Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 14:44:05 -0800
Subject: [PATCH 83/99] CVE-2021-44141: s4: torture: In
 raw.search:test_one_file() add a second connection.

Change from torture_suite_add_1smb_test() to torture_suite_add_2smb_test().

Not yet used. We will need this to do SMB1+POSIX search calls on
a connection on which we have negotiated SMB1+POSIX.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source4/torture/raw/search.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index 9b140928689..f6ad569dd4b 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -300,8 +300,9 @@ static union smb_search_data *find(const char *name)
 /* 
    basic testing of all RAW_SEARCH_* calls using a single file
 */
-static bool test_one_file(struct torture_context *tctx, 
-			  struct smbcli_state *cli)
+static bool test_one_file(struct torture_context *tctx,
+			  struct smbcli_state *cli,
+			  struct smbcli_state *cli_unix)
 {
 	bool ret = true;
 	int fnum;
@@ -1571,7 +1572,7 @@ struct torture_suite *torture_raw_search(TALLOC_CTX *mem_ctx)
 {
 	struct torture_suite *suite = torture_suite_create(mem_ctx, "search");
 
-	torture_suite_add_1smb_test(suite, "one file search", test_one_file);
+	torture_suite_add_2smb_test(suite, "one file search", test_one_file);
 	torture_suite_add_1smb_test(suite, "many files", test_many_files);
 	torture_suite_add_1smb_test(suite, "sorted", test_sorted);
 	torture_suite_add_1smb_test(suite, "modify search", test_modify_search);
-- 
2.25.1


From 08c40af638154fa009e6b6f526a357b10ba7e3ba Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 14:48:20 -0800
Subject: [PATCH 84/99] CVE-2021-44141: s4: torture: raw.search: Add
 setup_smb1_posix(). Call it on the second connection in test_one_file().

Not yet used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 source4/torture/raw/search.c | 59 ++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index f6ad569dd4b..3f7de80ad0f 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -297,6 +297,55 @@ static union smb_search_data *find(const char *name)
 	return NULL;
 }
 
+/*
+ * Negotiate SMB1+POSIX.
+ */
+
+static NTSTATUS setup_smb1_posix(struct torture_context *tctx,
+				 struct smbcli_state *cli_unix)
+{
+	struct smb_trans2 tp;
+	uint16_t setup;
+	uint8_t data[12];
+	uint8_t params[4];
+	uint32_t cap = cli_unix->transport->negotiate.capabilities;
+
+	if ((cap & CAP_UNIX) == 0) {
+		/*
+		 * Server doesn't support SMB1+POSIX.
+		 * The caller will skip the UNIX info
+		 * level anyway.
+		 */
+		torture_comment(tctx,
+			"Server doesn't support SMB1+POSIX\n");
+		return NT_STATUS_OK;
+	}
+
+	/* Setup POSIX on this connection. */
+	SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION);
+	SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION);
+	SBVAL(data,4,((uint64_t)(
+		CIFS_UNIX_POSIX_ACLS_CAP|
+		CIFS_UNIX_POSIX_PATHNAMES_CAP|
+		CIFS_UNIX_FCNTL_LOCKS_CAP|
+		CIFS_UNIX_EXTATTR_CAP|
+		CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
+	setup = TRANSACT2_SETFSINFO;
+	tp.in.max_setup = 0;
+	tp.in.flags = 0;
+	tp.in.timeout = 0;
+	tp.in.setup_count = 1;
+	tp.in.max_param = 0;
+	tp.in.max_data = 0;
+	tp.in.setup = &setup;
+	tp.in.trans_name = NULL;
+	SSVAL(params, 0, 0);
+	SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO);
+	tp.in.params = data_blob_talloc(tctx, params, 4);
+	tp.in.data = data_blob_talloc(tctx, data, 12);
+	return smb_raw_trans2(cli_unix->tree, tctx, &tp);
+}
+
 /* 
    basic testing of all RAW_SEARCH_* calls using a single file
 */
@@ -315,6 +364,16 @@ static bool test_one_file(struct torture_context *tctx,
 	    internal_info_supported;
 	union smb_search_data *s;
 
+	status = setup_smb1_posix(tctx, cli_unix);
+	if (!NT_STATUS_IS_OK(status)) {
+		torture_result(tctx,
+			TORTURE_FAIL,
+			__location__"setup_smb1_posix() failed (%s)\n",
+			nt_errstr(status));
+		ret = false;
+		goto done;
+	}
+
 	fnum = create_complex_file(cli, tctx, fname);
 	if (fnum == -1) {
 		torture_result(tctx,
-- 
2.25.1


From a7b6aa7d1f20dfb565605d662404d3988c83e5c8 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 14:51:39 -0800
Subject: [PATCH 85/99] CVE-2021-44141: s4: torture: Fix
 raw.search:test_one_file() by using the SMB1+POSIX connection for POSIX info
 levels.

Remove the following entry in knownfail.d/posix_infolevel_fails.

	^samba3.raw.search.one\ file\ search.*

from knownfail.d/posix_infolevel_fails

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails |  1 -
 source4/torture/raw/search.c               | 13 +++++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
index 78a6781684c..4ce4a9cec91 100644
--- a/selftest/knownfail.d/posix_infolevel_fails
+++ b/selftest/knownfail.d/posix_infolevel_fails
@@ -5,4 +5,3 @@
 ^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*
 ^samba3.unix.info2.info2\(nt4_dc_smb1\)
 ^samba3.unix.info2.info2\(ad_dc_smb1\)
-^samba3.raw.search.one\ file\ search.*
diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index 3f7de80ad0f..575bbd03fb7 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -389,10 +389,19 @@ static bool test_one_file(struct torture_context *tctx,
 	for (i=0;i<ARRAY_SIZE(levels);i++) {
 		NTSTATUS expected_status;
 		uint32_t cap = cli->transport->negotiate.capabilities;
+		struct smbcli_state *cli_search = cli;
 
 		torture_comment(tctx, "Testing %s\n", levels[i].name);
 
-		levels[i].status = torture_single_search(cli, tctx, fname, 
+		if (levels[i].data_level == RAW_SEARCH_DATA_UNIX_INFO) {
+			/*
+			 * For an SMB1+POSIX info level, use the cli_unix
+			 * connection.
+			 */
+			cli_search = cli_unix;
+		}
+
+		levels[i].status = torture_single_search(cli_search, tctx, fname,
 							 levels[i].level,
 							 levels[i].data_level,
 							 0,
@@ -416,7 +425,7 @@ static bool test_one_file(struct torture_context *tctx,
 			continue;
 		}
 
-		status = torture_single_search(cli, tctx, fname2, 
+		status = torture_single_search(cli_search, tctx, fname2,
 					       levels[i].level,
 					       levels[i].data_level,
 					       0,
-- 
2.25.1


From 300abd383ea7fc0b1b8c59d5a8c90201f216dcd6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 12:15:06 -0800
Subject: [PATCH 86/99] CVE-2021-44141: s4: torture: Fix unix.info2 test to
 actually negotiate SMB1+POSIX before using POSIX calls.

Cope with the minor difference in wildcard search return when
we're actually using SMB1+POSIX on the server (SMB1+POSIX treats
all directory search paths as wildcards).

Remove the following entries in knownfail.d/posix_infolevel_fails.

	samba3.unix.info2.info2\(nt4_dc_smb1\)
        samba3.unix.info2.info2\(ad_dc_smb1\)

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails |  2 --
 source4/torture/unix/unix_info2.c          | 42 ++++++++++++++++++++--
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
index 4ce4a9cec91..3bfff110771 100644
--- a/selftest/knownfail.d/posix_infolevel_fails
+++ b/selftest/knownfail.d/posix_infolevel_fails
@@ -3,5 +3,3 @@
 ^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
 ^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*
 ^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*
-^samba3.unix.info2.info2\(nt4_dc_smb1\)
-^samba3.unix.info2.info2\(ad_dc_smb1\)
diff --git a/source4/torture/unix/unix_info2.c b/source4/torture/unix/unix_info2.c
index 6b275435551..2098b225e7f 100644
--- a/source4/torture/unix/unix_info2.c
+++ b/source4/torture/unix/unix_info2.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
 #include "torture/util.h"
 #include "torture/unix/proto.h"
 #include "lib/cmdline/cmdline.h"
@@ -53,6 +54,10 @@ static struct smbcli_state *connect_to_server(struct torture_context *tctx)
 	const char *share = torture_setting_string(tctx, "share", NULL);
 	struct smbcli_options options;
 	struct smbcli_session_options session_options;
+	struct smb_trans2 tp;
+	uint16_t setup;
+	uint8_t data[12];
+	uint8_t params[4];
 
 	lpcfg_smbcli_options(tctx->lp_ctx, &options);
 	lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
@@ -72,6 +77,33 @@ static struct smbcli_state *connect_to_server(struct torture_context *tctx)
 		return NULL;
 	}
 
+	/* Setup POSIX on the server. */
+	SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION);
+	SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION);
+	SBVAL(data,4,((uint64_t)(
+		CIFS_UNIX_POSIX_ACLS_CAP|
+		CIFS_UNIX_POSIX_PATHNAMES_CAP|
+		CIFS_UNIX_FCNTL_LOCKS_CAP|
+		CIFS_UNIX_EXTATTR_CAP|
+		CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
+	setup = TRANSACT2_SETFSINFO;
+	tp.in.max_setup = 0;
+	tp.in.flags = 0;
+	tp.in.timeout = 0;
+	tp.in.setup_count = 1;
+	tp.in.max_param = 0;
+	tp.in.max_data = 0;
+	tp.in.setup = &setup;
+	tp.in.trans_name = NULL;
+	SSVAL(params, 0, 0);
+	SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO);
+	tp.in.params = data_blob_talloc(tctx, params, 4);
+	tp.in.data = data_blob_talloc(tctx, data, 12);
+
+	status = smb_raw_trans2(cli->tree, tctx, &tp);
+	torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+		"doing SMB_SET_CIFS_UNIX_INFO");
+
 	return cli;
 }
 
@@ -245,8 +277,14 @@ static bool find_single_info2(void *mem_ctx,
 
 	torture_assert_int_equal(torture, search.t2ffirst.out.count, 1,
 			"expected exactly one result");
-	torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 1,
-			"expected end_of_search to be true");
+	/*
+	 * In smbd directory listings using POSIX extensions
+	 * always treat the search pathname as a wildcard,
+	 * so don't expect end_of_search to be set here. Wildcard
+	 * searches always need a findnext to end the search.
+	 */
+	torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 0,
+			"expected end_of_search to be false");
 
 	return check_unix_info2(torture, info2);
 }
-- 
2.25.1


From a180e5726d598192e99ac4a26a2a3752bf7ac7c7 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 12:12:36 -0800
Subject: [PATCH 87/99] CVE-2021-44141: s3: tests: Fix the
 samba3.blackbox.inherit_owner test to actually negotiate SMB1+POSIX before
 using POSIX calls.

Remove the following entry in knownfail.d/posix_infolevel_fails.

	samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails | 1 -
 source3/script/tests/test_inherit_owner.sh | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
index 3bfff110771..a865a2055b2 100644
--- a/selftest/knownfail.d/posix_infolevel_fails
+++ b/selftest/knownfail.d/posix_infolevel_fails
@@ -2,4 +2,3 @@
 ^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.*
 ^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
 ^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*
-^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.*
diff --git a/source3/script/tests/test_inherit_owner.sh b/source3/script/tests/test_inherit_owner.sh
index 7e1333787aa..9783235883c 100755
--- a/source3/script/tests/test_inherit_owner.sh
+++ b/source3/script/tests/test_inherit_owner.sh
@@ -79,7 +79,7 @@ unix_owner_id_is() {
     local fname=$2
     local expected_id=$3
     local actual_id
-    actual_id=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null | sed -rn 's/^# owner: (.*)/\1/p')
+    actual_id=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null | sed -rn 's/^# owner: (.*)/\1/p')
     if ! test "x$actual_id" = "x$expected_id" ; then
         echo "Actual uid of $share/$fname is [$actual_id] expected [$expected_id]"
         exit 1
-- 
2.25.1


From c7aa173d2a44b3cf254b3739c7aedc2d5c8c0d58 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 19 Nov 2021 00:05:35 -0800
Subject: [PATCH 88/99] CVE-2021-44141: s3: tests: Fix the
 samba3.blackbox.acl_xattr test to actually negotiate SMB1+POSIX before using
 POSIX calls.

Remove the following entries in knownfail.d/posix_infolevel_fails.

    samba3.blackbox.acl_xattr.NT1.nt_affects_posix.*
    samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
    samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails |  3 ---
 source3/script/tests/test_acl_xattr.sh     | 12 ++++++------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
index a865a2055b2..bf8a884cb16 100644
--- a/selftest/knownfail.d/posix_infolevel_fails
+++ b/selftest/knownfail.d/posix_infolevel_fails
@@ -1,4 +1 @@
 ^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\)
-^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.*
-^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.*
-^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.*
diff --git a/source3/script/tests/test_acl_xattr.sh b/source3/script/tests/test_acl_xattr.sh
index f134ff79c91..8abd7476244 100755
--- a/source3/script/tests/test_acl_xattr.sh
+++ b/source3/script/tests/test_acl_xattr.sh
@@ -55,9 +55,9 @@ nt_affects_posix() {
     local b4
     local af
     local fname="$share.$$"
-    b4=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    b4=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/READ" 2>/dev/null || exit 1
-    af=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    af=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     echo "before: $b4"
     echo "after: $af"
     echo "${b4}" | grep -q "^# owner:" || exit 1
@@ -90,12 +90,12 @@ nt_affects_chown() {
     #basic sanity...
     test "$b4_expected != $af_expected" || exit 1
 
-    b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     echo "${b4_actual}" | grep -q "^# owner:" || exit 1
     b4_actual=$(echo "$b4_actual" | sed -rn 's/^# owner: (.*)/\1/p')
     $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/FULL" || exit 1
     $SMBCACLS //$SERVER/$share $fname -U force_user%$PASSWORD -C force_user 2>/dev/null || exit 1
-    af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     echo "${af_actual}" | grep -q "^# owner:" || exit 1
     af_actual=$(echo "$af_actual" | sed -rn 's/^# owner: (.*)/\1/p')
     echo "before: $b4_actual"
@@ -124,11 +124,11 @@ nt_affects_chgrp() {
     #basic sanity...
     test "$b4_expected" != "$af_expected" || exit 1
 
-    b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     echo "${b4_actual}" | grep -q "^# group:" || exit 1
     b4_actual=$(echo "$b4_actual" | sed -rn 's/^# group: (.*)/\1/p')
     $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -G domadmins 2>/dev/null || exit 1
-    af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1
+    af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1
     echo "${af_actual}" | grep -q "^# group:" || exit 1
     af_actual=$(echo "$af_actual" | sed -rn 's/^# group: (.*)/\1/p')
     echo "before: $b4_actual"
-- 
2.25.1


From 3e0d40f5481f2343fa93e204f2c432e1a2335c98 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 18 Nov 2021 12:16:44 -0800
Subject: [PATCH 89/99] CVE-2021-44141: s3: smbtorture3: Fix
 POSIX-BLOCKING-LOCK to actually negotiate SMB1+POSIX before using POSIX
 calls.

This must be done before doing POSIX calls on a connection.

Remove the final entry in knownfail.d/posix_infolevel_fails

    samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\)

And remove the file knownfail.d/posix_infolevel_fails itself.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_infolevel_fails | 1 -
 source3/torture/torture.c                  | 5 +++++
 2 files changed, 5 insertions(+), 1 deletion(-)
 delete mode 100644 selftest/knownfail.d/posix_infolevel_fails

diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails
deleted file mode 100644
index bf8a884cb16..00000000000
--- a/selftest/knownfail.d/posix_infolevel_fails
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\)
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 0d3b01326b1..e3d26ddb261 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -8929,6 +8929,11 @@ static bool run_posix_blocking_lock(int dummy)
 		return false;
 	}
 
+	status = torture_setup_unix_extensions(cli2);
+	if (!NT_STATUS_IS_OK(status)) {
+		return false;
+	}
+
 	cli_setatr(cli1, fname, 0, 0);
 	cli_posix_unlink(cli1, fname);
 
-- 
2.25.1


From 9e90f31639a71ba4c8099c9da4ad25102a36873b Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 12:28:54 -0800
Subject: [PATCH 90/99] CVE-2021-44141: s3: torture: Add
 samba3.blackbox.test_symlink_traversal.SMB2.

Add to knownfail.d/symlink_traversal

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal        |   1 +
 .../tests/test_symlink_traversal_smb2.sh      | 263 ++++++++++++++++++
 source3/selftest/tests.py                     |   6 +
 3 files changed, 270 insertions(+)
 create mode 100644 selftest/knownfail.d/symlink_traversal
 create mode 100755 source3/script/tests/test_symlink_traversal_smb2.sh

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
new file mode 100644
index 00000000000..a8ac4bbae1f
--- /dev/null
+++ b/selftest/knownfail.d/symlink_traversal
@@ -0,0 +1 @@
+^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
diff --git a/source3/script/tests/test_symlink_traversal_smb2.sh b/source3/script/tests/test_symlink_traversal_smb2.sh
new file mode 100755
index 00000000000..7e1de6dde1a
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb2.sh
@@ -0,0 +1,263 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_symlink_traversal_smb2.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+(
+#subshell.
+cd "$share_test_dir" || return
+rm -f "file_exists"
+rm -f "symlink_noexist"
+rm -f "symlink_file_outside_share"
+rm -f "symlink_file_outside_share_noexist"
+rm -f "symlink_dir_outside_share"
+rm -f "symlink_dir_outside_share_noexist"
+rm -f "symlink_file_outside_share_noperms"
+rm -f "symlink_dir_outside_share_noperms"
+rm -rf "emptydir"
+# Links inside share.
+rm -f "symlink_file_inside_share_noperms"
+rm -f "file_inside_share_noperms"
+rm -f "symlink_dir_inside_share_noperms"
+chmod 755 "dir_inside_share_noperms"
+rm -rf "dir_inside_share_noperms"
+)
+rm -f "$file_outside_share"
+rm -rf "$dir_outside_share"
+rm -f "$file_outside_share_noperms"
+rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+#subshell.
+cd "$share_test_dir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+#
+# Create the identical symlink set underneath "emptydir"
+mkdir "emptydir"
+(
+#subshell
+cd "emptydir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+)
+#
+# Create symlinks to access denied file and directory
+# objects within the share
+touch "file_inside_share_noperms"
+chmod 0 "file_inside_share_noperms"
+ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+mkdir "dir_inside_share_noperms"
+touch "dir_inside_share_noperms/noperm_file_exists"
+chmod 0 "dir_inside_share_noperms"
+ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+    filecmd="$1"
+    filename1="$2"
+    filename2="$3"
+    expected_error="$4"
+    tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+    cat > "$tmpfile" <<EOF
+$filecmd $filename1 $filename2
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=$(eval "$cmd")
+    ret=$?
+    rm -f "$tmpfile"
+
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed accessing local_symlinks with error %s\n" "$ret"
+	return 1
+    fi
+
+    if [ "$expected_error" = "NT_STATUS_OK" ] ; then
+        printf "%s" "$out" | grep -v "NT_STATUS_"
+    else
+        printf "%s" "$out" | grep "$expected_error"
+    fi
+    ret=$?
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed - should get %s doing \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+	return 1
+    fi
+}
+
+#
+# SMB2 tests.
+#
+test_symlink_traversal_SMB2_onename()
+{
+name="$1"
+do_rename="$2"
+#
+# get commands.
+#
+    smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+    smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+#
+# ls commands.
+#
+    smbclient_expect_error "ls" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+
+#
+# del commands.
+# smbclient internally does a cli_list, so we expect similar errors.
+#
+    smbclient_expect_error "del" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "del" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+    if [ "$do_rename" = "do rename" ] ; then
+#
+# rename commands.
+#
+		smbclient_expect_error "rename" "file_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+		smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+		smbclient_expect_error "rename" "file_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+		smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    fi
+    return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB2.
+#
+test_symlink_traversal_SMB2()
+{
+	test_symlink_traversal_SMB2_onename "symlink_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB2_onename "symlink_file_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB2_onename "symlink_dir_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB2_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB2_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+	test_symlink_traversal_SMB2_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+#
+# Test paths within share with no permissions.
+#
+# Can't 'get' file with no perms or a symlink to it.
+	smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+	smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# But can list it and the symlink to it.
+	smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+# Can't 'get' file inside a directory with no perms or a symlink to it.
+	smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+	smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# But can list the directory with no perms and the symlink to it.
+	smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+}
+
+testit "symlink_traversal_SMB2" \
+	test_symlink_traversal_SMB2 || \
+	failed=$((failed+1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 4751e4437aa..68483adbe4b 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -579,6 +579,12 @@ for env in ["fileserver"]:
                   [os.path.join(samba3srcdir, "script/tests/test_delete_veto_files_only_rmdir.sh"),
                   '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/veto', smbclient3])
 
+    plantestsuite("samba3.blackbox.test_symlink_traversal.SMB2", env,
+                  [os.path.join(samba3srcdir, "script/tests/test_symlink_traversal_smb2.sh"),
+                  '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
+                  '$PREFIX', smbclient3])
+
+
     #
     # tar command tests
     #
-- 
2.25.1


From e3f84b2b9f8eda2e5e3192452b698bfce4b7516c Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 12:32:19 -0800
Subject: [PATCH 91/99] CVE-2021-44141: s3: torture: Add
 samba3.blackbox.test_symlink_traversal.SMB1.

Add to knownfail.d/symlink_traversal.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal        |   1 +
 .../tests/test_symlink_traversal_smb1.sh      | 263 ++++++++++++++++++
 source3/selftest/tests.py                     |   4 +
 3 files changed, 268 insertions(+)
 create mode 100755 source3/script/tests/test_symlink_traversal_smb1.sh

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
index a8ac4bbae1f..2a51ff3f91d 100644
--- a/selftest/knownfail.d/symlink_traversal
+++ b/selftest/knownfail.d/symlink_traversal
@@ -1 +1,2 @@
 ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
+^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\)
diff --git a/source3/script/tests/test_symlink_traversal_smb1.sh b/source3/script/tests/test_symlink_traversal_smb1.sh
new file mode 100755
index 00000000000..1deaaccbb54
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb1.sh
@@ -0,0 +1,263 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_symlink_traversal_smb1.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+(
+#subshell.
+cd "$share_test_dir" || return
+rm -f "file_exists"
+rm -f "symlink_noexist"
+rm -f "symlink_file_outside_share"
+rm -f "symlink_file_outside_share_noexist"
+rm -f "symlink_dir_outside_share"
+rm -f "symlink_dir_outside_share_noexist"
+rm -f "symlink_file_outside_share_noperms"
+rm -f "symlink_dir_outside_share_noperms"
+rm -rf "emptydir"
+# Links inside share.
+rm -f "symlink_file_inside_share_noperms"
+rm -f "file_inside_share_noperms"
+rm -f "symlink_dir_inside_share_noperms"
+chmod 755 "dir_inside_share_noperms"
+rm -rf "dir_inside_share_noperms"
+)
+rm -f "$file_outside_share"
+rm -rf "$dir_outside_share"
+rm -f "$file_outside_share_noperms"
+rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+#subshell.
+cd "$share_test_dir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+#
+# Create the identical symlink set underneath "emptydir"
+mkdir "emptydir"
+(
+#subshell
+cd "emptydir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+)
+#
+# Create symlinks to access denied file and directory
+# objects within the share
+touch "file_inside_share_noperms"
+chmod 0 "file_inside_share_noperms"
+ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+mkdir "dir_inside_share_noperms"
+touch "dir_inside_share_noperms/noperm_file_exists"
+chmod 0 "dir_inside_share_noperms"
+ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+    filecmd="$1"
+    filename1="$2"
+    filename2="$3"
+    expected_error="$4"
+    tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+    cat > "$tmpfile" <<EOF
+$filecmd $filename1 $filename2
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=$(eval "$cmd")
+    ret=$?
+    rm -f "$tmpfile"
+
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed accessing local_symlinks with error %s\n" "$ret"
+	return 1
+    fi
+
+    if [ "$expected_error" = "NT_STATUS_OK" ] ; then
+        printf "%s" "$out" | grep -v "NT_STATUS_"
+    else
+        printf "%s" "$out" | grep "$expected_error"
+    fi
+    ret=$?
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed - should get %s doing \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+	return 1
+    fi
+}
+
+#
+# SMB1 tests.
+#
+test_symlink_traversal_SMB1_onename()
+{
+name="$1"
+do_rename="$2"
+#
+# get commands.
+#
+    smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+    smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+#
+# ls commands.
+#
+    smbclient_expect_error "ls" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_NAME_INVALID" || return 1
+
+#
+# del commands.
+# smbclient internally does a cli_list, so we expect similar errors.
+#
+    smbclient_expect_error "del" "$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "del" "emptydir/$name" "" "NT_STATUS_NO_SUCH_FILE" || return 1
+    smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+
+    if [ "$do_rename" = "do rename" ] ; then
+#
+# rename commands.
+#
+		smbclient_expect_error "rename" "file_exists" "$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+		smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+		smbclient_expect_error "rename" "file_exists" "emptydir/$name" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+		smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    fi
+    return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB1.
+#
+test_symlink_traversal_SMB1()
+{
+	test_symlink_traversal_SMB1_onename "symlink_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB1_onename "symlink_file_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB1_onename "symlink_dir_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB1_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB1_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+	test_symlink_traversal_SMB1_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+#
+# Test paths within share with no permissions.
+#
+# Can't 'get' file with no perms or a symlink to it.
+	smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+	smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# But can list it and the symlink to it.
+	smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+# Can't 'get' file inside a directory with no perms or a symlink to it.
+	smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+	smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# But can list the directory with no perms and the symlink to it.
+	smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+}
+
+testit "symlink_traversal_SMB1" \
+	test_symlink_traversal_SMB1 || \
+	failed=$((failed+1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 68483adbe4b..6e2ce4c1148 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -584,6 +584,10 @@ for env in ["fileserver"]:
                   '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
                   '$PREFIX', smbclient3])
 
+    plantestsuite("samba3.blackbox.test_symlink_traversal.SMB1", env + "_smb1_done",
+                  [os.path.join(samba3srcdir, "script/tests/test_symlink_traversal_smb1.sh"),
+                  '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
+                  '$PREFIX', smbclient3])
 
     #
     # tar command tests
-- 
2.25.1


From 700f80d551d85b3141c2cd0abd7be5efb6948a51 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 12:34:38 -0800
Subject: [PATCH 92/99] CVE-2021-44141: s3: torture: Add
 samba3.blackbox.test_symlink_traversal.SMB1.posix

Add to knownfail.d/symlink_traversal.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal        |   1 +
 .../test_symlink_traversal_smb1_posix.sh      | 270 ++++++++++++++++++
 source3/selftest/tests.py                     |   5 +
 3 files changed, 276 insertions(+)
 create mode 100755 source3/script/tests/test_symlink_traversal_smb1_posix.sh

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
index 2a51ff3f91d..25a4da8f250 100644
--- a/selftest/knownfail.d/symlink_traversal
+++ b/selftest/knownfail.d/symlink_traversal
@@ -1,2 +1,3 @@
 ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
 ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\)
+^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\)
diff --git a/source3/script/tests/test_symlink_traversal_smb1_posix.sh b/source3/script/tests/test_symlink_traversal_smb1_posix.sh
new file mode 100755
index 00000000000..6241434dcf6
--- /dev/null
+++ b/source3/script/tests/test_symlink_traversal_smb1_posix.sh
@@ -0,0 +1,270 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_symlink_traversal_smb1_posix.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_traverse_test_file.$$"
+dir_outside_share="/tmp/symlink_traverse_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_traverse_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_traverse_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_traverse_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_traverse_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+(
+#subshell.
+cd "$share_test_dir" || return
+rm -f "file_exists"
+rm -f "symlink_noexist"
+rm -f "symlink_file_outside_share"
+rm -f "symlink_file_outside_share_noexist"
+rm -f "symlink_dir_outside_share"
+rm -f "symlink_dir_outside_share_noexist"
+rm -f "symlink_file_outside_share_noperms"
+rm -f "symlink_dir_outside_share_noperms"
+rm -rf "emptydir"
+# Links inside share.
+rm -f "symlink_file_inside_share_noperms"
+rm -f "file_inside_share_noperms"
+rm -f "symlink_dir_inside_share_noperms"
+chmod 755 "dir_inside_share_noperms"
+rm -rf "dir_inside_share_noperms"
+)
+rm -f "$file_outside_share"
+rm -rf "$dir_outside_share"
+rm -f "$file_outside_share_noperms"
+rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+#subshell.
+cd "$share_test_dir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+#
+# Create the identical symlink set underneath "emptydir"
+mkdir "emptydir"
+(
+#subshell
+cd "emptydir" || return
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+)
+#
+# Create symlinks to access denied file and directory
+# objects within the share
+touch "file_inside_share_noperms"
+chmod 0 "file_inside_share_noperms"
+ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+mkdir "dir_inside_share_noperms"
+touch "dir_inside_share_noperms/noperm_file_exists"
+chmod 0 "dir_inside_share_noperms"
+ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+    filecmd="$1"
+    filename1="$2"
+    filename2="$3"
+    expected_error="$4"
+    tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+    cat > "$tmpfile" <<EOF
+posix
+$filecmd $filename1 $filename2
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=$(eval "$cmd")
+    ret=$?
+    rm -f "$tmpfile"
+
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed accessing local_symlinks with error %s\n" "$ret"
+	return 1
+    fi
+
+    if [ "$expected_error" = "NT_STATUS_OK" ] ; then
+        printf "%s" "$out" | grep -v "NT_STATUS_"
+    else
+        printf "%s" "$out" | grep "$expected_error"
+    fi
+    ret=$?
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed - should get %s doing posix \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+	return 1
+    fi
+}
+
+#
+# SMB1+posix tests.
+#
+test_symlink_traversal_SMB1_posix_onename()
+{
+name="$1"
+do_rename="$2"
+#
+# get commands.
+#
+# Remember in SMB1+POSIX, "*" is a perfectly valid pathname component,
+# and symlinks can be seen, but not necessarily followed.
+#
+    smbclient_expect_error "get" "$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/*" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "get" "emptydir/$name" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    smbclient_expect_error "get" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+#
+# ls commands.
+#
+    smbclient_expect_error "ls" "$name" "" "NT_STATUS_OK" || return 1
+    smbclient_expect_error "ls" "$name/noexist" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+    smbclient_expect_error "ls" "$name/*" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+    smbclient_expect_error "ls" "$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "ls" "emptydir/$name" "" "NT_STATUS_OK" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/noexist" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+    smbclient_expect_error "ls" "emptydir/$name/*/noexist" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+#
+# SMB1+POSIX stat commands. All symlinks can be stat'ed.
+#
+    smbclient_expect_error "stat" "$name" "" "NT_STATUS_OK" || return 1
+    smbclient_expect_error "stat" "emptydir/$name" "" "NT_STATUS_OK" || return 1
+#
+# del commands. Under SMB1+POSIX we can legitimately delete symlinks, so don't
+# try and delete symlink targets, we need them for the later tests.
+#
+    smbclient_expect_error "del" "$name/noexist" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+# Now in subdirectory emptydir
+    smbclient_expect_error "del" "emptydir/$name/noexist" "" "NT_STATUS_NOT_A_DIRECTORY" || return 1
+
+    if [ "$do_rename" = "do rename" ] ; then
+#
+# rename commands. Under SMB1+POSIX we can legitimately rename symlinks, so don't
+# try and rename symlink targets, we need them for the later tests.
+#
+		smbclient_expect_error "rename" "file_exists" "$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# Now in subdirectory emptydir
+		smbclient_expect_error "rename" "file_exists" "emptydir/$name/noexist" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+    fi
+    return 0
+}
+
+#
+# Check error code returns traversing through different
+# kinds of symlinks over SMB1+posix.
+#
+test_symlink_traversal_SMB1_posix()
+{
+	test_symlink_traversal_SMB1_posix_onename "symlink_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB1_posix_onename "symlink_file_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share" "do rename" || return 1
+	test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share_noexist" "no rename" || return 1
+	test_symlink_traversal_SMB1_posix_onename "symlink_file_outside_share_noperms" "do rename" || return 1
+	test_symlink_traversal_SMB1_posix_onename "symlink_dir_outside_share_noperms" "do rename" || return 1
+#
+# Test paths within share with no permissions.
+#
+# Can't 'get' file with no perms.
+	smbclient_expect_error "get" "file_inside_share_noperms" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# In SMB1+POSIX you can't "get" a symlink at all.
+	smbclient_expect_error "get" "symlink_file_inside_share_noperms" "" "NT_STATUS_OBJECT_NAME_NOT_FOUND" || return 1
+# But can list it and the symlink to it.
+	smbclient_expect_error "ls" "file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_file_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+# Can't 'get' file inside a directory with no perms.
+	smbclient_expect_error "get" "dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_ACCESS_DENIED" || return 1
+# In SMB1+POSIX you can't traverse through a symlink that points to a noperm directory.
+	smbclient_expect_error "get" "symlink_dir_inside_share_noperms/noperm_file_exists" "" "NT_STATUS_OBJECT_PATH_NOT_FOUND" || return 1
+# But can list the directory with no perms and the symlink to it.
+	smbclient_expect_error "ls" "dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+	smbclient_expect_error "ls" "symlink_dir_inside_share_noperms" "" "NT_STATUS_OK" || return 1
+}
+
+testit "symlink_traversal_SMB1_posix" \
+	test_symlink_traversal_SMB1_posix || \
+	failed=$((failed+1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 6e2ce4c1148..1746fbf2244 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -589,6 +589,11 @@ for env in ["fileserver"]:
                   '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
                   '$PREFIX', smbclient3])
 
+    plantestsuite("samba3.blackbox.test_symlink_traversal.SMB1.posix", env + "_smb1_done",
+                  [os.path.join(samba3srcdir, "script/tests/test_symlink_traversal_smb1_posix.sh"),
+                  '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
+                  '$PREFIX', smbclient3])
+
     #
     # tar command tests
     #
-- 
2.25.1


From f03c42ea77f4ec6a4a66583bfd1d195bd2ac6731 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 12:56:51 -0800
Subject: [PATCH 93/99] CVE-2021-44141: s3: torture: In test_smbclient_s3,
 change the error codes expected for test_widelinks() and test_nosymlinks()
 from ACCESS_DENIED to NT_STATUS_OBJECT_NAME_NOT_FOUND.

For SMB1/2/3 (minus posix) we need to treat bad symlinks
as though they don't exist.

Add to knwownfail.d/symlink_traversal

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal    |  2 ++
 selftest/target/Samba3.pm                 |  2 +-
 source3/script/tests/test_smbclient_s3.sh | 10 +++++-----
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
index 25a4da8f250..840ab38b0f9 100644
--- a/selftest/knownfail.d/symlink_traversal
+++ b/selftest/knownfail.d/symlink_traversal
@@ -1,3 +1,5 @@
 ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
 ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\)
 ^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\)
+^samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\)
+^samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 84903b87d3e..b901fd2677a 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -2496,7 +2496,7 @@ sub provision($$)
 	create_file_chmod("$widelinks_target", 0666) or return undef;
 
 	##
-	## This link should get ACCESS_DENIED
+	## This link should get an error
 	##
 	symlink "$widelinks_target", "$widelinks_shrdir/source";
 	##
diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh
index 89a17656159..e250d4dd106 100755
--- a/source3/script/tests/test_smbclient_s3.sh
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -1044,12 +1044,12 @@ EOF
 	return 1
     fi
 
-# This should fail with NT_STATUS_ACCESS_DENIED
-    echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+# This should fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+    echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
     ret=$?
     if [ $ret != 0 ] ; then
 	echo "$out"
-	echo "failed - should get NT_STATUS_ACCESS_DENIED listing \\widelinks_share\\source"
+	echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND listing \\widelinks_share\\source"
 	return 1
     fi
 }
@@ -1168,11 +1168,11 @@ EOF
        return 1
     fi
 
-    echo "$out" | grep 'NT_STATUS_ACCESS_DENIED'
+    echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
     ret=$?
     if [ $ret -ne 0 ] ; then
        echo "$out"
-       echo "failed - should get NT_STATUS_ACCESS_DENIED getting \\nosymlinks\\source"
+       echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND getting \\nosymlinks\\source"
        return 1
     fi
 
-- 
2.25.1


From dbeef6bc732f05da5b35274cb0782a914e7392d7 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 17:56:35 -0800
Subject: [PATCH 94/99] CVE-2021-44141: s3: torture: Change expected error
 return for samba3.smbtorture_s3.plain.POSIX.smbtorture.

Trying to open a symlink as a terminal component should return
NT_STATUS_OBJECT_NAME_NOT_FOUND, not NT_STATUS_OBJECT_PATH_NOT_FOUND.

Mark as knownfail.d/simple_posix_open until we fix the server.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/simple_posix_open | 1 +
 source3/torture/torture.c              | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)
 create mode 100644 selftest/knownfail.d/simple_posix_open

diff --git a/selftest/knownfail.d/simple_posix_open b/selftest/knownfail.d/simple_posix_open
new file mode 100644
index 00000000000..5fcbdbdc2c6
--- /dev/null
+++ b/selftest/knownfail.d/simple_posix_open
@@ -0,0 +1 @@
+^samba3.smbtorture_s3.plain.POSIX.smbtorture\(.*\)
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index e3d26ddb261..c5da3836eac 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -7984,9 +7984,9 @@ static bool run_simple_posix_open_test(int dummy)
 		goto out;
 	} else {
 		if (!check_both_error(__LINE__, status, ERRDOS, ERRbadpath,
-				NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+				NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 			printf("POSIX open of %s should have failed "
-				"with NT_STATUS_OBJECT_PATH_NOT_FOUND, "
+				"with NT_STATUS_OBJECT_NAME_NOT_FOUND, "
 				"failed with %s instead.\n",
 				sname, nt_errstr(status));
 			goto out;
-- 
2.25.1


From b97f4a6519f64cbcea2b6baa33d853faf4bc24cb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 11:44:09 -0800
Subject: [PATCH 95/99] CVE-2021-44141: s3: smbd: For SMB1+POSIX clients trying
 to open a symlink, always return NT_STATUS_OBJECT_NAME_NOT_FOUND.

Matches the error return from openat_pathref_fsp().

NT_STATUS_OBJECT_PATH_NOT_FOUND is for a bad component in a path, not
a bad terminal symlink.

Remove knownfail.d/simple_posix_open, we now pass.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/simple_posix_open |  1 -
 source3/smbd/open.c                    | 13 ++++++-------
 2 files changed, 6 insertions(+), 8 deletions(-)
 delete mode 100644 selftest/knownfail.d/simple_posix_open

diff --git a/selftest/knownfail.d/simple_posix_open b/selftest/knownfail.d/simple_posix_open
deleted file mode 100644
index 5fcbdbdc2c6..00000000000
--- a/selftest/knownfail.d/simple_posix_open
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smbtorture_s3.plain.POSIX.smbtorture\(.*\)
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 5ed2c035318..5d2e2a1abf2 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1447,12 +1447,10 @@ static NTSTATUS open_file(files_struct *fsp,
 			 * POSIX client that hit a symlink. We don't want to
 			 * return NT_STATUS_STOPPED_ON_SYMLINK to avoid handling
 			 * this special error code in all callers, so we map
-			 * this to NT_STATUS_OBJECT_PATH_NOT_FOUND. Historically
-			 * the lower level functions returned status code mapped
-			 * from errno by map_nt_error_from_unix() where ELOOP is
-			 * mapped to NT_STATUS_OBJECT_PATH_NOT_FOUND.
+			 * this to NT_STATUS_OBJECT_NAME_NOT_FOUND to match
+			 * openat_pathref_fsp().
 			 */
-			status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 		}
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
@@ -1535,9 +1533,10 @@ static NTSTATUS open_file(files_struct *fsp,
 		{
 			/*
 			 * Don't allow stat opens on symlinks directly unless
-			 * it's a POSIX open.
+			 * it's a POSIX open. Match the return code from
+			 * openat_pathref_fsp().
 			 */
-			return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 		}
 
 		if (!fsp->fsp_flags.is_pathref) {
-- 
2.25.1


From 66774e97e200d686be9c54739dc67ff0ed56af6f Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 14:33:17 -0800
Subject: [PATCH 96/99] CVE-2021-44141: s3: smbd: Inside check_reduced_name()
 ensure we return the correct error codes when failing symlinks.

NT_STATUS_OBJECT_PATH_NOT_FOUND for a path component failure.
NT_STATUS_OBJECT_NAME_NOT_FOUND for a terminal component failure.

Remove:

	samba3.blackbox.test_symlink_traversal.SMB1.posix
	samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\)
	samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\)

in knownfail.d/symlink_traversal as we now pass these. Only one more fix
remaining to get rid of knownfail.d/symlink_traversal completely.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal |  3 ---
 source3/smbd/vfs.c                     | 18 ++++++++++++++++--
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
index 840ab38b0f9..2a51ff3f91d 100644
--- a/selftest/knownfail.d/symlink_traversal
+++ b/selftest/knownfail.d/symlink_traversal
@@ -1,5 +1,2 @@
 ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
 ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\)
-^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\)
-^samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\)
-^samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\)
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index d8b7b1283fb..a6022902c1d 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1146,6 +1146,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
 	bool allow_symlinks = true;
 	const char *conn_rootdir;
 	size_t rootdir_len;
+	bool parent_dir_checked = false;
 
 	DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
 
@@ -1207,6 +1208,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
 		if (resolved_name == NULL) {
 			return NT_STATUS_NO_MEMORY;
 		}
+		parent_dir_checked = true;
 	} else {
 		resolved_name = resolved_fname->base_name;
 	}
@@ -1256,7 +1258,13 @@ NTSTATUS check_reduced_name(connection_struct *conn,
 				conn_rootdir,
 				resolved_name);
 			TALLOC_FREE(resolved_fname);
-			return NT_STATUS_ACCESS_DENIED;
+			if (parent_dir_checked) {
+				/* Part of a component path. */
+				return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			} else {
+				/* End of a path. */
+				return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+			}
 		}
 	}
 
@@ -1311,7 +1319,13 @@ NTSTATUS check_reduced_name(connection_struct *conn,
 				p);
 			TALLOC_FREE(resolved_fname);
 			TALLOC_FREE(new_fname);
-			return NT_STATUS_ACCESS_DENIED;
+			if (parent_dir_checked) {
+				/* Part of a component path. */
+				return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			} else {
+				/* End of a path. */
+				return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+			}
 		}
 	}
 
-- 
2.25.1


From 9371ace08e603c745be14d6131b7a7713b36e782 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 14:39:42 -0800
Subject: [PATCH 97/99] CVE-2021-44141: s3: smbd: Fix a subtle bug in the error
 returns from filename_convert().

If filename_convert() fails to convert the path, we never call
check_name(). This means we can return an incorrect error code
(NT_STATUS_ACCESS_DENIED) if we ran into a symlink that points
outside the share to a non-readable directory. We need to make
sure in this case we always call check_name().

Remove knownfail.d/symlink_traversal.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/symlink_traversal |  2 --
 source3/smbd/filename.c                | 36 ++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/symlink_traversal

diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal
deleted file mode 100644
index 2a51ff3f91d..00000000000
--- a/selftest/knownfail.d/symlink_traversal
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\)
-^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\)
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 0d82085870c..56ebdd9f370 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -30,6 +30,9 @@
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 
+static NTSTATUS check_name(connection_struct *conn,
+			   const struct smb_filename *smb_fname);
+
 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
 {
 	uint32_t ucf_flags = 0;
@@ -529,6 +532,39 @@ static NTSTATUS unix_convert_step_search_fail(struct uc_state *state)
 
 	if (errno == EACCES) {
 		if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
+			/*
+			 * Could be a symlink pointing to
+			 * a directory outside the share
+			 * to which we don't have access.
+			 * If so, we need to know that here
+			 * so we can return the correct error code.
+			 * check_name() is never called if we
+			 * error out of filename_convert().
+			 */
+			int ret;
+			NTSTATUS status;
+			struct smb_filename dname = (struct smb_filename) {
+					.base_name = state->dirpath,
+					.twrp = state->smb_fname->twrp,
+			};
+
+			/* handle null paths */
+			if ((dname.base_name == NULL) ||
+					(dname.base_name[0] == '\0')) {
+				return NT_STATUS_ACCESS_DENIED;
+			}
+			ret = SMB_VFS_LSTAT(state->conn, &dname);
+			if (ret != 0) {
+				return NT_STATUS_ACCESS_DENIED;
+			}
+			if (!S_ISLNK(dname.st.st_ex_mode)) {
+				return NT_STATUS_ACCESS_DENIED;
+			}
+			status = check_name(state->conn, &dname);
+			if (!NT_STATUS_IS_OK(status)) {
+				/* We know this is an intermediate path. */
+				return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			}
 			return NT_STATUS_ACCESS_DENIED;
 		} else {
 			/*
-- 
2.25.1


From d46ffccc0780b9ef6b5a49e3e17b665345bd4362 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 22:15:46 -0800
Subject: [PATCH 98/99] CVE-2021-44141: s3: torture: Add a test
 samba3.blackbox.test_symlink_rename.SMB1.posix that shows we still leak
 target info across a SMB1+POSIX rename.

Add a knownfail.d/posix_sylink_rename

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_sylink_rename      |   1 +
 .../tests/test_symlink_rename_smb1_posix.sh   | 186 ++++++++++++++++++
 source3/selftest/tests.py                     |   5 +
 3 files changed, 192 insertions(+)
 create mode 100644 selftest/knownfail.d/posix_sylink_rename
 create mode 100755 source3/script/tests/test_symlink_rename_smb1_posix.sh

diff --git a/selftest/knownfail.d/posix_sylink_rename b/selftest/knownfail.d/posix_sylink_rename
new file mode 100644
index 00000000000..9c3cc0a41ba
--- /dev/null
+++ b/selftest/knownfail.d/posix_sylink_rename
@@ -0,0 +1 @@
+^samba3.blackbox.test_symlink_rename.SMB1.posix.symlink_rename_SMB1_posix\(fileserver_smb1_done\)
diff --git a/source3/script/tests/test_symlink_rename_smb1_posix.sh b/source3/script/tests/test_symlink_rename_smb1_posix.sh
new file mode 100755
index 00000000000..7d2e0037b8d
--- /dev/null
+++ b/source3/script/tests/test_symlink_rename_smb1_posix.sh
@@ -0,0 +1,186 @@
+#!/bin/sh
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_symlink_rename_smb1_posix.sh SERVER SERVER_IP USERNAME PASSWORD LOCAL_PATH PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER="${1}"
+SERVER_IP="${2}"
+USERNAME="${3}"
+PASSWORD="${4}"
+LOCAL_PATH="${5}"
+PREFIX="${6}"
+SMBCLIENT="${7}"
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+shift 6
+
+incdir=$(dirname "$0")/../../../testprogs/blackbox
+. "$incdir"/subunit.sh
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+
+# Define the test environment/filenames.
+#
+share_test_dir="$LOCAL_PATH"
+#
+# These files/directories will be created.
+#
+file_outside_share="/tmp/symlink_rename_test_file.$$"
+dir_outside_share="/tmp/symlink_rename_test_dir.$$"
+file_outside_share_noperms="/tmp/symlink_rename_test_file_noperm.$$"
+dir_outside_share_noperms="/tmp/symlink_rename_test_dir_noperm.$$"
+#
+# These two objects do not exist.
+#
+file_outside_share_noexist="/tmp/symlink_rename_test_noexist.$$"
+dir_outside_share_noexist="/tmp/symlink_rename_test_dir_noexist.$$"
+
+#
+# Cleanup function.
+#
+do_cleanup()
+{
+(
+#subshell.
+cd "$share_test_dir" || return
+rm -f "file_exists"
+rm -f "symlink_noexist"
+rm -f "symlink_file_outside_share"
+rm -f "symlink_file_outside_share_noexist"
+rm -f "symlink_dir_outside_share"
+rm -f "symlink_dir_outside_share_noexist"
+rm -f "symlink_file_outside_share_noperms"
+rm -f "symlink_dir_outside_share_noperms"
+# Links inside share.
+rm -f "symlink_file_inside_share_noperms"
+rm -f "file_inside_share_noperms"
+rm -f "symlink_dir_inside_share_noperms"
+chmod 755 "dir_inside_share_noperms"
+rm -rf "dir_inside_share_noperms"
+)
+rm -f "$file_outside_share"
+rm -rf "$dir_outside_share"
+rm -f "$file_outside_share_noperms"
+rm -rf "$dir_outside_share_noperms"
+}
+
+#
+# Ensure we start from a clean slate.
+#
+do_cleanup
+
+#
+# Create the test files/directories/symlinks.
+#
+# File/directory explicitly outside share.
+touch "$file_outside_share"
+mkdir "$dir_outside_share"
+# File/directory explicitly outside share with permission denied.
+touch "$file_outside_share_noperms"
+chmod 0 "$file_outside_share_noperms"
+mkdir "$dir_outside_share_noperms"
+chmod 0 "$dir_outside_share_noperms"
+#
+# Create links to these objects inside the share definition.
+(
+#subshell.
+cd "$share_test_dir" || return
+# Source file for all renames. None of these should succeed.
+touch "file_exists"
+ln -s "noexist" "symlink_noexist"
+ln -s "$file_outside_share" "symlink_file_outside_share"
+ln -s "$file_outside_share_noexist" "symlink_file_outside_share_noexist"
+ln -s "$dir_outside_share" "symlink_dir_outside_share"
+ln -s "$dir_outside_share_noexist" "symlink_dir_outside_share_noexist"
+ln -s "$file_outside_share_noperms" "symlink_file_outside_share_noperms"
+ln -s "$dir_outside_share_noperms" "symlink_dir_outside_share_noperms"
+#
+# Create symlinks to access denied file and directory
+# objects within the share
+touch "file_inside_share_noperms"
+chmod 0 "file_inside_share_noperms"
+ln -s "file_inside_share_noperms" "symlink_file_inside_share_noperms"
+mkdir "dir_inside_share_noperms"
+touch "dir_inside_share_noperms/noperm_file_exists"
+chmod 0 "dir_inside_share_noperms"
+ln -s "dir_inside_share_noperms" "symlink_dir_inside_share_noperms"
+)
+
+#
+# smbclient function given command, path, expected error, and posix.
+#
+smbclient_expect_error()
+{
+    filecmd="$1"
+    filename1="$2"
+    filename2="$3"
+    expected_error="$4"
+    tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+    cat > "$tmpfile" <<EOF
+posix
+$filecmd $filename1 $filename2
+quit
+EOF
+    cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/local_symlinks -I$SERVER_IP -mNT1 < $tmpfile 2>&1'
+    eval echo "$cmd"
+    out=$(eval "$cmd")
+    ret=$?
+    rm -f "$tmpfile"
+
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed accessing local_symlinks with error %s\n" "$ret"
+	return 1
+    fi
+
+    if [ "$expected_error" = "NT_STATUS_OK" ] ; then
+        printf "%s" "$out" | grep -v "NT_STATUS_"
+    else
+        printf "%s" "$out" | grep "$expected_error"
+    fi
+    ret=$?
+    if [ $ret != 0 ] ; then
+	printf "%s\n" "$out"
+	printf "failed - should get %s doing posix \"%s %s %s\"\n" "$expected_error" "$filecmd" "$filename1" "$filename2"
+	return 1
+    fi
+}
+
+#
+# SMB1+posix tests.
+#
+test_symlink_rename_SMB1_posix()
+{
+#
+# rename commands.
+# As all the targets exist as symlinks, these should all fail.
+#
+    smbclient_expect_error "rename" "file_exists" "symlink_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share_noexist" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_file_outside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_dir_outside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_file_inside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    smbclient_expect_error "rename" "file_exists" "symlink_dir_inside_share_noperms" "NT_STATUS_OBJECT_NAME_COLLISION" || return 1
+    return 0
+}
+
+testit "symlink_rename_SMB1_posix" \
+	test_symlink_rename_SMB1_posix || \
+	failed=$((failed+1))
+
+#
+# Cleanup.
+do_cleanup
+
+testok "$0" "$failed"
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 1746fbf2244..701be011f70 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -594,6 +594,11 @@ for env in ["fileserver"]:
                   '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
                   '$PREFIX', smbclient3])
 
+    plantestsuite("samba3.blackbox.test_symlink_rename.SMB1.posix", env + "_smb1_done",
+                  [os.path.join(samba3srcdir, "script/tests/test_symlink_rename_smb1_posix.sh"),
+                  '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/local_symlinks',
+                  '$PREFIX', smbclient3])
+
     #
     # tar command tests
     #
-- 
2.25.1


From e7d0d40e684702d7fcbb781e0f6c072be86a1386 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Dec 2021 22:19:29 -0800
Subject: [PATCH 99/99] CVE-2021-44141: s3: smbd: Inside
 rename_internals_fsp(), we must use vfs_stat() for existence, not
 SMB_VFS_STAT().

We need to take SMB1+POSIX into account here and do an LSTAT if it's
a POSIX name.

Remove knownfail.d/posix_sylink_rename

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911

Signed-off-by: Jeremy Allison <jra@samba.org>
---
 selftest/knownfail.d/posix_sylink_rename | 1 -
 source3/smbd/reply.c                     | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/posix_sylink_rename

diff --git a/selftest/knownfail.d/posix_sylink_rename b/selftest/knownfail.d/posix_sylink_rename
deleted file mode 100644
index 9c3cc0a41ba..00000000000
--- a/selftest/knownfail.d/posix_sylink_rename
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.blackbox.test_symlink_rename.SMB1.posix.symlink_rename_SMB1_posix\(fileserver_smb1_done\)
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index cc95bfa3af0..69278a1da87 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7266,7 +7266,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 		goto out;
 	}
 
-	dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
+	dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
 
 	if(!replace_if_exists && dst_exists) {
 		DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
-- 
2.25.1

