日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编写安全的代码(ACL使用方法)

發(fā)布時(shí)間:2025/3/18 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编写安全的代码(ACL使用方法) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

http://www.lihuasoft.net/article/show.php?id=755

?

Windows NT/2K/XP版本的操作系統(tǒng)都支持NTFS格式的文件系統(tǒng),這是一個(gè)有安全性質(zhì)的文件系統(tǒng),你可以通過Windows的資源管理器來設(shè)置對(duì)每個(gè)目錄和文件的用戶訪問權(quán)限。這里我就不對(duì)NTFS的安全性進(jìn)行講述了,我默認(rèn)你對(duì)NTFS的文件目錄的安全設(shè)置有了一定的了解。在這里,我將向你介紹使用Windows的API函數(shù)來操縱NTFS的文件權(quán)限。

一、?????? 理論和術(shù)語

在Windows NT/2K?XP下的對(duì)象,不一定是文件系統(tǒng),還有其它的一些對(duì)象,如:進(jìn)程、命名管道、打印機(jī)、網(wǎng)絡(luò)共享、或是注冊(cè)表等等,都可以設(shè)置用戶訪問權(quán)限。在Windows系統(tǒng)中,其是用一個(gè)安全描述符(Security Descriptors)的結(jié)構(gòu)來保存其權(quán)限的設(shè)置信息,簡(jiǎn)稱為SD,其在Windows SDK中的結(jié)構(gòu)名是“SECURITY_DESCRIPTOR”,這是包括了安全設(shè)置信息的結(jié)構(gòu)體。一個(gè)安全描述符包含以下信息:

一個(gè)安全標(biāo)識(shí)符(Security identifiers),其標(biāo)識(shí)了該信息是哪個(gè)對(duì)象的,也就是用于記錄安全對(duì)象的ID。簡(jiǎn)稱為:SID。

一個(gè)DACL(Discretionary Access Control List),其指出了允許和拒絕某用戶或用戶組的存取控制列表。 當(dāng)一個(gè)進(jìn)程需要訪問安全對(duì)象,系統(tǒng)就會(huì)檢查DACL來決定進(jìn)程的訪問權(quán)。如果一個(gè)對(duì)象沒有DACL,那么就是說這個(gè)對(duì)象是任何人都可以擁有完全的訪問權(quán)限。

一個(gè)SACL(System Access Control List),其指出了在該對(duì)象上的一組存取方式(如,讀、寫、運(yùn)行等)的存取控制權(quán)限細(xì)節(jié)的列表。

還有其自身的一些控制位。

DACL和SACL構(gòu)成了整個(gè)存取控制列表Access Control List,簡(jiǎn)稱ACL,ACL中的每一項(xiàng),我們叫做ACE(Access Control Entry),ACL中的每一個(gè)ACE。

我們的程序不用直接維護(hù)SD這個(gè)結(jié)構(gòu),這個(gè)結(jié)構(gòu)由系統(tǒng)維護(hù)。我們只用使用Windows 提供的相關(guān)的API函數(shù)來取得并設(shè)置SD中的信息就行了。不過這些API函數(shù)只有Windows NT/2K/XP才支持。

安全對(duì)象Securable Object是擁有SD的Windows的對(duì)象。所有的被命名的Windows的對(duì)象都是安全對(duì)象。一些沒有命名的對(duì)象是安全對(duì)象,如:進(jìn)程和線程,也有安全描述符SD。在對(duì)大多數(shù)的創(chuàng)建安全對(duì)象的操作中都需要你傳遞一個(gè)SD的參數(shù),如:CreateFile和CreateProcess函數(shù)。另外,Windows還提供了一系列有關(guān)安全對(duì)象的安全信息的存取函數(shù),以供你取得對(duì)象上的安全設(shè)置,或修改對(duì)象上的安全設(shè)置。如:GetNamedSecurityInfo, SetNamedSecurityInfo,GetSecurityInfo, SetSecurityInfo。

下圖說明了,安全對(duì)象和DACL以及訪問者之間的聯(lián)系(來源于MSDN)。注意,DACL表中的每個(gè)ACE的順序是有意義的,如果前面的Allow(或denied)ACE通過了,那么,系統(tǒng)就不會(huì)檢查后面的ACE了。

系統(tǒng)會(huì)按照順序依次檢查所有的ACE規(guī)則,如下面的條件滿足,則退出:

1、?如果一個(gè)Access-Denied的ACE明顯地拒絕了請(qǐng)求者。

