编写安全的代码(ACL使用方法)
?
http://www.lihuasoft.net/article/show.php?id=755
?
Windows NT/2K/XP版本的操作系統都支持NTFS格式的文件系統,這是一個有安全性質的文件系統,你可以通過Windows的資源管理器來設置對每個目錄和文件的用戶訪問權限。這里我就不對NTFS的安全性進行講述了,我默認你對NTFS的文件目錄的安全設置有了一定的了解。在這里,我將向你介紹使用Windows的API函數來操縱NTFS的文件權限。
一、?????? 理論和術語
在Windows NT/2K?XP下的對象,不一定是文件系統,還有其它的一些對象,如:進程、命名管道、打印機、網絡共享、或是注冊表等等,都可以設置用戶訪問權限。在Windows系統中,其是用一個安全描述符(Security Descriptors)的結構來保存其權限的設置信息,簡稱為SD,其在Windows SDK中的結構名是“SECURITY_DESCRIPTOR”,這是包括了安全設置信息的結構體。一個安全描述符包含以下信息:
一個安全標識符(Security identifiers),其標識了該信息是哪個對象的,也就是用于記錄安全對象的ID。簡稱為:SID。
一個DACL(Discretionary Access Control List),其指出了允許和拒絕某用戶或用戶組的存取控制列表。 當一個進程需要訪問安全對象,系統就會檢查DACL來決定進程的訪問權。如果一個對象沒有DACL,那么就是說這個對象是任何人都可以擁有完全的訪問權限。
一個SACL(System Access Control List),其指出了在該對象上的一組存取方式(如,讀、寫、運行等)的存取控制權限細節的列表。
還有其自身的一些控制位。
DACL和SACL構成了整個存取控制列表Access Control List,簡稱ACL,ACL中的每一項,我們叫做ACE(Access Control Entry),ACL中的每一個ACE。
我們的程序不用直接維護SD這個結構,這個結構由系統維護。我們只用使用Windows 提供的相關的API函數來取得并設置SD中的信息就行了。不過這些API函數只有Windows NT/2K/XP才支持。
安全對象Securable Object是擁有SD的Windows的對象。所有的被命名的Windows的對象都是安全對象。一些沒有命名的對象是安全對象,如:進程和線程,也有安全描述符SD。在對大多數的創建安全對象的操作中都需要你傳遞一個SD的參數,如:CreateFile和CreateProcess函數。另外,Windows還提供了一系列有關安全對象的安全信息的存取函數,以供你取得對象上的安全設置,或修改對象上的安全設置。如:GetNamedSecurityInfo, SetNamedSecurityInfo,GetSecurityInfo, SetSecurityInfo。
下圖說明了,安全對象和DACL以及訪問者之間的聯系(來源于MSDN)。注意,DACL表中的每個ACE的順序是有意義的,如果前面的Allow(或denied)ACE通過了,那么,系統就不會檢查后面的ACE了。
系統會按照順序依次檢查所有的ACE規則,如下面的條件滿足,則退出:
1、?如果一個Access-Denied的ACE明顯地拒絕了請求者。
2、?如果某Access-Allowed的ACE明顯地同意了請求者。
3、?全部的ACE都檢查完了,但是沒有一條ACE明顯地允許或是拒絕請求者,那么系統將使用默認值,拒絕請求者的訪問。
更多的理論和描述,請參看MSDN。
二、?????? 實踐與例程
1、? 例程一:創建一個有權限設置的目錄
#include <windows.h>
void main(void)
{
??SECURITY_ATTRIBUTES sa;? //和文件有關的安全結構
??SECURITY_DESCRIPTOR sd;? //聲明一個SD
??BYTE aclBuffer[1024];
??PACL pacl=(PACL)&aclBuffer;?//聲明一個ACL,長度是1024
??BYTE sidBuffer[100];
??PSID psid=(PSID) &sidBuffer;? //聲明一個SID,長度是100
??DWORD sidBufferSize = 100;
??char domainBuffer[80];
??DWORD domainBufferSize = 80;
??SID_NAME_USE snu;
??HANDLE file;
??//初始化一個SD
??InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
??//初始化一個ACL
??InitializeAcl(pacl, 1024, ACL_REVISION);
??//查找一個用戶hchen,并取該用戶的SID
??LookupAccountName(0, "hchen", psid,
??????&sidBufferSize, domainBuffer,
??????&domainBufferSize, &snu);
??//設置該用戶的Access-Allowed的ACE,其權限為“所有權限”
AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid);
//把ACL設置到SD中
??SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);
??
??//把SD放到文件安全結構SA中
??sa.nLength = sizeof(SECURITY_ATTRIBUTES);
??sa.bInheritHandle = FALSE;
??sa.lpSecurityDescriptor = &sd;
??
??//創建文件
??file = CreateFile("c:\\testfile",
????0, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
??CloseHandle(file);
}
這個例子我是從網上找來的,改了改。其中使用到的關鍵的API函數,我都把其加粗了。從程序中我們可以看到,我們先初始化了一個SD和一個ACL,然后調用LookupAccountName取得用戶的SID,然后通過這個SID,對ACL中加入一個有允許訪問權限的ACE,然后再把整個ACL設置到SD中。最后,組織文件安全描述的SA結構,并調用CreateFile創建文件。如果你的操作系統是NTFS,那么,你可以看到你創建出來的文件的安全屬性的樣子:
這個程序旨在說明如何生成一個新的SD和ACL的用法,其有四個地方的不足和不清:
1、?對于ACL和SID的聲明采用了硬編碼的方式指定其長度。
2、?對于API函數,沒有出錯處理。
3、?沒有說明如何修改已有文件或目錄的安全設置。
4、?沒有說明安全設置的繼承性。
對于這些我將在下個例程中講述。
2、? 例程二、為目錄增加一個安全設置項
在我把這個例程序例出來以前,請允許我多說一下。
1、? 對于文件、目錄、命令管道,我們不一定要使用GetNamedSecurityInfo和SetNamedSecurityInfo函數,我們可以使用其專用函數GetFileSecurity和SetFileSecurity函數來取得或設置文件對象的SD,以設置其訪問權限。需要使用這兩個函數并不容易,正如前面我們所說的,我們還需要處理SD參數,要處理SD,就需要處理DACL和ACE,以及用戶的相關SID,于是,一系統列的函數就被這兩個函數帶出來了。
2、? 對于上一個例子中的使用硬編碼指定SID的處理方法是。調用LookupAccountName函數時,先把SID,Domain名的參數傳為空NULL,于是LookupAccountName會返回用戶的SID的長度和Domain名的長度,于是你可以根據這個長度分配內存,然后再次調用LookupAccountName函數。于是就可以達到到態分配內存的效果。對于ACL也一樣。
3、? 對于給文件的ACL中增加一個ACE條目,一般的做法是先取出文件上的ACL,逐條取出ACE,和現需要增加的ACE比較,如果有沖突,則刪除已有的ACE,把新加的ACE添置到最后。這里的最后,應該是非繼承而來的ACE的最后。關于ACL繼承,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++;
???? }
???}
??//
??// 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的函數
?
轉自:http://xue23.blog.163.com/blog/static/979344200926112725250/
總結
以上是生活随笔為你收集整理的编写安全的代码(ACL使用方法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC(MFC、ATL)中 得到2个SYS
- 下一篇: IPv6网络协议的安全疑云