Fix bug #Bug 6090 renaming or deleting a "not matching/resolving" symlink is failing.
authorJeremy Allison <jra@samba.org>
Wed, 4 Feb 2009 23:35:02 +0000 (15:35 -0800)
committerJeremy Allison <jra@samba.org>
Wed, 4 Feb 2009 23:35:02 +0000 (15:35 -0800)
Reported by Kukks. Make sure we correctly use LSTAT in all cases where
POSIX pathnames are being used. This matters when dealing with symlinks
pointing to invalid paths being renamed or deleted not all deletes and
renames are done via an nt_create open.
Jeremy.

source/smbd/filename.c
source/smbd/open.c
source/smbd/reply.c

index d240ecfa647ca8dfc34bb68772b76b3606cf6e9e..003cb0ffd44796d8d283f67956d0bf5114658861 100644 (file)
@@ -126,7 +126,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
        char *stream = NULL;
        bool component_was_mangled = False;
        bool name_has_wildcard = False;
+       bool posix_pathnames = false;
        NTSTATUS result;
+       int ret = -1;
 
        SET_STAT_INVALID(*pst);
        *pp_conv_path = NULL;
@@ -225,7 +227,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                }
        }
 
-       if (!lp_posix_pathnames()) {
+       posix_pathnames = lp_posix_pathnames();
+
+       if (!posix_pathnames) {
                stream = strchr_m(name, ':');
 
                if (stream != NULL) {
@@ -268,7 +272,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
         * stat the name - if it exists then we are all done!
         */
 
-       if (SMB_VFS_STAT(conn,name,&st) == 0) {
+       if (posix_pathnames) {
+               ret = SMB_VFS_LSTAT(conn,name,&st);
+       } else {
+               ret = SMB_VFS_STAT(conn,name,&st);
+       }
+
+       if (ret == 0) {
                /* Ensure we catch all names with in "/."
                   this is disallowed under Windows. */
                const char *p = strstr(name, "/."); /* mb safe. */
@@ -380,7 +390,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                 * Check if the name exists up to this point.
                 */
 
-               if (SMB_VFS_STAT(conn,name, &st) == 0) {
+               if (posix_pathnames) {
+                       ret = SMB_VFS_LSTAT(conn,name, &st);
+               } else {
+                       ret = SMB_VFS_STAT(conn,name, &st);
+               }
+
+               if (ret == 0) {
                        /*
                         * It exists. it must either be a directory or this must
                         * be the last part of the path for it to be OK.
@@ -598,7 +614,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                                 * if it exists. JRA.
                                 */
 
-                               if (SMB_VFS_STAT(conn,name, &st) == 0) {
+                               if (posix_pathnames) {
+                                       ret = SMB_VFS_LSTAT(conn,name, &st);
+                               } else {
+                                       ret = SMB_VFS_STAT(conn,name, &st);
+                               }
+
+                               if (ret == 0) {
                                        *pst = st;
                                } else {
                                        SET_STAT_INVALID(st);
index 7e127eafbf4d70c4e5ca56db92a0c08a497bbcb5..716b9ff492541fc02b9efc348553e10813184964 100644 (file)
@@ -415,28 +415,42 @@ static NTSTATUS open_file(files_struct *fsp,
                                        access_mask,
                                        &access_granted);
                        if (!NT_STATUS_IS_OK(status)) {
-
-                               /* Were we trying to do a stat open
-                                * for delete and didn't get DELETE
-                                * access (only) ? Check if the
-                                * directory allows DELETE_CHILD.
-                                * See here:
-                                * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
-                                * for details. */
-
-                               if (!(NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
-                                               (access_mask & DELETE_ACCESS) &&
-                                               (access_granted == DELETE_ACCESS) &&
-                                               can_delete_file_in_directory(conn, path))) {
-                                       DEBUG(10, ("open_file: Access denied on "
-                                               "file %s\n",
-                                               path));
+                               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                                       if ((access_mask & DELETE_ACCESS) &&
+                                                       (access_granted == DELETE_ACCESS) &&
+                                                       can_delete_file_in_directory(conn, path)) {
+                                               /* Were we trying to do a stat open
+                                                * for delete and didn't get DELETE
+                                                * access (only) ? Check if the
+                                                * directory allows DELETE_CHILD.
+                                                * See here:
+                                                * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+                                                * for details. */
+
+                                               DEBUG(10,("open_file: overrode ACCESS_DENIED "
+                                                       "on file %s\n",
+                                                       path ));
+                                       } else {
+                                               DEBUG(10, ("open_file: Access denied on "
+                                                       "file %s\n",
+                                                       path));
+                                               return status;
+                                       }
+                               } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+                                                       fsp->posix_open &&
+                                                       S_ISLNK(psbuf->st_mode)) {
+                                       /* This is a POSIX stat open for delete
+                                        * or rename on a symlink that points
+                                        * nowhere. Allow. */
+                                       DEBUG(10, ("open_file: allowing POSIX open "
+                                               "on bad symlink %s\n",
+                                               path ));
+                               } else {
+                                       DEBUG(10, ("open_file: check_open_rights "
+                                               "on file %s returned %s\n",
+                                               path, nt_errstr(status) ));
                                        return status;
                                }
-
-                               DEBUG(10,("open_file: overrode ACCESS_DENIED "
-                                       "on file %s\n",
-                                       path ));
                        }
                }
        }
index c192d4a13895a629ba2e5e16068a2cb556295ee9..8e757da7063e82678973076a96dfe15d2726d288 100644 (file)
@@ -5614,7 +5614,13 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                        return map_nt_error_from_unix(errno);
                }
        } else {
-               if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+               int ret = -1;
+               if (fsp->posix_open) {
+                       ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf);
+               } else {
+                       ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf);
+               }
+               if (ret == -1) {
                        return map_nt_error_from_unix(errno);
                }
        }
@@ -5718,6 +5724,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
        struct smb_Dir *dir_hnd = NULL;
        const char *dname;
        long offset = 0;
+       bool posix_pathnames = lp_posix_pathnames();
 
        ZERO_STRUCT(sbuf1);
        ZERO_STRUCT(sbuf2);
@@ -5829,19 +5836,30 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                }
 
                ZERO_STRUCT(sbuf1);
-               SMB_VFS_STAT(conn, directory, &sbuf1);
+               if (posix_pathnames) {
+                       SMB_VFS_LSTAT(conn, directory, &sbuf1);
+               } else {
+                       SMB_VFS_STAT(conn, directory, &sbuf1);
+               }
 
                status = S_ISDIR(sbuf1.st_mode) ?
                        open_directory(conn, req, directory, &sbuf1,
-                                      access_mask,
-                                      FILE_SHARE_READ|FILE_SHARE_WRITE,
-                                      FILE_OPEN, 0, 0, NULL,
-                                      &fsp)
+                                       access_mask,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                       FILE_OPEN,
+                                       0,
+                                       posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
+                                       NULL,
+                                       &fsp)
                        : open_file_ntcreate(conn, req, directory, &sbuf1,
-                                            access_mask,
-                                            FILE_SHARE_READ|FILE_SHARE_WRITE,
-                                            FILE_OPEN, 0, 0, 0, NULL,
-                                            &fsp);
+                                       access_mask,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                       FILE_OPEN,
+                                       0,
+                                       posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
+                                       0,
+                                       NULL,
+                                       &fsp);
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3, ("Could not open rename source %s: %s\n",
@@ -5933,19 +5951,30 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                }
 
                ZERO_STRUCT(sbuf1);
