Search code examples
c#file-permissionsntfsownership

Taking ownership of files with 'broken' permissions


I'm trying to overcome the following situation.

Given a directory stored on an NTFS volume, where:

  1. The directory owner is set to someone else (a non-privileged user for example)
  2. The directory DACL is configured to permit access to a specific group of people that does not include the system or Administrators
  3. The DACL on the directory actually grants no one access to either take ownership or change the DACL

(or in short, the all administrators have been locked out of the folder)

But!

  1. The account I am running under has administrative rights (SeBackupPrivilege, SeSecurityPrivilege)
  2. The existing DACL can be ignored as I am writing a new one anyway
  3. Using other tools (takeown.exe), I can get access to the directory in question.

(or in short, I have access to fix the DACL/owner)

I should have no problem with the following code:

WindowsIdentity privilegedUser = System.Security.Principal.WindowsIdentity.GetCurrent();

// I cannot use File.GetAccessControl() as I get access denied
// (working as intended! I have no access to read the ACL!)
// so I have to write a new ACL:
FileSecurity acl = new FileSecurity();
acl.SetOwner(admin.User);
acl.AddAccessRule(new FileSystemAccessRule(privilegedUser.User, FileSystemRights.FullControl, AccessControlType.Allow));

File.SetAccessControl("c:\\path\\to\\broken", acl);

But, the SetAccessControl call throws UnauthorizedAccessException. When I alter it to only adjust the owner, the same thing happens. When I only try to adjust the DACL, same thing.

I've verified that the issue is not UAC by checking the resulting process in Process Explorer, and verified that the Administrators group is set to "Owner" instead of "Disabled." I should have all of the necessary rights to do this (Backup Operators should be extraneous in the face of Administrators, but I added it for testing) -- but it just keeps throwing access denied.

Relevant technet documentation: http://technet.microsoft.com/en-us/library/cc783530%28WS.10%29.aspx

  • "If you own an object, you can grant any user or security group any permission on that object, including the permission to take ownership."
  • Ownership can be transferred in the following ways:
    • The current owner can grant the Take ownership permission to another user, allowing that user to take ownership at any time. The user must actually take ownership to complete the transfer. (Unfortunately, the owner cannot reassign ownership in this situation.)
    • An administrator can take ownership.
    • A user who has the Restore files and directories user right can assign ownership to any user or group.
  • The ability to take ownership of files and other objects is another case where an administrator’s need to maintain the system takes priority over an owner’s right to control access. Normally, you can take ownership of an object only if its current owner gives you permission to do so. Owners of NTFS objects can allow another user to take ownership by granting the other user Take Ownership permission; owners of Active Directory objects can grant another user Modify Owner permission. A user who has this privilege can take ownership of an object without the current owner’s permission. By default, the privilege is assigned only to the built-in Administrators group. It is normally used by administrators to take and reassign ownership of resources when their current owner is no longer available.

What am I missing here?


Solution

  • I had the same problem and just posting here for anybody else who may come here searching like me:

    You need to explicitly enable SeTakeOwnershipPrivilege in code. I found Process Privileges to be really helpful dealing with this sort of thing.

    Here is how it fixed my code (seems like for some reason even though i have the privilege, the process doesn't unless i explicitly enable it):

    using (new ProcessPrivileges.PrivilegeEnabler(Process.GetCurrentProcess(), Privilege.TakeOwnership))
    {
        directoryInfo = new DirectoryInfo(path);
        directorySecurity = directoryInfo.GetAccessControl();
    
        directorySecurity.SetOwner(WindowsIdentity.GetCurrent().User);
        Directory.SetAccessControl(path, directorySecurity);    
    }
    

    PS: Thanks Simon.. your answer gave me a place to start from.