Add support for inherited file ACLs.

This commit is contained in:
Erich E. Hoover 2014-02-07 20:20:32 -07:00
parent f352182c20
commit e77f05ee52
10 changed files with 1090 additions and 337 deletions

View File

@ -6,6 +6,7 @@ Daily updates for the Wine "Compholio" Edition.
Current patches include:
* Support for interface change notifications (http://bugs.winehq.org/show_bug.cgi?id=32328)
* Support for stored file ACLs (http://bugs.winehq.org/show_bug.cgi?id=31858)
* Support for inherited file ACLs (http://bugs.winehq.org/show_bug.cgi?id=34406)
* Support for Junction Points (http://bugs.winehq.org/show_bug.cgi?id=12401)
* Support for TransmitFile (http://bugs.winehq.org/show_bug.cgi?id=5048)
* Support for access security with named pipes (http://bugs.winehq.org/show_bug.cgi?id=34098)

View File

@ -0,0 +1,135 @@
From 8714b20a24dcfed7853a9483fd8ef04dd3292fd0 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 6 Feb 2014 18:21:11 -0700
Subject: server: Unify the storage of security attributes for files and
directories.
---
server/change.c | 46 ++++++----------------------------------------
server/file.c | 25 +++++++++++++++++--------
server/file.h | 2 ++
3 files changed, 25 insertions(+), 48 deletions(-)
diff --git a/server/change.c b/server/change.c
index f6d56b0..76fc9f7 100644
--- a/server/change.c
+++ b/server/change.c
@@ -317,49 +317,15 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
unsigned int set_info )
{
- struct dir *dir = (struct dir *)obj;
- const SID *owner;
- struct stat st;
- mode_t mode;
- int unix_fd;
+ struct fd *fd;
+ int ret;
assert( obj->ops == &dir_ops );
- unix_fd = get_dir_unix_fd( dir );
-
- if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
-
- if (set_info & OWNER_SECURITY_INFORMATION)
- {
- owner = sd_get_owner( sd );
- if (!owner)
- {
- set_error( STATUS_INVALID_SECURITY_DESCR );
- return 0;
- }
- if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) ))
- {
- /* FIXME: get Unix uid and call fchown */
- }
- }
- else if (obj->sd)
- owner = sd_get_owner( obj->sd );
- else
- owner = token_get_user( current->process->token );
-
- if (set_info & DACL_SECURITY_INFORMATION)
- {
- /* keep the bits that we don't map to access rights in the ACL */
- mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
- mode |= sd_to_mode( sd, owner );
-
- if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
- {
- file_set_error();
- return 0;
- }
- }
- return 1;
+ fd = dir_get_fd( obj );
+ ret = file_set_acls( obj, fd, sd, set_info );
+ release_object( fd );
+ return ret;
}
static struct change_record *get_first_change_record( struct dir *dir )
diff --git a/server/file.c b/server/file.c
index cceb8ad..13ebaf9 100644
--- a/server/file.c
+++ b/server/file.c
@@ -534,18 +534,13 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
return new_mode & ~denied_mode;
}
-static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
- unsigned int set_info )
+int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
+ unsigned int set_info )
{
- struct file *file = (struct file *)obj;
+ int unix_fd = get_unix_fd( fd );
const SID *owner;
struct stat st;
mode_t mode;
- int unix_fd;
-
- assert( obj->ops == &file_ops );
-
- unix_fd = get_file_unix_fd( file );
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
@@ -584,6 +579,20 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
return 1;
}
+static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
+ unsigned int set_info )
+{
+ struct fd *fd;
+ int ret;
+
+ assert( obj->ops == &file_ops );
+
+ fd = file_get_fd( obj );
+ ret = file_set_acls( obj, fd, sd, set_info );
+ release_object( fd );
+ return ret;
+}
+
static void file_destroy( struct object *obj )
{
struct file *file = (struct file *)obj;
diff --git a/server/file.h b/server/file.h
index 493d30b..11c3220 100644
--- a/server/file.h
+++ b/server/file.h
@@ -122,6 +122,8 @@ extern struct file *create_file_for_fd_obj( struct fd *fd, unsigned int access,
extern void file_set_error(void);
extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group );
extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
+extern int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
+ unsigned int set_info );
/* file mapping functions */
--
1.7.9.5

View File

