Click here to Skip to main content
15,949,741 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
I'm using this code snippet to turn inheritance on and off on a pre-determined folder.

I'm also using it to allow permissions to be added explicitly.

Although I believe the code works fine when the folder has only explicit permissions. As soon as I try to add a user/group when there are inherited permissions the code duplicates the inherited permissions so that I now have both inherited and explicit permissions which are identical. The user/group I'm trying to add doesn't get added.
<pre lang="xml">/// <summary>
/// Summary description for fsal
/// </summary>
public class fsAccessLayer
{

    public fsAccessLayer()
    {
        //
        // TODO: Add constructor logic here
        //
    }


    private List<ace> _dacl;                 //the descretionary access control list for the cached path
    private  string _cachedPath = "root";     //the current path that we are working with
    private  bool _isInheriting = false;      //signifies that there are ace's being inherited from the parent
    private  bool _updating = false;          //flag to stop re-entering whilst processing a command

    public  bool IsInheriting
    {
        get { return this._isInheriting; }
        set { this._isInheriting = value; }
    }
    private  string _errorMessage;

    public  string ErrorMessage
    {
        get { return this._errorMessage; }
        set { this._errorMessage = value; }
    }

    public  List<ace> Dacl
    {
        get { return _dacl; }
        set { _dacl = value; }
    }



    public  void AddAce(string user, string access)
    {
        //create the ace object which also builds the authorization rule
        ace entry = new ace();
        entry.UserAccount = user;   //set this before the access so that the rule gets created
        entry.IsInherited = false;
        entry.Access = access;
        _dacl.Add(entry);           //UpdateDacl is responsible for applying to the folders
    }


    /// <summary>
    /// Enumerates the subfolders for the parent folder passed in.
    /// </summary>
    /// <remarks>This method honours the permissions on the folders.
    /// It will not return a folder for which the caller does not have access.</remarks>
    /// <returns>String array of subfolders</returns>
    public  string[] GetDirectories(string folder)
    {
        //DirectoryInfo targetDirectory = null;
        DirectorySecurity dirSecurity = null;
        //AuthorizationRuleCollection dirRules = null;


        string[] folders = null;
        List<string> result = null;
        _errorMessage = null;

        try
        {

            folders = Directory.GetDirectories(folder);
        }
        catch (UnauthorizedAccessException ex)
        {
            _errorMessage = "You are not authorised to access this folder.";
            throw new Exception(_errorMessage, ex);
        }
        catch (DirectoryNotFoundException ex)
        {
            _errorMessage = "Trouble locating the folder. Please try again.";
            throw new Exception(_errorMessage, ex);
        }
        catch (Exception ex)
        {
            _errorMessage = ex.Message;
            throw new Exception(_errorMessage, ex);
        }
        result = new List<string>();
        foreach (string fld in folders)
        {
            try
            {
                //try to get the security on the folder. This will fail if the user does not
                //have full access. Ignore the exception which skips the folder.
                //Effectively Access Based Enumeration.
                dirSecurity = Directory.GetAccessControl(fld);
                result.Add(fld);
            }
            catch (Exception ex)
            {
            }
        }
        return result.ToArray();
    }

    /// <summary>
    /// Called from the datasource object in response to a sort on the datagrid
    /// </summary>
    /// <param name="path"></param>
    /// <param name="sortExpression"></param>
    /// <returns></returns>
    public  List<ace> GetDacl(string path, string sortExpression)
    {
        List<ace> _dacl = GetDacl(path);
        if (null != _dacl)
            switch (sortExpression)
            {
                case "UserAccount":
                    _dacl.Sort(new UserAccountComparer());
                    break;
                case "UserAccount DESC":
                    _dacl.Sort(new UserAccountDescComparer());
                    break;
                case "Access":
                    _dacl.Sort(new AccessComparer());
                    break;
                case "Access DESC":
                    _dacl.Sort(new AccessDescComparer());
                    break;
                default:
                    break;
            }

        return _dacl;
    }

    /// <summary>
    /// Called from GetDacl(path,sort). This overloaded method is responsible for updating
    /// the cached folder path prior to passing onto GetDacl() below.
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public  List<ace> GetDacl(string path)
    {
        if (null == path) return null;
        if (_cachedPath.CompareTo(path) == 0 && _dacl.Count > 0) return _dacl;
        _cachedPath = path;

        return GetDacl();
    }

