Removed version number from file header.
[kai/samba.git] / source3 / lib / util_seaccess.c
index 52696d2d306eef8e7349b247f5d3b15b4d534538..5a934789e4b879685e916ec3c394e392ceb5a299 100644 (file)
@@ -1,8 +1,8 @@
 /*
-   Unix SMB/Netbios implementation.
-   Version 2.0
+   Unix SMB/CIFS implementation.
    Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
    Copyright (C) Tim Potter 2000.
+   Copyright (C) Re-written by Jeremy Allison 2000.
 
    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
 #include "nterr.h"
 #include "sids.h"
 
-extern int DEBUGLEVEL;
+/**********************************************************************************
+ Check if this ACE has a SID in common with the token.
+**********************************************************************************/
 
-/* Process an access allowed ACE */
-
-static BOOL ace_grant(uint32 mask, uint32 *acc_desired, uint32 *acc_granted)
+static BOOL token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
 {
-       uint32 matches;
-
-       /* If there are any matches in the ACE mask and desired access,
-          turn them off in the desired access and on in the granted
-          mask. */ 
-
-       if (*acc_desired == SEC_RIGHTS_MAXIMUM_ALLOWED) {
-               matches = mask;
-               *acc_desired = mask;
-       } else {
-               matches = mask & *acc_desired;
-       }
+       size_t i;
 
-       if (matches) {
-               *acc_desired = *acc_desired & ~matches;
-               *acc_granted = *acc_granted | matches;
+       for (i = 0; i < token->num_sids; i++) {
+               if (sid_equal(&ace->trustee, &token->user_sids[i]))
+                       return True;
        }
 
-       return *acc_desired == 0;
+       return False;
 }
 
-/* Process an access denied ACE */
+/*********************************************************************************
+ Check an ACE against a SID.  We return the remaining needed permission
+ bits not yet granted. Zero means permission allowed (no more needed bits).
+**********************************************************************************/
 
-static BOOL ace_deny(uint32 mask, uint32 *acc_desired, uint32 *acc_granted)
+static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired, 
+                       NTSTATUS *status)
 {
-       uint32 matches;
+       uint32 mask = ace->info.mask;
 
-       /* If there are any matches in the ACE mask and the desired access,
-          all bits are turned off in the desired and granted mask. */
+       /*
+        * Inherit only is ignored.
+        */
 
-       if (*acc_desired == SEC_RIGHTS_MAXIMUM_ALLOWED) {
-               matches = mask;
-       } else {
-               matches = mask & *acc_desired;
+       if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+               return acc_desired;
        }
 
-       if (matches) {
-               *acc_desired = *acc_granted = 0;
+       /*
+        * If this ACE has no SID in common with the token,
+        * ignore it as it cannot be used to make an access
+        * determination.
+        */
+
+       if (!token_sid_in_ace( token, ace))
+               return acc_desired;     
+
+       switch (ace->type) {
+               case SEC_ACE_TYPE_ACCESS_ALLOWED:
+                       /*
+                        * This is explicitly allowed.
+                        * Remove the bits from the remaining
+                        * access required. Return the remaining
+                        * bits needed.
+                        */
+                       acc_desired &= ~mask;
+                       break;
+               case SEC_ACE_TYPE_ACCESS_DENIED:
+                       /*
+                        * This is explicitly denied.
+                        * If any bits match terminate here,
+                        * we are denied.
+                        */
+                       if (acc_desired & mask) {
+                               *status = NT_STATUS_ACCESS_DENIED;
+                               return 0xFFFFFFFF;
+                       }
+                       break;
+               case SEC_ACE_TYPE_SYSTEM_ALARM:
+               case SEC_ACE_TYPE_SYSTEM_AUDIT:
+                       *status = NT_STATUS_NOT_IMPLEMENTED;
+                       return 0xFFFFFFFF;
+               default:
+                       *status = NT_STATUS_INVALID_PARAMETER;
+                       return 0xFFFFFFFF;
        }
 
-       return *acc_desired == 0;
+       return acc_desired;
 }
 
-/* Check an ACE against a SID.  We return true if the ACE clears all the
-   permission bits in the access desired mask.  This indicates that we have
-   make a decision to deny or allow access and the status is updated
-   accordingly. */
+/*********************************************************************************
+ Maximum access was requested. Calculate the max possible. Fail if it doesn't
+ include other bits requested.
+**********************************************************************************/ 
 
-static BOOL check_ace(SEC_ACE *ace, BOOL is_owner, DOM_SID *sid, 
-                     uint32 *acc_desired, uint32 *acc_granted, 
-                     uint32 *status)
+static BOOL get_max_access( SEC_ACL *the_acl, NT_USER_TOKEN *token, uint32 *granted, 
+                           uint32 desired, 
+                           NTSTATUS *status)
 {
-       uint32 mask = ace->info.mask;
+       uint32 acc_denied = 0;
+       uint32 acc_granted = 0;
+       size_t i;
+       
+       for ( i = 0 ; i < the_acl->num_aces; i++) {
+               SEC_ACE *ace = &the_acl->ace[i];
+               uint32 mask = ace->info.mask;
+
+               if (!token_sid_in_ace( token, ace))
+                       continue;
+
+               switch (ace->type) {
+                       case SEC_ACE_TYPE_ACCESS_ALLOWED:
+                               acc_granted |= (mask & ~acc_denied);
+                               break;
+                       case SEC_ACE_TYPE_ACCESS_DENIED:
+                               acc_denied |= (mask & ~acc_granted);
+                               break;
+                       case SEC_ACE_TYPE_SYSTEM_ALARM:
+                       case SEC_ACE_TYPE_SYSTEM_AUDIT:
+                               *status = NT_STATUS_NOT_IMPLEMENTED;
+                               *granted = 0;
+                               return False;
+                       default:
+                               *status = NT_STATUS_INVALID_PARAMETER;
+                               *granted = 0;
+                               return False;
+               }                           
+       }
 
-       /* Inherit only is ignored */
+       /*
+        * If we were granted no access, or we desired bits that we
+        * didn't get, then deny.
+        */
 
-       if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+       if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
+               *status = NT_STATUS_ACCESS_DENIED;
+               *granted = 0;
                return False;
        }
 
-       /* Some debugging stuff */
+       /*
+        * Return the access we did get.
+        */
 
-       if (DEBUGLEVEL >= 3) {
-               fstring ace_sid_str, sid_str;
-               fstring ace_name, ace_name_dom, name, name_dom;
-               uint8 name_type;
-               
-               sid_to_string(sid_str, sid);
-               sid_to_string(ace_sid_str, &ace->sid);
+       *granted = acc_granted;
+       *status = NT_STATUS_OK;
+       return True;
+}
 
-               if (!lookup_sid(sid, name_dom, name, &name_type)) {
-                       fstrcpy(name_dom, "UNKNOWN");
-                       fstrcpy(name, "UNKNOWN");
-               }
+/* Map generic access rights to object specific rights.  This technique is
+   used to give meaning to assigning read, write, execute and all access to
+   objects.  Each type of object has its own mapping of generic to object
+   specific access rights. */
 
-               if (!lookup_sid(&ace->sid, ace_name_dom, ace_name, 
-                                       &name_type)) {
-                       fstrcpy(ace_name_dom, "UNKNOWN");
-                       fstrcpy(ace_name, "UNKNOWN");
-               }
+void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping)
+{
+       uint32 old_mask = *access_mask;
 
-               DEBUG(3, ("checking %s ACE sid %s (%s%s%s) mask 0x%08x "
-                         "against sid %s (%s%s%s)\n",
-                         (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? 
-                         "allowed" : ((ace->type ==
-                                       SEC_ACE_TYPE_ACCESS_DENIED) ?
-                                      "denied" : "unknown"),
-                         ace_sid_str, ace_name_dom, lp_winbind_separator(),
-                         ace_name, mask, sid_str, name_dom,
-                         lp_winbind_separator(), name));
+       if (*access_mask & GENERIC_READ_ACCESS) {
+               *access_mask &= ~GENERIC_READ_ACCESS;
+               *access_mask |= mapping->generic_read;
        }
 
-       /* Only owner allowed write-owner rights */
-
-       if (!is_owner) {
-               mask &= (~SEC_RIGHTS_WRITE_OWNER);
+       if (*access_mask & GENERIC_WRITE_ACCESS) {
+               *access_mask &= ~GENERIC_WRITE_ACCESS;
+               *access_mask |= mapping->generic_write;
        }
 
-       /* Check the ACE value.  This updates the access_desired and
-          access_granted values appropriately. */
-
-       switch (ace->type) {
-
-               /* Access allowed ACE */
-
-               case SEC_ACE_TYPE_ACCESS_ALLOWED: {
-
-                       /* Everyone - or us */
-
-                       if (sid_equal(&ace->sid, global_sid_everyone) ||
-                           sid_equal(&ace->sid, sid)) {
-
-                               /* Return true if access has been allowed */
-
-                               if (ace_grant(mask, acc_desired, 
-                                             acc_granted)) {
-                                       *status = NT_STATUS_NO_PROBLEMO;
-                                       DEBUG(3, ("access granted by ace\n"));
-                                       return True;
-                               }
-                       }
-
-                       break;
-               }
-
-               /* Access denied ACE */
-
-               case SEC_ACE_TYPE_ACCESS_DENIED: {
-
-                       /* Everyone - or us */
-
-                       if (sid_equal(&ace->sid, global_sid_everyone) ||
-                           sid_equal(&ace->sid, sid)) {
-                               
-                               /* Return false if access has been denied */
-
-                               if (ace_deny(mask, acc_desired, 
-                                            acc_granted)) {
-                                       *status = NT_STATUS_ACCESS_DENIED;
-                                       DEBUG(3, ("access denied by ace\n"));
-                                       return True;
-                               }
-                       }
-
-                       break;
-               }
-
-               /* Unimplemented ACE types.  These are ignored. */
-
-               case SEC_ACE_TYPE_SYSTEM_ALARM:
-               case SEC_ACE_TYPE_SYSTEM_AUDIT: {
-                       *status = NT_STATUS_NOT_IMPLEMENTED;
-                       return False;
-               }
-
-               /* Unknown ACE type */
-
-               default: {
-                       *status = NT_STATUS_INVALID_PARAMETER;
-                       return False;
-               }
+       if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+               *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+               *access_mask |= mapping->generic_execute;
        }
 
-       /* There are still some bits set in the access desired mask that
-          haven't been cleared by an ACE.  More checking is required. */
+       if (*access_mask & GENERIC_ALL_ACCESS) {
+               *access_mask &= ~GENERIC_ALL_ACCESS;
+               *access_mask |= mapping->generic_all;
+       }
 
-       return False;
+       if (old_mask != *access_mask) {
+               DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+                          old_mask, *access_mask));
+       }
 }
 
