Testing Managed ACL for IO [Lakshan Fernando]

One of the common requests we had after we shipped V1.1 was on managed ACL support for the Framework. We’ve added comprehensive ACL support in V2.0. This was a cross-group effort with multiple teams working on this feature; the windows core security team provided the base definitions and the interoperability with the OS. The CLR security team owns the base classes that supports Managed ACL (MACL) and the BCL provided the integrators (IO, Registry, Mutex etc) that build on top of it. This blog entry will talk specifically on a couple of issues that I came across while testing Managed ACL support for IO.

For an excellent discussion on MACL, read the article “Manage Access to Windows Objects with ACLs and the .NET Framework” https://msdn.microsoft.com/msdnmag/issues/04/11/AccessControlinNET/default.aspx by Mark Pustilnik. Although Mark talks of Managed ACL in general, he uses the file system to illustrate the features which is an extra benefit for someone who wants to use MACL for IO. The two issues that I want to talk here are viewing audit logs in EventLog and the special case for denying to view attributes for files using MACL.

Two things need to happen for auditing to be displayed in the EventLog. There has to be an audit rule(s) specified for a file or a directory and auditing has to be enabled in the machine. A code snipped from Mark’s article is shown that sets auditing on for an account when writing fails on a file.

using(FileStream file = new FileStream(
@"M:\temp\sample.txt",FileMode.Open, FileAccess.ReadWrite))
{
// Retrieve the file's security settings
FileSecurity security = file.GetAccessControl();

    // Create a new rule to generate audits any time that a full-time
// employee is denied write access to the file

    FileSystemAuditRule rule = new FileSystemAuditRule(
new NTAccount( @"FABRIKAM\Full_Time_Employees"),
FileSystemRights.Write, AuditFlags.Failure);

    // Add the rule to the existing rules
security.AddAuditRule(rule);

    // Persist the changes
file.SetAccessControl(security);
}

Auditing can be enabled in a XP Pro machine by setting ‘Success’ and ‘Failure’ check marks in the Audit object access in the 'Local Security Policy' security configuration tool (secpol.msc). Now any write failures on this file will be sent to the Security log and can be viewed in the Event Viewer. Note that auditing is a privileged operation and requires special permission.

The FileSystemRights enum lists the operations that users can be granted or denied using MACL. However, ACL treats attributes in a special way in that an additional operation (ListDirectory) is also tied with attributes. NTFS grants ReadAttributes if you have ListDirectory on the parent container and requires a deny on ListDirectory in addition to denying attributes in the file or directory. The following code snippet illustrates this for a file;

    String fileName = @"M:\temp\sample.txt";
using (FileStream file = new FileStream(
fileName, FileMode.Open, FileAccess.ReadWrite))
{
// Retrieve the file's security settings
FileSecurity security = file.GetAccessControl();

        // Create a new rule to generate audits any time that a full-time
// employee is denied write access to the file

        FileSystemAccessRule rule = new FileSystemAccessRule(
new NTAccount(@"FABRIKAM\Full_Time_Employees"),
FileSystemRights.ReadAttributes | FileSystemRights.ReadExtendedAttributes, AccessControlType.Deny);

        // Add the rule to the existing rules
security.AddAccessRule(rule);

        // Persist the changes
file.SetAccessControl(security);

        //Now for the parent directory
String parentDirectoryName = Path.GetDirectoryName(fileName);
DirectorySecurity dirSecurity = Directory.GetAccessControl(parentDirectoryName, AccessControlSections.Access);
rule = new FileSystemAccessRule(
new NTAccount(@"FABRIKAM\Full_Time_Employees"),
FileSystemRights.ListDirectory, AccessControlType.Deny);

        // Add the rule to the existing rules
dirSecurity.AddAccessRule(rule);

        // Persist the changes
Directory.SetAccessControl(parentDirectoryName, dirSecurity);
}