@ -1,178 +0,0 @@
From b5efc991444e6539adf73f42b44e333b8aa7de2f Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Mon, 13 Jan 2014 18:32:05 -0700
Subject: ntdll: Inherit security attributes from parent directories.
---
dlls/advapi32/tests/security.c | 40 ++++++++++++++++++-
dlls/ntdll/file.c | 83 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 297cf96..4b1c5a2 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3030,10 +3030,11 @@ static void test_CreateDirectoryA(void)
ACL_SIZE_INFORMATION acl_size;
ACCESS_ALLOWED_ACE *ace;
SECURITY_ATTRIBUTES sa;
+ char tmpfile[MAX_PATH];
char tmpdir[MAX_PATH];
+ HANDLE token, hTemp;
struct _SID *owner;
BOOL bret = TRUE;
- HANDLE token;
DWORD error;
PACL pDacl;
@@ -3125,6 +3126,43 @@ static void test_CreateDirectoryA(void)
ace->Mask);
}
+ /* Test inheritance of ACLs */
+ strcpy(tmpfile, tmpdir);
+ lstrcatA(tmpfile, "/tmpfile");
+ hTemp = CreateFileA(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW,
+ FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, (PSID*)&owner,
+ NULL, &pDacl, NULL, &pSD);
+ ok(error == ERROR_SUCCESS, "Failed to get permissions on file.\n");
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ ok(bret, "GetAclInformation failed\n");
+ ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n",
+ acl_size.AceCount);
+ if (acl_size.AceCount > 0)
+ {
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Current User ACE.\n");
+ bret = EqualSid(&ace->SidStart, user_sid);
+ ok(bret, "Inherited Current User ACE != Current User SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ if (acl_size.AceCount > 1)
+ {
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Administators Group ACE.\n");
+ bret = EqualSid(&ace->SidStart, admin_sid);
+ ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ CloseHandle(hTemp);
+
done:
HeapFree(GetProcessHeap(), 0, user);
bret = RemoveDirectoryA(tmpdir);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index d2efcc1..bdcaab4 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -103,6 +103,79 @@ mode_t FILE_umask = 0;
static const WCHAR ntfsW[] = {'N','T','F','S'};
+static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
+ PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
+ ULONG attributes, ULONG sharing, ULONG disposition,
+ ULONG options, PVOID ea_buffer, ULONG ea_length );
+
+struct security_descriptor *FILE_get_parent_sd(UNICODE_STRING *filenameW)
+{
+ SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION
+ |DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
+ WCHAR *p, parent[UNICODE_STRING_MAX_CHARS];
+ PSECURITY_DESCRIPTOR parentsd = NULL;
+ ACL_SIZE_INFORMATION acl_size;
+ BOOLEAN present, defaulted;
+ OBJECT_ATTRIBUTES pattr;
+ UNICODE_STRING parentW;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE hparent;
+ ULONG n1, n2;
+ PACL pDacl;
+ int i;
+
+ parentW.Buffer = parent;
+ parentW.Length = filenameW->Length;
+ memcpy(parentW.Buffer, filenameW->Buffer, filenameW->Length);
+ if ((p = strrchrW(parent, '\\')) == NULL) return NULL;
+ p[0] = 0;
+ parentW.Length = (p-parent)*sizeof(WCHAR);
+ memset(&pattr, 0x0, sizeof(pattr));
+ pattr.Length = sizeof(pattr);
+ pattr.Attributes = OBJ_CASE_INSENSITIVE;
+ pattr.ObjectName = &parentW;
+ status = FILE_CreateFile( &hparent, READ_CONTROL|ACCESS_SYSTEM_SECURITY, &pattr, &io, NULL,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0 );
+ if (status == STATUS_SUCCESS)
+ status = NtQuerySecurityObject( hparent, info, NULL, 0, &n1 );
+ if (status == STATUS_BUFFER_TOO_SMALL && (parentsd = RtlAllocateHeap( GetProcessHeap(), 0, n1 )) != NULL)
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
+ if (status == STATUS_SUCCESS)
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
+ if (hparent != INVALID_HANDLE_VALUE)
+ NtClose( hparent );
+ if (status != STATUS_SUCCESS) return NULL;
+ status = RtlGetDaclSecurityDescriptor(parentsd, &present, &pDacl, &defaulted);
+ if (status != STATUS_SUCCESS || !present) return NULL;
+ status = RtlQueryInformationAcl(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ if (status != STATUS_SUCCESS) return NULL;
+
+ for (i=acl_size.AceCount-1; i>=0; i--)
+ {
+ DWORD inheritance_mask = INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
+ ACE_HEADER *ace;
+
+ status = RtlGetAce(pDacl, i, (VOID **)&ace);
+ if (status != STATUS_SUCCESS || !(ace->AceFlags & inheritance_mask))
+ {
+ RtlDeleteAce(pDacl, i);
+ acl_size.AceCount--;
+ }
+ else
+ ace->AceFlags = (ace->AceFlags & ~inheritance_mask) | INHERITED_ACE;
+ }
+
+ if (!acl_size.AceCount)
+ {
+ return NULL;
+ }
+ return parentsd;
+}
+
+
/**************************************************************************
* FILE_CreateFile (internal)
* Open a file.
@@ -161,10 +234,18 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
{
struct security_descriptor *sd;
struct object_attributes objattr;
+ PSECURITY_DESCRIPTOR parentsd = NULL, psd;
objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
objattr.name_len = 0;
- io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
+ psd = attr->SecurityDescriptor;
+ if (!psd && (disposition == FILE_CREATE||disposition == FILE_OVERWRITE_IF))
+ parentsd = FILE_get_parent_sd( attr->ObjectName );
+ if (parentsd)
+ psd = parentsd;
+ io->u.Status = NTDLL_create_struct_sd( psd, &sd, &objattr.sd_len );
+ if (parentsd)
+ RtlFreeHeap( GetProcessHeap(), 0, parentsd );
if (io->u.Status != STATUS_SUCCESS)
{
RtlFreeAnsiString( &unix_name );
--
1.7.9.5

View File

@ -0,0 +1,133 @@
From ca4cf8fe5ed71c5ddcd5a41ae35f95e9d0f0767e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 6 Feb 2014 18:32:21 -0700
Subject: server: Unify the retrieval of security attributes for files and
directories.
---
server/change.c | 27 +++++----------------------
server/file.c | 34 ++++++++++++++++++++++------------
server/file.h | 2 ++
3 files changed, 29 insertions(+), 34 deletions(-)
diff --git a/server/change.c b/server/change.c
index 76fc9f7..0b7b979 100644
--- a/server/change.c
+++ b/server/change.c
@@ -286,31 +286,14 @@ static int get_dir_unix_fd( struct dir *dir )
static struct security_descriptor *dir_get_sd( struct object *obj )
{
struct dir *dir = (struct dir *)obj;
- int unix_fd;
- struct stat st;
struct security_descriptor *sd;
- assert( obj->ops == &dir_ops );
-
- unix_fd = get_dir_unix_fd( dir );
-
- if (unix_fd == -1 || fstat( unix_fd, &st ) == -1)
- return obj->sd;
-
- /* mode and uid the same? if so, no need to re-generate security descriptor */
- if (obj->sd &&
- (st.st_mode & (S_IRWXU|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXO)) &&
- (st.st_uid == dir->uid))
- return obj->sd;
+ struct fd *fd;
- sd = mode_to_sd( st.st_mode,
- security_unix_uid_to_sid( st.st_uid ),
- token_get_primary_group( current->process->token ));
- if (!sd) return obj->sd;
+ assert( obj->ops == &dir_ops );
- dir->mode = st.st_mode;
- dir->uid = st.st_uid;
- free( obj->sd );
- obj->sd = sd;
+ fd = dir_get_fd( obj );
+ sd = file_get_acls( obj, fd, &dir->mode, &dir->uid );
+ release_object( fd );
return sd;
}
diff --git a/server/file.c b/server/file.c
index 13ebaf9..8baa712 100644
--- a/server/file.c
+++ b/server/file.c
@@ -424,23 +424,19 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID
return sd;
}
-static struct security_descriptor *file_get_sd( struct object *obj )
+struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mode_t *mode,
+ uid_t *uid )
{
- struct file *file = (struct file *)obj;
- struct stat st;
- int unix_fd;
+ int unix_fd = get_unix_fd( fd );
struct security_descriptor *sd;
-
- assert( obj->ops == &file_ops );
-
- unix_fd = get_file_unix_fd( file );
+ struct stat st;
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1)
return obj->sd;
/* mode and uid the same? if so, no need to re-generate security descriptor */
- if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (file->mode & (S_IRWXU|S_IRWXO)) &&
- (st.st_uid == file->uid))
+ if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (*mode & (S_IRWXU|S_IRWXO)) &&
+ (st.st_uid == *uid))
return obj->sd;
sd = mode_to_sd( st.st_mode,
@@ -448,13 +444,27 @@ static struct security_descriptor *file_get_sd( struct object *obj )
token_get_primary_group( current->process->token ));
if (!sd) return obj->sd;
- file->mode = st.st_mode;
- file->uid = st.st_uid;
+ *mode = st.st_mode;
+ *uid = st.st_uid;
free( obj->sd );
obj->sd = sd;
return sd;
}
+static struct security_descriptor *file_get_sd( struct object *obj )
+{
+ struct file *file = (struct file *)obj;
+ struct security_descriptor *sd;
+ struct fd *fd;
+
+ assert( obj->ops == &file_ops );
+
+ fd = file_get_fd( obj );
+ sd = file_get_acls( obj, fd, &file->mode, &file->uid );
+ release_object( fd );
+ return sd;
+}
+
static mode_t file_access_to_mode( unsigned int access )
{
mode_t mode = 0;
diff --git a/server/file.h b/server/file.h
index 11c3220..89b5888 100644
--- a/server/file.h
+++ b/server/file.h
@@ -124,6 +124,8 @@ extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, con
extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
extern int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
unsigned int set_info );
+extern struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mode_t *mode,
+ uid_t *uid );
/* file mapping functions */
--
1.7.9.5

