Setting Security on an Asynchronous Call

Asynchronous calls present serious security risks because a callback to the sink may not be a result of the asynchronous call by the original application or script. Security in remote connections is based on encryption of the communication between the client and the provider on the remote computer. In C++ you can set encryption through the authentication level parameter in the call to CoInitializeSecurity. In scripting, set the AuthenticationLevel in the moniker connection or on an SWbemSecurity object. For more information, see Setting the Default Process Security Level Using VBScript.

The security risks for asynchronous calls exist because WMI lowers the authentication level on a callback until the callback succeeds. On an outgoing asynchronous call, the client can set the authentication level on the connection to WMI. WMI retrieves the security settings on the client call and attempts to call back with the same authentication level. The callback is always initiated at the RPC_C_AUTHN_LEVEL_PKT_PRIVACY level. If the callback fails, WMI lowers the authentication level to a level where the callback can succeed, if necessary, to RPC_C_AUTHN_LEVEL_NONE. In the context of calls within the local system where the authentication service is not Kerberos, the callback is always returned at RPC_C_AUTHN_LEVEL_NONE.

The minimum authentication level is RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelPktfor scripting). However, you can specify a higher level, such as RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). It is recommended that client applications or scripts set the authentication level to RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault) which allows the authentication level to be negotiated to the level specified by the server.

The HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault registry value controls whether WMI checks for an acceptable authentication level in callbacks. This is the only mechanism for protecting sink security for asynchronous calls made in scripting or Visual Basic. By default, this registry key is set to zero. If the registry key is zero then WMI does not verify authentication levels. To secure asynchronous calls in scripting, set the registry key to 1. C++ clients can call IWbemUnsecuredApartment::CreateSinkStub to control access to the sink. The value is created anywhere by default.

The following topics provide examples of setting asynchronous call security:

Setting Asynchronous Call Security in C++

The IWbemUnsecuredApartment::CreateSinkStub method is similar to IUnsecuredApartment::CreateObjectStub method and creates a sink in a separate process, Unsecapp.exe, to receive callbacks. However, the CreateSinkStub method has a dwFlagparameter that specifies how the separate process handles access control.

The dwFlag parameter specifies one of the following actions for Unsecapp.exe:

  • Use the registry key setting to determine whether or not to check access.
  • Ignore the registry key and always check access.
  • Ignore the registry key and never check access.

The code example in this topic requires the following #include statement to correctly compile.

#include <wbemidl.h>

The following procedure describes how to perform an asynchronous call with IWbemUnsecuredApartment.

To perform an asynchronous call with IWbemUnsecuredApartment

  1. Create a dedicated process with a call to CoCreateInstance.

    The following code example calls CoCreateInstance to create a dedicated process.

    CLSID                    CLSID_WbemUnsecuredApartment;
    IWbemUnsecuredApartment* pUnsecApp = NULL;
    
    CoCreateInstance(CLSID_WbemUnsecuredApartment, 
                     NULL, 
                     CLSCTX_LOCAL_SERVER, 
                     IID_IWbemUnsecuredApartment, 
                     (void**)&pUnsecApp);
    
  2. Instantiate the sink object.

    The following code example creates a new sink object.

    CMySink* pSink = new CMySink;
    pSink->AddRef();
    
  3. Create a stub for the sink.

    A stub is a wrapper function produced from the sink.

    The following code example creates a stub for the sink.

    LPCWSTR          wszReserved = NULL;           
    IWbemObjectSink* pStubSink   = NULL;
    IUnknown*        pStubUnk    = NULL; 
    
    pUnsecApp->CreateSinkStub(pSink,
                              WBEM_FLAG_UNSECAPP_CHECK_ACCESS,  //Authenticate callbacks regardless of registry key
                              wszReserved,
                              &pStubSink);
    
  4. Release the sink object pointer.

    You can release the object pointer because the stub now owns the pointer.

    The following code example releases the object pointer.

    pSink->Release();
    
  5. Use the stub in any asynchronous call.

    When finished with the call, release the local reference count.

    The following code example uses the stub in an asynchronous call.

    // pServices is an IWbemServices* object
    pServices->CreateInstanceEnumAsync(strClassName, 0, NULL, pStubSink);
    

    At times you may have to cancel an asynchronous call after you make the call. If you need to cancel the call, cancel the call with the same pointer that originally made the call.

    The following code example describes how to cancel an asynchronous call.

    pServices->CancelAsyncCall(pStubSink);
    
  6. Release the local reference count when you are done using the asynchronous call.

    Make sure to release the pStubSink pointer only after you confirm that the asynchronous call does not must be canceled. Further, do not release pStubSink after WMI releases the pSink sink pointer. Releasing pStubSink after pSink creates a circular reference count in which both the sink and the stub stay in memory forever. Instead, a possible location to release the pointer is in the IWbemObjectSink::SetStatus call, made by WMI to report that the original asynchronous call is complete.

  7. When finished, uninitialize COM with a call to Release().

    The following code example shows how to call Release() on the pUnsecApp pointer.

    pUnsecApp->Release();
    

For more information about the CoInitializeSecurity function and parameters, see the COM documentation.