The branch, master has been updated
       via  3355601fe85 s3/4: libsmbclient test. Test using 
smbc_telldir/smbc_lseekdir with smbc_readdir/smbc_readdirplus/smbc_getdents.
       via  0d9b1645499 s3: libsmbclient: Fix smbc_lseekdir() to work with 
smbc_readdirplus().
       via  754cec7756b s3: libsmbclient: Ensure SMBC_getdents_ctx() also 
updates the readdirplus pointers.
       via  3d82b7d11cd s3: libsmbclient: Ensure SMBC_readdirplus_ctx() also 
updates the readdir pointers.
       via  4bca8e097f5 s3: libsmbclient: Ensure SMBC_readdir_ctx() also 
updates the readdirplus pointers.
      from  efd4832c2cf CVE-2019-10197: smbd: split 
change_to_user_impersonate() out of change_to_user_internal()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 3355601fe8541994cc41f5ed800aab9b6a2294f4
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Aug 26 11:22:35 2019 -0700

    s3/4: libsmbclient test. Test using smbc_telldir/smbc_lseekdir with 
smbc_readdir/smbc_readdirplus/smbc_getdents.
    
    Ensure that for file access you can mix any of these
    three access methods for directory entries and the
    returned names/structs stay in sync across telldir/seekdir
    changes.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Ralph Böhme <s...@samba.org>
    
    Autobuild-User(master): Jeremy Allison <j...@samba.org>
    Autobuild-Date(master): Tue Sep  3 17:31:29 UTC 2019 on sn-devel-184

commit 0d9b1645499ce12a79a137d3482434aa5d2eb47c
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Aug 26 10:18:28 2019 -0700

    s3: libsmbclient: Fix smbc_lseekdir() to work with smbc_readdirplus().
    
    If returning files the dir_list and the dirplus_list have exactly the same
    entries, we just need to keep the next pointers in sync on seek.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Ralph Böhme <s...@samba.org>

commit 754cec7756b2ddb1cfcc3984265f01cb366beb76
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Aug 26 10:07:32 2019 -0700

    s3: libsmbclient: Ensure SMBC_getdents_ctx() also updates the readdirplus 
pointers.
    
    If we are returning file entries, we
    have a duplicate list in dirplus.
    
    Update dirplus_next also so readdir and
    readdirplus are kept in sync.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Ralph Böhme <s...@samba.org>

commit 3d82b7d11cd7b78adc6b3642e64e3a8f251de869
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Aug 26 10:02:47 2019 -0700

    s3: libsmbclient: Ensure SMBC_readdirplus_ctx() also updates the readdir 
pointers.
    
    If we are returning file entries, we
    have a duplicate list in dir_list.
    
    Update dir_next also so readdir and
    readdirplus are kept in sync.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Ralph Böhme <s...@samba.org>

commit 4bca8e097f5a909c628daa4dbfa932ddc1725ebc
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Aug 26 09:54:06 2019 -0700

    s3: libsmbclient: Ensure SMBC_readdir_ctx() also updates the readdirplus 
pointers.
    
    If we are returning file entries, we
    have a duplicate list in dirplus.
    
    Update dirplus_next also so readdir and
    readdirplus are kept in sync.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Ralph Böhme <s...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/libsmb/libsmb_dir.c                 | 102 ++++++---
 source3/selftest/tests.py                   |   3 +-
 source4/torture/libsmbclient/libsmbclient.c | 340 ++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+), 27 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index 886aa626509..df606c4adfe 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -1174,6 +1174,17 @@ SMBC_readdir_ctx(SMBCCTX *context,
 
         dir->dir_next = dir->dir_next->next;
 
+       /*
+        * If we are returning file entries, we
+        * have a duplicate list in dirplus.
+        *
+        * Update dirplus_next also so readdir and
+        * readdirplus are kept in sync.
+        */
+       if (dir->dirplus_list != NULL) {
+               dir->dirplus_next = dir->dirplus_next->next;
+       }
+
        TALLOC_FREE(frame);
         return dirp;
 }
@@ -1220,6 +1231,17 @@ SMBC_readdirplus_ctx(SMBCCTX *context,
        }
        dir->dirplus_next = dir->dirplus_next->next;
 
+       /*
+        * If we are returning file entries, we
+        * have a duplicate list in dir_list
+        *
+        * Update dir_next also so readdir and
+        * readdirplus are kept in sync.
+        */
+       if (dir->dir_list) {
+               dir->dir_next = dir->dir_next->next;
+       }
+
        TALLOC_FREE(frame);
        return smb_finfo;
 }