2、?如果某Access-Allowed的ACE明顯地同意了請(qǐng)求者。

3、?全部的ACE都檢查完了,但是沒有一條ACE明顯地允許或是拒絕請(qǐng)求者,那么系統(tǒng)將使用默認(rèn)值,拒絕請(qǐng)求者的訪問。

更多的理論和描述,請(qǐng)參看MSDN。

二、?????? 實(shí)踐與例程

1、? 例程一:創(chuàng)建一個(gè)有權(quán)限設(shè)置的目錄

#include <windows.h>

void main(void)

{

??SECURITY_ATTRIBUTES sa;? //和文件有關(guān)的安全結(jié)構(gòu)

??SECURITY_DESCRIPTOR sd;? //聲明一個(gè)SD

??BYTE aclBuffer[1024];

??PACL pacl=(PACL)&aclBuffer;?//聲明一個(gè)ACL,長度是1024

??BYTE sidBuffer[100];

??PSID psid=(PSID) &sidBuffer;? //聲明一個(gè)SID,長度是100

??DWORD sidBufferSize = 100;

??char domainBuffer[80];

??DWORD domainBufferSize = 80;

??SID_NAME_USE snu;

??HANDLE file;

??//初始化一個(gè)SD

??InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);

??//初始化一個(gè)ACL

??InitializeAcl(pacl, 1024, ACL_REVISION);

??//查找一個(gè)用戶hchen,并取該用戶的SID

??LookupAccountName(0, "hchen", psid,

??????&sidBufferSize, domainBuffer,

??????&domainBufferSize, &snu);

??//設(shè)置該用戶的Access-Allowed的ACE,其權(quán)限為“所有權(quán)限”

AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid);

//把ACL設(shè)置到SD中

??SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);

??

??//把SD放到文件安全結(jié)構(gòu)SA中

??sa.nLength = sizeof(SECURITY_ATTRIBUTES);

??sa.bInheritHandle = FALSE;

??sa.lpSecurityDescriptor = &sd;

??

??//創(chuàng)建文件

??file = CreateFile("c:\\testfile",

????0, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);

??CloseHandle(file);

}

這個(gè)例子我是從網(wǎng)上找來的,改了改。其中使用到的關(guān)鍵的API函數(shù),我都把其加粗了。從程序中我們可以看到,我們先初始化了一個(gè)SD和一個(gè)ACL,然后調(diào)用LookupAccountName取得用戶的SID,然后通過這個(gè)SID,對(duì)ACL中加入一個(gè)有允許訪問權(quán)限的ACE,然后再把整個(gè)ACL設(shè)置到SD中。最后,組織文件安全描述的SA結(jié)構(gòu),并調(diào)用CreateFile創(chuàng)建文件。如果你的操作系統(tǒng)是NTFS,那么,你可以看到你創(chuàng)建出來的文件的安全屬性的樣子:

這個(gè)程序旨在說明如何生成一個(gè)新的SD和ACL的用法,其有四個(gè)地方的不足和不清:

1、?對(duì)于ACL和SID的聲明采用了硬編碼的方式指定其長度。

2、?對(duì)于API函數(shù),沒有出錯(cuò)處理。

3、?沒有說明如何修改已有文件或目錄的安全設(shè)置。

4、?沒有說明安全設(shè)置的繼承性。

對(duì)于這些我將在下個(gè)例程中講述。

2、? 例程二、為目錄增加一個(gè)安全設(shè)置項(xiàng)

在我把這個(gè)例程序例出來以前,請(qǐng)?jiān)试S我多說一下。

1、? 對(duì)于文件、目錄、命令管道,我們不一定要使用GetNamedSecurityInfo和SetNamedSecurityInfo函數(shù),我們可以使用其專用函數(shù)GetFileSecurity和SetFileSecurity函數(shù)來取得或設(shè)置文件對(duì)象的SD,以設(shè)置其訪問權(quán)限。需要使用這兩個(gè)函數(shù)并不容易,正如前面我們所說的,我們還需要處理SD參數(shù),要處理SD,就需要處理DACL和ACE,以及用戶的相關(guān)SID,于是,一系統(tǒng)列的函數(shù)就被這兩個(gè)函數(shù)帶出來了。

2、? 對(duì)于上一個(gè)例子中的使用硬編碼指定SID的處理方法是。調(diào)用LookupAccountName函數(shù)時(shí),先把SID,Domain名的參數(shù)傳為空NULL,于是LookupAccountName會(huì)返回用戶的SID的長度和Domain名的長度,于是你可以根據(jù)這個(gè)長度分配內(nèi)存,然后再次調(diào)用LookupAccountName函數(shù)。于是就可以達(dá)到到態(tài)分配內(nèi)存的效果。對(duì)于ACL也一樣。