    public  List<ace> GetDacl()
    {
        //get out if there is an update in progress
        if (_updating) return null;

        //define our variables
        DirectoryInfo targetDirectory = null;           //the directory object we are working on
        DirectorySecurity dirSecurity = null;           //the DACL for the directory
        AuthorizationRuleCollection dirRules = null;    //the ACE's in the DACL

        //lots of errors could occur in here
        try
        {
            targetDirectory = new DirectoryInfo(_cachedPath);
            dirSecurity = targetDirectory.GetAccessControl(AccessControlSections.Access);   //get the dacl not sacl
            dirRules = dirSecurity.GetAccessRules(true, true, typeof(NTAccount));   //get explicit and inherited in account format
        }
        catch (Exception ex)
        {
            _errorMessage = ex.Message;
            return null;
        }

        //process all accounts in the dacl and create more friendly ace objects
        string acct = null;
        _dacl.Clear();                  //discard any info even if same directory
        _isInheriting = false;          //assume we're not for the moment
        foreach (AuthorizationRule rule in dirRules)
        {
            acct = rule.IdentityReference.Value;

            //filter out some default groups as well as un-resolved accounts
            if (acct.Contains("Administrators")) continue;
            if (acct.Contains("File-Managers")) continue;
            //if (acct.Contains("AUTHORITY")) continue;           //no need to have any nt_authority acounts (ie.System)

            //create the user friendly ace
            ace entry = new ace();
            entry.Rule = (FileSystemAccessRule)rule;    //add the rule which populates the other fields in the ace

            //if any of the ace's are inherited then flag the folder as inheriting
            _isInheriting |= rule.IsInherited;

            //add the ace's to the databound list
            //if more than one ace, keep the one that gives the greater permission
            foreach (ace item in _dacl)
            {
                if (item.UserAccount == entry.UserAccount)
                {
                    if (item.Rule.FileSystemRights < entry.Rule.FileSystemRights)
                        item.Rule = entry.Rule;     //can't modify list during an enumeration
                                                    //modify the attributes for the existing entry instead
                    entry = null;           //dont want to add it again below
                    break;                  //done with this entry, get the next one
                }
            }
            if (null != entry)      //if the entry is null it was added above
                _dacl.Add(entry);   //this is the add for all accounts with a single ace
        }
        return _dacl;
    }


    /// <summary>
    /// Takes the current dacl list and applies it to the cachedFolder path.
    /// The inheritance flag is read and applied.
    /// </summary>
    public  void UpdateDacl()
    {

        //let fsal know that an update is in progress.
        //this method could take some time and we dont want to process another or change the cachedFolder
        _updating = true;
        _errorMessage = string.Empty;

        DirectorySecurity dirSecurity = new DirectorySecurity();

        if (IsInheriting == false)
        {
            dirSecurity = Directory.GetAccessControl(_cachedPath);
            dirSecurity.SetAccessRuleProtection(true, true);

            foreach (ace entry in _dacl)
            {

                if (entry.Rule == null)
                // Get the account SID
                {
                    NTAccount acct = new NTAccount(entry.UserAccount);
                    IdentityReference id = acct.Translate(typeof(SecurityIdentifier));
                    //Remove the User based on SID
                    dirSecurity.PurgeAccessRules(id);
                }
                else
                    //Change/Add user to DACL.

                    dirSecurity.ResetAccessRule(entry.Rule);
            }
            Directory.SetAccessControl(_cachedPath, dirSecurity);
        }
        else if (IsInheriting == true)
        {
            dirSecurity.SetAccessRuleProtection(false, false);
            Directory.SetAccessControl(_cachedPath, dirSecurity);

            foreach (ace entry in _dacl)
                if (entry.Rule == null)
                // Get the account SID
                {
                    NTAccount acct = new NTAccount(entry.UserAccount);
                    IdentityReference id = acct.Translate(typeof(SecurityIdentifier));
                    //Remove the User based on SID
                    dirSecurity.PurgeAccessRules(id);
                }
                else
                    //Change/Add user to DACL.

                    dirSecurity.ResetAccessRule(entry.Rule);
            }
            Directory.SetAccessControl(_cachedPath, dirSecurity);


        _updating = false;
        //Now we need to refresh the local list with the new settings in case the inheritance has changed
        GetDacl();
        if (Updated != null)
            Updated(null,new EventArgs());      //raise an event
    }



I've included more of the code above to show where the isinherited value comes from. I believe the code pulls it from the current value associated with the DACL "rule.isinherited". However there is also a tick box that users can turn on/off inherited permissions. The idea being when inheritance is on permissions are inherited from above but explicit permissions can be added as well. When inheritance is turned off only explicit permissions can be manipuulated.

[edit]Re-formatted to include indentation - OriginalGriff[/edit]
Posted
Updated 16-Jan-11 14:13pm
v5
Comments
Toniyo Jackson 14-Dec-10 6:52am    
Always put your code inside code block.
senguptaamlan 14-Dec-10 8:06am    
from where the IsInheriting flag gets its value ? please provide a bit more code...
aburrow 21-Jan-11 1:06am    
I've put more of the code in my initial message. If I comment out "if (item.Rule.FileSystemRights < entry.Rule.FileSystemRights)" the feedback the user gets displays the inherited and explicit permissions correctly. But I haven't been able to replicate that on the backend.
aburrow 28-Jan-11 1:01am    
I was thinking perhaps some code that compares the ace entries and if an explicit and inherited permission matches then it removes the explicit.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900