Avoid duplicate aces
[ira/wip.git] / source3 / smbd / posix_acls.c
index e9b581efe82a44e67e3bfb86886f44fd9f2ffbe8..39fb32f654c6f34013d0e7f20681e64919bd024f 100644 (file)
@@ -3,6 +3,7 @@
    SMB NT Security Descriptor / Unix permission conversion.
    Copyright (C) Jeremy Allison 1994-2009.
    Copyright (C) Andreas Gruenbacher 2002.
+   Copyright (C) Simo Sorce <idra@samba.org> 2009.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -719,12 +720,12 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
  Count a linked list of canonical ACE entries.
 ****************************************************************************/
 
-static size_t count_canon_ace_list( canon_ace *list_head )
+static size_t count_canon_ace_list( canon_ace *l_head )
 {
        size_t count = 0;
        canon_ace *ace;
 
-       for (ace = list_head; ace; ace = ace->next)
+       for (ace = l_head; ace; ace = ace->next)
                count++;
 
        return count;
@@ -734,13 +735,13 @@ static size_t count_canon_ace_list( canon_ace *list_head )
  Free a linked list of canonical ACE entries.
 ****************************************************************************/
 
-static void free_canon_ace_list( canon_ace *list_head )
+static void free_canon_ace_list( canon_ace *l_head )
 {
        canon_ace *list, *next;
 
-       for (list = list_head; list; list = next) {
+       for (list = l_head; list; list = next) {
                next = list->next;
-               DLIST_REMOVE(list_head, list);
+               DLIST_REMOVE(l_head, list);
                SAFE_FREE(list);
        }
 }
@@ -916,7 +917,7 @@ static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
 
 static void merge_aces( canon_ace **pp_list_head )
 {
-       canon_ace *list_head = *pp_list_head;
+       canon_ace *l_head = *pp_list_head;
        canon_ace *curr_ace_outer;
        canon_ace *curr_ace_outer_next;
 
@@ -925,7 +926,7 @@ static void merge_aces( canon_ace **pp_list_head )
         * with identical SIDs.
         */
 
-       for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+       for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
                canon_ace *curr_ace;
                canon_ace *curr_ace_next;
 
@@ -947,7 +948,7 @@ static void merge_aces( canon_ace **pp_list_head )
                                /* Merge two allow or two deny ACE's. */
 
                                curr_ace_outer->perms |= curr_ace->perms;
-                               DLIST_REMOVE(list_head, curr_ace);
+                               DLIST_REMOVE(l_head, curr_ace);
                                SAFE_FREE(curr_ace);
                                curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
                        }
@@ -960,7 +961,7 @@ static void merge_aces( canon_ace **pp_list_head )
         * appears only once in the list.
         */
 
-       for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+       for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
                canon_ace *curr_ace;
                canon_ace *curr_ace_next;
 
@@ -992,7 +993,7 @@ static void merge_aces( canon_ace **pp_list_head )
                                         * The deny overrides the allow. Remove the allow.
                                         */
 
-                                       DLIST_REMOVE(list_head, curr_ace);
+                                       DLIST_REMOVE(l_head, curr_ace);
                                        SAFE_FREE(curr_ace);
                                        curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
 
@@ -1008,7 +1009,7 @@ static void merge_aces( canon_ace **pp_list_head )
                                         * before we can get to an allow ace.
                                         */
 
-                                       DLIST_REMOVE(list_head, curr_ace_outer);
+                                       DLIST_REMOVE(l_head, curr_ace_outer);
                                        SAFE_FREE(curr_ace_outer);
                                        break;
                                }
@@ -1019,7 +1020,7 @@ static void merge_aces( canon_ace **pp_list_head )
 
        /* We may have modified the list. */
 
-       *pp_list_head = list_head;
+       *pp_list_head = l_head;
 }
 
 /****************************************************************************
@@ -2305,12 +2306,12 @@ static bool unpack_canon_ace(files_struct *fsp,
 
 static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
 {
-       canon_ace *list_head = *pp_list_head;
+       canon_ace *l_head = *pp_list_head;
        canon_ace *owner_ace = NULL;
        canon_ace *other_ace = NULL;
        canon_ace *ace = NULL;
 
-       for (ace = list_head; ace; ace = ace->next) {
+       for (ace = l_head; ace; ace = ace->next) {
                if (ace->type == SMB_ACL_USER_OBJ)
                        owner_ace = ace;
                else if (ace->type == SMB_ACL_OTHER) {
@@ -2331,16 +2332,16 @@ static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
         */
 
        if (owner_ace) {
-               DLIST_PROMOTE(list_head, owner_ace);
+               DLIST_PROMOTE(l_head, owner_ace);
        }
 
        if (other_ace) {
-               DLIST_DEMOTE(list_head, other_ace, canon_ace *);
+               DLIST_DEMOTE(l_head, other_ace, canon_ace *);
        }
 
        /* We have probably changed the head of the list. */
 