-/* Check access rights of a user against a security descriptor.  Look at
-   each ACE in the security descriptor until an access denied ACE denies
-   any of the desired rights to the user or any of the users groups, or one
-   or more ACEs explicitly grant all requested access rights.  See
-   "Access-Checking" document in MSDN. */ 
-
-BOOL se_access_check(SEC_DESC *sd, struct current_user *user,
-                    uint32 acc_desired, uint32 *acc_granted, uint32 *status)
+/*****************************************************************************
+ Check access rights of a user against a security descriptor.  Look at
+ each ACE in the security descriptor until an access denied ACE denies
+ any of the desired rights to the user or any of the users groups, or one
+ or more ACEs explicitly grant all requested access rights.  See
+ "Access-Checking" document in MSDN.
+*****************************************************************************/ 
+
+BOOL se_access_check(SEC_DESC *sd, NT_USER_TOKEN *token,
+                    uint32 acc_desired, uint32 *acc_granted, 
+                    NTSTATUS *status)
 {
-       DOM_SID user_sid, group_sid;
-       DOM_SID owner_sid;
-       DOM_SID **group_sids = NULL;
-       int i, j;
-       uint ngroup_sids = 0;
-       SEC_ACL *acl;
-       uint8 check_ace_type;
+       extern NT_USER_TOKEN anonymous_token;
+       size_t i;
+       SEC_ACL *the_acl;
        fstring sid_str;
+       uint32 tmp_acc_desired = acc_desired;
 
        if (!status || !acc_granted)
                return False;
 
-       *status = NT_STATUS_ACCESS_DENIED;
+       if (!token)
+               token = &anonymous_token;
+
+       *status = NT_STATUS_OK;
        *acc_granted = 0;
 
+       DEBUG(10,("se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s.\n",
+                (unsigned int)acc_desired, (unsigned int)token->num_sids,
+               sid_to_string(sid_str, &token->user_sids[0])));
+
        /*
         * No security descriptor or security descriptor with no DACL
         * present allows all access.
         */
 
+       /* ACL must have something in it */
+
        if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
-               *status = NT_STATUS_NOPROBLEMO;
+               *status = NT_STATUS_OK;
                *acc_granted = acc_desired;
-               acc_desired = 0;
-               DEBUG(3, ("se_access_check: no sd or blank DACL, access allowed\n"));
-               goto done;
+               DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
+               return True;
        }
 
