]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
Convert samba4.base.mangle test to smb2
authorDavid Mulder <dmulder@suse.com>
Mon, 23 Dec 2019 20:58:47 +0000 (13:58 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 28 Apr 2020 18:09:39 +0000 (18:09 +0000)
Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Noel Power <noel.power@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit 9437b44668c9f7742d6d4fe0891ac4d9fda7c804)

selftest/skip
selftest/todo_smb2_tests_to_port.list
source3/selftest/tests.py
source4/torture/smb2/mangle.c [new file with mode: 0644]
source4/torture/smb2/smb2.c
source4/torture/smb2/wscript_build

index f54a23c9235b6777c2bd2e59ebfa19b8b0041737..440c7cea6b7df8e0752ab83315abcbec93a06149 100644 (file)
@@ -158,3 +158,4 @@ bench # don't run benchmarks in our selftest
 ^samba4.blackbox.ktpass # this test isn't portable ...
 ^samba4.rpc.unixinfo # This contains a server-side getpwuid call which hangs the server when nss_winbindd is in use
 ^samba.tests.dcerpc.unix  # This contains a server-side getpwuid call which hangs the server when nss_winbindd is in use
+^samba4.smb2.mangle.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test
index 819ff69e677faf4118cb01ac445f9a01fbd5376c..595329ed7bb48da04371559cd2333d24b7f1e5f4 100644 (file)
@@ -35,8 +35,6 @@ samba3.base.disconnect(nt4_dc_smb1)
 samba3.base.fdpass(ad_dc_smb1)
 samba3.base.fdpass(nt4_dc_smb1)
 samba3.base.lock(nt4_dc_smb1)
-samba3.base.mangle(ad_dc_smb1)
-samba3.base.mangle(nt4_dc_smb1)
 samba3.base.negnowait(ad_dc_smb1)
 samba3.base.negnowait(nt4_dc_smb1)
 samba3.base.ntdeny1(ad_dc_smb1)
