還是請看例程,這個程式比較長,來源于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());
}
pUserSID = myheapalloc(cbUserSID);
if (!pUserSID) {
_tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
szDomain = (TCHAR *) myheapalloc(cbDomain * sizeof(TCHAR));
if (!szDomain) {
if (!fAPISuccess) {
// STEP 2: 取得檔案(目錄)相關的安全描述符SD
// 使用GetFileSecurity函數取得一份檔案SD的拷貝,同樣,這個函數也
// 是被調用兩次,第一次同樣是取SD的記憶體長度。注意,SD有兩種格式:自相關的
// (self-relative)和 完全的(absolute),GetFileSecurity隻能取到“自
// 相關的”,而SetFileSecurity則需要完全的。這就是為什麼需要一個新的SD,
// 而不是直接在GetFileSecurity傳回的SD上進行修改。因為“自相關的”資訊
// 是不完整的。
fAPISuccess = GetFileSecurity(lpszFileName,
secInfo, pFileSD, 0, &cbFileSD);
_tprintf(TEXT("GetFileSecurity() failed. Error %d\n"),
pFileSD = myheapalloc(cbFileSD);
if (!pFileSD) {
secInfo, pFileSD, cbFileSD, &cbFileSD);
// STEP 3: 初始化一個新的SD
//
if (!InitializeSecurityDescriptor(&newSD,
SECURITY_DESCRIPTOR_REVISION)) {
_tprintf(TEXT("InitializeSecurityDescriptor() failed.")
TEXT("Error %d\n"), GetLastError());
// STEP 4: 從GetFileSecurity 傳回的SD中取DACL
if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
&fDaclDefaulted)) {
_tprintf(TEXT("GetSecurityDescriptorDacl() failed. Error %d\n"),
// 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) {
// STEP 8: 初始化新的ACL結構
if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
_tprintf(TEXT("InitializeAcl() failed. Error %d\n"),
(程式未完,請看下篇)
// 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"),
newAceIndex++;
本文轉自 haoel 51CTO部落格,原文連結:http://blog.51cto.com/haoel/124665,如需轉載請自行聯系原作者