Winapi 使用MoveFileEx、CreateDirectoryEx、Get/SetNamedSecurityInfo时是否会破坏ACL/ACE

Winapi 使用MoveFileEx、CreateDirectoryEx、Get/SetNamedSecurityInfo时是否会破坏ACL/ACE,winapi,Winapi,我正在存档文件,并希望在使用winapi将文件夹移动到不同卷时,在文件夹上保留相同的ACL 对于文件,我使用MoveFileEx;对于目录,我使用CreateDirectoryEx和sourceDir作为模板,然后获取/SetNamedSecurityInfo并将所有条目复制到存档版本 我是否将保留与完全功能继承相同的权限? 或者可能是因为我在不同的卷之间移动而导致ACL断开(断开的继承) 这篇文章(非常古老)指出,这种情况可能发生: ACL断裂可能有多种原因。众所周知,一些自动复制程序会产生意

我正在存档文件,并希望在使用winapi将文件夹移动到不同卷时,在文件夹上保留相同的ACL

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

我是否将保留与完全功能继承相同的权限? 或者可能是因为我在不同的卷之间移动而导致ACL断开(断开的继承)

这篇文章(非常古老)指出,这种情况可能发生:

ACL断裂可能有多种原因。众所周知,一些自动复制程序会产生意想不到的结果。国产脚本也会产生这些问题。如果某人只是将文件或文件夹从卷上的一个文件夹移动到同一卷上具有不同权限的另一个文件夹,则可能会导致另一种不一致。当文件或文件夹在卷内移动时,它实际上只是在文件分配表中重命名,其权限不会更改。当文件或文件夹跨卷移动(从一个卷移动到另一个卷)时,它将继承其新父级的权限

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


选项1

使用
CreateFile
功能和
file\u FLAG\u BACKUP\u语义打开文件,以查看
dwFlagsAndAttributes

使用
BackupRead
BackupWrite
调用传输数据:

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

不要忘记启用SE_BACKUP_NAME和SE_RESTORE_NAME权限


选项2

与选项1类似,但不使用
BackupRead
BackupWrite
,而是以正常方式复制文件数据

然后: 使用
GetKernelObjectSecurity
/
SetKernelObjectSecurity
读取和写入安全描述符:

请看最后一段的解释

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

背景:

主要是因为继承

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

如果使用
SetNamedSecurityInfo
设置某个目录的ACL,该目录带有标记为继承的ACE,并且该目录包含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);
可以尝试以官方/常规方式执行此操作(您已经提到Get/SetNamedSecurityInfo)。但是,还有其他选项可以对安全描述符进行真正的1:1传输


选项1

使用
CreateFile
功能和
file\u FLAG\u BACKUP\u语义打开文件,以查看
dwFlagsAndAttributes

使用
BackupRead
BackupWrite
调用传输数据:

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

别忘了启用SE_BACKUP_NAME和SE_RE权限