3、? 對(duì)于給文件的ACL中增加一個(gè)ACE條目,一般的做法是先取出文件上的ACL,逐條取出ACE,和現(xiàn)需要增加的ACE比較,如果有沖突,則刪除已有的ACE,把新加的ACE添置到最后。這里的最后,應(yīng)該是非繼承而來的ACE的最后。關(guān)于ACL繼承,NTFS中,你可以設(shè)置文件和目錄是否繼承于其父目錄的設(shè)置。在程序中同樣可以設(shè)置。

還是請(qǐng)看例程,這個(gè)程序比較長,來源于MSDN,我做了一點(diǎn)點(diǎn)修改,并把自己的理解加在注釋中,所以,請(qǐng)注意代碼中的注釋:

#include <windows.h>

#include <tchar.h>

#include <stdio.h>

//使用Windows的HeapAlloc函數(shù)進(jìn)行動(dòng)態(tài)內(nèi)存分配

#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相關(guān)的變量(注意,全為0,要在程序中動(dòng)態(tài)分配)

? TCHAR *????szDomain??? = NULL;

? DWORD?????cbDomain??? = 0;

? LPVOID???? pUserSID??? = NULL;

? DWORD?????cbUserSID???= 0;

? // 和文件相關(guān)的安全描述符 SD 的變量

? PSECURITY_DESCRIPTOR pFileSD?= NULL;?? // 結(jié)構(gòu)變量

? DWORD?????cbFileSD??? = 0;????// SD的size

? // 一個(gè)新的SD的變量,用于構(gòu)造新的ACL(把已有的ACL和需要新加的ACL整合起來)

? SECURITY_DESCRIPTOR?newSD;

? // 和ACL 相關(guān)的變量

? PACL????? pACL????? = NULL;

? BOOL????? fDaclPresent;

? BOOL????? fDaclDefaulted;

? ACL_SIZE_INFORMATION AclInfo;

? // 一個(gè)新的 ACL 變量

? PACL????? pNewACL????= NULL;?//結(jié)構(gòu)指針變量

? DWORD?????cbNewACL??? = 0;?? //ACL的size

? // 一個(gè)臨時(shí)使用的 ACE 變量

? LPVOID???? pTempAce??? = NULL;

? UINT????? CurrentAceIndex = 0;?//ACE在ACL中的位置

? UINT????? newAceIndex = 0;?//新添的ACE在ACL中的位置

? //API函數(shù)的返回值,假設(shè)所有的函數(shù)都返回失敗。

? BOOL????? fResult;

? BOOL????? fAPISuccess;

? SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

? // 下面的兩個(gè)函數(shù)是新的API函數(shù),僅在Windows 2000以上版本的操作系統(tǒng)支持。

? // 在此將從Advapi32.dll文件中動(dòng)態(tài)載入。如果你使用VC++ 6.0編譯程序,而且你想

? // 使用這兩個(gè)函數(shù)的靜態(tài)鏈接。則請(qǐng)為你的編譯加上:/D_WIN32_WINNT=0x0500

? // 的編譯參數(shù)。并且確保你的SDK的頭文件和lib文件是最新的。

? SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl = NULL;

? AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx = NULL;

