액세스 검사 수행
액세스 검사를 통해 보안 설명자가 액세스 토큰으로 식별된 클라이언트 또는 스레드에 지정된 액세스 권한 집합을 부여할지 여부를 결정합니다. C++ 또는 C#으로 작성된 WMI 클라이언트 애플리케이션 또는 공급자에서 보안 함수 AccessCheck를 호출할 수 있습니다. 스크립트 및 Visual Basic 애플리케이션은 여기서 설명하는 메서드를 사용하여 액세스 검사를 수행할 수 없습니다.
클라이언트 애플리케이션은 클라이언트 비동기 호출에서 제공하는 싱크로 결과를 반환할 때 콜백의 ID를 확인하기 위해 액세스 검사를 수행해야 합니다.
공급자가 데이터를 요청하는 클라이언트 애플리케이션 또는 스크립트를 가장할 수 없는 경우 다음과 같은 상황에 대한 액세스 검사를 수행해야 합니다.
- ACL(액세스 제어 목록)으로 보호되지 않는 리소스에 액세스하는 경우
- 클라이언트가 RPC_C_LEVEL_IDENTIFY 가장 수준에서 연결된 경우
참고
C++ 및 C# 애플리케이션은 별도의 프로세스에서 액세스 검사를 수행하는지 여부를 제어할 수 있습니다. 스크립트 및 Visual Basic 애플리케이션은 레지스트리 키를 읽거나 변경하여 WMI가 액세스 검사를 수행하도록 할 수 있습니다. 자세한 내용은 비동기 호출에서 보안 설정을 참조하세요.
이 항목의 코드 예제를 올바르게 컴파일하려면 다음 참조 및 #include 문이 필요합니다.
#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")
다음 코드 예제는 클라이언트 애플리케이션 스레드의 보안 토큰에 지정된 보안 설명자에 적합한 권한이 포함되어 있는지 확인하는 방법을 보여줍니다. 함수는 문자열 "domain\user"를 사용하고 SID를 반환합니다. 호출에 실패하면 함수는 NULL을 반환하는데, 아닌 경우에는 호출자가 반환된 포인터를 해제해야 합니다.
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;
}
관련 항목