View File

@ -1,20 +1,17 @@
From acc6aac3356b0ec9024362488016945b76f67111 Mon Sep 17 00:00:00 2001
From 9eeab4088f54ab8f00fa36e3d3046e756a732a1e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 11 Jan 2014 09:18:16 -0700
Date: Thu, 6 Feb 2014 23:13:11 -0700
Subject: server: Store and return security attributes with extended file
attributes.
---
configure.ac | 6 ++
dlls/advapi32/tests/security.c | 25 +++---
server/change.c | 11 ++-
server/fd.c | 68 +++++++++++++++-
server/file.c | 176 +++++++++++++++++++++++++++++++++++++++-
server/file.h | 5 +-
6 files changed, 269 insertions(+), 22 deletions(-)
configure.ac | 6 +
dlls/advapi32/tests/security.c | 25 ++--
server/file.c | 245 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 260 insertions(+), 16 deletions(-)
diff --git a/configure.ac b/configure.ac
index dcabb55..fc8bd5c 100644
index de807d2..ddf0000 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,6 +73,7 @@ AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthrea
@ -25,7 +22,7 @@ index dcabb55..fc8bd5c 100644
AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]),
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
@@ -665,6 +666,11 @@ AC_CHECK_HEADERS([libprocstat.h],,,
@@ -660,6 +661,11 @@ AC_CHECK_HEADERS([libprocstat.h],,,
#include <sys/socket.h>
#endif])
@ -38,7 +35,7 @@ index dcabb55..fc8bd5c 100644
AC_SUBST(dlldir,"\${libdir}/wine")
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 2efe80e..297cf96 100644
index f3cc85d..ceea60e 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3105,10 +3105,10 @@ static void test_CreateDirectoryA(void)
@ -108,49 +105,21 @@ index 2efe80e..297cf96 100644
ok(((ACE_HEADER *)ace)->AceFlags == 0,
"Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
diff --git a/server/change.c b/server/change.c
index f6d56b0..022c780 100644
--- a/server/change.c
+++ b/server/change.c
@@ -286,6 +286,7 @@ static int get_dir_unix_fd( struct dir *dir )
static struct security_descriptor *dir_get_sd( struct object *obj )
{
struct dir *dir = (struct dir *)obj;
+ const SID *user, *group;
int unix_fd;
struct stat st;
struct security_descriptor *sd;
@@ -302,9 +303,11 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
(st.st_uid == dir->uid))
return obj->sd;
- sd = mode_to_sd( st.st_mode,
- security_unix_uid_to_sid( st.st_uid ),
- token_get_primary_group( current->process->token ));
+ user = security_unix_uid_to_sid( st.st_uid );
+ group = token_get_primary_group( current->process->token );
+ sd = get_file_acls( unix_fd, user, group );
+ if (!sd)
+ sd = mode_to_sd( st.st_mode, user, group );
if (!sd) return obj->sd;
dir->mode = st.st_mode;
@@ -353,6 +356,8 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
mode |= sd_to_mode( sd, owner );
+ set_file_acls( unix_fd, sd );
+
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
{
file_set_error();
diff --git a/server/fd.c b/server/fd.c
index fa8874c..98e3eca 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -91,6 +91,9 @@
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
diff --git a/server/file.c b/server/file.c
index 8baa712..0df2245 100644
--- a/server/file.c
+++ b/server/file.c
@@ -32,6 +32,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
+#include <limits.h>
#include <unistd.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
@@ -39,6 +40,9 @@
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
@ -158,19 +127,11 @@ index fa8874c..98e3eca 100644
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -99,6 +102,7 @@
#include "handle.h"
#include "process.h"
#include "request.h"
+#include "security.h"
#include "winternl.h"
#include "winioctl.h"
@@ -1726,9 +1730,69 @@ static char *dup_fd_name( struct fd *root, const char *name )
return ret;
@@ -178,6 +182,66 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
return &file->obj;
}
+void set_file_acls( int fd, const struct security_descriptor *sd )
+void set_xattr_acls( int fd, const struct security_descriptor *sd )
+{
+#ifdef HAVE_ATTR_XATTR_H
+ char buffer[XATTR_SIZE_MAX], *p = buffer;
@ -230,58 +191,22 @@ index fa8874c..98e3eca 100644
+#endif
+}
+
/* open() wrapper that returns a struct fd with no fd user set */
struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
- unsigned int sharing, unsigned int options )
+ unsigned int sharing, unsigned int options, const struct security_descriptor *sd )
{
struct stat st;
struct closed_fd *closed_fd;
@@ -1804,6 +1868,8 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
}
}
+ set_file_acls( fd->unix_fd, sd );
+
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink[0] = 0;
fstat( fd->unix_fd, &st );
diff --git a/server/file.c b/server/file.c
index cceb8ad..9ac9188 100644
--- a/server/file.c
+++ b/server/file.c
@@ -32,6 +32,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
+#include <limits.h>
#include <unistd.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
@@ -39,6 +40,9 @@
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -237,7 +241,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
access = generic_file_map_access( access );
static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len,
unsigned int access, unsigned int sharing, int create,
unsigned int options, unsigned int attrs,
@@ -239,6 +303,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
/* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
- fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
+ fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options, sd );
fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
if (!fd) goto done;
+ set_xattr_acls( get_unix_fd( fd ), sd );
if (S_ISDIR(mode))
@@ -424,9 +428,169 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID
obj = create_dir_obj( fd, access, mode );
@@ -424,11 +489,181 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID
return sd;
}
+struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group )
+struct security_descriptor *get_xattr_acls( int fd, const SID *user, const SID *group )
+{
+#ifdef HAVE_ATTR_XATTR_H
+ int ace_count = 0, dacl_size = sizeof(ACL), i, n;
@ -397,17 +322,6 @@ index cceb8ad..9ac9188 100644
+ while(p);
+ sid->SubAuthorityCount = sub_authority_count;
+
+ /* Convert generic rights into standard access rights */
+ if (mask & GENERIC_ALL)
+ mask |= WRITE_DAC | WRITE_OWNER | DELETE | FILE_DELETE_CHILD;
+ if (mask & (GENERIC_ALL|GENERIC_READ))
+ mask |= FILE_GENERIC_READ;
+ if (mask & (GENERIC_ALL|GENERIC_WRITE))
+ mask |= FILE_GENERIC_WRITE;
+ if (mask & (GENERIC_ALL|GENERIC_EXECUTE))
+ mask |= FILE_GENERIC_EXECUTE;
+ mask &= 0x0FFFFFFF;
+
+ /* Handle the specific ACE */
+ switch (type)
+ {
@ -440,15 +354,38 @@ index cceb8ad..9ac9188 100644
+#endif
+}
+
static struct security_descriptor *file_get_sd( struct object *obj )
+/* Convert generic rights into standard access rights */
+void convert_generic_sd( struct security_descriptor *sd )
+{
+ const ACL *dacl;
+ int present;
+
+ dacl = sd_get_dacl( sd, &present );
+ if (present && dacl)
+ {
+ const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1);
+ ULONG i;
+
+ for (i = 0; i < dacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ DWORD *mask = (DWORD *)(ace + 1);
+
+ *mask = generic_file_map_access( *mask );
+ }
+ }
+}
+
struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mode_t *mode,
uid_t *uid )
{
struct file *file = (struct file *)obj;
int unix_fd = get_unix_fd( fd );
struct security_descriptor *sd;
+ const SID *user, *group;
struct stat st;
int unix_fd;
struct security_descriptor *sd;
@@ -443,9 +607,11 @@ static struct security_descriptor *file_get_sd( struct object *obj )
(st.st_uid == file->uid))
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1)
@@ -439,9 +674,11 @@ struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mo
(st.st_uid == *uid))
return obj->sd;
- sd = mode_to_sd( st.st_mode,
@ -456,44 +393,21 @@ index cceb8ad..9ac9188 100644
- token_get_primary_group( current->process->token ));
+ user = security_unix_uid_to_sid( st.st_uid );
+ group = token_get_primary_group( current->process->token );
+ sd = get_file_acls( unix_fd, user, group );
+ if (!sd)
+ sd = mode_to_sd( st.st_mode, user, group);
+ sd = get_xattr_acls( unix_fd, user, group );
+ if (sd) convert_generic_sd( sd );
+ if (!sd) sd = mode_to_sd( st.st_mode, user, group);
if (!sd) return obj->sd;
file->mode = st.st_mode;
@@ -575,6 +741,8 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
*mode = st.st_mode;
@@ -580,6 +817,8 @@ int file_set_acls( struct object *obj, struct fd *fd, const struct security_desc
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
mode |= sd_to_mode( sd, owner );
+ set_file_acls( unix_fd, sd );
+ set_xattr_acls( unix_fd, sd );
+
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
{
file_set_error();
diff --git a/server/file.h b/server/file.h
index 493d30b..721c087 100644
--- a/server/file.h
+++ b/server/file.h
@@ -56,7 +56,8 @@ extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct obje
unsigned int options );
extern void set_no_fd_status( struct fd *fd, unsigned int status );
extern struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
- unsigned int access, unsigned int sharing, unsigned int options );
+ unsigned int access, unsigned int sharing, unsigned int options,
+ const struct security_descriptor *sd );
extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops,
int unix_fd, struct object *user, unsigned int options );
extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing,
@@ -122,6 +123,8 @@ extern struct file *create_file_for_fd_obj( struct fd *fd, unsigned int access,
extern void file_set_error(void);
extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group );
extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
+extern void set_file_acls( int fd, const struct security_descriptor *sd );
+extern struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group );
/* file mapping functions */
--
1.7.9.5

