win32 - 將檔案的訪問許可權給特定的使用者
阿新 • • 發佈:2020-12-22
需要首先獲取特定使用者的SID。
這是一些步驟,
- 驗證輸入引數。
- 為可能足夠大的SID和域名建立緩衝區。
- 在迴圈中,呼叫
LookupAccountName
以檢索提供的帳戶名的SID。如果SID的緩衝區或域名的緩衝區不夠大,則分別在cbSid
或中返回所需的緩衝區大小cchDomainName
,並在下一次呼叫之前分配一個新的緩衝區LookupAccountName
。請注意,當lpSystemName
引數設定為NULL時,將在本地系統上檢索資訊。 - 釋放分配給域名緩衝區的記憶體。
然後將SID傳遞給SetEntriesInAclA函式,
SetEntriesInAcl函式通過將新的訪問控制或稽核控制資訊合併到現有ACL結構中來建立新的訪問控制列表(ACL)。
這是傳遞給SetEntriesInAcl的結構引數,
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = GENERIC_ALL; //許可權設定 ea.grfAccessMode = SET_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; ea.Trustee.TrusteeType = TRUSTEE_IS_USER; //特定的物件 ea.Trustee.ptstrName= (LPTSTR)sid; //特定使用者的sid // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
完整程式碼:
#pragma comment(lib, "advapi32.lib") #include <windows.h> #include <stdio.h> #include <aclapi.h> #include <tchar.h> #include <mq.h.> HRESULT GetSid( LPCWSTR wszAccName, PSID* ppSid ) { // Validate the input parameters. if (wszAccName == NULL || ppSid == NULL) { return MQ_ERROR_INVALID_PARAMETER; } // Create buffers that may be large enough. // If a buffer is too small, the count parameter will be set to the size needed. const DWORD INITIAL_SIZE = 32; DWORD cbSid = 0; DWORD dwSidBufferSize = INITIAL_SIZE; DWORD cchDomainName = 0; DWORD dwDomainBufferSize = INITIAL_SIZE; WCHAR* wszDomainName = NULL; SID_NAME_USE eSidType; DWORD dwErrorCode = 0; HRESULT hr = MQ_OK; // Create buffers for the SID and the domain name. *ppSid = (PSID) new BYTE[dwSidBufferSize]; if (*ppSid == NULL) { return MQ_ERROR_INSUFFICIENT_RESOURCES; } memset(*ppSid, 0, dwSidBufferSize); wszDomainName = new WCHAR[dwDomainBufferSize]; if (wszDomainName == NULL) { return MQ_ERROR_INSUFFICIENT_RESOURCES; } memset(wszDomainName, 0, dwDomainBufferSize * sizeof(WCHAR)); // Obtain the SID for the account name passed. for (; ; ) { // Set the count variables to the buffer sizes and retrieve the SID. cbSid = dwSidBufferSize; cchDomainName = dwDomainBufferSize; if (LookupAccountNameW( NULL, // Computer name. NULL for the local computer wszAccName, *ppSid, // Pointer to the SID buffer. Use NULL to get the size needed, &cbSid, // Size of the SID buffer needed. wszDomainName, // wszDomainName, &cchDomainName, &eSidType )) { if (IsValidSid(*ppSid) == FALSE) { wprintf(L"The SID for %s is invalid.\n", wszAccName); dwErrorCode = MQ_ERROR; } break; } dwErrorCode = GetLastError(); // Check if one of the buffers was too small. if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER) { if (cbSid > dwSidBufferSize) { // Reallocate memory for the SID buffer. wprintf(L"The SID buffer was too small. It will be reallocated.\n"); FreeSid(*ppSid); *ppSid = (PSID) new BYTE[cbSid]; if (*ppSid == NULL) { return MQ_ERROR_INSUFFICIENT_RESOURCES; } memset(*ppSid, 0, cbSid); dwSidBufferSize = cbSid; } if (cchDomainName > dwDomainBufferSize) { // Reallocate memory for the domain name buffer. wprintf(L"The domain name buffer was too small. It will be reallocated.\n"); delete[] wszDomainName; wszDomainName = new WCHAR[cchDomainName]; if (wszDomainName == NULL) { return MQ_ERROR_INSUFFICIENT_RESOURCES; } memset(wszDomainName, 0, cchDomainName * sizeof(WCHAR)); dwDomainBufferSize = cchDomainName; } } else { wprintf(L"LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode); hr = HRESULT_FROM_WIN32(dwErrorCode); break; } } delete[] wszDomainName; return hr; } void main() { PSID sid; GetSid(L"strive", &sid); DWORD dwRes, dwDisposition; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea; SECURITY_ATTRIBUTES sa; HANDLE lRes = NULL; // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = GENERIC_ALL; ea.grfAccessMode = SET_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; ea.Trustee.TrusteeType = TRUSTEE_IS_USER; ea.Trustee.ptstrName = (LPTSTR)sid; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (NULL == pSD) { _tprintf(_T("LocalAlloc Error %u\n"), GetLastError()); goto Cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { _tprintf(_T("InitializeSecurityDescriptor Error %u\n"), GetLastError()); goto Cleanup; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // bDaclPresent flag pACL, FALSE)) // not a default DACL { _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security attributes structure. sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; // Use the security attributes to set the security descriptor // when you create a key. lRes = CreateFile(_T("D:\\File.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &sa, OPEN_ALWAYS, 0, NULL); if (lRes != NULL) { _tprintf(_T("Create file success\n")); } Cleanup: if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); if (lRes) CloseHandle(lRes); return; }
結果: 建立了一個文字,我們可以檢查文字的屬性來驗證是否成功。
文件參考:在C ++中為新物件建立安全描述符
C-C++ Code Example: Creating a Security Descriptor
拓展:
我們可以使用SetNamedSecurityInfo函式,將訪問許可權限制為特定的使用者帳戶和/或組。 不過如果具有足夠許可權的合適使用者帳戶執行您的應用程式(或與此相關的任何應用程式),或者您的應用程式(或其他應用程式)冒充了該帳戶,則它將能夠訪問該檔案。
案例參考:使用C ++製作具有僅使用者可以檢視和編輯的許可權的檔案
關於ACL和ACE的詳細介紹:關於Windows安全許可權的學習(三)
部分內容(防止丟失):
一個安全描述符包含以下安全資訊:
- 兩個安全識別符號(Security identifiers),簡稱為SID,分別是OwnerSid和GroupSid.所謂SID就是每次當我們建立一個使用者或一個組的時候,系統會分配給改使用者或組一個唯一SID,當你重新安裝系統後,也會得到一個唯一的SID。SID是唯一的,不隨使用者的刪除而分配到另外的使用者使用。
請記住,SID永遠都是唯一的SIF是由計算機名、當前時間、當前使用者態執行緒的CPU耗費時間的總和三個引數決定以保證它的唯一性。
例: S-1-5-21-1763234323-3212657521-1234321321-500 - 一個DACL(Discretionary Access Control List),其指出了允許和拒絕某使用者或使用者組的存取控制列表。 當一個程序需要訪問安全物件,系統就會檢查DACL來決定程序的訪問權。如果一個物件沒有DACL,那麼就是說這個物件是任何人都可以擁有完全的訪問許可權。
- 一個SACL(System Access Control List),其指出了在該物件上的一組存取方式(如,讀、寫、執行等)的存取控制權限細節的列表。
- 還有其自身的一些控制位。SECURITY_DESCRIPTOR_CONTROL
DACL和SACL構成了整個存取控制列表Access Control List,簡稱ACL,ACL中的每一項,我們叫做ACE(Access Control Entry),ACL中的每一個ACE。