-       /* If desired access mask is empty then no access is allowed */
+       /* The user sid is the first in the token */
 
-       if (acc_desired == 0) {
-               *status = NT_STATUS_ACCESS_DENIED;
-               *acc_granted = 0;
-               goto done;
-       }
+       DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[PRIMARY_USER_SID_INDEX]) ));
 
-       /* We must know the owner sid */
+       for (i = 1; i < token->num_sids; i++) {
+               DEBUG(3, ("se_access_check: also %s\n",
+                         sid_to_string(sid_str, &token->user_sids[i])));
+       }
 
-       if (sd->owner_sid == NULL) {
-               DEBUG(1, ("no owner for security descriptor\n"));
-               goto done;
+       /* Is the token the owner of the SID ? */
+
+       if (sd->owner_sid) {
+               for (i = 0; i < token->num_sids; i++) {
+                       if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
+                               /*
+                                * The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL.
+                                */
+                               if (tmp_acc_desired & WRITE_DAC_ACCESS)
+                                       tmp_acc_desired &= ~WRITE_DAC_ACCESS;
+                               if (tmp_acc_desired & READ_CONTROL_ACCESS)
+                                       tmp_acc_desired &= ~READ_CONTROL_ACCESS;
+                       }
+               }
        }
 
-       /* Create user sid */
+       the_acl = sd->dacl;
 
