ACLs: high-volume restoration management

When manipulating files and/or folders, it is not only the content that matters. The files/folders could also carry other valuable information that needs to be treated carefully. One discovers this (hopefully not the painful way) when restoring files, especially when ACLs need to be copied. Or it can hit during check-ups on an entity’s access to files/folders, or a file’s/folder’s permissions.

When looking for ready-made solutions to solve our internal ACL-related tasks, we discovered that there’s not a single app to do what we need. We have, therefore, developed a set of mechanisms that allow us to read the original file’s/folder’s access rights and replicate them on the copy file/folder. Although this is not a tool that we can just put on the market, the set of principles and the work mode should help if you have the same struggles.

If you are a sysadmin, security manager, backup personnel, or just struggle with a high volume/high complexity system of files/folders that’s accessed by an ever-changing pool of users – welcome to our club! and read on.


What are the ACLs? In shared environments, where many users and groups are allowed access to files/folders, defining the specific rights can be pretty challenging.

In the Windows ecosystem, the file/folder rights have a generic name: ACL / Access Control Lists. They are actually not just lists but entire trees of rights that inherit from a group to its members (who could be individual users or groups).

Here’s how the Microsoft documentation defines the various ACL-related elements:

  • An access control list (ACL) is a list of access control entries (ACE). Each ACE in an ACL identifies a trustee and specifies the access rights allowed, denied, or audited for that trustee. The security descriptor for a securable object can contain two types of ACLs: a DACL and a SACL.
  • A discretionary access control list (DACL) identifies the trustees that are allowed or denied access to a securable object. When a process tries to access a securable object, the system checks the ACEs in the object’s DACL to determine whether to grant access to it. If the object does not have a DACL, the system grants full access to everyone. If the object’s DACL has no ACEs, the system denies all attempts to access the object because the DACL does not allow any access rights. The system checks the ACEs in sequence until it finds one or more ACEs that allow all the requested access rights, or until any of the requested access rights are denied. […]
  • A system access control list (SACL) enables administrators to log attempts to access a secured object. Each ACE specifies the types of access attempts by a specified trustee that cause the system to generate a record in the security event log. An ACE in a SACL can generate audit records when an access attempt fails, when it succeeds, or both. For more information about SACLs, see Audit Generation and SACL Access Right.
  • A trustee is the user account, group account, or logon session to which an access control entry (ACE) applies. Each ACE in an access control list (ACL) has one security identifier (SID) that identifies a trustee.

If this looks complicated, let’s simplify: “ACE defines who has what type of access to a file/folder.

ACLs: Who has access?

So, let’s talk about “who”. For a home user, usually “who” = “me”. But for shared environments, where specific information should only be visible/editable to specific users, it can get complicated:

  • “who” could be an individual user or a group
  • a group could be a list of individual users and/or a list of groups

In Windows OS there are no restrictions on how groups and hierarchies of groups can be defined, so just be aware of circular indexing.

ACLs: What type of access?

The “what type of access” part is more complicated. At first sight, it is about the access to read, access to write, etc. – but it gets more detailed than that.

First, here’s the Windows documentation again: “The system compares the trustee in each ACE to the trustees identified in the thread’s access token. An access token contains security identifiers (SIDs) that identify the user and the group accounts to which the user belongs.

So, “what” the user or group is allowed to do with the file/folder is either defined on file/folder level, or inherited from the parent folder, or both. For example, if we have some rights on a parent folder, and its child file’s ACL is not modified to change these rights, then we will preserve the same rights on both the folder and the file. However, if the file has a different set of rights (i.e., “broken inheritance”), then we will obey the new rights.

The specific ACL rights

Here’s the list of rights at granular level:

