diff --git a/patches/02-ACL_Extended_Attributes/0003-server-Store-file-security-attributes-with-extended-.patch b/patches/02-ACL_Extended_Attributes/0003-server-Store-file-security-attributes-with-extended-.patch index cdd1808f..6ab084d2 100644 --- a/patches/02-ACL_Extended_Attributes/0003-server-Store-file-security-attributes-with-extended-.patch +++ b/patches/02-ACL_Extended_Attributes/0003-server-Store-file-security-attributes-with-extended-.patch @@ -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" -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) { diff --git a/patches/02-ACL_Extended_Attributes/0004-server-Store-user-and-group-inside-stored-extended-f.patch b/patches/02-ACL_Extended_Attributes/0004-server-Store-user-and-group-inside-stored-extended-f.patch new file mode 100644 index 00000000..8f773884 --- /dev/null +++ b/patches/02-ACL_Extended_Attributes/0004-server-Store-user-and-group-inside-stored-extended-f.patch @@ -0,0 +1,162 @@ +From ea0c98e71750a0a55273c8cfb4a9c8931d3cf510 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 + diff --git a/patches/02-ACL_Extended_Attributes/0004-server-Retrieve-file-security-attributes-with-extend.patch b/patches/02-ACL_Extended_Attributes/0005-server-Retrieve-file-security-attributes-with-extend.patch similarity index 100% rename from patches/02-ACL_Extended_Attributes/0004-server-Retrieve-file-security-attributes-with-extend.patch rename to patches/02-ACL_Extended_Attributes/0005-server-Retrieve-file-security-attributes-with-extend.patch diff --git a/patches/02-ACL_Extended_Attributes/0005-server-Convert-return-of-file-security-masks-with-ge.patch b/patches/02-ACL_Extended_Attributes/0006-server-Convert-return-of-file-security-masks-with-ge.patch similarity index 100% rename from patches/02-ACL_Extended_Attributes/0005-server-Convert-return-of-file-security-masks-with-ge.patch rename to patches/02-ACL_Extended_Attributes/0006-server-Convert-return-of-file-security-masks-with-ge.patch diff --git a/patches/02-ACL_Extended_Attributes/0006-server-Inherit-security-attributes-from-parent-direc.patch b/patches/02-ACL_Extended_Attributes/0006-server-Inherit-security-attributes-from-parent-direc.patch deleted file mode 100644 index af1ce485..00000000 --- a/patches/02-ACL_Extended_Attributes/0006-server-Inherit-security-attributes-from-parent-direc.patch +++ /dev/null @@ -1,295 +0,0 @@ -From fba93c12801c694d0e1248cd582c9d679e3a246a Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -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 - diff --git a/patches/02-ACL_Extended_Attributes/0007-server-Inherit-security-attributes-from-parent-direc.patch b/patches/02-ACL_Extended_Attributes/0007-server-Inherit-security-attributes-from-parent-direc.patch index 13fa0d29..af1ce485 100644 --- a/patches/02-ACL_Extended_Attributes/0007-server-Inherit-security-attributes-from-parent-direc.patch +++ b/patches/02-ACL_Extended_Attributes/0007-server-Inherit-security-attributes-from-parent-direc.patch @@ -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" -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 diff --git a/patches/02-ACL_Extended_Attributes/0008-server-Inherit-security-attributes-from-parent-direc.patch b/patches/02-ACL_Extended_Attributes/0008-server-Inherit-security-attributes-from-parent-direc.patch new file mode 100644 index 00000000..ff0fe766 --- /dev/null +++ b/patches/02-ACL_Extended_Attributes/0008-server-Inherit-security-attributes-from-parent-direc.patch @@ -0,0 +1,324 @@ +From 04bbc2e2841b01a5a5344bb1f62c94ff84b25350 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 + diff --git a/patches/02-ACL_Extended_Attributes/0008-shell32-Set-the-default-security-attributes-for-user.patch b/patches/02-ACL_Extended_Attributes/0009-shell32-Set-the-default-security-attributes-for-user.patch similarity index 100% rename from patches/02-ACL_Extended_Attributes/0008-shell32-Set-the-default-security-attributes-for-user.patch rename to patches/02-ACL_Extended_Attributes/0009-shell32-Set-the-default-security-attributes-for-user.patch diff --git a/patches/02-ACL_Extended_Attributes/0009-server-Add-compatibility-code-for-handling-the-old-m.patch b/patches/02-ACL_Extended_Attributes/0010-server-Add-compatibility-code-for-handling-the-old-m.patch similarity index 100% rename from patches/02-ACL_Extended_Attributes/0009-server-Add-compatibility-code-for-handling-the-old-m.patch rename to patches/02-ACL_Extended_Attributes/0010-server-Add-compatibility-code-for-handling-the-old-m.patch