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 によって作成されます。

 

WMI での認証の設定