アクセス チェックの実行
アクセス チェックは、セキュリティ記述子が、アクセス トークンによって識別されるクライアントまたはスレッドに対して、指定されたアクセス権のセットを付与するかどうかを決定します。 セキュリティ関数 AccessCheck は、C++ または C# で記述された WMI クライアント アプリケーションまたはプロバイダーから呼び出すことができます。 スクリプトと 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;
}
関連トピック