以“损坏”的权限获取文件所有权

9

我试图解决以下情况。

给定一个存储在NTFS卷上的目录,其中:

  1. 目录所有者设置为其他人(例如非特权用户)
  2. 目录DACL配置为允许访问一组特定的人员,但不包括系统或管理员
  3. 目录上的DACL实际上未授予任何人访问以获取所有权或更改DACL的权限

(简而言之,所有管理员都被锁定在文件夹外)

但是!

  1. 我正在运行的帐户具有管理权限(SeBackupPrivilege,SeSecurityPrivilege)
  2. 现有的DACL可以忽略,因为我将写一个新的DACL
  3. 使用其他工具(takeown.exe),我可以访问相关的目录。

(简而言之,我有权限修复DACL /所有者)

我应该没有问题使用以下代码:

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);

但是,SetAccessControl 调用会抛出 UnauthorizedAccessException 异常。当我仅更改所有者时,同样的事情发生了。当我尝试仅调整DACL时,也是同样的情况。

我已经通过检查Process Explorer中的结果进程并验证管理员组设置为“Owner”而不是“Disabled”,证明问题不是UAC引起的。在这种情况下,我应该拥有必要的权限来执行此操作(在Administrators面前,Backup Operators应该是多余的,但我添加它进行测试) - 但它仍然不断地抛出访问被拒绝的错误。

相关的technet文档:http://technet.microsoft.com/en-us/library/cc783530%28WS.10%29.aspx

  • “如果您拥有一个对象,您可以授予任何用户或安全组对该对象的任何权限,包括取得所有权的权限。”
  • 可以通过以下方式传输所有权:
    • 当前所有者可以向另一个用户授予取得所有权的权限,允许该用户随时取得所有权。用户必须实际取得所有权才能完成传输。 (不幸的是,在这种情况下,所有者无法重新分配所有权。)
    • 管理员可以取得所有权。
    • 具有恢复文件和目录用户权限的用户可以将所有权分配给任何用户或组。
  • 拥有文件和其他对象所有权的能力是另一种情况,其中管理员维护系统的需要优先于所有者控制访问的权利。通常情况下,只有当前所有者允许您执行此操作时,您才能取得对象的所有权。NTFS对象的所有者可以通过授予其他用户获取所有权的权限来允许另一个用户获得所有权;Active Directory对象的所有者可以授予另一个用户修改所有者的权限。具有此特权的用户可以在没有当前所有者的权限的情况下拥有对象的所有权。默认情况下,该特权仅分配给内置的Administrators组。通常情况下,管理员用于在当前所有者不再可用时接管和重新分配资源的所有权。

我错过了什么?


你遇到了完全相同的问题。你最终找到解决方案了吗? - Maverik
请参考以下链接 https://dev59.com/wlXTa4cB1Zd3GeqP1GW7 和 https://dev59.com/S3VC5IYBdhLWcg3w4Vf6。 - Chris J
2个回答

7
我遇到了同样的问题,现在在这里发布帖子以供其他像我一样搜索的人参考:
您需要在代码中明确启用SeTakeOwnershipPrivilege。 我发现Process Privileges 在处理此类问题时非常有用。
以下是它如何修复我的代码(似乎由于某种原因,即使我拥有特权,该进程也不会除非我明确启用它):
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:谢谢Simon..你的答案给了我一个起点。


这确实是我的问题!好老的UAC。如果没有别的,谢谢Simon的启动器。 - Kyle Brantley
1
我曾经遇到过这个问题,甚至没有启用UAC...但是这个方法有效! - emfurry
1
这与UAC无关。权限在UAC引入之前就一直是这样工作的;如果您想使用它们,必须先启用它们。(大概是为了防止程序员错误地使用特权。) - Harry Johnston
如果我运行这段代码并测试Privilege.TakeOwnership,它会显示为已删除。我似乎找不到任何关于如何“添加”它回来的文档。 - Joe Stellato
@JStellato,你以管理员身份运行程序了吗?(右键点击“以管理员身份运行”)。只要“以...身份运行”的用户具有特权访问权限,以管理员模式运行应该会将该特权传递给进程。 - Maverik

6

在添加访问权限之前,您需要先取得所有权。

using (var user = WindowsIdentity.GetCurrent())
{
    var ownerSecurity = new FileSecurity();
    ownerSecurity.SetOwner(user.User);
    File.SetAccessControl("c:\\path\\to\\broken", ownerSecurity);

    var accessSecurity = new FileSecurity();
    accessSecurity.AddAccessRule(new FileSystemAccessRule(user.User, FileSystemRights.FullControl, AccessControlType.Allow));
    File.SetAccessControl("c:\\path\\to\\broken", accessSecurity);
}

此外,如果您正在设置DirectorySecurity,您将需要这个。
using (var user = WindowsIdentity.GetCurrent())
{
    var ownerSecurity = new DirectorySecurity();
    ownerSecurity.SetOwner(user.User);
    Directory.SetAccessControl("c:\\path\\to\\broken", ownerSecurity);

    var accessSecurity = new DirectorySecurity();
    accessSecurity.AddAccessRule(new FileSystemAccessRule(user.User, FileSystemRights.FullControl, AccessControlType.Allow));
    Directory.SetAccessControl("c:\\path\\to\\broken", accessSecurity);
}

如果那个方法没有生效,请尝试这个:

http://blog.mikeobrien.net/2009/11/taking-ownership-and-setting-admin.html


谢谢,Simon。我为这个问题苦恼了一段时间。我读了马克的MSDN文章,很高兴我这样做了,但是你的帖子拯救了今天。 - Dave Harding
Mike O'Brien博客中的代码对我来说完美运行。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接