`
javatgo
  • 浏览: 1169378 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

以程序的方式操纵NTFS的文件权限(中)

阅读更多

还是请看例程,这个程序比较长,来源于MSDN,我做了一点点修改,并把自己的理解加在注释中,所以,请注意代码中的注释:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

//使用WindowsHeapAlloc函数进行动态内存分配
#define myheapalloc(x) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, x))
#define myheapfree(x) (HeapFree(GetProcessHeap(), 0, x))

typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);

typedef BOOL (WINAPI *AddAccessAllowedAceExFnPtr)(
PACL pAcl,
DWORD dwAceRevision,
DWORD AceFlags,
DWORD AccessMask,
PSID pSid
);

BOOL AddAccessRights(TCHAR *lpszFileName, TCHAR *lpszAccountName,
DWORD dwAccessMask) {

// 声明SID变量
SID_NAME_USE snuType;

// 声明和LookupAccountName相关的变量(注意,全为0,要在程序中动态分配)
TCHAR * szDomain = NULL;
DWORD cbDomain = 0;
LPVOID pUserSID = NULL;
DWORD cbUserSID = 0;

// 和文件相关的安全描述符 SD 的变量
PSECURITY_DESCRIPTOR pFileSD = NULL; // 结构变量
DWORD cbFileSD = 0;// SDsize

// 一个新的SD的变量,用于构造新的ACL(把已有的ACL和需要新加的ACL整合起来)
SECURITY_DESCRIPTOR newSD;

// ACL 相关的变量
PACL pACL = NULL;
BOOL fDaclPresent;
BOOL fDaclDefaulted;
ACL_SIZE_INFORMATION AclInfo;

// 一个新的 ACL 变量
PACL pNewACL = NULL; //结构指针变量
DWORD cbNewACL = 0; //ACLsize

// 一个临时使用的 ACE 变量
LPVOID pTempAce = NULL;
UINT CurrentAceIndex = 0; //ACEACL中的位置

UINT newAceIndex = 0; //新添的ACEACL中的位置

//API函数的返回值,假设所有的函数都返回失败。
BOOL fResult;
BOOL fAPISuccess;

SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

// 下面的两个函数是新的API函数,仅在Windows 2000以上版本的操作系统支持。
// 在此将从Advapi32.dll文件中动态载入。如果你使用VC++ 6.0编译程序,而且你想
// 使用这两个函数的静态链接。则请为你的编译加上:/D_WIN32_WINNT=0x0500
// 的编译参数。并且确保你的SDK的头文件和lib文件是最新的。
SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl = NULL;
AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx = NULL;

__try {

//
// STEP 1: 通过用户名取得SID
// 在这一步中LookupAccountName函数被调用了两次,第一次是取出所需要
// 的内存的大小,然后,进行内存分配。第二次调用才是取得了用户的帐户信息。
// LookupAccountName同样可以取得域用户或是用户组的信息。(请参看MSDN
//

fAPISuccess = LookupAccountName(NULL, lpszAccountName,
pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);

// 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。
// 下面是处理非内存不足的错误。

if (fAPISuccess)
__leave;
else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
_tprintf(TEXT("LookupAccountName() failed. Error %d\n"),
GetLastError());
__leave;
}

pUserSID = myheapalloc(cbUserSID);
if (!pUserSID) {
_tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
__leave;
}

szDomain = (TCHAR *) myheapalloc(cbDomain * sizeof(TCHAR));
if (!szDomain) {
_tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
__leave;
}

fAPISuccess = LookupAccountName(NULL, lpszAccountName,
pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);
if (!fAPISuccess) {
_tprintf(TEXT("LookupAccountName() failed. Error %d\n"),
GetLastError());
__leave;
}

//
// STEP 2: 取得文件(目录)相关的安全描述符SD
// 使用GetFileSecurity函数取得一份文件SD的拷贝,同样,这个函数也
// 是被调用两次,第一次同样是取SD的内存长度。注意,SD有两种格式:自相关的
// self-relative)和 完全的(absolute),GetFileSecurity只能取到“自
// 相关的”,而SetFileSecurity则需要完全的。这就是为什么需要一个新的SD
// 而不是直接在GetFileSecurity返回的SD上进行修改。因为“自相关的”信息
// 是不完整的。

fAPISuccess = GetFileSecurity(lpszFileName,
secInfo, pFileSD, 0, &cbFileSD);

// 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。
// 下面是处理非内存不足的错误。
if (fAPISuccess)
__leave;
else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
_tprintf(TEXT("GetFileSecurity() failed. Error %d\n"),
GetLastError());
__leave;
}

pFileSD = myheapalloc(cbFileSD);
if (!pFileSD) {
_tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
__leave;
}

fAPISuccess = GetFileSecurity(lpszFileName,
secInfo, pFileSD, cbFileSD, &cbFileSD);
if (!fAPISuccess) {
_tprintf(TEXT("GetFileSecurity() failed. Error %d\n"),
GetLastError());
__leave;
}

//
// STEP 3: 初始化一个新的SD
//
if (!InitializeSecurityDescriptor(&newSD,
SECURITY_DESCRIPTOR_REVISION)) {
_tprintf(TEXT("InitializeSecurityDescriptor() failed.")
TEXT("Error %d\n"), GetLastError());
__leave;
}

//
// STEP 4: GetFileSecurity 返回的SD中取DACL
//
if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
&fDaclDefaulted)) {
_tprintf(TEXT("GetSecurityDescriptorDacl() failed. Error %d\n"),
GetLastError());
__leave;
}

//
// STEP 5: DACL的内存size
// GetAclInformation可以提供DACL的内存大小。只传入一个类型为
// ACL_SIZE_INFORMATIONstructure的参数,需DACL的信息,是为了
// 方便我们遍历其中的ACE
AclInfo.AceCount = 0; // Assume NULL DACL.
AclInfo.AclBytesFree = 0;
AclInfo.AclBytesInUse = sizeof(ACL);

if (pACL == NULL)
fDaclPresent = FALSE;

// 如果DACL不为空,则取其信息。(大多数情况下“自关联”的DACL为空)
if (fDaclPresent) {
if (!GetAclInformation(pACL, &AclInfo,
sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
_tprintf(TEXT("GetAclInformation() failed. Error %d\n"),
GetLastError());
__leave;
}
}

//
// STEP 6: 计算新的ACLsize
// 计算的公式是:原有的DACLsize加上需要添加的一个ACEsize,以
// 及加上一个和ACE相关的SIDsize,最后减去两个字节以获得精确的大小。
cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
+ GetLengthSid(pUserSID) - sizeof(DWORD);

//
// STEP 7: 为新的ACL分配内存
//
pNewACL = (PACL) myheapalloc(cbNewACL);
if (!pNewACL) {
_tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
__leave;
}

//
// STEP 8: 初始化新的ACL结构
//
if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
_tprintf(TEXT("InitializeAcl() failed. Error %d\n"),
GetLastError());
__leave;
}

(程序未完,请看下篇)

//
// STEP 9 如果文件(目录) DACL 有数据,拷贝其中的ACE到新的DACL
//
// 下面的代码假设首先检查指定文件(目录)是否存在的DACL,如果有的话,
// 那么就拷贝所有的ACE到新的DACL结构中,我们可以看到其遍历的方法是采用
// ACL_SIZE_INFORMATION结构中的AceCount成员来完成的。在这个循环中,
// 会按照默认的ACE的顺序来进行拷贝(ACEACL中的顺序是很关键的),在拷
// 贝过程中,先拷贝非继承的ACE(我们知道ACE会从上层目录中继承下来)
//

newAceIndex = 0;

if (fDaclPresent && AclInfo.AceCount) {

for (CurrentAceIndex = 0;
CurrentAceIndex < AclInfo.AceCount;
CurrentAceIndex++) {

//
// STEP 10: DACL中取ACE
//
if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {
_tprintf(TEXT("GetAce() failed. Error %d\n"),
GetLastError());
__leave;
}

//
// STEP 11: 检查是否是非继承的ACE
// 如果当前的ACE是一个从父目录继承来的ACE,那么就退出循环。
// 因为,继承的ACE总是在非继承的ACE之后,而我们所要添加的ACE
// 应该在已有的非继承的ACE之后,所有的继承的ACE之前。退出循环
// 正是为了要添加一个新的ACE到新的DACL中,这后,我们再把继承的
// ACE拷贝到新的DACL中。
//
if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
& INHERITED_ACE)
break;

//
// STEP 12: 检查要拷贝的ACESID是否和需要加入的ACESID一样
// 如果一样,那么就应该废掉已存在的ACE,也就是说,同一个用户的存取
// 权限的设置的ACE,在DACL中应该唯一。这在里,跳过对同一用户已设置
// 了的ACE,仅是拷贝其它用户的ACE
//
if (EqualSid(pUserSID,
&(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
continue;

//
// STEP 13: ACE加入到新的DACL
// 下面的代码中,注意 AddAce 函数的第三个参数,这个参数的意思是
// ACL中的索引值,意为要把ACE加到某索引位置之后,参数MAXDWORD
// 意思是确保当前的ACE是被加入到最后的位置。
//
if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
((PACE_HEADER) pTempAce)->AceSize)) {
_tprintf(TEXT("AddAce() failed. Error %d\n"),
GetLastError());
__leave;
}

newAceIndex++;
}
}

<-上一页下一页->

(版权所有,转载时请注明出处和作者信息)

分享到:
评论

相关推荐

    以程序的方式操纵NTFS的文件权限

    ### 以程序的方式操纵NTFS的文件权限 #### 一、理论基础与术语解析 在深入探讨如何通过编程方式操作NTFS文件权限之前,我们首先需要理解几个关键概念。 ##### 安全描述符 (Security Descriptors) 在Windows NT/...

    NTFS文件权限设置软件 V2.0

    软件功能:通过设置NTFS文件权限达到禁止或恢复使用某文件(夹)的目的。可以用来防止文件误删误改等操作,同时也可用来防止一些未经自己允许的后台程序悄悄运行。 XP系统测试的,其他系统不知道。 做这个软件主要...

    实验七 NTFS文件系统权限实验.doc

    NTFS 文件系统权限管理可以通过以下方式实现: 1. 权限继承:NTFS 文件系统权限可以继承自父文件夹的权限。 2. 权限赋予:可以对文件和文件夹进行权限赋予,例如读取、写入、执行等权限。 3. 权限撤销:可以对文件...

    NTFS文件系统扇区存储探秘_扫描完整版

     《NTFS文件系统扇区存储探秘》附送的光盘里收录了书中使用的全部工具程序,读者可以使用这些工具程序对硬盘扇区数据进行各种读写与分析。  《NTFS文件系统扇区存储探秘》可作为从事数据恢复和硬盘维修的技术人员...

    NTFS 文件系统及NTFS权限应用原则

    管理员可以通过多种方式管理NTFS权限,包括使用“属性”对话框中的“安全”选项卡来设置和修改权限,以及使用命令行工具如icacls来批量处理权限问题。此外,NTFS还支持磁盘配额,以限制用户占用的磁盘空间;文件压缩...

    如何不丢失文件NTFS权限地拷贝文件

    ### 如何不丢失文件NTFS权限地拷贝文件 在Windows操作系统中,NTFS(New Technology File System)是一种被广泛使用的文件系统格式。它不仅提供了高级功能如文件压缩、加密等,还支持权限管理,这对于保护文件的...

    Windows下NTFS权限设置详解

    3. 执行权限(Execute):允许用户执行文件或文件夹中的程序。 4. 删除权限(Delete):允许用户删除文件或文件夹。 5. 修改权限(Modify):允许用户修改文件或文件夹的属性。 NTFS 权限设置的应用 NTFS 权限设置...

    NTFS文件系统若干技术研究

    NTFS 文件系统广泛应用于 Windows 操作系统中,主要用于存储操作系统文件和应用程序文件。同时,NTFS 文件系统也应用于其他领域,如数据存储、数据保护和云存储等。 NTFS 文件系统技术研究是计算机技术中一个重要的...

    NTFS文件系统参考书籍(全部中文版本)

    - 文件分配:NTFS采用变长记录方式,文件可以分布在多个簇中。 - 文件命名:支持长文件名和扩展属性。 - NTFS流:一个文件可以有多个数据流,扩展了文件的用途。 4. **NTFS的恢复与故障排除** - 使用Winhex等...

    NTFS文件系统中创建一个文件的基本步骤

    在NTFS文件系统中,每一个文件或目录都拥有一个MFT记录,MFT记录中记录了文件或目录的基本信息,对于普通文件来说,一般拥有文件序号,文件名,创建时间,文件大小,文件属性,文件数据地址索引等基本文件信息,而一...

    NTFS文件系统研究

    在NTFS文件系统中,用户可以执行诸如创建、删除、复制文件和目录等基本操作,同时还能利用高级特性如文件加密、压缩和权限管理进行更复杂的文件管理。 ### NTFS文件系统数据恢复研究 数据恢复是指在文件被删除、...

    Linux下挂载使用NTFS文件系统

    1. **权限问题**:由于Linux和Windows对文件权限的处理方式不同,可能需要调整权限设置,以确保Linux用户能够正确读写NTFS分区上的文件。 2. **性能优化**:挂载选项如`noatime`和`nodiratime`可以提高读取性能,但...

    ntfs文件系统源码包

    NTFS(New Technology File System)是微软Windows操作系统中使用的文件系统,它提供了高效的数据存储和检索功能,同时支持大容量磁盘。NTFS文件系统源码包是开发者和系统移植工程师的重要资源,允许他们深入了解其...

    NTFS文件系统详解

    NTFS中的文件和目录是由一系列的属性组成的,这些属性包括标准信息、文件名、对象ID、安全描述符等。下面将对几种常见的属性进行详细介绍: ##### 1. 属性-$STANDARD_INFORMATION (0x10) 该属性包含了文件的基本...

    NTFS文件系统若干技术

    介绍了如何在Ubuntu系统中安全地读写NTFS分区格式的文件,通常涉及到安装特定的软件包或驱动程序。 **5.3 在FAT32中读写NTFS分区的数据** 尽管FAT32文件系统无法直接读写NTFS分区,但通过某些特殊的技术手段,仍然...

    ntfs文件系统的备份

    1. **NTFS结构理解**:首先,开发者需要理解NTFS的内部结构,如MFT(Master File Table)、VFT(Volume File Table)、Bitmap、AttrDef等,这些都是NTFS中存储文件和目录信息的关键组件。 2. **读取元数据**:备份...

    NTFS文件系统分析

    在NTFS中,还有如Reparse Points这样的高级特性,它们允许文件系统支持符号链接、硬链接和文件系统过滤驱动,增强了系统的灵活性和可扩展性。Reparse Points在文件系统层次结构中提供了一种灵活的指向其他位置的方式...

    NTFS文件结构

    4. **属性**:NTFS文件的属性更加强大,除了基本的如文件名、大小、时间戳外,还支持扩展属性,如文件的索引、安全权限、流(例如,一个文件可能包含可执行代码和资源数据,这两个部分在NTFS中可以被视为独立的流)...

Global site tag (gtag.js) - Google Analytics