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

本文详细介绍如何使用Windows API函数操作NTFS文件系统的安全属性,包括创建、修改访问控制列表(ACL)以及设置特殊权限等高级操作。此外,还列举了一些常用的低级别安全描述符函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    // 
    // STEP 14: 把一个 access-allowed ACE 加入到新的DACL
    //     前面的循环拷贝了所有的非继承且SID为其它用户的ACE,退出循环的第一件事
    // 就是加入我们指定的ACE。请注意首先先动态装载了一个AddAccessAllowedAceEx
    // API函数,如果装载不成功,就调用AddAccessAllowedAce函数。前一个函数仅
    // Windows 2000以后的版本支持,NT则没有,我们为了使用新版本的函数,我们首
    // 先先检查一下当前系统中可不可以装载这个函数,如果可以则就使用。使用动态链接
    // 使用静态链接的好处是,程序运行时不会因为没有这个API函数而报错。
    // 
    // Ex版的函数多出了一个参数AceFlag(第三人参数),用这个参数我们可以来设置一
    // 个叫ACE_HEADER的结构,以便让我们所设置的ACE可以被其子目录所继承下去,而 
    // AddAccessAllowedAce函数不能定制这个参数,在AddAccessAllowedAce函数
    // 中,其会把ACE_HEADER这个结构设置成非继承的。
    // 
      _AddAccessAllowedAceEx = (AddAccessAllowedAceExFnPtr)
            GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
            "AddAccessAllowedAceEx");
      if (_AddAccessAllowedAceEx) {
           if (!_AddAccessAllowedAceEx(pNewACL, ACL_REVISION2,
              CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE ,
                dwAccessMask, pUserSID)) {
             _tprintf(TEXT("AddAccessAllowedAceEx() failed. Error %d\n"),
                   GetLastError());
             __leave;
          }
      }else{
          if (!AddAccessAllowedAce(pNewACL, ACL_REVISION2, 
                dwAccessMask, pUserSID)) {
             _tprintf(TEXT("AddAccessAllowedAce() failed. Error %d\n"),
                   GetLastError());
             __leave;
          }
      }
      // 
      // STEP 15:  按照已存在的 ACE 的顺序拷贝从父目录继承而来的 ACE
      // 
      if (fDaclPresent && AclInfo.AceCount) {
         for (; 
              CurrentAceIndex < AclInfo.AceCount;
              CurrentAceIndex++) {
            // 
            // STEP 16:  从文件(目录)的 DACL 中继续取 ACE
            // 
            if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {
               _tprintf(TEXT("GetAce() failed. Error %d\n"), 
                     GetLastError());
               __leave;
            }
            // 
            // STEP 17:  ACE 加入到新的 DACL
            // 
            if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
                  ((PACE_HEADER) pTempAce)->AceSize)) {
               _tprintf(TEXT("AddAce() failed. Error %d\n"), 
                     GetLastError());
               __leave;
            }
         }
      }
      // 
      // STEP 18:  把新的 ACL 设置到新的 SD
      // 
      if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL, 
            FALSE)) {
         _tprintf(TEXT("SetSecurityDescriptorDacl() failed. Error %d\n"),
               GetLastError());
         __leave;
      }
      // 
      // STEP 19:  把老的 SD 中的控制标记再拷贝到新的 SD ,我们使用的是一个叫  
      // SetSecurityDescriptorControl()  API 函数,这个函数同样只存在于
      // Windows 2000 以后的版本中,所以我们还是要动态地把其从 advapi32.dll 
      //  中载入,如果系统不支持这个函数,那就不拷贝老的 SD 的控制标记了。
      // 
      _SetSecurityDescriptorControl =(SetSecurityDescriptorControlFnPtr)
            GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
            "SetSecurityDescriptorControl");
      if (_SetSecurityDescriptorControl) {
         SECURITY_DESCRIPTOR_CONTROL controlBitsOfInterest = 0;
         SECURITY_DESCRIPTOR_CONTROL controlBitsToSet = 0;
         SECURITY_DESCRIPTOR_CONTROL oldControlBits = 0;
         DWORD dwRevision = 0;
         if (!GetSecurityDescriptorControl(pFileSD, &oldControlBits,
            &dwRevision)) {
            _tprintf(TEXT("GetSecurityDescriptorControl() failed.")
                  TEXT("Error %d\n"), GetLastError());
            __leave;
         }
         if (oldControlBits & SE_DACL_AUTO_INHERITED) {
            controlBitsOfInterest =
               SE_DACL_AUTO_INHERIT_REQ |
               SE_DACL_AUTO_INHERITED ;
            controlBitsToSet = controlBitsOfInterest;
         }
         else if (oldControlBits & SE_DACL_PROTECTED) {
            controlBitsOfInterest = SE_DACL_PROTECTED;
            controlBitsToSet = controlBitsOfInterest;
         }        
         if (controlBitsOfInterest) {
            if (!_SetSecurityDescriptorControl(&newSD,
               controlBitsOfInterest,
               controlBitsToSet)) {
               _tprintf(TEXT("SetSecurityDescriptorControl() failed.")
                     TEXT("Error %d\n"), GetLastError());
               __leave;
            }
         }
      }
      // 
      // STEP 20:  把新的 SD 设置设置到文件的安全属性中 (千山万水啊,终于到了)
      // 
      if (!SetFileSecurity(lpszFileName, secInfo,
            &newSD)) {
         _tprintf(TEXT("SetFileSecurity() failed. Error %d\n"), 
               GetLastError());
         __leave;
      }
      fResult = TRUE;
   } __finally {
      // 
      // STEP 21:  释放已分配的内存,以免 Memory Leak
      // 
      if (pUserSID)  myheapfree(pUserSID);
      if (szDomain)  myheapfree(szDomain);
      if (pFileSD) myheapfree(pFileSD);
      if (pNewACL) myheapfree(pNewACL);
   }
    return fResult;
}
 