index 03ffc9951140a2eb73bc4b401e791c8780852c55..d36ee6c6ebb2050dd53937db68b1632ae7781542 100755 (executable)
@@ -826,6 +826,9 @@ for t in tests:
                   "raw.write",]) :
         plansmbtorture4testsuite(t, "nt4_dc_smb1", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc_smb1", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
+    elif t == "base.mangle":
+        plansmbtorture4testsuite(t, "nt4_dc_smb1_done", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+        plansmbtorture4testsuite(t, "ad_dc_smb1_done", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
     else:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
diff --git a/source4/torture/smb2/mangle.c b/source4/torture/smb2/mangle.c
new file mode 100644 (file)
index 0000000..f489f25
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+   Unix SMB/CIFS implementation.
+   SMB torture tester - mangling test
+   Copyright (C) Andrew Tridgell 2002
+   Copyright (C) David Mulder 2019
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include <tdb.h>
+#include "../lib/util/util_tdb.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+static TDB_CONTEXT *tdb;
+
+#define NAME_LENGTH 20
+
+static unsigned int total, collisions, failures;
+
+static bool test_one(struct torture_context *tctx, struct smb2_tree *tree,
+                    const char *name)
+{
+       struct smb2_handle fnum;
+       const char *shortname;
+       const char *name2;
+       NTSTATUS status;
+       TDB_DATA data;
+       struct smb2_create io = {0};
+
+       total++;
+
+       io.in.fname = name;
+       io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA |
+                              SEC_FILE_EXECUTE;
+       io.in.create_disposition = NTCREATEX_DISP_CREATE;
+       io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+                            NTCREATEX_SHARE_ACCESS_WRITE |
+                            NTCREATEX_SHARE_ACCESS_DELETE;
+       io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+       status = smb2_create(tree, tree, &io);
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "open of %s failed (%s)\n", name,
+                               nt_errstr(status));
+               return false;
+       }
+       fnum = io.out.file.handle;
+
+       status = smb2_util_close(tree, fnum);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_comment(tctx, "close of %s failed (%s)\n", name,
+                               nt_errstr(status));
+               return false;
+       }
+
+       /* get the short name */
+       status = smb2_qpathinfo_alt_name(tctx, tree, name, &shortname);
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "query altname of %s failed (%s)\n",
+                               name, nt_errstr(status));
+               return false;
+       }
+
+       name2 = talloc_asprintf(tctx, "mangle_test\\%s", shortname);
+       status = smb2_util_unlink(tree, name2);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_comment(tctx, "unlink of %s  (%s) failed (%s)\n",
+                      name2, name, nt_errstr(status));
+               return false;
+       }
+
+       /* recreate by short name */
+       io = (struct smb2_create){0};
+       io.in.fname = name2;
+       io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA |
+                              SEC_FILE_EXECUTE;
+       io.in.create_disposition = NTCREATEX_DISP_CREATE;
+       io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+                            NTCREATEX_SHARE_ACCESS_WRITE |
+                            NTCREATEX_SHARE_ACCESS_DELETE;
+       io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+       status = smb2_create(tree, tree, &io);
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "open2 of %s failed (%s)\n", name2,
+                               nt_errstr(status));
+               return false;
+       }
+       fnum = io.out.file.handle;
+
+       status = smb2_util_close(tree, fnum);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_comment(tctx, "close of %s failed (%s)\n", name,
+                               nt_errstr(status));
+               return false;
+       }
+
+       /* and unlink by long name */
+       status = smb2_util_unlink(tree, name);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_comment(tctx, "unlink2 of %s  (%s) failed (%s)\n",
+                               name, name2, nt_errstr(status));
+               failures++;
+               smb2_util_unlink(tree, name2);
+               return true;
+       }
+
+       /* see if the short name is already in the tdb */
+       data = tdb_fetch_bystring(tdb, shortname);
+       if (data.dptr) {
+               /* maybe its a duplicate long name? */
+               if (strcasecmp(name, (const char *)data.dptr) != 0) {
+                       /* we have a collision */
+                       collisions++;
+                       torture_comment(tctx, "Collision between %s and %s"
+                                       "   ->  %s  (coll/tot: %u/%u)\n",
+                                       name, data.dptr, shortname, collisions,
+                                       total);
+               }
+               free(data.dptr);
+       } else {
+               TDB_DATA namedata;
+               /* store it for later */
+               namedata.dptr = discard_const_p(uint8_t, name);
+               namedata.dsize = strlen(name)+1;
+               tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
+       }
+
+       return true;
+}
+
+
+static char *gen_name(struct torture_context *tctx)
+{
+       const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~...";
+       unsigned int max_idx = strlen(chars);
+       unsigned int len;
+       int i;
+       char *p = NULL;
+       char *name = NULL;
+
+       name = talloc_strdup(tctx, "mangle_test\\");
+       if (!name) {
+               return NULL;
+       }
+
+       len = 1 + random() % NAME_LENGTH;
+
+       name = talloc_realloc(tctx, name, char, strlen(name) + len + 6);
+       if (!name) {
+               return NULL;
+       }
+       p = name + strlen(name);
+
+       for (i=0;i<len;i++) {
+               p[i] = chars[random() % max_idx];
+       }
+
+       p[i] = 0;
+
+       if (ISDOT(p) || ISDOTDOT(p)) {
+               p[0] = '_';
+       }
+
+       /* have a high probability of a common lead char */
+       if (random() % 2 == 0) {
+               p[0] = 'A';
+       }
+
+       /* and a medium probability of a common lead string */
+       if ((len > 5) && (random() % 10 == 0)) {
+               strlcpy(p, "ABCDE", 6);
+       }
+
+       /* and a high probability of a good extension length */
+       if (random() % 2 == 0) {
+               char *s = strrchr(p, '.');
+               if (s) {
+                       s[4] = 0;
+               }
+       }
+
+       return name;
+}
+
+
+bool torture_smb2_mangle(struct torture_context *torture,
+                        struct smb2_tree *tree)
+{
+       extern int torture_numops;
+       int i;
+       bool ok;
+       NTSTATUS status;
+
+       /* we will use an internal tdb to store the names we have used */
+       tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
+       torture_assert(torture, tdb, "ERROR: Failed to open tdb\n");
+
+       ok = smb2_util_setup_dir(torture, tree, "mangle_test");
+       torture_assert(torture, ok, "smb2_util_setup_dir failed\n");
+
+       for (i=0;i<torture_numops;i++) {
+               char *name;
+
+               name = gen_name(torture);
+               torture_assert(torture, name, "Name allocation failed\n");
+
+               ok = test_one(torture, tree, name);
+               torture_assert(torture, ok, talloc_asprintf(torture,
+                              "Mangle names failed with %s", name));
+               if (total && total % 100 == 0) {
+                       if (torture_setting_bool(torture, "progress", true)) {
+                               torture_comment(torture,
+                                      "collisions %u/%u  - %.2f%%   (%u failures)\r",
+                                      collisions, total, (100.0*collisions) / total, failures);
+                       }
+               }
+       }
+
+       smb2_util_unlink(tree, "mangle_test\\*");
+       status = smb2_util_rmdir(tree, "mangle_test");
+       torture_assert_ntstatus_ok(torture, status,
+                                  "ERROR: Failed to remove directory\n");
+
+       torture_comment(torture,
+                       "\nTotal collisions %u/%u  - %.2f%%   (%u failures)\n",
+                       collisions, total, (100.0*collisions) / total, failures);
+
+       return (failures == 0);
+}
index 26eca9f364a45c4e61f1dfc1344fe9c086c74038..85bced0bb3ca42207dc1144e49b95126f2325763 100644 (file)
@@ -204,6 +204,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
        torture_suite_add_1smb2_test(suite, "sdread", torture_smb2_sdreadtest);
        torture_suite_add_suite(suite, torture_smb2_readwrite_init(suite));
        torture_suite_add_1smb2_test(suite, "maximum_allowed", torture_smb2_maximum_allowed);
+       torture_suite_add_1smb2_test(suite, "mangle", torture_smb2_mangle);
 
        torture_suite_add_suite(suite, torture_smb2_charset(suite));
        suite->description = talloc_strdup(suite, "SMB2-specific tests");
index 55c7a3bc0b4e0c3ad1f8ab72cd21ffb2b5f91821..14d1ce151bc1a2255907f0ec69bdbfaeeb6eb8fe 100644 (file)
@@ -21,6 +21,7 @@ bld.SAMBA_MODULE('TORTURE_SMB2',
         lease_break_handler.c
         lock.c
         max_allowed.c
+        mangle.c
         maxfid.c
         maxwrite.c
         multichannel.c