-               SMB_VFS_STAT(conn, fname, &sbuf1);
+               if (posix_pathnames) {
+                       SMB_VFS_LSTAT(conn, fname, &sbuf1);
+               } else {
+                       SMB_VFS_STAT(conn, fname, &sbuf1);
+               }
 
                status = S_ISDIR(sbuf1.st_mode) ?
                        open_directory(conn, req, fname, &sbuf1,
-                                      access_mask,
-                                      FILE_SHARE_READ|FILE_SHARE_WRITE,
-                                      FILE_OPEN, 0, 0, NULL,
-                                      &fsp)
+                                       access_mask,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                       FILE_OPEN,
+                                       0,
+                                       posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
+                                       NULL,
+                                       &fsp)
                        : open_file_ntcreate(conn, req, fname, &sbuf1,
-                                            access_mask,
-                                            FILE_SHARE_READ|FILE_SHARE_WRITE,
-                                            FILE_OPEN, 0, 0, 0, NULL,
-                                            &fsp);
+                                       access_mask,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                       FILE_OPEN,
+                                       0,
+                                       posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
+                                       0,
+                                       NULL,
+                                       &fsp);
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("rename_internals: open_file_ntcreate "
@@ -7123,7 +7152,14 @@ void reply_setattrE(struct smb_request *req)
                        return;
                }
        } else {
-               if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) {
+               int ret = -1;
+
+               if (fsp->posix_open) {
+                       ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf);
+               } else {
+                       ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf);
+               }
+               if (ret == -1) {
                        status = map_nt_error_from_unix(errno);
                        reply_nterror(req, status);
                        END_PROFILE(SMBsetattrE);