Click here to Skip to main content
15,891,375 members
Articles / Programming Languages / C#
Article

Modifying ACEs on file and directory DACLs, using the Win32 API Security assembly

Rate me:
Please Sign up or sign in to vote.
4.07/5 (3 votes)
15 Nov 2006CPOL 54.8K   12   2
Sample code for setting ACE on file and directory DACLs just as the OS does.

Introduction

Sometimes, we face the need to programmatically set the security on folders and files. This is a sample code for setting the Modify, and Write and Read access to folders, subfolders, and files.

Using the code

First, you will need the Win32 API security assembly. You can browse the win32security.dll code here. Next, add a reference to Win32 API security assembly:

C#
using System;
using System.IO;
using Microsoft.Win32.Security;

Now, create a new class and add the following enumeration declaration:

C#
public enum TPermisos : uint{   
   ACCESO_TOTAL         = 0x00000001,   
   ACCESO_LECTURA       = 0x00000002,   
   ACCESO_MODIFICAR     = 0x00000003
}

Next, add the RemoveFileSec method. This method calls itself recursively to remove all previous ACEs for the username, to a file or directory.

C#
/// <summary>
/// Remove all ACEs from the file/dir DACL, corresponding to userName
/// </summary>
/// <param name="filename">file/dir full path</param>
/// <param name="userName">username Id</param>
public static void RemoveFileSec (string filename, string userName)
{   
   // Every time we delete an ACE, we should delete inherited ACEs   
   // from children just as the OS system tools do   
   if (Directory.Exists(filename))   
   {      
      DirectoryInfo d = new DirectoryInfo(filename);
      // Remove ACE from children files      
      FileInfo[] fis = d.GetFiles();      
      foreach (FileInfo fi in fis)          
         RemoveFileSec( fi.FullName, userName);      
      // Remove ACE from children Dirs      
      DirectoryInfo[] dis = d.GetDirectories();      
      foreach (DirectoryInfo di in dis)          
         RemoveFileSec( di.FullName, userName);   
   }   
   else if (!File.Exists(filename))      
      throw new IOException("File or directory '"+ filename 
      +"' does not exist, while trying to remove security ACE.");   

   // Remove ACE access rights for username for current File/Dir   
   // Get DACLs for File/Dir   
   SecurityDescriptor secDesc = 
            SecurityDescriptor.GetFileSecurity (filename,
            SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);   

   Dacl dacl = secDesc.Dacl;            
   // Remove previous access rights for userName   
   dacl.RemoveAces(new Sid (userName));   
   secDesc.SetDacl(dacl);   

   // actually apply the new DACL   
   secDesc.SetFileSecurity(filename, 
       SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);   
}

Now, add the SetChildSec method. This is a recursive method which calls itself, and is called in turn by the SetFileSec method, to set the inherited ACEs.

C#
/// <summary>
/// Set new inherited ACEs to children Files/Dir, recursive procedure
/// </summary>
/// <param name="filename">file/dir full path</param>
/// <param name="userName">username Id</param>
/// <param name="Permisos">Enum specifing Custom Defined ACEs</param>
private static void SetChildSec (string filename, 
        string userName, TPermisos Permisos)
{                           
   // Every time we change an ACE, we should set inherited ACEs   
   // from children just as the OS system tools do    
   if (Directory.Exists(filename))   
   {      
      DirectoryInfo d = new DirectoryInfo(filename);                  
      // Set ACE for children files      
      FileInfo[] fis = d.GetFiles();      
      foreach (FileInfo fi in fis)          
         SetChildSec( fi.FullName, userName, Permisos);      
      // Set ACE for children Dirs      
      DirectoryInfo[] dis = d.GetDirectories();      
      foreach (DirectoryInfo di in dis)          
         SetChildSec( di.FullName, userName, Permisos);   }   
      SecurityDescriptor secDesc = 
                  SecurityDescriptor.GetFileSecurity (filename, 
                  SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);   
      Dacl dacl = secDesc.Dacl;            
      // Remove previous ACE for current File/Dir for username   
      dacl.RemoveAces(new Sid (userName));   
      // Apply Standard Windows security defined ACE   
      switch (Permisos)    {      
      case TPermisos.ACCESO_TOTAL:                     
         // Grant All access to this Folder, subflders and files      
         dacl.AddAce (new AceAccessAllowed (new Sid (userName), 
                      AccessType.GENERIC_ALL, 
                      AceFlags.INHERITED_ACE | 
                      AceFlags.OBJECT_INHERIT_ACE | 
                      AceFlags.INHERITED_ACE));         
      break;             
      case TPermisos.ACCESO_LECTURA:      
         // Grant Read access to this Folder,
         // set INHERITED_ACE flag 
         dacl.AddAce (new AceAccessAllowed (new Sid (userName), 
                      AccessType.GENERIC_READ | 
                      AccessType.GENERIC_EXECUTE, 
                      AceFlags.CONTAINER_INHERIT_ACE | 
                      AceFlags.OBJECT_INHERIT_ACE | 
                      AceFlags.INHERITED_ACE));         
      break;      
      case TPermisos.ACCESO_MODIFICAR:      
         // Grant Modify access to this Folder,
         // set INHERITED_ACE flag 
         dacl.AddAce (new AceAccessAllowed (new Sid (userName), 
                      AccessType.GENERIC_READ | 
                      AccessType.GENERIC_WRITE | 
                      AccessType.DELETE | 
                      AccessType.GENERIC_EXECUTE, 
                      AceFlags.CONTAINER_INHERIT_ACE | 
                      AceFlags.OBJECT_INHERIT_ACE | 
                      AceFlags.INHERITED_ACE));      

      break;

   }      
      
   secDesc.SetDacl(dacl);      

   // actually apply the new DACL      
   secDesc.SetFileSecurity(filename, 
           SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);
}