? __try {

???//

???// STEP 1: 通過用戶名取得SID

???//?? 在這一步中LookupAccountName函數(shù)被調(diào)用了兩次,第一次是取出所需要

???// 的內(nèi)存的大小,然后,進(jìn)行內(nèi)存分配。第二次調(diào)用才是取得了用戶的帳戶信息。

???// LookupAccountName同樣可以取得域用戶或是用戶組的信息。(請(qǐng)參看MSDN)

???//

???fAPISuccess = LookupAccountName(NULL, lpszAccountName,

??????pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);

???// 以上調(diào)用API會(huì)失敗,失敗原因是內(nèi)存不足。并把所需要的內(nèi)存大小傳出。

???// 下面是處理非內(nèi)存不足的錯(cuò)誤。

???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: 取得文件(目錄)相關(guān)的安全描述符SD

???//?? 使用GetFileSecurity函數(shù)取得一份文件SD的拷貝,同樣,這個(gè)函數(shù)也

??? // 是被調(diào)用兩次,第一次同樣是取SD的內(nèi)存長度。注意,SD有兩種格式:自相關(guān)的

??? // (self-relative)和 完全的(absolute),GetFileSecurity只能取到“自

??? // 相關(guān)的”,而SetFileSecurity則需要完全的。這就是為什么需要一個(gè)新的SD,

??? // 而不是直接在GetFileSecurity返回的SD上進(jìn)行修改。因?yàn)椤白韵嚓P(guān)的”信息

??? // 是不完整的。

???fAPISuccess = GetFileSecurity(lpszFileName,

??????secInfo, pFileSD, 0, &cbFileSD);

???// 以上調(diào)用API會(huì)失敗,失敗原因是內(nèi)存不足。并把所需要的內(nèi)存大小傳出。

???// 下面是處理非內(nèi)存不足的錯(cuò)誤。

???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: 初始化一個(gè)新的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的內(nèi)存size

???//?? GetAclInformation可以提供DACL的內(nèi)存大小。只傳入一個(gè)類型為

???// ACL_SIZE_INFORMATION的structure的參數(shù),需DACL的信息,是為了

???// 方便我們遍歷其中的ACE。

???AclInfo.AceCount = 0; // Assume NULL DACL.

???AclInfo.AclBytesFree = 0;

???AclInfo.AclBytesInUse = sizeof(ACL);

???if (pACL == NULL)

???? fDaclPresent = FALSE;

???// 如果DACL不為空,則取其信息。(大多數(shù)情況下“自關(guān)聯(lián)”的DACL為空)

???if (fDaclPresent) {??????

???? if (!GetAclInformation(pACL, &AclInfo,

??????? sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {

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

?????????GetLastError());

??????__leave;

???? }

???}

???//

???// STEP 6: 計(jì)算新的ACL的size

???//??計(jì)算的公式是:原有的DACL的size加上需要添加的一個(gè)ACE的size,以

???// 及加上一個(gè)和ACE相關(guān)的SID的size,最后減去兩個(gè)字節(jié)以獲得精確的大小。

???cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)

??????+ GetLengthSid(pUserSID) - sizeof(DWORD);

???//

???// STEP 7: 為新的ACL分配內(nèi)存

???//

???pNewACL = (PACL) myheapalloc(cbNewACL);

???if (!pNewACL) {

???? _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());

???? __leave;

???}

???//

???// STEP 8: 初始化新的ACL結(jié)構(gòu)

???//

???if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {

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

??????? GetLastError());

???? __leave;

???}

???//

???// STEP 9?如果文件(目錄) DACL 有數(shù)據(jù),拷貝其中的ACE到新的DACL中

???//

???//?? 下面的代碼假設(shè)首先檢查指定文件(目錄)是否存在的DACL,如果有的話,

???// 那么就拷貝所有的ACE到新的DACL結(jié)構(gòu)中,我們可以看到其遍歷的方法是采用

???// ACL_SIZE_INFORMATION結(jié)構(gòu)中的AceCount成員來完成的。在這個(gè)循環(huán)中,

???// 會(huì)按照默認(rèn)的ACE的順序來進(jìn)行拷貝(ACE在ACL中的順序是很關(guān)鍵的),在拷

???// 貝過程中,先拷貝非繼承的ACE(我們知道ACE會(huì)從上層目錄中繼承下來)

???//

???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

??????//?? 如果當(dāng)前的ACE是一個(gè)從父目錄繼承來的ACE,那么就退出循環(huán)。

??????// 因?yàn)?#xff0c;繼承的ACE總是在非繼承的ACE之后,而我們所要添加的ACE

??????// 應(yīng)該在已有的非繼承的ACE之后,所有的繼承的ACE之前。退出循環(huán)

??????// 正是為了要添加一個(gè)新的ACE到新的DACL中,這后,我們?cè)侔牙^承的

??????// ACE拷貝到新的DACL中。

??????//

??????if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags

??????? & INHERITED_ACE)

??????? break;

??????//

??????// STEP 12: 檢查要拷貝的ACE的SID是否和需要加入的ACE的SID一樣,

??????// 如果一樣,那么就應(yīng)該廢掉已存在的ACE,也就是說,同一個(gè)用戶的存取

??????// 權(quán)限的設(shè)置的ACE,在DACL中應(yīng)該唯一。這在里,跳過對(duì)同一用戶已設(shè)置

??????// 了的ACE,僅是拷貝其它用戶的ACE。

??????//

??????if (EqualSid(pUserSID,

??????? &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))

??????? continue;

??????//

??????// STEP 13: 把ACE加入到新的DACL中

