Melakukan Pemeriksaan Akses
Pemeriksaan akses menentukan apakah deskriptor keamanan memberikan serangkaian hak akses tertentu kepada klien atau utas yang diidentifikasi oleh token akses. Anda dapat memanggil fungsi keamanan AccessCheck dari aplikasi klien WMI atau penyedia yang ditulis dalam C++ atau C#. Skrip dan aplikasi Visual Basic tidak dapat melakukan pemeriksaan akses menggunakan metode yang dijelaskan di sini.
Aplikasi klien harus melakukan pemeriksaan akses untuk menentukan identitas panggilan balik saat mengembalikan hasil ke sink yang disediakan oleh panggilan asinkron klien.
Ketika penyedia tidak dapat meniru aplikasi klien atau skrip yang meminta data, mereka harus melakukan pemeriksaan akses untuk situasi berikut:
- Saat mengakses sumber daya yang tidak dilindungi oleh daftar kontrol akses (ACL).
- Ketika klien telah terhubung pada tingkat peniruan RPC_C_LEVEL_IDENTIFY .
Catatan
Aplikasi C++ dan C# dapat mengontrol apakah pemeriksaan akses dilakukan oleh proses terpisah. Skrip dan aplikasi Visual Basic dapat membaca atau mengubah kunci registri untuk memastikan bahwa WMI melakukan pemeriksaan akses. Untuk informasi selengkapnya, lihat Mengatur Keamanan pada Panggilan Asinkron.
Contoh kode dalam topik ini memerlukan referensi dan pernyataan #include berikut untuk dikompilasi dengan benar.
#include <lmcons.h>
#define _WIN32_DCOM
#define SECURITY_WIN32
#include <wbemidl.h>
#include <security.h>
#include <safestr.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "Secur32.lib")
Contoh kode berikut menunjukkan cara memeriksa apakah token keamanan utas aplikasi klien berisi izin yang sesuai dengan deskriptor keamanan tertentu. Fungsi ini mengambil string "domain\user" dan mengembalikan SID. Jika panggilan gagal, fungsi mengembalikan NULL, jika tidak, pemanggil harus membebaskan penunjuk yang dikembalikan.
BYTE * GetSid(LPWSTR pwcUserName)
{
DWORD dwSidSize = 0, dwDomainSize = 0;
SID_NAME_USE use;
// first call is to get the size
BOOL bRet = LookupAccountNameW(
NULL, // system name
pwcUserName, // account name
NULL, // security identifier
&dwSidSize, // size of security identifier
NULL, // domain name
&dwDomainSize, // size of domain name
&use // SID-type indicator
);
if(bRet == FALSE && ERROR_INSUFFICIENT_BUFFER
!= GetLastError())\
return NULL;
BYTE * buff = new BYTE[dwSidSize];
if(buff == NULL)
return NULL;
WCHAR * pwcDomain = new WCHAR[dwDomainSize];
if(pwcDomain == NULL)
{
delete [] buff;
return FALSE;
}
// Call to LookupAccountNameW actually gets the SID
bRet = LookupAccountNameW(
NULL, // system name
pwcUserName, // account name
buff, // security identifier
&dwSidSize, // size of security identifier
pwcDomain, // domain name
&dwDomainSize, // size of domain name
&use // SID-type indicator
);
delete [] pwcDomain;
if(bRet == FALSE)
{
delete [] buff;
return NULL;
}
return buff;
}
// This returns true if the caller is coming
// from the expected computer in the expected domain.
BOOL IsAllowed(LPWSTR pwsExpectedDomain,
LPWSTR pwsExpectedMachine)
{
WCHAR wCallerName[UNLEN + 1];
DWORD nSize = UNLEN + 1;
// Impersonate the caller and get its name
HRESULT hr = CoImpersonateClient();
if(FAILED(hr))
return FALSE;
BOOL bRet = GetUserNameExW(NameSamCompatible,
wCallerName, &nSize);
CoRevertToSelf();
if(bRet == FALSE)
return FALSE;
// take the expected domain and lan manager
// style name and create a SID. In actual
// production code, it would be more efficient
// to do this only when necessary
WCHAR wExpectedName[UNLEN + 1];
HRESULT hrCopyCat;
hrCopyCat = StringCchCopy(wExpectedName,
sizeof(pwsExpectedDomain)*sizeof(WCHAR)+1,
pwsExpectedDomain);
if (FAILED(hrCopyCat))
{
return FALSE;
}
hrCopyCat =
StringCchCat(wExpectedName,sizeof(wExpectedName)
+ 2*sizeof(WCHAR)+1, L"\\");
if (FAILED(hrCopyCat))
{
return FALSE;
}
hrCopyCat = StringCchCat(wExpectedName,sizeof(wExpectedName)
+ sizeof(pwsExpectedMachine)*sizeof(WCHAR)+1,
pwsExpectedMachine);
if (FAILED(hrCopyCat))
{
return FALSE;
}
hrCopyCat = StringCchCat(wExpectedName,sizeof(wExpectedName)
+ sizeof(WCHAR)+1, L"$");
if (FAILED(hrCopyCat))
{
return FALSE;
}
// convert the two names to SIDs and compare.
// Note that SIDs are used since
// the format of the names might vary.
BYTE * pCaller = GetSid(wCallerName);
if(pCaller == NULL)
return FALSE;
BYTE * pExpected = GetSid(wExpectedName);
if(pExpected == NULL)
{
delete [] pCaller;
return FALSE;
}
bRet = EqualSid((PSID)pCaller, (PSID)pExpected);
delete [] pCaller;
delete [] pExpected;
return bRet;
}
Topik terkait