Finally, add the SetFileSec method to set the security for the parent directory, without the INHERITED_ACE flag set. This is the Recursive Caller wrapper.

C#
/// <summary>
/// Set ACEs to Files/Dir, recursive procedure
/// </summary>
/// <param name="filename">file/dir full path</param>
/// <param name="userName">username Id</param>
/// <param name="Permisos">Enum specifing Custom Defined ACEs</param>
public static void SetFileSec (string filename, 
       string userName, TPermisos Permisos)
{            
   if (Directory.Exists(filename))   
   {      
      DirectoryInfo d = new DirectoryInfo(filename);                  
      // Set ACE for username to children files      
      FileInfo[] fis = d.GetFiles();      
      foreach (FileInfo fi in fis)          
         SetChildSec( fi.FullName, userName, Permisos);      
      
      // Set ACE for username to children children dirs      
      DirectoryInfo[] dis = d.GetDirectories();      
      foreach (DirectoryInfo di in dis)          
         SetChildSec( di.FullName, userName, Permisos);   
   }   
   else if (!File.Exists(filename))   
      throw new IOException("File or directory '"+ filename 
        +"' does not exist, while trying to change security ACE.");   
   
   SecurityDescriptor secDesc = 
             SecurityDescriptor.GetFileSecurity (filename, 
             SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);   
   Dacl dacl = secDesc.Dacl;            
   // Remove previous access rights for userName
   dacl.RemoveAces(new Sid (userName));   
   switch (Permisos)    
   {      
      case TPermisos.ACCESO_TOTAL:                     
         // Grant All access to this Folder, set inheritable flags      
         dacl.AddAce (new AceAccessAllowed 
           (new Sid (userName), AccessType.GENERIC_ALL, 
            AceFlags.CONTAINER_INHERIT_ACE | 
            AceFlags.OBJECT_INHERIT_ACE));         
      break;      
      case TPermisos.ACCESO_LECTURA:      
         // Grant Read access to this Folder, set inheritable flags      
         dacl.AddAce (new AceAccessAllowed (new Sid (userName), 
              AccessType.GENERIC_READ | 
              AccessType.GENERIC_EXECUTE, 
              AceFlags.CONTAINER_INHERIT_ACE | 
              AceFlags.OBJECT_INHERIT_ACE));   
      break;      
      case TPermisos.ACCESO_MODIFICAR:      
         // Grant Modify access to this Folder, set inheritable flags
         dacl.AddAce (new AceAccessAllowed (new Sid 
             (userName), AccessType.GENERIC_READ | 
              AccessType.GENERIC_WRITE | AccessType.DELETE | 
              AccessType.GENERIC_EXECUTE, 
              AceFlags.CONTAINER_INHERIT_ACE | 
              AceFlags.OBJECT_INHERIT_ACE));      
      break;      
   }      
   
   secDesc.SetDacl(dacl); 
     
   // actually apply the new DACL      
   secDesc.SetFileSecurity(filename, 
      SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);
}

Points of Interest

That’s it! It works for me. Maybe you can change the Recursive Caller wrapper to do other things, just add a new set of enums for your custom Windows Security flags, and permissions.

History

  • Nov. 14, 2006 - Initial version.

License

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


Written By
Software Developer CIMEX S.A.
Cuba Cuba
Rodolfo Ortega is a Cuban Computer Scientist. He works as IT Auditor for the CIMEX S.A. subsidiary in Holguin, Cuba. He lives and works in Holguin, in the eastern part of the island of Cuba.

You can contact him at rodolfom[]cimex.com.cu for any personal message: Ideas on new articles, bibliography about new APIs, questions, are wellcome.

Submit questions related with current article to the article forum.

Comments and Discussions

 
QuestionHow ro apply Registry Permissions Pin
Harkamal Singh13-Sep-07 0:49
Harkamal Singh13-Sep-07 0:49 
QuestionSend as permissions on a group in AD Pin
shashankkadge1-May-07 6:18
shashankkadge1-May-07 6:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.