-       if (!uid_to_sid(&user_sid, user->uid)) {
-               DEBUG(3, ("could not lookup sid for uid %d\n", user->uid));
-               goto done;
+       if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
+               tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
+               return get_max_access( the_acl, token, acc_granted, tmp_acc_desired, 
+                                      status);
        }
 
-       DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &user_sid) ));
+       for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
+               SEC_ACE *ace = &the_acl->ace[i];
 
-       /* If we're the owner, then we can do anything */
-
-       if (sid_equal(&user_sid, sd->owner_sid)) {
-               *status = NT_STATUS_NOPROBLEMO;
-               *acc_granted = acc_desired;
-               acc_desired = 0;
-               DEBUG(3, ("is owner, access allowed\n"));
+               DEBUG(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n",
+                         (unsigned int)i, ace->type, ace->flags,
+                         sid_to_string(sid_str, &ace->trustee),
+                         (unsigned int) ace->info.mask, 
+                         (unsigned int)tmp_acc_desired ));
 
-                goto done;
+               tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
+               if (NT_STATUS_V(*status)) {
+                       *acc_granted = 0;
+                       DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, get_nt_error_msg(*status)));
+                       return False;
+               }
        }
 
-       /* Create group sid */
+       /*
+        * If there are no more desired permissions left then
+        * access was allowed.
+        */
 
