C++ を使用した認証の設定
WMI 用 IWbemLocator::ConnectServer の主なタスクの 1 つが、IWbemServices プロキシへのポインターを返すことです。 IWbemServices プロキシを通して、WMI インフラストラクチャの機能にアクセスできます。 ただし、IWbemServices プロキシへのポインターには、IWbemServices プロセスの ID ではなく、クライアント アプリケーション プロセスの ID があります。 したがって、IWbemServices にこのポインターでアクセスしようとすると、E_ACCESSDENIED のようなアクセス拒否コードを受け取る可能性があります。 アクセス拒否エラーを回避するには、CoSetProxyBlanket インターフェイスの呼び出しで新しいポインターの ID を設定する必要があります。
プロバイダーでは、その名前空間への接続でパケット プライバシー (PktPrivacy) を使用しない限りデータが一切返されないように、名前空間に対してセキュリティを設定できます。 これで、データがネットワークを通過するときに確実に暗号化されます。 低い認証レベルを設定しようとすると、アクセス拒否メッセージが表示されます。 詳細については、「名前空間セキュリティ記述子の設定」を参照してください。
スクリプトでの認証の設定の詳細については、「VBScript を使用した既定のプロセス セキュリティ レベルの設定」を参照してください。
リモート IUnknown インターフェイスでのセキュリティの設定
状況によっては、プロキシへのポインターだけでなく、サーバーへのより多くのアクセスが必要になる場合があります。 ときには、プロキシの IUnknown インターフェイスへの安全な接続が必要になる場合があります。 IUnknown を使用すると、リモート システムに対してインターフェイスや他の必要な手法についてクエリを行うことができます。
プロキシがリモート コンピューター上にあるとき、サーバーはプロキシの IUnknown インターフェイスへのすべての呼び出しを IUnknown インターフェイスに委任します。 たとえば、QueryInterface をプロキシで呼び出し、要求されたインターフェイスがプロキシの一部ではない場合、プロキシは呼び出しをリモート サーバーに送信します。 次に、リモート サーバーは適切なインターフェイスのサポートがあるか調べます。 サーバーが インターフェイスをサポートしている場合、COM は新しいプロキシをクライアントにマーシャリングするので、アプリケーションは新しいインターフェイスを使用できるようになります。
問題が発生するのは、クライアントはリモート サーバーへのアクセス許可を持っていないけれども、それを行うユーザーの資格情報を使用している場合です。 この状況では、リモート サーバー上の QueryInterface にアクセスしようとすると失敗します。 プロキシでの最終リリースも失敗するのは、現在のユーザーがリモート サーバーにアクセスできないからです。 この現象は、クライアント アプリケーションが最終的なプロキシ リリースに失敗するまでに 1 ~ 2 秒のラグが発生することです。 このエラーは COM が現在のユーザーの既定のセキュリティ設定を使用してリモート サーバーにアクセスしようとしたために発生するのであり、この設定には、最初にサーバーへのアクセスを許可した変更後の資格情報は含まれません。 詳細については、「IWbemServices およびその他のプロキシでのセキュリティの設定」を参照してください。
接続に失敗しないようにするには、CoSetProxyBlanket を使用して IUnknown から返されるポインターに対してセキュリティ認証を明示的に設定します。 CoSetProxyBlanket を使用すると、リモート サーバーが正しい認証 ID を受け取るようにすることができます。
次のコード例は、CoSetProxyBlanket を使用してリモートの IUnknown インターフェイスにアクセスする方法を示しています。
SEC_WINNT_AUTH_IDENTITY_W* pAuthIdentity =
new SEC_WINNT_AUTH_IDENTITY_W;
ZeroMemory(pAuthIdentity, sizeof(SEC_WINNT_AUTH_IDENTITY_W));
pAuthIdentity->User = new WCHAR[32];
StringCbCopyW(pAuthIdentity->User,sizeof(L"MyUser"),L"MyUser");
pAuthIdentity->UserLength = wcslen(pAuthIdentity->User);
pAuthIdentity->Domain = new WCHAR[32];
StringCbCopyW(pAuthIdentity->Domain,sizeof(L"MyDomain"),L"MyDomain");
pAuthIdentity->DomainLength = wcslen(pAuthIdentity->Domain);
pAuthIdentity->Password = new WCHAR[32];
pAuthIdentity->Password[0] = NULL;
pAuthIdentity->PasswordLength = wcslen( pAuthIdentity->Password);
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
IWbemServices* pWbemServices = 0;
// Set proxy security
hr = CoSetProxyBlanket(pWbemServices,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_NONE,
COLE_DEFAULT_PRINCIPAL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE
);
if (FAILED(hr))
{
cout << "Count not set proxy blanket. Error code = 0x"
<< hex << hr << endl;
pWbemServices->Release();
return 1;
}
// Set IUnknown security
IUnknown* pUnk = NULL;
pWbemServices->QueryInterface(IID_IUnknown, (void**) &pUnk);
hr = CoSetProxyBlanket(pUnk,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_NONE,
COLE_DEFAULT_PRINCIPAL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE
);
if (FAILED(hr))
{
cout << "Count not set proxy blanket. Error code = 0x"
<< hex << hr << endl;
pUnk->Release();
pWbemServices->Release();
delete [] pAuthIdentity->User;
delete [] pAuthIdentity->Domain;
delete [] pAuthIdentity->Password;
delete pAuthIdentity;
return 1;
}
// cleanup IUnknown
pUnk->Release();
//
// Perform a bunch of operations
//
// Cleanup
pWbemServices->Release();
delete [] pAuthIdentity->User;
delete [] pAuthIdentity->Domain;
delete [] pAuthIdentity->Password;
delete pAuthIdentity;
注意
プロキシの IUnknown インターフェイスでセキュリティを設定すると、COUninitialize を呼び出すまで解放できないプロキシのコピーが COM によって作成されます。
関連トピック