-       *pp_list_head = list_head;
+       *pp_list_head = l_head;
 }
 
 /****************************************************************************
@@ -2353,7 +2354,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                                   const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
 {
        mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
-       canon_ace *list_head = NULL;
+       canon_ace *l_head = NULL;
        canon_ace *ace = NULL;
        canon_ace *next_ace = NULL;
        int entry_id = SMB_ACL_FIRST_ENTRY;
@@ -2457,14 +2458,14 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                ace->owner_type = owner_type;
                ace->ace_flags = get_pai_flags(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
 
-               DLIST_ADD(list_head, ace);
+               DLIST_ADD(l_head, ace);
        }
 
        /*
         * This next call will ensure we have at least a user/group/world set.
         */
 
-       if (!ensure_canon_entry_valid(&list_head, conn->params,
+       if (!ensure_canon_entry_valid(&l_head, conn->params,
                                      S_ISDIR(psbuf->st_mode), powner, pgroup,
                                      psbuf, False))
                goto fail;
@@ -2476,7 +2477,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
 
        DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
 
-       for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
+       for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
                next_ace = ace->next;
 
                /* Masks are only applied to entries other than USER_OBJ and OTHER. */
@@ -2484,7 +2485,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                        ace->perms &= acl_mask;
 
                if (ace->perms == 0) {
-                       DLIST_PROMOTE(list_head, ace);
+                       DLIST_PROMOTE(l_head, ace);
                }
 
                if( DEBUGLVL( 10 ) ) {
@@ -2492,15 +2493,15 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                }
        }
 
-       arrange_posix_perms(fname,&list_head );
+       arrange_posix_perms(fname,&l_head );
 
-       print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
+       print_canon_ace_list( "canonicalise_acl: ace entries after arrange", l_head );
 
-       return list_head;
+       return l_head;
 
   fail:
 
-       free_canon_ace_list(list_head);
+       free_canon_ace_list(l_head);
        return NULL;
 }
 
@@ -2972,6 +2973,42 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
        return num_aces;
 }
 
+/*
+ * Add or Replace ACE entry.
+ * In some cases we need to add a specific ACE for compatibility reasons.
+ * When doing that we must make sure we are not actually creating a duplicate
+ * entry. So we need to search whether an ACE entry already exist and eventually
+ * replacce the access mask, or add a completely new entry if none was found.
+ *
+ * This function assumes the array has enough space to add a new entry without
+ * any reallocation of memory.
+ */
+
+static void add_or_replace_ace(SEC_ACE *nt_ace_list, size_t *num_aces,
+                               const DOM_SID *sid, enum security_ace_type type,
+                               uint32_t mask, uint8_t flags)
+{
+       int i;
+
+       /* first search for a duplicate */
+       for (i = 0; i < *num_aces; i++) {
+               if (sid_equal(&nt_ace_list[i].trustee, sid) &&
+                   (nt_ace_list[i].flags == flags)) break;
+       }
+
+       if (i < *num_aces) { /* found */
+               nt_ace_list[i].type = type;
+               nt_ace_list[i].access_mask = mask;
+               DEBUG(10, ("Replacing ACE %d with SID %s and flags %02x\n",
+                          i, sid_string_dbg(sid), flags));
+               return;
+       }
+
+       /* not found, append it */
+       init_sec_ace(&nt_ace_list[(*num_aces)++], sid, type, mask, flags);
+}
+
+
 /****************************************************************************
  Reply to query a security descriptor from an fsp. If it succeeds it allocates
  the space for the return elements and returns the size needed to return the
@@ -3132,10 +3169,10 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        /* The User must have access to a profile share - even
                         * if we can't map the SID. */
                        if (lp_profile_acls(SNUM(conn))) {
-                               init_sec_ace(&nt_ace_list[num_aces++],
-                                               &global_sid_Builtin_Users,
-                                               SEC_ACE_TYPE_ACCESS_ALLOWED,
-                                               FILE_GENERIC_ALL, 0);
+                               add_or_replace_ace(nt_ace_list, &num_aces,
+                                                  &global_sid_Builtin_Users,
+                                                  SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                                  FILE_GENERIC_ALL, 0);
                        }
 
                        for (ace = dir_ace; ace != NULL; ace = ace->next) {
@@ -3156,9 +3193,13 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        /* The User must have access to a profile share - even
                         * if we can't map the SID. */
                        if (lp_profile_acls(SNUM(conn))) {
-                               init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_ALL,
-                                               SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
-                                               SEC_ACE_FLAG_INHERIT_ONLY|0);
+                               add_or_replace_ace(nt_ace_list, &num_aces,
+                                               &global_sid_Builtin_Users,
+                                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                               FILE_GENERIC_ALL,
+                                               SEC_ACE_FLAG_OBJECT_INHERIT |
+                                               SEC_ACE_FLAG_CONTAINER_INHERIT |
+                                               SEC_ACE_FLAG_INHERIT_ONLY);
                        }
 
                        /*