??????//??下面的代碼中,注意 AddAce 函數(shù)的第三個(gè)參數(shù),這個(gè)參數(shù)的意思是

??????// ACL中的索引值,意為要把ACE加到某索引位置之后,參數(shù)MAXDWORD的

???????// 意思是確保當(dāng)前的ACE是被加入到最后的位置。

??????//

??????if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,

?????????((PACE_HEADER) pTempAce)->AceSize)) {

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

?????????? GetLastError());

??????? __leave;

??????}

??????newAceIndex++;

???? }

???}

??//

??// STEP 14: 把一個(gè) access-allowed 的ACE 加入到新的DACL中

??//?? 前面的循環(huán)拷貝了所有的非繼承且SID為其它用戶的ACE,退出循環(huán)的第一件事

??// 就是加入我們指定的ACE。請(qǐng)注意首先先動(dòng)態(tài)裝載了一個(gè)AddAccessAllowedAceEx

??// 的API函數(shù),如果裝載不成功,就調(diào)用AddAccessAllowedAce函數(shù)。前一個(gè)函數(shù)僅

??// 在Windows 2000以后的版本支持,NT則沒有,我們?yōu)榱耸褂眯掳姹镜暮瘮?shù),我們首

??// 先先檢查一下當(dāng)前系統(tǒng)中可不可以裝載這個(gè)函數(shù),如果可以則就使用。使用動(dòng)態(tài)鏈接

??// 比使用靜態(tài)鏈接的好處是,程序運(yùn)行時(shí)不會(huì)因?yàn)闆]有這個(gè)API函數(shù)而報(bào)錯(cuò)。

??//

??// Ex版的函數(shù)多出了一個(gè)參數(shù)AceFlag(第三人參數(shù)),用這個(gè)參數(shù)我們可以來設(shè)置一

??// 個(gè)叫ACE_HEADER的結(jié)構(gòu),以便讓我們所設(shè)置的ACE可以被其子目錄所繼承下去,而

??// AddAccessAllowedAce函數(shù)不能定制這個(gè)參數(shù),在AddAccessAllowedAce函數(shù)

??// 中,其會(huì)把ACE_HEADER這個(gè)結(jié)構(gòu)設(shè)置成非繼承的。

??//

???_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中繼續(xù)取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設(shè)置到新的SD中

???//

???if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL,

??????FALSE)) {

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

??????? GetLastError());

???? __leave;

???}

???//

???// STEP 19: 把老的SD中的控制標(biāo)記再拷貝到新的SD中,我們使用的是一個(gè)叫

???// SetSecurityDescriptorControl() 的API函數(shù),這個(gè)函數(shù)同樣只存在于

???// Windows 2000以后的版本中,所以我們還是要?jiǎng)討B(tài)地把其從advapi32.dll

???// 中載入,如果系統(tǒng)不支持這個(gè)函數(shù),那就不拷貝老的SD的控制標(biāo)記了。

???//

???_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設(shè)置設(shè)置到文件的安全屬性中(千山萬水啊,終于到了)

???//

???if (!SetFileSecurity(lpszFileName, secInfo,

??????&newSD)) {

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

??????? GetLastError());

???? __leave;

???}

???fResult = TRUE;

? } __finally {

???//

???// STEP 21: 釋放已分配的內(nèi)存,以免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表示所有的權(quán)限,其是一系列的NTFS權(quán)限的或

? //???NTFS的文件權(quán)限很細(xì),還請(qǐng)參看MSDN。

? if (!AddAccessRights(argv[1], argv[2], GENERIC_ALL)) {

???_tprintf(TEXT("AddAccessRights() failed.\n"));

???return 1;

? }

? else {

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

???return 0;

? }

}

三、?????? 一些相關(guān)的API函數(shù)

通過以上的示例,相信你已知道如何操作NTFS文件安全屬性了,還有一些API函數(shù)需要介紹一下。

1、?如果你要加入一個(gè)Access-Denied 的ACE,你可以使用AddAccessDeniedAce函數(shù)

2、?如果你要?jiǎng)h除一個(gè)ACE,你可以使用DeleteAce函數(shù)

3、?如果你要檢查你所設(shè)置的ACL是否合法,你可以使用IsValidAcl函數(shù),同樣,對(duì)于SD的合法也有一個(gè)叫IsValidSecurityDescriptor的函數(shù)

?

轉(zhuǎn)自:http://xue23.blog.163.com/blog/static/979344200926112725250/

總結(jié)

以上是生活随笔為你收集整理的编写安全的代码(ACL使用方法)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。