FILE_READ_DATA = 0x00000001; // 1 List Folder/Read Data
FILE_WRITE_DATA = 0x00000002; // 2 Create Files/Write Data
FILE_APPEND_DATA = 0x00000004; // 3 Create Folders/Append Data
FILE_READ_EA = 0x00000008; // 4 Read Extended Attributes
FILE_WRITE_EA = 0x00000010; // 5 Write Extended Attributes
FILE_EXECUTE = 0x00000020; // 6 Traverse Folder/Execute File
FILE_DELETE = 0x00000040; // 7 Delete Subfolders and Files
FILE_READ_ATTRIBUTES = 0x00000080; // 8 Read Attributes
FILE_WRITE_ATTRIBUTES = 0x00000100; // 9 Write Attributes
DELETE = 0x00010000; // 16 Delete
READ_CONTROL = 0x00020000; // 17 Read Permissions
WRITE_DAC = 0x00040000; // 18 Change Permissions
WRITE_OWNER = 0x00080000; // 19 Take Ownership
SYSTEM_SECURITY = 0x01000000; // 19
SYNCHRONIZE = 0x00100000; // 20 Synchronize
GENERIC_ALL = 0x10000000; // 28
GENERIC_EXECUTE = 0x20000000; // 29
GENERIC_WRITE = 0x40000000; // 30
GENERIC_READ = 0x80000000; // 31

…And the inheritance flags:


…And finally, here are the individual permissions, grouped in a more user-friendly manner:

We, therefore, have a simple set of rights (Full Control, Modify, Read/Execute, List, Read, Write) with simple definitions (Allowed, Not Allowed, Not defined – where Not Allowed is always stronger than Allowed).

ACL example

Let’s assume a user of both Group1 and Group2:

  • File1 permits Group1 to Read, while Group2 is Not defined. In this case, the user will be allowed to Read the content of File1.
  • …But if File1 also has Group2 on Read with Not Allowed, the user will not be able to read the file content (because “Not” always wins).

(Now imagine this simple scenario for an entire company hierarchy with hundreds/thousands of users on a shared structure that includes Accounting, Marketing, Technical documentation, etc., and assume that individuals regularly move from a group to another based on work needs. Can you assess the work of Sysadmins to add/delete individuals to/from groups? The slightest imperfection in rights allocation can generate unwanted permissions to access secure information.)

ACL restoring: “how to”

Back to our example: the user needs to restore a previously deleted file. Although we have the original file within a backup, just copying it will not be enough because the ACLs will not be preserved in their initial form.

We, therefore, need to read the ACLs from the source file and restore them on destination. It is not the simplest thing to do, because the mechanism is a security breach. Therefore, writing ACLs is not possible using common libraries. (Oh well, just imagine a tool that can change ACLs for any file/folder you want – possibly allowing access to the entire file system.)

What we did was to use a forked version of JCIFS (an open-source library for manipulating files), which we patched (/expanded) to read/write ACLs according to our needs:

  • We extended the copy mechanism to also read the ACLs when the file content is read. Once the new file was created, we applied these ACLs (including ownership for user and group).
  • For our application’s purpose, we processed these ACLs into human-readable format, and saved them into a database that allows queries and statistics regarding files’/folders’ rights.
  • Moreover, within the database, we have enriched the ACL information by adding the AD names for each SID.

Because the Active Directory elements are not embedded (like .Net libraries), our using of a Linux machine got us into minor complications. For example, each SID translation was made by query to the LDAP server, instead of using direct calls. Then in order to minimize the load when solving thousands of ACLs, we have used a second-level cache. (We’ll not go into further details – the library is public, and we’re happy to support, should you need it.)

So, yes! we reached our goal to put back the proper ACL for the restored files/folders. But then, we achieved something more: because we implemented an ACL-reading mechanism, we were able to generate reports for the system administrators, such as:

  • “who has what access” to the files
  • which files could be accessed by a specific person, etc.


We are sure that every sysadmin has his/her own tools to maintain the trustee hierarchies (either own build or provided directly by Microsoft). But then, who can 100% swear by their own system? So, by sharing our experiences, principles and work mode, we can hopefully make your life easier – at least when it comes to ACLs.


Feel like sharing your own experiences? Please get in touch!

29 years in business | 2700 software projects | 760 clients | 24 countries

We turn ideas into software. What is yours?

Get in touch

1 + 6 =