-       if (!gid_to_sid(&group_sid, user->gid)) {
-               DEBUG(3, ("could not lookup sid for gid %d\n", user->gid));
-               goto done;
+       if (tmp_acc_desired == 0) {
+               *acc_granted = acc_desired;
+               *status = NT_STATUS_OK;
+               DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
+               return True;
        }
+               
+       *acc_granted = 0;
+       *status = NT_STATUS_ACCESS_DENIED;
+       DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
+       return False;
+}
 
-       sid_to_string(sid_str, &group_sid);
-       DEBUG(3, ("group sid is %s\n", sid_str));
-
-       /* Create array of group sids */
-
-       add_sid_to_array(&ngroup_sids, &group_sids, &group_sid);
-
-       for (i = 0; i < user->ngroups; i++) {
-               if (user->groups[i] != user->gid) {
-                       if (gid_to_sid(&group_sid, user->groups[i])) {
-
-                               /* If we're a group member then we can also
-                                  do anything */
-
-                               if (sid_equal(&group_sid, sd->grp_sid)) {
-                                       *status = NT_STATUS_NOPROBLEMO;
-                                       *acc_granted = acc_desired;
-                                       acc_desired = 0;
-                                       DEBUG(3, ("is group member "
-                                                 "access allowed\n"));
-
-                                       goto done;
-                               }
+/* Create a child security descriptor using another security descriptor as
+   the parent container.  This child object can either be a container or
+   non-container object. */
 
-                               add_sid_to_array(&ngroup_sids, &group_sids, 
-                                                &group_sid);
+SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, 
+                                     BOOL child_container)
+{
+       SEC_DESC_BUF *sdb;
+       SEC_DESC *sd;
+       SEC_ACL *new_dacl, *the_acl;
+       SEC_ACE *new_ace_list = NULL;
+       int new_ace_list_ndx = 0, i;
+       size_t size;
+
+       /* Currently we only process the dacl when creating the child.  The
+          sacl should also be processed but this is left out as sacls are
+          not implemented in Samba at the moment.*/
+
+       the_acl = parent_ctr->dacl;
+
+       if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces))) 
+               return NULL;
+
+       for (i = 0; the_acl && i < the_acl->num_aces; i++) {
+               SEC_ACE *ace = &the_acl->ace[i];
+               SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
+               uint8 new_flags = 0;
+               BOOL inherit = False;
+               fstring sid_str;
+
+               /* The OBJECT_INHERIT_ACE flag causes the ACE to be
+                  inherited by non-container children objects.  Container
+                  children objects will inherit it as an INHERIT_ONLY
+                  ACE. */
+
+               if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+
+                       if (!child_container) {
+                               new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
                        } else {
-                               DEBUG(3, ("could not lookup sid for gid %d\n", 
-                                         user->gid));
+                               new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
                        }
 
-                       sid_to_string(sid_str, &group_sid);
-                       DEBUG(3, ("supplementary group %s\n", sid_str));
+                       inherit = True;
                }
-       }
-
-        /* ACL must have something in it */
 
-       acl = sd->dacl;
+               /* The CONAINER_INHERIT_ACE flag means all child container
+                  objects will inherit and use the ACE. */
 
