天天看點

以程式的方式操縱NTFS的檔案權限(下)

    // 

    // 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, 

             _tprintf(TEXT("AddAccessAllowedAce() failed. Error %d\n"),

      }

      // 

      // 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"), 

         }

      // 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)

            "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());

      // STEP 20: 把新的SD設定設定到檔案的安全屬性中(千山萬水啊,終于到了)

      if (!SetFileSecurity(lpszFileName, secInfo,

            &newSD)) {

         _tprintf(TEXT("SetFileSecurity() failed. Error %d\n"), 

      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"));

   else {

      _tprintf(TEXT("AddAccessRights() succeeded.\n"));

      return 0;

通過以上的示例,相信你已知道如何操作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。

本文轉自 haoel 51CTO部落格,原文連結:http://blog.51cto.com/haoel/124664,如需轉載請自行聯系原作者

繼續閱讀