mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
Split the storage of the ownership information into a separate patch.
This commit is contained in:
parent
4328f2e964
commit
c35db80eae
@ -1,13 +1,13 @@
|
||||
From 4f9fa356757454feea9c84a51dacbfa39b013503 Mon Sep 17 00:00:00 2001
|
||||
From 4ae376bebffe60ef378e08528d50c1e5723be739 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Fri, 18 Apr 2014 13:58:24 -0600
|
||||
Date: Fri, 18 Apr 2014 15:34:47 -0600
|
||||
Subject: server: Store file security attributes with extended file
|
||||
attributes.
|
||||
|
||||
---
|
||||
configure.ac | 12 ++++++++
|
||||
server/file.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 106 insertions(+), 2 deletions(-)
|
||||
configure.ac | 12 ++++++++++++
|
||||
server/file.c | 31 +++++++++++++++++++++++++++++++
|
||||
2 files changed, 43 insertions(+)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 46602d6..99fcb9b 100644
|
||||
@ -40,7 +40,7 @@ index 46602d6..99fcb9b 100644
|
||||
|
||||
AC_SUBST(dlldir,"\${libdir}/wine")
|
||||
diff --git a/server/file.c b/server/file.c
|
||||
index 1f008ea..b9106a8 100644
|
||||
index 1f008ea..ceb57be 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -32,6 +32,7 @@
|
||||
@ -61,16 +61,15 @@ index 1f008ea..b9106a8 100644
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
@@ -178,11 +182,75 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
|
||||
@@ -178,6 +182,30 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
|
||||
return &file->obj;
|
||||
}
|
||||
|
||||
+void set_xattr_sd( int fd, const struct security_descriptor *sd, const SID *user, const SID *group )
|
||||
+void set_xattr_sd( int fd, const struct security_descriptor *sd )
|
||||
+{
|
||||
+#ifdef HAVE_ATTR_XATTR_H
|
||||
+ char buffer[XATTR_SIZE_MAX], *dst_ptr = &buffer[2], *src_ptr = (char *)sd;
|
||||
+ int present, len, owner_len, group_len;
|
||||
+ struct security_descriptor *dst_sd;
|
||||
+ char buffer[XATTR_SIZE_MAX];
|
||||
+ int present, len;
|
||||
+ const ACL *dacl;
|
||||
+
|
||||
+ /* there's no point in storing the security descriptor if there's no DACL */
|
||||
@ -78,52 +77,14 @@ index 1f008ea..b9106a8 100644
|
||||
+ dacl = sd_get_dacl( sd, &present );
|
||||
+ if (!present || !dacl) return;
|
||||
+
|
||||
+ /* make sure that we always store the ownership information */
|
||||
+ if (!sd->owner_len)
|
||||
+ owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]);
|
||||
+ else
|
||||
+ owner_len = sd->owner_len;
|
||||
+ if (!sd->group_len)
|
||||
+ group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
|
||||
+ else
|
||||
+ group_len = sd->group_len;
|
||||
+ len = 2 + sizeof(struct security_descriptor) + owner_len + group_len + sd->sacl_len
|
||||
+ len = 2 + sizeof(struct security_descriptor) + sd->owner_len + sd->group_len + sd->sacl_len
|
||||
+ + sd->dacl_len;
|
||||
+ if (len > XATTR_SIZE_MAX) return;
|
||||
+
|
||||
+ /* include the descriptor revision and resource manager control bits */
|
||||
+ buffer[0] = SECURITY_DESCRIPTOR_REVISION;
|
||||
+ buffer[1] = 0;
|
||||
+ memcpy( dst_ptr, sd, sizeof(struct security_descriptor) );
|
||||
+ dst_sd = (struct security_descriptor *)dst_ptr;
|
||||
+ src_ptr += sizeof(struct security_descriptor);
|
||||
+ dst_ptr += sizeof(struct security_descriptor);
|
||||
+ dst_sd->owner_len = owner_len;
|
||||
+ dst_sd->group_len = group_len;
|
||||
+ /* copy the appropriate ownership information (explicit or inferred) */
|
||||
+ if (sd->owner_len)
|
||||
+ {
|
||||
+ memcpy( dst_ptr, src_ptr, sd->owner_len );
|
||||
+ src_ptr += sd->owner_len;
|
||||
+ }
|
||||
+ else
|
||||
+ memcpy( dst_ptr, user, owner_len );
|
||||
+ dst_ptr += owner_len;
|
||||
+ if (sd->group_len)
|
||||
+ {
|
||||
+ memcpy( dst_ptr, src_ptr, sd->group_len );
|
||||
+ src_ptr += sd->group_len;
|
||||
+ }
|
||||
+ else
|
||||
+ memcpy( dst_ptr, group, group_len );
|
||||
+ dst_ptr += group_len;
|
||||
+ /* copy the ACL information (explicit only) */
|
||||
+ memcpy( dst_ptr, src_ptr, sd->sacl_len );
|
||||
+ src_ptr += sd->sacl_len;
|
||||
+ dst_ptr += sd->sacl_len;
|
||||
+ memcpy( dst_ptr, src_ptr, sd->dacl_len );
|
||||
+ src_ptr += sd->dacl_len;
|
||||
+ dst_ptr += sd->dacl_len;
|
||||
+ memcpy( &buffer[2], sd, len - 2 );
|
||||
+ fsetxattr( fd, "user.wine.sd", buffer, len, 0 );
|
||||
+#endif
|
||||
+}
|
||||
@ -131,73 +92,19 @@ index 1f008ea..b9106a8 100644
|
||||
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 )
|
||||
{
|
||||
+ const SID *owner = NULL, *group = NULL;
|
||||
struct object *obj = NULL;
|
||||
struct fd *fd;
|
||||
int flags;
|
||||
@@ -213,9 +281,12 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
|
||||
if (sd)
|
||||
{
|
||||
- const SID *owner = sd_get_owner( sd );
|
||||
+ owner = sd_get_owner( sd );
|
||||
if (!owner)
|
||||
owner = token_get_user( current->process->token );
|
||||
+ group = sd_get_group( sd );
|
||||
+ if (!group)
|
||||
+ group = token_get_primary_group( current->process->token );
|
||||
mode = sd_to_mode( sd, owner );
|
||||
}
|
||||
else if (options & FILE_DIRECTORY_FILE)
|
||||
@@ -239,6 +310,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
@@ -239,6 +267,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 );
|
||||
if (!fd) goto done;
|
||||
+ set_xattr_sd( get_unix_fd( fd ), sd, owner, group );
|
||||
+ set_xattr_sd( get_unix_fd( fd ), sd );
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
obj = create_dir_obj( fd, access, mode );
|
||||
@@ -548,7 +620,7 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
unsigned int set_info )
|
||||
{
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
- const SID *owner;
|
||||
+ const SID *owner, *group;
|
||||
struct stat st;
|
||||
mode_t mode;
|
||||
|
||||
@@ -572,6 +644,24 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
else
|
||||
owner = token_get_user( current->process->token );
|
||||
|
||||
+ if (set_info & GROUP_SECURITY_INFORMATION)
|
||||
+ {
|
||||
+ group = sd_get_group( sd );
|
||||
+ if (!group)
|
||||
+ {
|
||||
+ set_error( STATUS_INVALID_SECURITY_DESCR );
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (!obj->sd || !security_equal_sid( group, sd_get_group( obj->sd ) ))
|
||||
+ {
|
||||
+ /* FIXME: get Unix uid and call fchown */
|
||||
+ }
|
||||
+ }
|
||||
+ else if (obj->sd)
|
||||
+ group = sd_get_group( obj->sd );
|
||||
+ else
|
||||
+ group = token_get_primary_group( current->process->token );
|
||||
+
|
||||
/* group and sacl not supported */
|
||||
|
||||
if (set_info & DACL_SECURITY_INFORMATION)
|
||||
@@ -580,6 +670,8 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
@@ -580,6 +609,8 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
|
||||
mode |= sd_to_mode( sd, owner );
|
||||
|
||||
+ set_xattr_sd( unix_fd, sd, owner, group );
|
||||
+ set_xattr_sd( unix_fd, sd );
|
||||
+
|
||||
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
|
||||
{
|
||||
|
@ -0,0 +1,162 @@
|
||||
From ea0c98e71750a0a55273c8cfb4a9c8931d3cf510 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Fri, 18 Apr 2014 15:35:24 -0600
|
||||
Subject: server: Store user and group inside stored extended file attribute
|
||||
information.
|
||||
|
||||
---
|
||||
server/file.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 70 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/server/file.c b/server/file.c
|
||||
index ceb57be..b9106a8 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -182,11 +182,12 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
|
||||
return &file->obj;
|
||||
}
|
||||
|
||||
-void set_xattr_sd( int fd, const struct security_descriptor *sd )
|
||||
+void set_xattr_sd( int fd, const struct security_descriptor *sd, const SID *user, const SID *group )
|
||||
{
|
||||
#ifdef HAVE_ATTR_XATTR_H
|
||||
- char buffer[XATTR_SIZE_MAX];
|
||||
- int present, len;
|
||||
+ char buffer[XATTR_SIZE_MAX], *dst_ptr = &buffer[2], *src_ptr = (char *)sd;
|
||||
+ int present, len, owner_len, group_len;
|
||||
+ struct security_descriptor *dst_sd;
|
||||
const ACL *dacl;
|
||||
|
||||
/* there's no point in storing the security descriptor if there's no DACL */
|
||||
@@ -194,14 +195,52 @@ void set_xattr_sd( int fd, const struct security_descriptor *sd )
|
||||
dacl = sd_get_dacl( sd, &present );
|
||||
if (!present || !dacl) return;
|
||||
|
||||
- len = 2 + sizeof(struct security_descriptor) + sd->owner_len + sd->group_len + sd->sacl_len
|
||||
+ /* make sure that we always store the ownership information */
|
||||
+ if (!sd->owner_len)
|
||||
+ owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]);
|
||||
+ else
|
||||
+ owner_len = sd->owner_len;
|
||||
+ if (!sd->group_len)
|
||||
+ group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
|
||||
+ else
|
||||
+ group_len = sd->group_len;
|
||||
+ len = 2 + sizeof(struct security_descriptor) + owner_len + group_len + sd->sacl_len
|
||||
+ sd->dacl_len;
|
||||
if (len > XATTR_SIZE_MAX) return;
|
||||
|
||||
/* include the descriptor revision and resource manager control bits */
|
||||
buffer[0] = SECURITY_DESCRIPTOR_REVISION;
|
||||
buffer[1] = 0;
|
||||
- memcpy( &buffer[2], sd, len - 2 );
|
||||
+ memcpy( dst_ptr, sd, sizeof(struct security_descriptor) );
|
||||
+ dst_sd = (struct security_descriptor *)dst_ptr;
|
||||
+ src_ptr += sizeof(struct security_descriptor);
|
||||
+ dst_ptr += sizeof(struct security_descriptor);
|
||||
+ dst_sd->owner_len = owner_len;
|
||||
+ dst_sd->group_len = group_len;
|
||||
+ /* copy the appropriate ownership information (explicit or inferred) */
|
||||
+ if (sd->owner_len)
|
||||
+ {
|
||||
+ memcpy( dst_ptr, src_ptr, sd->owner_len );
|
||||
+ src_ptr += sd->owner_len;
|
||||
+ }
|
||||
+ else
|
||||
+ memcpy( dst_ptr, user, owner_len );
|
||||
+ dst_ptr += owner_len;
|
||||
+ if (sd->group_len)
|
||||
+ {
|
||||
+ memcpy( dst_ptr, src_ptr, sd->group_len );
|
||||
+ src_ptr += sd->group_len;
|
||||
+ }
|
||||
+ else
|
||||
+ memcpy( dst_ptr, group, group_len );
|
||||
+ dst_ptr += group_len;
|
||||
+ /* copy the ACL information (explicit only) */
|
||||
+ memcpy( dst_ptr, src_ptr, sd->sacl_len );
|
||||
+ src_ptr += sd->sacl_len;
|
||||
+ dst_ptr += sd->sacl_len;
|
||||
+ memcpy( dst_ptr, src_ptr, sd->dacl_len );
|
||||
+ src_ptr += sd->dacl_len;
|
||||
+ dst_ptr += sd->dacl_len;
|
||||
fsetxattr( fd, "user.wine.sd", buffer, len, 0 );
|
||||
#endif
|
||||
}
|
||||
@@ -211,6 +250,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
unsigned int options, unsigned int attrs,
|
||||
const struct security_descriptor *sd )
|
||||
{
|
||||
+ const SID *owner = NULL, *group = NULL;
|
||||
struct object *obj = NULL;
|
||||
struct fd *fd;
|
||||
int flags;
|
||||
@@ -241,9 +281,12 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
|
||||
if (sd)
|
||||
{
|
||||
- const SID *owner = sd_get_owner( sd );
|
||||
+ owner = sd_get_owner( sd );
|
||||
if (!owner)
|
||||
owner = token_get_user( current->process->token );
|
||||
+ group = sd_get_group( sd );
|
||||
+ if (!group)
|
||||
+ group = token_get_primary_group( current->process->token );
|
||||
mode = sd_to_mode( sd, owner );
|
||||
}
|
||||
else if (options & FILE_DIRECTORY_FILE)
|
||||
@@ -267,7 +310,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 );
|
||||
if (!fd) goto done;
|
||||
- set_xattr_sd( get_unix_fd( fd ), sd );
|
||||
+ set_xattr_sd( get_unix_fd( fd ), sd, owner, group );
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
obj = create_dir_obj( fd, access, mode );
|
||||
@@ -577,7 +620,7 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
unsigned int set_info )
|
||||
{
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
- const SID *owner;
|
||||
+ const SID *owner, *group;
|
||||
struct stat st;
|
||||
mode_t mode;
|
||||
|
||||
@@ -601,6 +644,24 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
else
|
||||
owner = token_get_user( current->process->token );
|
||||
|
||||
+ if (set_info & GROUP_SECURITY_INFORMATION)
|
||||
+ {
|
||||
+ group = sd_get_group( sd );
|
||||
+ if (!group)
|
||||
+ {
|
||||
+ set_error( STATUS_INVALID_SECURITY_DESCR );
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (!obj->sd || !security_equal_sid( group, sd_get_group( obj->sd ) ))
|
||||
+ {
|
||||
+ /* FIXME: get Unix uid and call fchown */
|
||||
+ }
|
||||
+ }
|
||||
+ else if (obj->sd)
|
||||
+ group = sd_get_group( obj->sd );
|
||||
+ else
|
||||
+ group = token_get_primary_group( current->process->token );
|
||||
+
|
||||
/* group and sacl not supported */
|
||||
|
||||
if (set_info & DACL_SECURITY_INFORMATION)
|
||||
@@ -609,7 +670,7 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
|
||||
mode |= sd_to_mode( sd, owner );
|
||||
|
||||
- set_xattr_sd( unix_fd, sd );
|
||||
+ set_xattr_sd( unix_fd, sd, owner, group );
|
||||
|
||||
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
|
||||
{
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -1,295 +0,0 @@
|
||||
From fba93c12801c694d0e1248cd582c9d679e3a246a Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Fri, 18 Apr 2014 14:08:36 -0600
|
||||
Subject: server: Inherit security attributes from parent directories on
|
||||
creation.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 40 +++++++++++-
|
||||
server/change.c | 2 +-
|
||||
server/file.c | 141 +++++++++++++++++++++++++++++++++++++++-
|
||||
server/file.h | 2 +-
|
||||
4 files changed, 179 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 5b7e6a6..68b63a0 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 77c01bb..2cf1cab 100644
|
||||
--- a/server/change.c
|
||||
+++ b/server/change.c
|
||||
@@ -287,7 +287,7 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
|
||||
assert( obj->ops == &dir_ops );
|
||||
|
||||
fd = dir_get_fd( obj );
|
||||
- sd = get_file_sd( obj, fd, &dir->mode, &dir->uid );
|
||||
+ sd = get_file_sd( obj, fd, &dir->mode, &dir->uid, TRUE );
|
||||
release_object( fd );
|
||||
return sd;
|
||||
}
|
||||
diff --git a/server/file.c b/server/file.c
|
||||
index 75f015b..6ce8806 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -245,11 +245,141 @@ void set_xattr_sd( int fd, const struct security_descriptor *sd, const SID *user
|
||||
#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 ))
|
||||
+ {
|
||||
+ if (!(parent_ace->AceFlags & inheritance_mask)) continue;
|
||||
+
|
||||
+ ace_count++;
|
||||
+ dacl_size += 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, const char *child_name,
|
||||
+ int child_len, int is_dir )
|
||||
+{
|
||||
+ char *parent_name = strndup( child_name, child_len );
|
||||
+ 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 );
|
||||
+ free(parent_name);
|
||||
+ 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 = get_file_sd( 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;
|
||||
const SID *owner = NULL, *group = NULL;
|
||||
struct object *obj = NULL;
|
||||
struct fd *fd;
|
||||
@@ -279,6 +409,10 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
default: set_error( STATUS_INVALID_PARAMETER ); goto done;
|
||||
}
|
||||
|
||||
+ /* Note: inheritance of security descriptors only occurs on creation when sd is NULL */
|
||||
+ if (!sd && (create == FILE_CREATE || create == FILE_OVERWRITE_IF))
|
||||
+ sd = temp_sd = file_get_parent_sd( root, nameptr, len, options & FILE_DIRECTORY_FILE );
|
||||
+
|
||||
if (sd)
|
||||
{
|
||||
owner = sd_get_owner( sd );
|
||||
@@ -322,6 +456,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;
|
||||
}
|
||||
@@ -538,7 +673,7 @@ void convert_generic_sd( struct security_descriptor *sd )
|
||||
}
|
||||
|
||||
struct security_descriptor *get_file_sd( 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 stat st;
|
||||
@@ -556,7 +691,7 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode
|
||||
user = security_unix_uid_to_sid( st.st_uid );
|
||||
group = token_get_primary_group( current->process->token );
|
||||
sd = get_xattr_sd( unix_fd );
|
||||
- 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;
|
||||
|
||||
@@ -576,7 +711,7 @@ static struct security_descriptor *file_get_sd( struct object *obj )
|
||||
assert( obj->ops == &file_ops );
|
||||
|
||||
fd = file_get_fd( obj );
|
||||
- sd = get_file_sd( obj, fd, &file->mode, &file->uid );
|
||||
+ sd = get_file_sd( obj, fd, &file->mode, &file->uid, TRUE );
|
||||
release_object( fd );
|
||||
return sd;
|
||||
}
|
||||
diff --git a/server/file.h b/server/file.h
|
||||
index 43a234f..2f537cf 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 set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
|
||||
unsigned int set_info );
|
||||
extern struct security_descriptor *get_file_sd( 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
|
||||
|
@ -1,324 +1,295 @@
|
||||
From 8a71e25b01c3910d022ca5f1c8d54af343190d57 Mon Sep 17 00:00:00 2001
|
||||
From fba93c12801c694d0e1248cd582c9d679e3a246a Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Fri, 18 Apr 2014 14:10:49 -0600
|
||||
Date: Fri, 18 Apr 2014 14:08:36 -0600
|
||||
Subject: server: Inherit security attributes from parent directories on
|
||||
SetSecurityInfo.
|
||||
creation.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 68 ++++++++++++++++++++++
|
||||
include/winnt.h | 7 ++-
|
||||
server/fd.c | 13 ++++-
|
||||
server/file.c | 126 +++++++++++++++++++++++++++++++++++++++-
|
||||
server/file.h | 1 +
|
||||
5 files changed, 207 insertions(+), 8 deletions(-)
|
||||
dlls/advapi32/tests/security.c | 40 +++++++++++-
|
||||
server/change.c | 2 +-
|
||||
server/file.c | 141 +++++++++++++++++++++++++++++++++++++++-
|
||||
server/file.h | 2 +-
|
||||
4 files changed, 179 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 68b63a0..c981c1b 100644
|
||||
index 5b7e6a6..68b63a0 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);
|
||||
@@ -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);
|
||||
}
|
||||
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,
|
||||
|
||||
+ /* 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);
|
||||
+ 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);
|
||||
+
|
||||
+ 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, "Failed to get Current User ACE.\n");
|
||||
+ ok(bret, "Inherited 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(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, "Failed to get Administators Group ACE.\n");
|
||||
+ ok(bret, "Inherited 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);
|
||||
+ 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);
|
||||
+ }
|
||||
+ LocalFree(pSD);
|
||||
+ CloseHandle(hTemp);
|
||||
+
|
||||
done:
|
||||
HeapFree(GetProcessHeap(), 0, user);
|
||||
CloseHandle(hTemp);
|
||||
bret = RemoveDirectoryA(tmpdir);
|
||||
diff --git a/server/change.c b/server/change.c
|
||||
index 77c01bb..2cf1cab 100644
|
||||
--- a/server/change.c
|
||||
+++ b/server/change.c
|
||||
@@ -287,7 +287,7 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
|
||||
assert( obj->ops == &dir_ops );
|
||||
|
||||
diff --git a/include/winnt.h b/include/winnt.h
|
||||
index 3f33c6b..5d2234f 100644
|
||||
--- a/include/winnt.h
|
||||
+++ b/include/winnt.h
|
||||
@@ -5057,14 +5057,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 6ce8806..e29d06b 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -325,6 +325,105 @@ struct security_descriptor *inherit_sd( const struct security_descriptor *parent
|
||||
fd = dir_get_fd( obj );
|
||||
- sd = get_file_sd( obj, fd, &dir->mode, &dir->uid );
|
||||
+ sd = get_file_sd( obj, fd, &dir->mode, &dir->uid, TRUE );
|
||||
release_object( fd );
|
||||
return sd;
|
||||
}
|
||||
diff --git a/server/file.c b/server/file.c
|
||||
index 75f015b..6ce8806 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -245,11 +245,141 @@ void set_xattr_sd( int fd, const struct security_descriptor *sd, const SID *user
|
||||
#endif
|
||||
}
|
||||
|
||||
+struct security_descriptor *file_combine_sds( const struct security_descriptor *parent_sd,
|
||||
+ const struct security_descriptor *child_sd )
|
||||
+struct security_descriptor *inherit_sd( const struct security_descriptor *parent_sd, int is_dir )
|
||||
+{
|
||||
+ size_t dacl_size = sizeof(ACL), ace_count = 0;
|
||||
+ const struct security_descriptor *old_sd;
|
||||
+ DWORD inheritance_mask = INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
|
||||
+ 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;
|
||||
+ const ACL *parent_dacl;
|
||||
+ int present;
|
||||
+ ACL *dacl;
|
||||
+ char *ptr;
|
||||
+ ULONG i;
|
||||
+
|
||||
+ child_dacl = sd_get_dacl( child_sd, &child_present );
|
||||
+ if (child_present && child_dacl)
|
||||
+ parent_dacl = sd_get_dacl( parent_sd, &present );
|
||||
+ if (present && parent_dacl)
|
||||
+ {
|
||||
+ old_ace = (const ACE_HEADER *)(child_dacl + 1);
|
||||
+ for (i = 0; i < child_dacl->AceCount; i++, old_ace = ace_next( old_ace ))
|
||||
+ 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 ))
|
||||
+ {
|
||||
+ if (!(parent_ace->AceFlags & inheritance_mask)) continue;
|
||||
+
|
||||
+ ace_count++;
|
||||
+ dacl_size += sizeof(ACE_HEADER) + old_ace->AceSize;
|
||||
+ dacl_size += parent_ace->AceSize;
|
||||
+ }
|
||||
+ }
|
||||
+ if(!ace_count) return sd; /* No inheritance */
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+ }
|
||||
+ /* 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);
|
||||
+
|
||||
+ 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 ))
|
||||
+ parent_ace = (const ACE_HEADER *)(parent_dacl + 1);
|
||||
+ for (i = 0; i < parent_dacl->AceCount; i++, parent_ace = ace_next( parent_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);
|
||||
+ 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 );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ 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, const char *child_name,
|
||||
int child_len, int is_dir )
|
||||
{
|
||||
@@ -795,16 +894,33 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
|
||||
return new_mode & ~denied_mode;
|
||||
}
|
||||
|
||||
-int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
|
||||
+int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *new_sd,
|
||||
unsigned int set_info )
|
||||
{
|
||||
+ const struct security_descriptor *sd = new_sd;
|
||||
+ struct security_descriptor *parent_sd = NULL;
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
const SID *owner, *group;
|
||||
struct stat st;
|
||||
mode_t mode;
|
||||
+ int ret = 1;
|
||||
|
||||
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
|
||||
|
||||
+ if (!(set_info & PROTECTED_DACL_SECURITY_INFORMATION))
|
||||
+static struct security_descriptor *file_get_parent_sd( struct fd *root, const char *child_name,
|
||||
+ int child_len, int is_dir )
|
||||
+{
|
||||
+ char *parent_name = strndup( child_name, child_len );
|
||||
+ 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 );
|
||||
+ free(parent_name);
|
||||
+ if(parent_fd)
|
||||
+ {
|
||||
+ char *child_name = fd_get_unix_name( fd );
|
||||
+ struct object *obj;
|
||||
+
|
||||
+ if (child_name)
|
||||
+ if ((obj = create_file_obj( parent_fd, READ_CONTROL|ACCESS_SYSTEM_SECURITY, parent_mode )))
|
||||
+ {
|
||||
+ parent_sd = file_get_parent_sd( NULL, child_name, strlen(child_name),
|
||||
+ S_ISDIR(st.st_mode) );
|
||||
+ free( child_name );
|
||||
+ if (parent_sd)
|
||||
+ sd = file_combine_sds( parent_sd, new_sd );
|
||||
+ }
|
||||
+ }
|
||||
+ struct file *file = (struct file *)obj;
|
||||
+ struct fd *fd;
|
||||
+
|
||||
if (set_info & OWNER_SECURITY_INFORMATION)
|
||||
+ fd = file_get_fd( obj );
|
||||
+ if (fd)
|
||||
+ {
|
||||
+ sd = get_file_sd( 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;
|
||||
const SID *owner = NULL, *group = NULL;
|
||||
struct object *obj = NULL;
|
||||
struct fd *fd;
|
||||
@@ -279,6 +409,10 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
|
||||
default: set_error( STATUS_INVALID_PARAMETER ); goto done;
|
||||
}
|
||||
|
||||
+ /* Note: inheritance of security descriptors only occurs on creation when sd is NULL */
|
||||
+ if (!sd && (create == FILE_CREATE || create == FILE_OVERWRITE_IF))
|
||||
+ sd = temp_sd = file_get_parent_sd( root, nameptr, len, options & FILE_DIRECTORY_FILE );
|
||||
+
|
||||
if (sd)
|
||||
{
|
||||
owner = sd_get_owner( sd );
|
||||
@@ -854,10 +970,14 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
- return 0;
|
||||
+ ret = 0;
|
||||
}
|
||||
}
|
||||
- return 1;
|
||||
+
|
||||
+ if (parent_sd)
|
||||
+ free( parent_sd );
|
||||
+
|
||||
+ return ret;
|
||||
@@ -322,6 +456,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;
|
||||
}
|
||||
@@ -538,7 +673,7 @@ void convert_generic_sd( struct security_descriptor *sd )
|
||||
}
|
||||
|
||||
static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
|
||||
struct security_descriptor *get_file_sd( 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 stat st;
|
||||
@@ -556,7 +691,7 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode
|
||||
user = security_unix_uid_to_sid( st.st_uid );
|
||||
group = token_get_primary_group( current->process->token );
|
||||
sd = get_xattr_sd( unix_fd );
|
||||
- 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;
|
||||
|
||||
@@ -576,7 +711,7 @@ static struct security_descriptor *file_get_sd( struct object *obj )
|
||||
assert( obj->ops == &file_ops );
|
||||
|
||||
fd = file_get_fd( obj );
|
||||
- sd = get_file_sd( obj, fd, &file->mode, &file->uid );
|
||||
+ sd = get_file_sd( obj, fd, &file->mode, &file->uid, TRUE );
|
||||
release_object( fd );
|
||||
return sd;
|
||||
}
|
||||
diff --git a/server/file.h b/server/file.h
|
||||
index 2f537cf..fa83001 100644
|
||||
index 43a234f..2f537cf 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 );
|
||||
@@ -125,7 +125,7 @@ extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner
|
||||
extern int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
|
||||
unsigned int set_info );
|
||||
extern struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode,
|
||||
- uid_t *uid );
|
||||
+ uid_t *uid, int convert_generic );
|
||||
|
||||
/* file mapping functions */
|
||||
|
||||
+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
|
||||
|
||||
|
@ -0,0 +1,324 @@
|
||||
From 04bbc2e2841b01a5a5344bb1f62c94ff84b25350 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Fri, 18 Apr 2014 14:10:49 -0600
|
||||
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 | 126 +++++++++++++++++++++++++++++++++++++++-
|
||||
server/file.h | 1 +
|
||||
5 files changed, 207 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 68b63a0..c981c1b 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 3f33c6b..5d2234f 100644
|
||||
--- a/include/winnt.h
|
||||
+++ b/include/winnt.h
|
||||
@@ -5057,14 +5057,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 6ce8806..e29d06b 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -325,6 +325,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, const char *child_name,
|
||||
int child_len, int is_dir )
|
||||
{
|
||||
@@ -795,16 +894,33 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
|
||||
return new_mode & ~denied_mode;
|
||||
}
|
||||
|
||||
-int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *sd,
|
||||
+int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *new_sd,
|
||||
unsigned int set_info )
|
||||
{
|
||||
+ const struct security_descriptor *sd = new_sd;
|
||||
+ struct security_descriptor *parent_sd = NULL;
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
const SID *owner, *group;
|
||||
struct stat st;
|
||||
mode_t mode;
|
||||
+ int ret = 1;
|
||||
|
||||
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
|
||||
|
||||
+ if (!(set_info & PROTECTED_DACL_SECURITY_INFORMATION))
|
||||
+ {
|
||||
+ char *child_name = fd_get_unix_name( fd );
|
||||
+
|
||||
+ if (child_name)
|
||||
+ {
|
||||
+ parent_sd = file_get_parent_sd( NULL, child_name, strlen(child_name),
|
||||
+ S_ISDIR(st.st_mode) );
|
||||
+ free( child_name );
|
||||
+ if (parent_sd)
|
||||
+ sd = file_combine_sds( parent_sd, new_sd );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (set_info & OWNER_SECURITY_INFORMATION)
|
||||
{
|
||||
owner = sd_get_owner( sd );
|
||||
@@ -854,10 +970,14 @@ int set_file_sd( struct object *obj, struct fd *fd, const struct security_descri
|
||||
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
|
||||
{
|
||||
file_set_error();
|
||||
- return 0;
|
||||
+ ret = 0;
|
||||
}
|
||||
}
|
||||
- return 1;
|
||||
+
|
||||
+ if (parent_sd)
|
||||
+ free( parent_sd );
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
|
||||
diff --git a/server/file.h b/server/file.h
|
||||
index 2f537cf..fa83001 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
|
||||
|
Loading…
Reference in New Issue
Block a user