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






4.07/5 (3 votes)
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:
using System;
using System.IO;
using Microsoft.Win32.Security;
Now, create a new class and add the following enumeration declaration:
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.
/// <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.
/// <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.
/// <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.