-       if (acl == NULL || acl->ace == NULL || acl->num_aces == 0) {
-
-               /* Checks against a NULL ACL succeed and return access
-                       granted = access requested. */
-
-               *status = NT_STATUS_NOPROBLEMO;
-               *acc_granted = acc_desired;
-               acc_desired = 0;
-               DEBUG(3, ("null ace, access allowed\n"));
-
-               goto done;
-       }
-
-       /* Check each ACE in ACL.  We break out of the loop if an ACE is
-          either explicitly denied or explicitly allowed by the
-          check_ace2() function.  We also check the Access Denied ACEs
-          before Access allowed ones as the Platform SDK documentation is
-          unclear whether ACEs in a ACL are necessarily always in this
-          order.  See the discussion on "Order of ACEs in a DACL" in
-          MSDN. */
-
-       check_ace_type = SEC_ACE_TYPE_ACCESS_DENIED;
+               if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+                       if (!child_container) {
+                               inherit = False;
+                       } else {
+                               new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
+                       }
+               }
 
-    check_aces:
+               /* The INHERIT_ONLY_ACE is not used by the se_access_check()
+                  function for the parent container, but is inherited by
+                  all child objects as a normal ACE. */
 
-        for (i = 0; i < acl->num_aces; i++) {
-                SEC_ACE *ace = &acl->ace[i];
-               BOOL is_group_owner;
+               if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+                       /* Move along, nothing to see here */
+               }
 
-               /* Check user sid */
+               /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
+                  is inherited by child objects but not grandchildren
+                  objects.  We clear the object inherit and container
+                  inherit flags in the inherited ACE. */
 
-                if (ace->type == check_ace_type &&
-                   check_ace(ace, False, &user_sid, &acc_desired,
-                             acc_granted, status)) {
-                       goto done;
-                }
+               if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+                       new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
+                                      SEC_ACE_FLAG_CONTAINER_INHERIT);
+               }
 
-                /* Check group sids */
+               /* Add ACE to ACE list */
 
-                for (j = 0; j < ngroup_sids; j++) {
+               if (!inherit)
+                       continue;
 
-                       is_group_owner = sd->grp_sid ? 
-                               sid_equal(group_sids[j], sd->grp_sid) : False;
+               init_sec_access(&new_ace->info, ace->info.mask);
+               init_sec_ace(new_ace, &ace->trustee, ace->type,
+                            new_ace->info, new_flags);
 
-                        if (ace->type == check_ace_type &&
-                           check_ace(ace, is_group_owner, group_sids[j], 
-                                     &acc_desired, acc_granted, status)) {
-                               goto done;
-                        }
-                }
-        }
+               sid_to_string(sid_str, &ace->trustee);
 
-       /* Check access allowed ACEs */
+               DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+                         " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
+                         ace->type, ace->flags, ace->info.mask,
+                         sid_str, new_ace->type, new_ace->flags,
+                         new_ace->info.mask));
 
-       if (check_ace_type == SEC_ACE_TYPE_ACCESS_DENIED) {
-               check_ace_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
-               goto check_aces;
+               new_ace_list_ndx++;
        }
 
- done:
-
-       free_sid_array(ngroup_sids, group_sids);
+       /* Create child security descriptor to return */
        
-       /* If any access desired bits are still on, return access denied
-          and turn off any bits already granted. */
+       new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
 
-       if (acc_desired) {
-               *acc_granted = 0;
-               *status = NT_STATUS_ACCESS_DENIED;
-       }
+       /* Use the existing user and group sids.  I don't think this is
+          correct.  Perhaps the user and group should be passed in as
+          parameters by the caller? */
+
+       sd = make_sec_desc(ctx, SEC_DESC_REVISION,
+                          parent_ctr->owner_sid,
+                          parent_ctr->grp_sid,
+                          parent_ctr->sacl,
+                          new_dacl, &size);
+
+       sdb = make_sec_desc_buf(ctx, size, sd);
 
-       return *status == NT_STATUS_NOPROBLEMO;
+       return sdb;
 }