]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3/smbd: let non_widelink_open() chdir() to directories directly
authorRalph Boehme <slow@samba.org>
Fri, 7 Jul 2017 10:57:57 +0000 (12:57 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 13 Jul 2017 08:51:16 +0000 (10:51 +0200)
If the caller passes O_DIRECTORY we just try to chdir() to smb_fname
directly, not to the parent directory.

The security check in check_reduced_name() will continue to work, but
this fixes the case of an open() for a previous version of a
subdirectory that contains snapshopt.

Eg:

[share]
    path = /shares/test
    vfs objects = shadow_copy2
    shadow:snapdir = .snapshots
    shadow:snapdirseverywhere = yes

Directory tree with fake snapshots:

$ tree -a /shares/test/
/shares/test/
├── dir
│   ├── file
│   └── .snapshots
│       └── @GMT-2017.07.04-04.30.12
│           └── file
├── dir2
│   └── file
├── file
├── .snapshots
│   └── @GMT-2001.01.01-00.00.00
│       ├── dir2
│       │   └── file
│       └── file
└── testfsctl.dat

./bin/smbclient -U slow%x //localhost/share -c 'ls @GMT-2017.07.04-04.30.12/dir/*'
NT_STATUS_OBJECT_NAME_NOT_FOUND listing \@GMT-2017.07.04-04.30.12\dir\*

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12885

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit b886a9443d49f6e27fa3863d87c9e24d12e62874)

source3/smbd/open.c

index c96bc9ba98d02c9f6fea4043e69ebb08a44cd849..50fbcc66b944876f33d30ee2fabdc7a88da64bf5 100644 (file)
@@ -537,12 +537,32 @@ static int non_widelink_open(struct connection_struct *conn,
        char *oldwd = NULL;
        char *parent_dir = NULL;
        const char *final_component = NULL;
+       bool is_directory = false;
+       bool ok;
 
-       if (!parent_dirname(talloc_tos(),
-                       smb_fname->base_name,
-                       &parent_dir,
-                       &final_component)) {
-               goto out;
+#ifdef O_DIRECTORY
+       if (flags & O_DIRECTORY) {
+               is_directory = true;
+       }
+#endif
+
+       if (is_directory) {
+               parent_dir = talloc_strdup(talloc_tos(), smb_fname->base_name);
+               if (parent_dir == NULL) {
+                       saved_errno = errno;
+                       goto out;
+               }
+
+               final_component = ".";
+       } else {
+               ok = parent_dirname(talloc_tos(),
+                                   smb_fname->base_name,
+                                   &parent_dir,
+                                   &final_component);
+               if (!ok) {
+                       saved_errno = errno;
+                       goto out;
+               }
        }
 
        oldwd = vfs_GetWd(talloc_tos(), conn);