From 066f6c856fccc791009f85492289276267e24bcf Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 19 Jun 2008 14:53:46 +0200 Subject: Fix checks in can_delete_file_in_directory() With at least NFSv4 ACLs around the write permission for the owner is a bogus check if we can delete a file in a directory. Like in Windows, there are two ways which can grant us such: First, the DELETE permission on the file itself, or if that does not help, the DELETE_CHILD permission on the directory. It might be a bit more code that runs, but essentially we should end up with the same set of syscalls in the non-acl case. (This used to be commit daa9b056645a45edfb3a70e3536011ebe5678970) --- source3/smbd/file_access.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'source3') diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 0552a16b50..e61a8c3a5a 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -87,11 +87,6 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) return True; } - /* Check primary owner write access. */ - if (conn->server_info->uid == sbuf.st_uid) { - return (sbuf.st_mode & S_IWUSR) ? True : False; - } - #ifdef S_ISVTX /* sticky bit means delete only by owner or root. */ if (sbuf.st_mode & S_ISVTX) { @@ -117,7 +112,21 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) /* now for ACL checks */ - return can_access_file_acl(conn, dname, FILE_WRITE_DATA); + /* + * There's two ways to get the permission to delete a file: First by + * 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. + */ + + if (can_access_file_acl(conn, dname, FILE_DELETE_CHILD)) { + return true; + } + + return can_access_file_acl(conn, fname, DELETE_ACCESS); } /**************************************************************************** -- cgit