View File

@ -0,0 +1,300 @@
From d1b4f66da4a58f3efadcf20957ed90b30211a1cb Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 7 Feb 2014 16:02:26 -0700
Subject: server: Inherit security attributes from parent directories on
creation.
---
dlls/advapi32/tests/security.c | 40 ++++++++++-
server/change.c | 2 +-
server/file.c | 146 +++++++++++++++++++++++++++++++++++++++-
server/file.h | 2 +-
4 files changed, 184 insertions(+), 6 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index ceea60e..1bf3185 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3030,10 +3030,11 @@ static void test_CreateDirectoryA(void)
ACL_SIZE_INFORMATION acl_size;
ACCESS_ALLOWED_ACE *ace;
SECURITY_ATTRIBUTES sa;
+ char tmpfile[MAX_PATH];
char tmpdir[MAX_PATH];
+ HANDLE token, hTemp;
struct _SID *owner;
BOOL bret = TRUE;
- HANDLE token;
DWORD error;
PACL pDacl;
@@ -3125,6 +3126,43 @@ static void test_CreateDirectoryA(void)
ace->Mask);
}
+ /* Test inheritance of ACLs */
+ strcpy(tmpfile, tmpdir);
+ lstrcatA(tmpfile, "/tmpfile");
+ hTemp = CreateFileA(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW,
+ FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, (PSID*)&owner,
+ NULL, &pDacl, NULL, &pSD);
+ ok(error == ERROR_SUCCESS, "Failed to get permissions on file.\n");
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ ok(bret, "GetAclInformation failed\n");
+ ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n",
+ acl_size.AceCount);
+ if (acl_size.AceCount > 0)
+ {
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Current User ACE.\n");
+ bret = EqualSid(&ace->SidStart, user_sid);
+ ok(bret, "Inherited Current User ACE != Current User SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ if (acl_size.AceCount > 1)
+ {
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Administators Group ACE.\n");
+ bret = EqualSid(&ace->SidStart, admin_sid);
+ ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ CloseHandle(hTemp);
+
done:
HeapFree(GetProcessHeap(), 0, user);
bret = RemoveDirectoryA(tmpdir);
diff --git a/server/change.c b/server/change.c
index 0b7b979..14f37c3 100644
--- a/server/change.c
+++ b/server/change.c
@@ -292,7 +292,7 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
assert( obj->ops == &dir_ops );
fd = dir_get_fd( obj );
- sd = file_get_acls( obj, fd, &dir->mode, &dir->uid );
+ sd = file_get_acls( obj, fd, &dir->mode, &dir->uid, TRUE );
release_object( fd );
return sd;
}
diff --git a/server/file.c b/server/file.c
index 0df2245..c115ff7 100644
--- a/server/file.c
+++ b/server/file.c
@@ -242,11 +242,141 @@ void set_xattr_acls( int fd, const struct security_descriptor *sd )
#endif
}
+struct security_descriptor *inherit_sd( const struct security_descriptor *parent_sd, int is_dir )
+{
+ DWORD inheritance_mask = INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
+ struct security_descriptor *sd = NULL;
+ const ACL *parent_dacl;
+ int present;
+ ACL *dacl;
+
+ parent_dacl = sd_get_dacl( parent_sd, &present );
+ if (present && parent_dacl)
+ {
+ size_t dacl_size = sizeof(ACL), ace_count = 0;
+ const ACE_HEADER *parent_ace;
+ const SID *user, *group;
+ ACE_HEADER *ace;
+ char *ptr;
+ ULONG i;
+
+ /* Calculate the size of the DACL */
+ parent_ace = (const ACE_HEADER *)(parent_dacl + 1);
+ for (i = 0; i < parent_dacl->AceCount; i++, parent_ace = ace_next( parent_ace ))
+ {
+ int multiplier = 1;
+
+ if (!(parent_ace->AceFlags & inheritance_mask)) continue;
+
+ ace_count += multiplier;
+ dacl_size += multiplier * parent_ace->AceSize;
+ }
+ if(!ace_count) return sd; /* No inheritance */
+
+ /* Fill in the security descriptor so that it is compatible with our DACL */
+ user = (const SID *)(parent_sd + 1);
+ group = (const SID *)((char *)(parent_sd + 1) + parent_sd->owner_len);
+ sd = mem_alloc( sizeof(struct security_descriptor) + security_sid_len( user )
+ + security_sid_len( group ) + dacl_size );
+ if (!sd) return sd;
+ sd->control = SE_DACL_PRESENT;
+ sd->owner_len = parent_sd->owner_len;
+ sd->group_len = parent_sd->group_len;
+ sd->sacl_len = 0;
+ sd->dacl_len = dacl_size;
+ ptr = (char *)(sd + 1);
+ memcpy( ptr, user, sd->owner_len );
+ ptr += sd->owner_len;
+ memcpy( ptr, group, sd->group_len );
+ ptr += sd->group_len;
+ dacl = (ACL *)ptr;
+ dacl->AclRevision = ACL_REVISION;
+ dacl->Sbz1 = 0;
+ dacl->AclSize = dacl_size;
+ dacl->AceCount = ace_count;
+ dacl->Sbz2 = 0;
+ ace = (ACE_HEADER *)(dacl + 1);
+
+ /* Build the new DACL, inheriting from the parent's information */
+ parent_ace = (const ACE_HEADER *)(parent_dacl + 1);
+ for (i = 0; i < parent_dacl->AceCount; i++, parent_ace = ace_next( parent_ace ))
+ {
+ DWORD flags = parent_ace->AceFlags;
+
+ if (!(flags & inheritance_mask)) continue;
+
+ ace->AceType = parent_ace->AceType;
+ if(is_dir && (flags & CONTAINER_INHERIT_ACE))
+ flags &= ~INHERIT_ONLY_ACE;
+ else if(!is_dir && (flags & OBJECT_INHERIT_ACE))
+ flags &= ~INHERIT_ONLY_ACE;
+ else if(is_dir && (flags & OBJECT_INHERIT_ACE))
+ flags |= INHERIT_ONLY_ACE;
+ if(is_dir)
+ ace->AceFlags = flags | INHERITED_ACE;
+ else
+ ace->AceFlags = (parent_ace->AceFlags & ~inheritance_mask) | INHERITED_ACE;
+ ace->AceSize = parent_ace->AceSize;
+ memcpy( ace + 1, parent_ace + 1, parent_ace->AceSize - sizeof(ACE_HEADER));
+ ace = (ACE_HEADER *)ace_next( ace );
+ }
+ }
+ return sd;
+}
+
+static struct security_descriptor *file_get_parent_sd( struct fd *root, char *parent_name,
+ int is_dir )
+{
+ struct security_descriptor *sd = NULL;
+ int len = strlen( parent_name );
+ mode_t parent_mode = 0555;
+ struct fd *parent_fd;
+ char *slash;
+
+ /* Even if the file is a directory we need its parent, so skip any terminating slash */
+ if (parent_name[len-1] == '/')
+ parent_name[len-1] = 0;
+ /* Find the last slash in the filename and terminate the name there */
+ slash = strrchr(parent_name, '/');
+ if (slash)
+ slash[0] = 0;
+ else
+ parent_name[0] = 0;
+
+ parent_fd = open_fd( root, parent_name, O_NONBLOCK | O_LARGEFILE, &parent_mode,
+ READ_CONTROL|ACCESS_SYSTEM_SECURITY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN_FOR_BACKUP_INTENT );
+ if(parent_fd)
+ {
+ struct object *obj;
+
+ if ((obj = create_file_obj( parent_fd, READ_CONTROL|ACCESS_SYSTEM_SECURITY, parent_mode )))
+ {
+ struct file *file = (struct file *)obj;
+ struct fd *fd;
+
+ fd = file_get_fd( obj );
+ if (fd)
+ {
+ sd = file_get_acls( obj, fd, &file->mode, &file->uid, FALSE );
+ release_object( fd );
+ }
+ if (sd)
+ sd = inherit_sd( sd, is_dir );
+ release_object( obj );
+ }
+ release_object( parent_fd );
+ }
+ return sd;
+}
+
static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len,
unsigned int access, unsigned int sharing, int create,
unsigned int options, unsigned int attrs,
const struct security_descriptor *sd )
{
+ struct security_descriptor *temp_sd = NULL;
struct object *obj = NULL;
struct fd *fd;
int flags;
@@ -275,6 +405,15 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
default: set_error( STATUS_INVALID_PARAMETER ); goto done;
}
+ if (!sd && (create == FILE_CREATE || create == FILE_OVERWRITE_IF))
+ {
+ /* Note: inheritance of security descriptors only occurs on creation when sd is NULL */
+ char *child_name = strndup( nameptr, len );
+
+ sd = temp_sd = file_get_parent_sd( root, child_name, options & FILE_DIRECTORY_FILE );
+ free(child_name);
+ }
+
if (sd)
{
const SID *owner = sd_get_owner( sd );
@@ -315,6 +454,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
release_object( fd );
done:
+ free( temp_sd );
free( name );
return obj;
}
@@ -659,7 +799,7 @@ void convert_generic_sd( struct security_descriptor *sd )
}
struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mode_t *mode,
- uid_t *uid )
+ uid_t *uid, int convert_generic )
{
int unix_fd = get_unix_fd( fd );
struct security_descriptor *sd;
@@ -677,7 +817,7 @@ struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mo
user = security_unix_uid_to_sid( st.st_uid );
group = token_get_primary_group( current->process->token );
sd = get_xattr_acls( unix_fd, user, group );
- if (sd) convert_generic_sd( sd );
+ if (sd && convert_generic) convert_generic_sd( sd );
if (!sd) sd = mode_to_sd( st.st_mode, user, group);
if (!sd) return obj->sd;
@@ -697,7 +837,7 @@ static struct security_descriptor *file_get_sd( struct object *obj )
assert( obj->ops == &file_ops );
fd = file_get_fd( obj );
- sd = file_get_acls( obj, fd, &file->mode, &file->uid );
+ sd = file_get_acls( obj, fd, &file->mode, &file->uid, TRUE );
release_object( fd );
return sd;
}
diff --git a/server/file.h b/server/file.h
index 89b5888..0905fbb 100644
--- a/server/file.h
+++ b/server/file.h
@@ -125,7 +125,7 @@ extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner
extern int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
unsigned int set_info );
extern struct security_descriptor *file_get_acls( struct object *obj, struct fd *fd, mode_t *mode,
- uid_t *uid );
+ uid_t *uid, int convert_generic );
/* file mapping functions */
--
1.7.9.5

