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.
public static void RemoveFileSec (string filename, string userName)
{
if (Directory.Exists(filename))
{
DirectoryInfo d = new DirectoryInfo(filename);
FileInfo[] fis = d.GetFiles();
foreach (FileInfo fi in fis)
RemoveFileSec( fi.FullName, userName);
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.");
SecurityDescriptor secDesc =
SecurityDescriptor.GetFileSecurity (filename,
SECURITY_INFORMATION.DACL_SECURITY_INFORMATION);
Dacl dacl = secDesc.Dacl;
dacl.RemoveAces(new Sid (userName));
secDesc.SetDacl(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.
private static void SetChildSec (string filename,
string userName, TPermisos Permisos)
{
if (Directory.Exists(filename))
{
DirectoryInfo d = new DirectoryInfo(filename);
FileInfo[] fis = d.GetFiles();
foreach (FileInfo fi in fis)
SetChildSec( fi.FullName, userName, Permisos);
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;
dacl.RemoveAces(new Sid (userName));
switch (Permisos) {
case TPermisos.ACCESO_TOTAL:
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:
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:
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);
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.
public static void SetFileSec (string filename,
string userName, TPermisos Permisos)
{
if (Directory.Exists(filename))
{
DirectoryInfo d = new DirectoryInfo(filename);
FileInfo[] fis = d.GetFiles();
foreach (FileInfo fi in fis)
SetChildSec( fi.FullName, userName, Permisos);
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;
dacl.RemoveAces(new Sid (userName));
switch (Permisos)
{
case TPermisos.ACCESO_TOTAL:
dacl.AddAce (new AceAccessAllowed
(new Sid (userName), AccessType.GENERIC_ALL,
AceFlags.CONTAINER_INHERIT_ACE |
AceFlags.OBJECT_INHERIT_ACE));
break;
case TPermisos.ACCESO_LECTURA:
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:
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);
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.
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.