The branch, v3-3-test has been updated
       via  c5462c8b43435763783185a03029903efe3b0c11 (commit)
      from  64982295fccc5758aff4464b5527a27621386bc9 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-3-test


- Log -----------------------------------------------------------------
commit c5462c8b43435763783185a03029903efe3b0c11
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Feb 2 17:11:15 2009 -0800

    Fix bug #6082 - smbd_gpfs_getacl failed: Windows client can´t rename or 
delete file
    This fixes the generic rename/delete problem for 3.3.0 and above.
    Fixed slightly differently to discussions, user viewable modified
    ACLs are not a good idea :-).
    Jeremy.

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

Summary of changes:
 source/include/smb.h       |    2 +-
 source/lib/util_seaccess.c |    5 +++-
 source/smbd/file_access.c  |   11 ++------
 source/smbd/open.c         |   56 ++++++++++++++++++++++++++++++++++++--------
 4 files changed, 54 insertions(+), 20 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/include/smb.h b/source/include/smb.h
index e7f08a3..a98d151 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -1251,7 +1251,7 @@ struct bitmap {
 /* Mapping of access rights to UNIX perms. for a UNIX directory. */
 #define UNIX_DIRECTORY_ACCESS_RWX              FILE_GENERIC_ALL
 #define UNIX_DIRECTORY_ACCESS_R                FILE_GENERIC_READ
-#define UNIX_DIRECTORY_ACCESS_W                        FILE_GENERIC_WRITE
+#define UNIX_DIRECTORY_ACCESS_W                        
(FILE_GENERIC_WRITE|FILE_DELETE_CHILD)
 #define UNIX_DIRECTORY_ACCESS_X                        FILE_GENERIC_EXECUTE
 
 #if 0
diff --git a/source/lib/util_seaccess.c b/source/lib/util_seaccess.c
index fdc10f2..0da7442 100644
--- a/source/lib/util_seaccess.c
+++ b/source/lib/util_seaccess.c
@@ -149,7 +149,9 @@ static uint32_t access_check_max_allowed(const struct 
security_descriptor *sd,
 }
 
 /*
-  the main entry point for access checking. 
+  The main entry point for access checking. If returning ACCESS_DENIED
+  this function returns the denied bits in the uint32_t pointed
+  to by the access_granted pointer.
 */
 NTSTATUS se_access_check(const struct security_descriptor *sd, 
                          const NT_USER_TOKEN *token,
@@ -238,6 +240,7 @@ NTSTATUS se_access_check(const struct security_descriptor 
*sd,
 
 done:
        if (bits_remaining != 0) {
+               *access_granted = bits_remaining;
                return NT_STATUS_ACCESS_DENIED;
        }
 
diff --git a/source/smbd/file_access.c b/source/smbd/file_access.c
index c535bc7..743e079 100644
--- a/source/smbd/file_access.c
+++ b/source/smbd/file_access.c
@@ -116,16 +116,11 @@ bool can_delete_file_in_directory(connection_struct 
*conn, const char *fname)
         * having the DELETE bit on the file itself and second if that does
         * not help, by the DELETE_CHILD bit on the containing directory.
         *
-        * Here we check the other way round because with just posix
-        * permissions looking at the file itself will never grant DELETE, so
-        * by looking at the directory first we save one get_acl call.
+        * Here we only check the directory permissions, we will
+        * check the file DELETE permission separately.
         */
 
-       if (can_access_file_acl(conn, dname, FILE_DELETE_CHILD)) {
-               return true;
-       }
-
-       return can_access_file_acl(conn, fname, DELETE_ACCESS);
+       return can_access_file_acl(conn, dname, FILE_DELETE_CHILD);
 }
 
 /****************************************************************************
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 3c07dba..7e127ea 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -50,13 +50,15 @@ NTSTATUS smb1_file_se_access_check(const struct 
security_descriptor *sd,
 
 static NTSTATUS check_open_rights(struct connection_struct *conn,
                                const char *fname,
-                               uint32_t access_mask)
+                               uint32_t access_mask,
+                               uint32_t *access_granted)
 {
        /* Check if we have rights to open. */
        NTSTATUS status;
-       uint32_t access_granted = 0;
        struct security_descriptor *sd;
 
+       *access_granted = 0;
+
        status = SMB_VFS_GET_NT_ACL(conn, fname,
                        (OWNER_SECURITY_INFORMATION |
                        GROUP_SECURITY_INFORMATION |
@@ -73,9 +75,17 @@ static NTSTATUS check_open_rights(struct connection_struct 
*conn,
        status = smb1_file_se_access_check(sd,
                                conn->server_info->ptok,
                                access_mask,
-                               &access_granted);
+                               access_granted);
 
        TALLOC_FREE(sd);
+
+       DEBUG(10,("check_open_rights: file %s requesting "
+               "0x%x returning 0x%x (%s)\n",
+               fname,
+               (unsigned int)access_mask,
+               (unsigned int)*access_granted,
+               nt_errstr(status) ));
+
        return status;
 }
 
@@ -398,14 +408,35 @@ static NTSTATUS open_file(files_struct *fsp,
        } else {
                fsp->fh->fd = -1; /* What we used to call a stat open. */
                if (file_existed) {
+                       uint32_t access_granted = 0;
+
                        status = check_open_rights(conn,
                                        path,
-                                       access_mask);
+                                       access_mask,
+                                       &access_granted);
                        if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(10, ("open_file: Access denied on "
-                                       "file %s\n",
-                                       path));
-                               return 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));
+                                       return status;
+                               }
+
+                               DEBUG(10,("open_file: overrode ACCESS_DENIED "
+                                       "on file %s\n",
+                                       path ));
                        }
                }
        }
@@ -2398,9 +2429,11 @@ NTSTATUS open_directory(connection_struct *conn,
        }
 
        if (info == FILE_WAS_OPENED) {
+               uint32_t access_granted = 0;
                status = check_open_rights(conn,
                                        fname,
-                                       access_mask);
+                                       access_mask,
+                                       &access_granted);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("open_directory: check_open_rights on "
                                "file  %s failed with %s\n",
@@ -2819,8 +2852,11 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
            && (create_disposition != FILE_CREATE)
            && (share_access & FILE_SHARE_DELETE)
            && (access_mask & DELETE_ACCESS)
-           && (!can_delete_file_in_directory(conn, fname))) {
+           && (!(can_delete_file_in_directory(conn, fname) ||
+                can_access_file_acl(conn, fname, DELETE_ACCESS)))) {
                status = NT_STATUS_ACCESS_DENIED;
+               DEBUG(10,("create_file_unixpath: open file %s "
+                       "for delete ACCESS_DENIED\n", fname ));
                goto fail;
        }
 


-- 
Samba Shared Repository

Reply via email to