View File

@ -0,0 +1,309 @@
From d944c7710c60e2cc1599bd6da75a41f876d647af Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 7 Feb 2014 16:03:46 -0700
Subject: server: Inherit security attributes from parent directories on
SetSecurityInfo.
---
dlls/advapi32/tests/security.c | 68 +++++++++++++++++++++++
include/winnt.h | 7 ++-
server/fd.c | 13 ++++-
server/file.c | 120 +++++++++++++++++++++++++++++++++++++++-
server/file.h | 1 +
5 files changed, 203 insertions(+), 6 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 1bf3185..302f6b9 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3350,6 +3350,74 @@ static void test_GetNamedSecurityInfoA(void)
"Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask);
}
LocalFree(pSD);
+ CloseHandle(hTemp);
+
+ /* Create security descriptor with no inheritance and test that it comes back the same */
+ pSD = &sd;
+ pDacl = HeapAlloc(GetProcessHeap(), 0, 100);
+ InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
+ pCreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size);
+ bret = InitializeAcl(pDacl, 100, ACL_REVISION);
+ ok(bret, "Failed to initialize ACL.\n");
+ bret = pAddAccessAllowedAceEx(pDacl, ACL_REVISION, 0, GENERIC_ALL, user_sid);
+ ok(bret, "Failed to add Current User to ACL.\n");
+ bret = pAddAccessAllowedAceEx(pDacl, ACL_REVISION, 0, GENERIC_ALL, admin_sid);
+ ok(bret, "Failed to add Administrator Group to ACL.\n");
+ bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE);
+ ok(bret, "Failed to add ACL to security desciptor.\n");
+ GetTempFileNameA(".", "foo", 0, tmpfile);
+ hTemp = CreateFileA(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ SetLastError(0xdeadbeef);
+ error = pSetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION,
+ NULL, NULL, pDacl, NULL);
+ HeapFree(GetProcessHeap(), 0, pDacl);
+ if (error != ERROR_SUCCESS && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+ {
+ win_skip("SetNamedSecurityInfoA is not implemented\n");
+ HeapFree(GetProcessHeap(), 0, user);
+ CloseHandle(hTemp);
+ return;
+ }
+ ok(!error, "SetNamedSecurityInfoA failed with error %d\n", error);
+ SetLastError(0xdeadbeef);
+ error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+ NULL, NULL, &pDacl, NULL, &pSD);
+ if (error != ERROR_SUCCESS && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+ {
+ win_skip("GetNamedSecurityInfoA is not implemented\n");
+ HeapFree(GetProcessHeap(), 0, user);
+ CloseHandle(hTemp);
+ return;
+ }
+ ok(!error, "GetNamedSecurityInfo failed with error %d\n", error);
+
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ ok(bret, "GetAclInformation failed\n");
+ if (acl_size.AceCount > 0)
+ {
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
+ ok(bret, "Failed to get Current User ACE.\n");
+ bret = EqualSid(&ace->SidStart, user_sid);
+ ok(bret, "Current User ACE != Current User SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == 0,
+ "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ if (acl_size.AceCount > 1)
+ {
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
+ ok(bret, "Failed to get Administators Group ACE.\n");
+ bret = EqualSid(&ace->SidStart, admin_sid);
+ ok(bret || broken(!bret) /* win2k */, "Administators Group ACE != Administators Group SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == 0,
+ "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff || broken(ace->Mask == GENERIC_ALL) /* win2k */,
+ "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask);
+ }
+ LocalFree(pSD);
HeapFree(GetProcessHeap(), 0, user);
CloseHandle(hTemp);
diff --git a/include/winnt.h b/include/winnt.h
index f785d33..5151638 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -5054,14 +5054,15 @@ typedef struct _TAPE_GET_MEDIA_PARAMETERS {
BOOLEAN WriteProtected;
} TAPE_GET_MEDIA_PARAMETERS, *PTAPE_GET_MEDIA_PARAMETERS;
-/* ----------------------------- begin registry ----------------------------- */
-
-/* Registry security values */
#define OWNER_SECURITY_INFORMATION 0x00000001
#define GROUP_SECURITY_INFORMATION 0x00000002
#define DACL_SECURITY_INFORMATION 0x00000004
#define SACL_SECURITY_INFORMATION 0x00000008
+#define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000
+/* ----------------------------- begin registry ----------------------------- */
+
+/* Registry security values */
#define REG_OPTION_RESERVED 0x00000000
#define REG_OPTION_NON_VOLATILE 0x00000000
#define REG_OPTION_VOLATILE 0x00000001
diff --git a/server/fd.c b/server/fd.c
index fa8874c..9e6b9a8 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1629,6 +1629,16 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
return fd;
}
+char *fd_get_unix_name( struct fd *obj )
+{
+ char *unix_name;
+
+ unix_name = mem_alloc( strlen(obj->unix_name) + 1 );
+ if (!unix_name) return NULL;
+ strcpy( unix_name, obj->unix_name );
+ return unix_name;
+}
+
/* duplicate an fd object for a different user */
struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, unsigned int options )
{
@@ -1642,8 +1652,7 @@ struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sha
if (orig->unix_name)
{
- if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed;
- strcpy( fd->unix_name, orig->unix_name );
+ if (!(fd->unix_name = fd_get_unix_name( orig ))) goto failed;
}
if (orig->inode)
diff --git a/server/file.c b/server/file.c
index c115ff7..f6abc8c 100644
--- a/server/file.c
+++ b/server/file.c
@@ -324,6 +324,105 @@ struct security_descriptor *inherit_sd( const struct security_descriptor *parent
return sd;
}
+struct security_descriptor *file_combine_sds( const struct security_descriptor *parent_sd,
+ const struct security_descriptor *child_sd )
+{
+ size_t dacl_size = sizeof(ACL), ace_count = 0;
+ const struct security_descriptor *old_sd;
+ struct security_descriptor *sd = NULL;
+ const ACL *child_dacl, *parent_dacl;
+ int child_present, parent_present;
+ const SID *user, *group;
+ const ACE_HEADER *old_ace;
+ ACE_HEADER *ace;
+ ACL *dacl;
+ char *ptr;
+ ULONG i;
+
+ child_dacl = sd_get_dacl( child_sd, &child_present );
+ if (child_present && child_dacl)
+ {
+ old_ace = (const ACE_HEADER *)(child_dacl + 1);
+ for (i = 0; i < child_dacl->AceCount; i++, old_ace = ace_next( old_ace ))
+ {
+ ace_count++;
+ dacl_size += sizeof(ACE_HEADER) + old_ace->AceSize;
+ }
+ }
+
+ parent_dacl = sd_get_dacl( parent_sd, &parent_present );
+ if (parent_present && parent_dacl)
+ {
+ old_ace = (const ACE_HEADER *)(parent_dacl + 1);
+ for (i = 0; i < parent_dacl->AceCount; i++, old_ace = ace_next( old_ace ))
+ {
+ ace_count++;
+ dacl_size += sizeof(ACE_HEADER) + old_ace->AceSize;
+ }
+ }
+
+ if(!ace_count) return sd; /* No inheritance */
+
+ if (child_present && child_dacl)
+ old_sd = child_sd;
+ else
+ old_sd = parent_sd;
+
+ /* Fill in the security descriptor so that it is compatible with our DACL */
+ user = (const SID *)(old_sd + 1);
+ group = (const SID *)((char *)(old_sd + 1) + old_sd->owner_len);
+ sd = mem_alloc( sizeof(struct security_descriptor) + security_sid_len( user )
+ + security_sid_len( group ) + dacl_size );
+ if (!sd) return sd;
+ sd->control = SE_DACL_PRESENT;
+ sd->owner_len = old_sd->owner_len;
+ sd->group_len = old_sd->group_len;
+ sd->sacl_len = 0;
+ sd->dacl_len = dacl_size;
+ ptr = (char *)(sd + 1);
+ memcpy( ptr, user, sd->owner_len );
+ ptr += sd->owner_len;
+ memcpy( ptr, group, sd->group_len );
+ ptr += sd->group_len;
+ dacl = (ACL *)ptr;
+ dacl->AclRevision = ACL_REVISION;
+ dacl->Sbz1 = 0;
+ dacl->AclSize = dacl_size;
+ dacl->AceCount = ace_count;
+ dacl->Sbz2 = 0;
+ ace = (ACE_HEADER *)(dacl + 1);
+
+ if (parent_present && parent_dacl)
+ {
+ /* Build the new DACL, inheriting from the parent's information */
+ old_ace = (const ACE_HEADER *)(parent_dacl + 1);
+ for (i = 0; i < parent_dacl->AceCount; i++, old_ace = ace_next( old_ace ))
+ {
+ ace->AceType = old_ace->AceType;
+ ace->AceFlags = old_ace->AceFlags;
+ ace->AceSize = old_ace->AceSize;
+ memcpy( ace + 1, old_ace + 1, old_ace->AceSize);
+ ace = (ACE_HEADER *)ace_next( ace );
+ }
+ }
+
+ if (child_present && child_dacl)
+ {
+ /* Build the new DACL, inheriting from the child's information */
+ old_ace = (const ACE_HEADER *)(child_dacl + 1);
+ for (i = 0; i < child_dacl->AceCount; i++, old_ace = ace_next( old_ace ))
+ {
+ ace->AceType = old_ace->AceType;
+ ace->AceFlags = old_ace->AceFlags;
+ ace->AceSize = old_ace->AceSize;
+ memcpy( ace + 1, old_ace + 1, old_ace->AceSize);
+ ace = (ACE_HEADER *)ace_next( ace );
+ }
+ }
+
+ return sd;
+}
+
static struct security_descriptor *file_get_parent_sd( struct fd *root, char *parent_name,
int is_dir )
{
@@ -921,16 +1020,35 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
return new_mode & ~denied_mode;
}
-int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
+int file_set_acls( struct object *obj, struct fd *fd, const struct security_descriptor *new_sd,
unsigned int set_info )
{
+ const struct security_descriptor *sd = new_sd;
int unix_fd = get_unix_fd( fd );
+ char *child_name = NULL;
const SID *owner;
struct stat st;
mode_t mode;
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
+ if (!(set_info & PROTECTED_DACL_SECURITY_INFORMATION))
+ {
+ child_name = fd_get_unix_name( fd );
+ if (child_name)
+ {
+ struct security_descriptor *parent_sd;
+
+ parent_sd = file_get_parent_sd( NULL, child_name, S_ISDIR(st.st_mode) );
+ free( child_name );
+ if (parent_sd)
+ {
+ sd = file_combine_sds( parent_sd, new_sd );
+ free( parent_sd );
+ }
+ }
+ }
+
if (set_info & OWNER_SECURITY_INFORMATION)
{
owner = sd_get_owner( sd );
diff --git a/server/file.h b/server/file.h
index 0905fbb..8cbc4cb 100644
--- a/server/file.h
+++ b/server/file.h
@@ -77,6 +77,7 @@ extern void allow_fd_caching( struct fd *fd );
extern void set_fd_signaled( struct fd *fd, int signaled );
extern int is_fd_signaled( struct fd *fd );
+extern char *fd_get_unix_name( struct fd *obj );
extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry );
extern unsigned int default_fd_map_access( struct object *obj, unsigned int access );
extern int default_fd_get_poll_events( struct fd *fd );
--
1.7.9.5

View File

@ -0,0 +1,139 @@
From 14a4e501f57bd10cb55b317ff6f4d45b06c0f0cd Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 7 Feb 2014 16:04:05 -0700
Subject: shell32: Set the default security attributes for user shell folders.
---
dlls/shell32/shellpath.c | 94 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index 875be38..3476a88 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -2169,6 +2169,70 @@ cleanup:
return hr;
}
+PSECURITY_DESCRIPTOR _SHGetUserSecurityDescriptor( void )
+{
+ PSECURITY_DESCRIPTOR sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
+ PACL dacl = HeapAlloc(GetProcessHeap(), 0, 100);
+ PSID admin_sid = NULL, user_sid;
+ TOKEN_USER *user = NULL;
+ BOOL ret = FALSE;
+ DWORD sid_size;
+ HANDLE token;
+
+ if(!sd || !dacl) goto cleanup;
+
+ /* find the user SID */
+ ret = TRUE;
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token))
+ {
+ if (GetLastError() != ERROR_NO_TOKEN) ret = FALSE;
+ else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token)) ret = FALSE;
+ }
+ if (!ret) goto cleanup;
+ sid_size = 0;
+ ret = GetTokenInformation(token, TokenUser, NULL, 0, &sid_size);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto cleanup;
+ user = HeapAlloc(GetProcessHeap(), 0, sid_size);
+ if (!user) goto cleanup;
+ ret = GetTokenInformation(token, TokenUser, user, sid_size, &sid_size);
+ if (!ret) goto cleanup;
+ CloseHandle(token);
+ user_sid = user->User.Sid;
+
+ /* find the administrator group SID */
+ sid_size = 0;
+ ret = CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, NULL, &sid_size);
+ if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto cleanup;
+ admin_sid = HeapAlloc(GetProcessHeap(), 0, sid_size);
+ if(!admin_sid) goto cleanup;
+ ret = CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size);
+ if(!ret) goto cleanup;
+
+ /* build the DACL */
+ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+ if(!ret) goto cleanup;
+ ret = InitializeAcl(dacl, 100, ACL_REVISION);
+ if(!ret) goto cleanup;
+ ret = AddAccessAllowedAceEx(dacl, ACL_REVISION, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE,
+ GENERIC_ALL, user_sid);
+ if(!ret) goto cleanup;
+ ret = AddAccessAllowedAceEx(dacl, ACL_REVISION, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE,
+ GENERIC_ALL, admin_sid);
+ if(!ret) goto cleanup;
+ ret = SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE);
+
+cleanup:
+ HeapFree(GetProcessHeap(), 0, user);
+ HeapFree(GetProcessHeap(), 0, admin_sid);
+ if(!ret)
+ {
+ HeapFree(GetProcessHeap(), 0, dacl);
+ HeapFree(GetProcessHeap(), 0, sd);
+ sd = NULL;
+ }
+ return sd;
+}
+
/*************************************************************************
* SHGetFolderPathAndSubDirW [SHELL32.@]
*/
@@ -2180,6 +2244,8 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */
LPWSTR pszPath) /* [O] converted path */
{
+ SECURITY_ATTRIBUTES sa, *sec = NULL;
+ PSECURITY_DESCRIPTOR sd = NULL;
HRESULT hr;
WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH];
DWORD folder = nFolder & CSIDL_FOLDER_MASK;
@@ -2292,8 +2358,25 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
goto end;
}
+ /* build the appropriate security attributes for the directory */
+ switch (type)
+ {
+ case CSIDL_Type_User:
+ sd = _SHGetUserSecurityDescriptor();
+ break;
+ default:
+ break;
+ }
+ if (sd)
+ {
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = sd;
+ sa.bInheritHandle = TRUE;
+ sec = &sa;
+ }
+
/* create directory/directories */
- ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL);
+ ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, sec);
if (ret && ret != ERROR_ALREADY_EXISTS)
{
ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath));
@@ -2303,6 +2386,15 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath));
end:
+ if (sd)
+ {
+ BOOL present, defaulted;
+ PACL dacl = NULL;
+
+ GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted);
+ HeapFree(GetProcessHeap(), 0, dacl);
+ HeapFree(GetProcessHeap(), 0, sd);
+ }
TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath));
return hr;
}
--
1.7.9.5

View File

@ -1,3 +1,3 @@
Revision: 1
Revision: 2
Author: Erich E. Hoover
Title: Store and return security attributes with extended file attributes.

View File

@ -43,7 +43,7 @@ index a273502..5fa0cd5 100644
+ const char *title;
+} wine_patch_data[] = {
+ { "8a366b6d-8ad6-4581-8aa9-66a03590a57b:1", "Erich E. Hoover", "Implement SIO_ADDRESS_LIST_CHANGE." },
+ { "92938b89-506b-430a-ba50-32de8b286e56:1", "Erich E. Hoover", "Store and return security attributes with extended file attributes." },
+ { "92938b89-506b-430a-ba50-32de8b286e56:2", "Erich E. Hoover", "Store and return security attributes with extended file attributes." },
+ { "9cb0f665-bf7c-485f-89cc-554adcdf8880:1", "Erich E. Hoover", "Allow string comparison with linguistic casing." },
+ { "5d6bb7b5-ec88-4ed3-907d-9ad2173a2f88:1", "Sebastian Lackner", "Enable/disable windows when they are (un)mapped by foreign applications." },
+ { "94186fff-6dbf-44d0-8eb1-2463d1608a0f:1", "Sebastian Lackner", "Update gl_drawable for embedded windows." },