int _tmain(int argc, TCHAR *argv[]) {
   if (argc < 3) {
      _tprintf(TEXT("usage: \"%s\" <FileName> <AccountName>\n"), argv[0]);
      return 1;
   }
   // argv[1] –  文件(目录)名
   // argv[2] –  用户(组)名
   // GENERIC_ALL 表示所有的权限,其是一系列的 NTFS 权限的或
   
//      NTFS 的文件权限很细,还请参看 MSDN
   if (!AddAccessRights(argv[1], argv[2], GENERIC_ALL)) {
      _tprintf(TEXT("AddAccessRights() failed.\n"));
      return 1;
   }
   else {
      _tprintf(TEXT("AddAccessRights() succeeded.\n"));
      return 0;
   }
}




三、             一些相关的API函数

 
通过以上的示例,相信你已知道如何操作 NTFS 文件安全属性了,还有一些 API 函数需要介绍一下。
1、   如果你要加入一个 Access-Denied  ACE ,你可以使用 AddAccessDeniedAce 函数
2、   如果你要删除一个 ACE ,你可以使用 DeleteAce 函数
3、   如果你要检查你所设置的 ACL 是否合法,你可以使用 IsValidAcl 函数 ,同样,对于 SD 的合法也有一个叫 IsValidSecurityDescriptor 的函数
4、   MakeAbsoluteSD MakeSelfRelativeSD 两个函数可以在两种 SD 的格式中进行转换。
5、   使用 SetSecurityDescriptorDacl     SetSecurityDescriptorSacl 可以方便地把 ACL 设置到 SD 中。
6、   使用 GetSecurityDescriptorDacl  or GetSecurityDescriptorSacl 可以方便地取得 SD 中的 ACL 结构。
我们把一干和 SD/ACL/ACE 相关的 API 函数叫作 Low-Level Security Descriptor Functions ,其详细信息还请参看 MSDN
我的 MSN [email]haoel@hotmail.com[/email] ,专栏在 [url]http://haoel.blog.51cto.com/[/url] 欢迎大家和我交流。









本文转自 haoel 51CTO博客,原文链接:http://blog.51cto.com/haoel/124664,如需转载请自行联系原作者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值