The branch, master has been updated
via 8995d3d... Fix bug 6878 - Cannot change ACL's inherit flag. Based
on a patch submitted by Tsukasa Hamano <[email protected]>, this is a change
in the POSIX ACL mapping to deal with the lossy mapping for directory ACE
entries:
from b11e11a... mount.cifs: get rid of CONST_DISCARD
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 8995d3d813978a00b50f33943c60784ddfe308bf
Author: Jeremy Allison <[email protected]>
Date: Wed Nov 11 12:17:47 2009 -0800
Fix bug 6878 - Cannot change ACL's inherit flag.
Based on a patch submitted by Tsukasa Hamano <[email protected]>,
this is a change in the POSIX ACL mapping to deal with the lossy
mapping for directory ACE entries:
We have a lossy mapping: directory ACE entries
CREATOR_OWNER ------\
(map to) +---> SMB_ACL_USER_OBJ
owning sid ------/
CREATOR_GROUP ------\
(map to) +---> SMB_ACL_GROUP_OBJ
primary group sid --/
on set. And on read of a directory ACL
SMB_ACL_USER_OBJ ----> CREATOR_OWNER
SMB_ACL_GROUP_OBJ ---> CREATOR_GROUP.
Deal with this on set by duplicating
owning sid and primary group sid ACE
entries into the directory ACL.
Jeremy.
-----------------------------------------------------------------------
Summary of changes:
source3/smbd/posix_acls.c | 152 ++++++++++++++++++++++++++++++++-------------
1 files changed, 108 insertions(+), 44 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index ae36492..26e609f 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -913,33 +913,12 @@ void create_file_sids(const SMB_STRUCT_STAT *psbuf,
DOM_SID *powner_sid, DOM_SID
}
/****************************************************************************
- Is the identity in two ACEs equal ? Check both SID and uid/gid.
-****************************************************************************/
-
-static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
-{
- if (sid_equal(&ace1->trustee, &ace2->trustee)) {
- return True;
- }
- if (ace1->owner_type == ace2->owner_type) {
- if (ace1->owner_type == UID_ACE &&
- ace1->unix_ug.uid == ace2->unix_ug.uid) {
- return True;
- } else if (ace1->owner_type == GID_ACE &&
- ace1->unix_ug.gid == ace2->unix_ug.gid) {
- return True;
- }
- }
- return False;
-}
-
-/****************************************************************************
Merge aces with a common sid - if both are allow or deny, OR the permissions
together and
delete the second one. If the first is deny, mask the permissions off and
delete the allow
if the permissions become zero, delete the deny if the permissions are non
zero.
****************************************************************************/
-static void merge_aces( canon_ace **pp_list_head )
+static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
{
canon_ace *l_head = *pp_list_head;
canon_ace *curr_ace_outer;
@@ -957,12 +936,24 @@ static void merge_aces( canon_ace **pp_list_head )
curr_ace_outer_next = curr_ace_outer->next; /* Save the link in
case we delete. */
for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace =
curr_ace_next) {
+ bool can_merge = false;
curr_ace_next = curr_ace->next; /* Save the link in
case of delete. */
- if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
- (curr_ace->attr == curr_ace_outer->attr)) {
+ /* For file ACLs we can merge if the SIDs and ALLOW/DENY
+ * types are the same. For directory acls we must also
+ * ensure the POSIX ACL types are the same. */
+
+ if (!dir_acl) {
+ can_merge = (sid_equal(&curr_ace->trustee,
&curr_ace_outer->trustee) &&
+ (curr_ace->attr ==
curr_ace_outer->attr));
+ } else {
+ can_merge = (sid_equal(&curr_ace->trustee,
&curr_ace_outer->trustee) &&
+ (curr_ace->type ==
curr_ace_outer->type) &&
+ (curr_ace->attr ==
curr_ace_outer->attr));
+ }
+ if (can_merge) {
if( DEBUGLVL( 10 )) {
dbgtext("merge_aces: Merging ACE's\n");
print_canon_ace( curr_ace_outer, 0);
@@ -971,7 +962,13 @@ static void merge_aces( canon_ace **pp_list_head )
/* Merge two allow or two deny ACE's. */
+ /* Theoretically we shouldn't merge a dir ACE if
+ * one ACE has the CI flag set, and the other
+ * ACE has the OI flag set, but this is rare
+ * enough we can ignore it. */
+
curr_ace_outer->perms |= curr_ace->perms;
+ curr_ace_outer->ace_flags |=
curr_ace->ace_flags;
DLIST_REMOVE(l_head, curr_ace);
SAFE_FREE(curr_ace);
curr_ace_outer_next = curr_ace_outer->next; /*
We may have deleted the link. */
@@ -1000,7 +997,7 @@ static void merge_aces( canon_ace **pp_list_head )
* we've put on the ACL, we know the deny must be the
first one.
*/
- if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
+ if (sid_equal(&curr_ace->trustee,
&curr_ace_outer->trustee) &&
(curr_ace_outer->attr == DENY_ACE) &&
(curr_ace->attr == ALLOW_ACE)) {
if( DEBUGLVL( 10 )) {
@@ -1525,6 +1522,50 @@ static void check_owning_objs(canon_ace *ace, DOM_SID
*pfile_owner_sid, DOM_SID
}
/****************************************************************************
+ If an ACE entry is SMB_ACL_USER_OBJ and not CREATOR_OWNER, map to
SMB_ACL_USER.
+ If an ACE entry is SMB_ACL_GROUP_OBJ and not CREATOR_GROUP, map to
SMB_ACL_GROUP
+****************************************************************************/
+
+static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
+{
+ /* dir ace must be followings.
+ SMB_ACL_USER_OBJ : trustee(CREATOR_OWNER) -> Posix ACL d:u::perm
+ SMB_ACL_USER : not trustee -> Posix ACL u:user:perm
+ SMB_ACL_USER_OBJ : trustee -> convert to SMB_ACL_USER : trustee
+ Posix ACL u:trustee:perm
+
+ SMB_ACL_GROUP_OBJ: trustee(CREATOR_GROUP) -> Posix ACL d:g::perm
+ SMB_ACL_GROUP : not trustee -> Posix ACL g:group:perm
+ SMB_ACL_GROUP_OBJ: trustee -> convert to SMB_ACL_GROUP : trustee
+ Posix ACL g:trustee:perm
+ */
+
+ if (ace->type == SMB_ACL_USER_OBJ &&
+ !(sid_equal(&ace->trustee, &global_sid_Creator_Owner)))
{
+ canon_ace *dup_ace = dup_canon_ace(ace);
+
+ if (dup_ace == NULL) {
+ return false;
+ }
+ dup_ace->type = SMB_ACL_USER;
+ DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+ }
+
+ if (ace->type == SMB_ACL_GROUP_OBJ &&
+ !(sid_equal(&ace->trustee, &global_sid_Creator_Group)))
{
+ canon_ace *dup_ace = dup_canon_ace(ace);
+
+ if (dup_ace == NULL) {
+ return false;
+ }
+ dup_ace->type = SMB_ACL_GROUP;
+ DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+ }
+
+ return true;
+}
+
+/****************************************************************************
Unpack a SEC_DESC into two canonical ace lists.
****************************************************************************/
@@ -1655,11 +1696,11 @@ static bool create_canon_ace_lists(files_struct *fsp,
/*
* The Creator Owner entry only specifies inheritable
permissions,
* never access permissions. WinNT doesn't always set
the ACE to
- *INHERIT_ONLY, though.
+ * INHERIT_ONLY, though.
*/
- if (nt4_compatible_acls())
- psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
} else if (sid_equal(¤t_ace->trustee,
&global_sid_Creator_Group)) {
current_ace->owner_type = GID_ACE;
current_ace->unix_ug.gid = pst->st_ex_gid;
@@ -1668,10 +1709,9 @@ static bool create_canon_ace_lists(files_struct *fsp,
/*
* The Creator Group entry only specifies inheritable
permissions,
* never access permissions. WinNT doesn't always set
the ACE to
- *INHERIT_ONLY, though.
+ * INHERIT_ONLY, though.
*/
- if (nt4_compatible_acls())
- psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
} else if (sid_to_uid( ¤t_ace->trustee,
¤t_ace->unix_ug.uid)) {
current_ace->owner_type = UID_ACE;
@@ -1768,6 +1808,34 @@ static bool create_canon_ace_lists(files_struct *fsp,
}
/*
+ * We have a lossy mapping: directory ACE
entries
+ * CREATOR_OWNER ------\
+ * (map to) +---> SMB_ACL_USER_OBJ
+ * owning sid ------/
+ *
+ * CREATOR_GROUP ------\
+ * (map to) +---> SMB_ACL_GROUP_OBJ
+ * primary group sid --/
+ *
+ * on set. And on read of a directory ACL
+ *
+ * SMB_ACL_USER_OBJ ----> CREATOR_OWNER
+ * SMB_ACL_GROUP_OBJ ---> CREATOR_GROUP.
+ *
+ * Deal with this on set by duplicating
+ * owning sid and primary group sid ACE
+ * entries into the directory ACL.
+ * Fix from Tsukasa Hamano
<[email protected]>.
+ */
+
+ if (!dup_owning_ace(dir_ace, current_ace)) {
+ DEBUG(0,("create_canon_ace_lists:
malloc fail !\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
+
+ /*
* If this is not an inherit only ACE we need
to add a duplicate
* to the file acl.
*/
@@ -1787,6 +1855,13 @@ static bool create_canon_ace_lists(files_struct *fsp,
* pointer is now owned by the dir_ace
list.
*/
current_ace = dup_ace;
+ /* We've essentially split this ace
into two,
+ * and added the ace with inheritance
request
+ * bits to the directory ACL. Drop
those bits for
+ * the ACE we're adding to the file
list. */
+ current_ace->ace_flags &=
~(SEC_ACE_FLAG_OBJECT_INHERIT|
+
SEC_ACE_FLAG_CONTAINER_INHERIT|
+
SEC_ACE_FLAG_INHERIT_ONLY);
} else {
/*
* We must not free current_ace here as
its
@@ -2277,10 +2352,10 @@ static bool unpack_canon_ace(files_struct *fsp,
*/
print_canon_ace_list( "file ace - before merge", file_ace);
- merge_aces( &file_ace );
+ merge_aces( &file_ace, false);
print_canon_ace_list( "dir ace - before merge", dir_ace);
- merge_aces( &dir_ace );
+ merge_aces( &dir_ace, true);
/*
* NT ACLs are order dependent. Go through the acl lists and
@@ -2446,17 +2521,6 @@ static canon_ace *canonicalise_acl(struct
connection_struct *conn,
DEBUG(0,("canonicalise_acl:
Failed to get uid.\n"));
continue;
}
- /*
- * A SMB_ACL_USER entry for the owner
is shadowed by the
- * SMB_ACL_USER_OBJ entry and Windows
also cannot represent
- * that entry, so we ignore it. We also
don't create such
- * entries out of the blue when setting
ACLs, so a get/set
- * cycle will drop them.
- */
- if (the_acl_type == SMB_ACL_TYPE_ACCESS
&& *puid == psbuf->st_ex_uid) {
-
SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
- continue;
- }
uid_to_sid( &sid, *puid);
unix_ug.uid = *puid;
owner_type = UID_ACE;
--
Samba Shared Repository