使用MoveFileEx,CreateDirectoryEx,Get / SetNamedSecurityInfo

时间:2017-11-07 17:44:07

标签: winapi

我正在归档文件,并希望使用winapi将文件夹保留在不同卷 /网络共享时保留相同的ACL。

对于文件,我使用MoveFileEx,对于目录,我使用CreateDirectoryEx,sourceDir作为模板,然后使用Get / SetNamedSecurityInfo并将所有条目复制到存档版本。

我是否会使用完全功能继承保留相同的权限? 或者可能是因为我在不同的卷之间移动而会破坏ACL(破坏的继承)?

这篇文章https://blog.varonis.com/fix-windows-permissions-by-brian-vecci/(很老)说这可能发生:

  

由于多种原因,可能会出现ACL损坏。已知一些自动复制程序会产生意外结果。自行编写的脚本也可以产生这些问题。当有人只是将文件或文件夹从卷上的一个文件夹移动到具有不同权限的同一卷上的另一个文件夹时,可能会导致另一种不一致。当文件或文件夹在卷内移动时,它实际上只是在文件分配表中重命名,并且其权限不会更改。当文件或文件夹在卷间(从一个卷移动到另一个卷)时,它会继承其新父级的权限。

1 个答案:

答案 0 :(得分:2)

可以 尝试以官方/普通方式执行此操作(您已经提到了Get / SetNamedSecurityInfo)。但是还有其他选项可以实现安全描述符的真正1:1传输。

选项1

使用CreateFile功能打开文件,FILE_FLAG_BACKUP_SEMANTICS打开dwFlagsAndAttributes

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx

使用BackupReadBackupWrite来电转移数据:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa362509.aspx https://msdn.microsoft.com/en-us/library/windows/desktop/aa362511.aspx

这两个函数不仅复制普通数据,还复制安全描述符和NTFS备用数据流(如果存在)。您甚至可以使用它们来复制类似于文件的目录。 另见SO中的这篇文章:

Windows BackupRead / BackupWrite and ACLs

不要忘记启用权限SE_BACKUP_NAME和SE_RESTORE_NAME

选项2

与选项1类似,但未使用BackupReadBackupWrite,而是使用正常方式复制文件数据。

然后: 使用GetKernelObjectSecurity / SetKernelObjectSecurity来读写安全描述符:

https://msdn.microsoft.com/en-us/library/aa446641.aspx

https://msdn.microsoft.com/en-us/library/aa379578.aspx

查看最后一段中的https://msdn.microsoft.com/en-us/library/aa364399.aspx以获得解释。

重要提示: SetKernelObjectSecurity的文档包含警告,该函数不应用于设置文件系统中的权限。

背景:

主要是因为继承...

Microsoft仅将继承功能实现为伪继承。每个对象(文件,目录)仍包含所有相关的访问控制条目(ACE)。但是如果它们是从父级继承的,则它们包含一个标志。在这种情况下,Windows资源管理器中的ACL编辑器会将它们显示为灰色。

如果使用SetNamedSecurityInfo来设置具有一些标记为继承的ACE的目录的ACL,并且此目录包含100000个子目录和文件,并且没有子目录阻止继承,则这将自动导致设置所有这100000个对象的安全描述符。

系统DLL NTMARTA.DLL负责这种“递归”。 如果这些子对象的所有ACL都设置正确(就ACE顺序,继承标志......而言)这基本上是件好事,因为操作系统会为你处理这个。

但是如果某些对象的ACL具有错误的条目,则会导致更多的损坏。

现在,如果您使用SetKernelObjectSecurity,则必须处理通常由NTMARTA.DLL自己完成的所有工作。

SetKernelObjectSecurity的一大优势,如果使用得当:

它可以在每种情况下覆盖具有错误条目的对象。可能存在SetNamedSecurityInfo无法纠正有缺陷的ACL(可能由不了解继承的旧工具创建)的情况。

我编写了一个程序来管理文件系统的文件和文件夹权限,该程序使用SetKernelObjectSecurity。此工具允许使用业务用户无法重命名/删除的“托管文件夹”(他们只能在下面删除/重命名)。此外,它还会自动处理上层文件夹所需的所有列表权限(能够向下走)。

我们使用它来设置包含数百万个文件和数千个用户的文件系统。这是生产超过5年没有任何问题。

如果您还有其他问题,请不要犹豫。 Windows权限是一个相当复杂的主题,如果我可以分享我作为以前的Windows管理员(从NT4开始)和开发人员多年来收集的一些知识,我很高兴。

...在我的源代码库中搜索我多年前写的一些旧东西......

    // omitting the CreateFile opening here and error handling too :-)
    // and also the creation of a buffer (it is a BYTE[])
    // ... just the copy loop


    LPVOID lpContextRead, lpContextWrite;

    lpContextRead = NULL;
    lpContextWrite = NULL;

    while (TRUE)
    {
        bSuccess = BackupRead(hRead, bBuffer, sizeof (bBuffer), 
                &dwBytesRead, FALSE, TRUE, &lpContextRead);

        if (!bSuccess) 
        {
            // ... error exit
        }

        if (!dwBytesRead) break;

        bSuccess = BackupWrite(hWrite, bBuffer, dwBytesRead, 
                &dwBytesWritten, FALSE, TRUE, &lpContextWrite);

        if (!bSuccess) 
        {
            // ... error exit
        }
    }

    // cleanup 
    BackupRead(hRead, bBuffer, 0, &dwBytesRead, TRUE, TRUE, &lpContextRead);
    BackupWrite(hWrite, bBuffer, 0, &dwBytesWritten, TRUE, TRUE, &lpContextWrite);

    CloseHandle(hRead);
    CloseHandle(hWrite);