1. 程式人生 > 實用技巧 >win32 - 將檔案的訪問許可權給特定的使用者

win32 - 將檔案的訪問許可權給特定的使用者

需要首先獲取特定使用者的SID。

這是一些步驟,

  1. 驗證輸入引數。
  2. 為可能足夠大的SID和域名建立緩衝區。
  3. 在迴圈中,呼叫LookupAccountName以檢索提供的帳戶名的SID。如果SID的緩衝區或域名的緩衝區不夠大,則分別cbSid或中返回所需的緩衝區大小cchDomainName,並在下一次呼叫之前分配一個新的緩衝區LookupAccountName請注意,當lpSystemName引數設定為NULL時,將在本地系統上檢索資訊
  4. 釋放分配給域名緩衝區的記憶體。

然後將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。