@@ -1336,6 +1358,17 @@ SMBC_getdents_ctx(SMBCCTX *context,
                }
 
                dir->dir_next = dirlist = dirlist -> next;
+
+               /*
+                * If we are returning file entries, we
+                * have a duplicate list in dirplus.
+                *
+                * Update dirplus_next also so readdir and
+                * readdirplus are kept in sync.
+                */
+               if (dir->dirplus_list != NULL) {
+                       dir->dirplus_next = dir->dirplus_next->next;
+               }
        }
 
        TALLOC_FREE(frame);
@@ -1639,35 +1672,43 @@ SMBC_telldir_ctx(SMBCCTX *context,
 
 /*
  * A routine to run down the list and see if the entry is OK
+ * Modifies the dir list and the dirplus list (if it exists)
+ * to point at the correct next entry on success.
  */
 
-static struct smbc_dir_list *
-check_dir_ent(struct smbc_dir_list *list,
-              struct smbc_dirent *dirent)
+static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
 {
+       struct smbc_dir_list *tmp_dir = dir->dir_list;
+       struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
 
-       /* Run down the list looking for what we want */
-
-       if (dirent) {
-
-               struct smbc_dir_list *tmp = list;
-
-               while (tmp) {
-
-                       if (tmp->dirent == dirent)
-                               return tmp;
-
-                       tmp = tmp->next;
+       /*
+        * Run down the list looking for what we want.
+        * If we're enumerating files both dir_list
+        * and dirplus_list contain the same entry
+        * list, as they were seeded from the same
+        * cli_list callback.
+        *
+        * If we're enumerating servers then
+        * dirplus_list will be NULL, so don't
+        * update in that case.
+        */
 
+       while (tmp_dir != NULL) {
+               if (tmp_dir->dirent == dirent) {
+                       dir->dir_next = tmp_dir;
+                       if (tmp_dirplus != NULL) {
+                               dir->dirplus_next = tmp_dirplus;
+                       }
+                       return true;
+               }
+               tmp_dir = tmp_dir->next;
+               if (tmp_dirplus != NULL) {
+                       tmp_dirplus = tmp_dirplus->next;
                }
-
        }
-
-       return NULL;  /* Not found, or an error */
-
+       return false;
 }
 
-
 /*
  * Routine to seek on a directory
  */
@@ -1679,8 +1720,8 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
 {
        long int l_offset = offset;  /* Handle problems of size */
        struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
-       struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
        TALLOC_CTX *frame = talloc_stackframe();
+       bool ok;
 
        if (!context || !context->internal->initialized) {
 
@@ -1703,6 +1744,10 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
        if (dirent == NULL) {  /* Seek to the begining of the list */
 
                dir->dir_next = dir->dir_list;
+
+               /* Do the same for dirplus. */
+               dir->dirplus_next = dir->dirplus_list;
+
                TALLOC_FREE(frame);
                return 0;
 
@@ -1710,21 +1755,26 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
 
         if (offset == -1) {     /* Seek to the end of the list */
                 dir->dir_next = NULL;
+
+               /* Do the same for dirplus. */
+               dir->dirplus_next = NULL;
+
                TALLOC_FREE(frame);
                 return 0;
         }
 
-       /* Now, run down the list and make sure that the entry is OK       */
-       /* This may need to be changed if we change the format of the list */
+        /*
+         * Run down the list and make sure that the entry is OK.
+         * Update the position of both dir and dirplus lists.
+         */
 
-       if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
+       ok = update_dir_ents(dir, dirent);
+       if (!ok) {
                errno = EINVAL;   /* Bad entry */
                TALLOC_FREE(frame);
                return -1;
        }
 
-       dir->dir_next = list_ent;
-
        TALLOC_FREE(frame);
        return 0;
 }
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 8bdc7038362..589c3347b84 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -509,7 +509,8 @@ nbt = ["nbt.dgram"]
 libsmbclient = ["libsmbclient.version", "libsmbclient.initialize",
                 "libsmbclient.configuration", "libsmbclient.setConfiguration",
                 "libsmbclient.options", "libsmbclient.opendir",
-                "libsmbclient.list_shares", "libsmbclient.readdirplus"]
+                "libsmbclient.list_shares", "libsmbclient.readdirplus",
+               "libsmbclient.readdirplus_seek"]
 
 vfs = [
     "vfs.fruit",
diff --git a/source4/torture/libsmbclient/libsmbclient.c 
b/source4/torture/libsmbclient/libsmbclient.c
index f9154e8a19c..7bc407ac905 100644
--- a/source4/torture/libsmbclient/libsmbclient.c
+++ b/source4/torture/libsmbclient/libsmbclient.c
@@ -18,6 +18,7 @@
 */
 
 #include "includes.h"
+#include "system/dir.h"
 #include "torture/smbtorture.h"
 #include "auth/credentials/credentials.h"
 #include "lib/cmdline/popt_common.h"
@@ -375,6 +376,343 @@ static bool torture_libsmbclient_readdirplus(struct 
torture_context *tctx)
        return true;
 }
 
+static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx)
+{
+       SMBCCTX *ctx;
+       int ret = -1;
+       int dhandle = -1;
+       int fhandle = -1;
+       const char *dname = NULL;
+       const char *full_filename[100] = {0};
+       const char *filename[100] = {0};
+       const struct libsmb_file_info *direntries[102] = {0};
+       unsigned int i = 0;
+       const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+       bool success = false;
+       off_t telldir_50 = (off_t)-1;
+       off_t telldir_20 = (off_t)-1;
+       size_t getdentries_size = 0;
+       struct smbc_dirent *getdentries = NULL;
+       struct smbc_dirent *dirent_20 = NULL;
+       const struct libsmb_file_info *direntries_20 = NULL;
+
+       if (smburl == NULL) {
+               torture_fail(tctx,
+                       "option --option=torture:smburl="
+                       "smb://user:password@server/share missing\n");
+       }
+
+       DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n"));
+
+       torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+       smbc_set_context(ctx);
+
+       dname = talloc_asprintf(tctx,
+                               "%s/rd_seek",
+                               smburl);
+       if (dname == NULL) {
+               torture_fail_goto(tctx,
+                       done,
+                       "talloc fail\n");
+       }
+
+       /* Ensure the files don't exist. */
+       for (i = 0; i < 100; i++) {
+               filename[i] = talloc_asprintf(tctx,
+                               "test_readdirplus_%u.txt",
+                               i);
+               if (full_filename == NULL) {
+                       torture_fail_goto(tctx,
+                               done,
+                               "talloc fail\n");
+               }
+               full_filename[i] = talloc_asprintf(tctx,
+                               "%s/%s",
+                               dname,
+                               filename[i]);
+               if (full_filename == NULL) {
+                       torture_fail_goto(tctx,
+                               done,
+                               "talloc fail\n");
+               }
+               (void)smbc_unlink(full_filename[i]);
+       }
+       /* Ensure the directory doesn't exist. */
+       (void)smbc_rmdir(dname);
+
+       /* Create containing directory. */
+       ret = smbc_mkdir(dname, 0777);
+       if (ret != 0) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "failed to create directory '%s': %s",
+                               dname,
+                               strerror(errno)));
+       }
+
+       DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n"));
+
+       /* Create them. */
+       for (i = 0; i < 100; i++) {
+               fhandle = smbc_creat(full_filename[i], 0666);
+               if (fhandle < 0) {
+                       torture_fail_goto(tctx,
+                               done,
+                               talloc_asprintf(tctx,
+                                       "failed to create file '%s': %s",
+                                       full_filename[i],
+                                       strerror(errno)));
+               }
+               ret = smbc_close(fhandle);
+               torture_assert_int_equal_goto(tctx,
+                       ret,
+                       0,
+                       success,
+                       done,
+                       talloc_asprintf(tctx,
+                               "failed to close handle for '%s'",
+                               full_filename[i]));
+       }
+
+       DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n"));
+
+       /* Now enumerate the directory. */
+       dhandle = smbc_opendir(dname);
+       if (dhandle < 0) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "failed to obtain "
+                               "directory handle for '%s' : %s",
+                               dname,
+                               strerror(errno)));
+       }
+
+       /* Read all the files. 100 we created plus . and .. */
+       for (i = 0; i < 102; i++) {
+               bool found = false;
+               unsigned int j;
+
+               direntries[i] = smbc_readdirplus(dhandle);
+               if (direntries[i] == NULL) {
+                       break;
+               }
+
+               /* Store at offset 50. */
+               if (i == 50) {
+                       telldir_50 = smbc_telldir(dhandle);
+                       if (telldir_50 == (off_t)-1) {
+                               torture_fail_goto(tctx,
+                                       done,
+                                       talloc_asprintf(tctx,
+                                               "telldir failed file %s\n",
+                                               direntries[i]->name));
+                       }
+               }
+
+               if (ISDOT(direntries[i]->name)) {
+                       continue;
+               }
+               if (ISDOTDOT(direntries[i]->name)) {
+                       continue;
+               }
+
+               /* Ensure all our files exist. */
+               for (j = 0; j < 100; j++) {
+                       if (strcmp(direntries[i]->name,
+                               filename[j]) == 0) {
+                               found = true;
+                       }
+               }
+               if (!found) {
+                       torture_fail_goto(tctx,
+                               done,
+                               talloc_asprintf(tctx,
+                                       "failed to find file %s\n",
+                                       direntries[i]->name));
+               }
+       }
+
+       /*
+        * We're seeking on in-memory lists here, so
+        * whilst the handle is open we really should
+        * get the same files back in the same order.
+        */
+
+       ret = smbc_lseekdir(dhandle, telldir_50);
+       torture_assert_int_equal_goto(tctx,
+               ret,
+               0,
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "failed to seek (50) directory handle for '%s'",
+                       dname));
+
+       DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n"));
+
+       for (i = 51; i < 102; i++) {
+               const struct libsmb_file_info *entry =
+                               smbc_readdirplus(dhandle);
+               if (entry != direntries[i]) {
+                       torture_fail_goto(tctx,
+                               done,
+                               talloc_asprintf(tctx,
+                                       "after seek - failed to find "
+                                       "file %s - got %s\n",
+                                       direntries[i]->name,
+                                       entry->name));
+               }
+       }
+
+       /* Seek back to the start. */
+       ret = smbc_lseekdir(dhandle, 0);
+       torture_assert_int_equal_goto(tctx,
+               ret,
+               0,
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "failed to seek directory handle to start for '%s'",
+                       dname));
+
+       /*
+        * Mix getdents/readdir/readdirplus with lseek to ensure
+        * we get the same result.
+        */
+
+       /* Allocate the space for 20 entries.
+        * Tricky as we need to allocate 20 struct smbc_dirent's + space
+        * for the name lengths.
+        */
+       getdentries_size = 20 * (sizeof(struct smbc_dirent) +
+                               strlen("test_readdirplus_1000.txt") + 1);
+
+       getdentries = (struct smbc_dirent *)talloc_array_size(tctx,
+                                               getdentries_size,
+                                               1);
+
+       ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+       torture_assert_goto(tctx,
+               (ret != -1),
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "smbd_getdents(1) for '%s' failed\n",
+                       dname));
+
+       telldir_20 = smbc_telldir(dhandle);
+       if (telldir_20 == (off_t)-1) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "telldir (20) failed\n"));
+       }
+       /* Read another 20. */
+       ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+       torture_assert_goto(tctx,
+               (ret != -1),
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "smbd_getdents(2) for '%s' failed\n",
+                       dname));
+
+       /* Seek back to 20. */
+       ret = smbc_lseekdir(dhandle, telldir_20);
+       torture_assert_int_equal_goto(tctx,
+               ret,
+               0,
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "failed to seek (20) directory handle for '%s'",
+                       dname));
+
+       /* Read with readdir. */
+       dirent_20 = smbc_readdir(dhandle);
+       if (dirent_20 == NULL) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "smbc_readdir (20) failed\n"));
+       }
+
+       /* Ensure the getdents and readdir names are the same. */
+       ret = strcmp(dirent_20->name, getdentries[0].name);
+       if (ret != 0) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "after seek (20) readdir name missmatch "
+                               "file %s - got %s\n",
+                               dirent_20->name,
+                               getdentries[0].name));
+       }
+
+       /* Seek back to 20. */
+       ret = smbc_lseekdir(dhandle, telldir_20);
+       torture_assert_int_equal_goto(tctx,
+               ret,
+               0,
+               success,
+               done,
+               talloc_asprintf(tctx,
+                       "failed to seek (20) directory handle for '%s'",
+                       dname));
+       /* Read with readdirplus. */
+       direntries_20 = smbc_readdirplus(dhandle);
+       if (direntries_20 == NULL) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "smbc_readdirplus (20) failed\n"));
+       }
+
+       /* Ensure the readdirplus and readdir names are the same. */


-- 
Samba Shared Repository

Reply via email to