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

简介:
还是请看例程,这个程序比较长,来源于MSDN,我做了一点点修改,并把自己的理解加在注释中,所以,请注意代码中的注释:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
// 使用 Windows HeapAlloc 函数进行动态内存分配
#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;        // SD size
   //  一个新的 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;     //ACL size
   //  一个临时使用的  ACE  变量
   LPVOID         pTempAce       = NULL;
   UINT           CurrentAceIndex = 0;  //ACE ACL 中的位置
   UINT           newAceIndex = 0;  // 新添的 ACE ACL 中的位置
   //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_INFORMATION structure 的参数,需 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:  计算新的 ACL size
      //     计算的公式是:原有的 DACL size 加上需要添加的一个 ACE size ,以
      //  及加上一个和 ACE 相关的 SID size ,最后减去两个字节以获得精确的大小。
      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 的顺序来进行拷贝( ACE ACL 中的顺序是很关键的),在拷
      //  贝过程中,先拷贝非继承的 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:  检查要拷贝的 ACE SID 是否和需要加入的 ACE SID 一样
            //  如果一样,那么就应该废掉已存在的 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++;
         }
      }









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

目录
相关文章
|
8月前
|
算法 Linux C++
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
103 0
|
5月前
|
存储 Linux C++
|
8月前
|
安全 Linux
【亮剑】`chattr`是Linux中用于管理文件和目录扩展属性的命令,影响文件系统处理方式
【4月更文挑战第30天】`chattr`是Linux中用于管理文件和目录扩展属性的命令,影响文件系统处理方式。常用属性包括:`a`(追加)、`i`(不可变)、`s`(安全删除)和`S`(同步更新)。通过`chattr [选项] <模式> <文件或目录>`设置属性,如`chattr +i <文件名>`使文件不可变,`-i`移除不可变属性。`lsattr`用于查看属性。注意,只有root用户有权更改属性,不是所有文件系统都支持所有属性,且更改关键文件属性前应备份。`chattr`有助于提升系统安全性和数据保护。
78 1
|
Linux Shell
Linux中的shell外壳与权限(包含目录文件的权限,粘滞位的来龙去脉)(下)
Linux中的shell外壳与权限(包含目录文件的权限,粘滞位的来龙去脉)
|
Linux Shell 数据安全/隐私保护
Linux中的shell外壳与权限(包含目录文件的权限,粘滞位的来龙去脉)(上)
Linux中的shell外壳与权限(包含目录文件的权限,粘滞位的来龙去脉)
112 0
|
缓存 Linux Shell
【看表情包学Linux】shell 命令及运行原理 | Linux 权限 | 文件权限的修改和转让 | 目录的权限 | Sticky bit 粘滞位(二)
本章我们将重点讲解 Linux 权限,这是 Linux 基础部分中非常重要的一部分。内容比较干,我会稍稍正经些去讲解。话不多说,我们直接切入正题。
231 0
【看表情包学Linux】shell 命令及运行原理 | Linux 权限 | 文件权限的修改和转让 | 目录的权限 | Sticky bit 粘滞位(二)
|
安全 Linux Shell
【看表情包学Linux】shell 命令及运行原理 | Linux 权限 | 文件权限的修改和转让 | 目录的权限 | Sticky bit 粘滞位(一)
本章我们将重点讲解 Linux 权限,这是 Linux 基础部分中非常重要的一部分。内容比较干,我会稍稍正经些去讲解。话不多说,我们直接切入正题。
349 0
【看表情包学Linux】shell 命令及运行原理 | Linux 权限 | 文件权限的修改和转让 | 目录的权限 | Sticky bit 粘滞位(一)
随心所欲操作 Linux 更改文件属性
Linux 文件基本属性 ls -l(查看文件基本属性) chgrp(更改文件属组) chown(更改文件属主,也可以同时更改文件属组) chmod(更改文件9个属性)
随心所欲操作 Linux 更改文件属性
随心所欲操作 Dos
打开CMD的方式 常用的Dos命令
随心所欲操作 Dos
|
关系型数据库 Shell Windows
DOS环境下强制删除文件或非空文件夹_
DOS环境下强制删除文件或非空文件夹_
682 0