Figure 1   COM Authentication Levels

Constant Value Authentication Quality of Service
RPC_C_AUTHN_LEVEL_NONE 1 All calls are anonymous
RPC_C_AUTHN_LEVEL_CONNECT 2 Authenticate first fragment of first call
RPC_C_AUTHN_LEVEL_CALL 3 Authenticate first fragment of every call
RPC_C_AUTHN_LEVEL_PKT 4 Authenticate every packet of every call
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5 Adds tamper detection
RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6 Adds encryption


Figure 2   IClientSecurity


///////////////////////
// excerpt from objidl.idl

[
    local,
    object,
    uuid(0000013D-0000-0000-C000-000000000046)
]
interface IClientSecurity : IUnknown
{
    // obtains the current settings for an interface proxy
    HRESULT QueryBlanket
    (
        [in]  IUnknown  *pProxy,
        [out] DWORD     *pAuthnSvc,
        [out] DWORD     *pAuthzSvc,
        [out] OLECHAR  **pServerPrincName,
        [out] DWORD     *pAuthnLevel,
        [out] DWORD     *pImpLevel,
        [out] void     **pAuthInfo,
        [out] DWORD     *pCapabilites
    );

    // changes the settings for an interface proxy
    HRESULT SetBlanket
    (
        [in] IUnknown *pProxy,
        [in] DWORD     AuthnSvc,
        [in] DWORD     AuthzSvc,
        [in] OLECHAR  *pServerPrincName,
        [in] DWORD     AuthnLevel,
        [in] DWORD     ImpLevel,
        [in] void     *pAuthInfo,
        [in] DWORD     Capabilities
    );

    // provided to help avoid race conditions in the MTA
    HRESULT CopyProxy
    (
        [in]  IUnknown  *pProxy,
        [out] IUnknown **ppCopy
    );
}


Figure 3   IServerSecurity


///////////////////////
// excerpt from objidl.idl

[
    local,
    object,
    uuid(0000013E-0000-0000-C000-000000000046)
]
interface IServerSecurity : IUnknown
{
    // determine the settings used by the client
    HRESULT QueryBlanket
    (
        [out] DWORD    *pAuthnSvc,
        [out] DWORD    *pAuthzSvc,
        [out] OLECHAR **pServerPrincName,
        [out] DWORD    *pAuthnLevel,
        [out] DWORD    *pImpLevel,
        [out] void    **pPrivs,
        [out] DWORD    *pCapabilities
    );

    HRESULT ImpersonateClient();
    HRESULT RevertToSelf();
    BOOL IsImpersonating();
}

// exerpt from objbase.h
WINOLEAPI CoGetCallContext( REFIID riid, void **ppInterface );

Figure 4   CoInitializeSecurity


///////////////////////
// excerpt from objbase.h

WINOLEAPI CoInitializeSecurity(
    PSECURITY_DESCRIPTOR         pSecDesc,
    LONG                         cAuthSvc,
    SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
    void                        *pReserved1,
    DWORD                        dwAuthnLevel,
    DWORD                        dwImpLevel,
    void                        *pReserved2,
    DWORD                        dwCapabilities,
    void                        *pReserved3 );

Figure 7   SetBlanket.cpp


// SetBlanket.cpp - sample code for explicitly turning off authentication
//                  on various interfaces of a proxy.

// The following function uses QueryBlanket and SetBlanket to correctly
// drop the authentication level to NONE, without mucking up any other
// security settings.
HRESULT TurnOffAuthenticationOnThisInterface( IUnknown* pUnk )
{
    IClientSecurity* pcs;
    HRESULT hr = pUnk->QueryInterface( IID_IClientSecurity, (void**)&pcs );
    if ( FAILED( hr ) )
        return hr;

    // Use QueryBlanket to obtain all the other settings that
    // we want to leave the same (don't just call SetBlanket blindly!)
    // Also, since we are turning *off* authentication, we don't care about
    // the RPC_AUTH_IDENTITY_HANDLE parameter.
    DWORD dwAuthnSvc, dwAuthzSvc, dwImpLevel, grfCaps;
    OLECHAR* pszServerPrincipal;
    hr = pcs->QueryBlanket( pUnk, &dwAuthnSvc, &dwAuthzSvc,
                            &pszServerPrincipal,
                            0,
                            &dwImpLevel, 0, &grfCaps );

    // Important note: SetBlanket on the proxy manager (IUnknown) only controls 
    // the settings for QueryInterface in Windows NT 4.0 SP3. In Windows 
    // NT 4.0 SP4 and Windows NT 5.0, this will control Release as well.
    if ( SUCCEEDED( hr ) )
        hr = pcs->SetBlanket( pUnk, dwAuthnSvc, dwAuthzSvc,
                              pszServerPrincipal,
                              RPC_C_AUTHN_LEVEL_NONE,
                              dwImpLevel, 0, grfCaps );
    pcs->Release();

    return hr;
}

// The following code snippet demonstrates that you need to explicitly
// use SetBlanket on each interface you want to make calls through,
// since security settings are stored separately for individual
// interface proxies.
// After calling this function, we can use both IUnknown and IFoo to make
// unauthenticated calls. If you needed to also make calls via IBar,
// just repeat for that interface as well.
HRESULT TurnOffAuthenticationForMultipleInterfaces( IFoo* pFoo )
{
    // turn off authentication on the IFoo interface proxy
    HRESULT hr = TurnOffAuthenticationOnThisInterface( pFoo );
    
    // turn off authentication for IUnknown (on the proxy manager)
    IUnknown* pUnk;
    hr = pFoo->QueryInterface( IID_IUnknown, (void**)&pUnk );
    if ( SUCCEEDED( hr ) )
    {
        hr = TurnOffAuthenticationOnThisInterface( pUnk );
        pUnk->Release();
    }
    return hr;
}

Figure 8   lsa.cpp



// lsa.cpp - Sample code for programming the LSAAPI
//           to set the RunAs password and privileges.
//           Error handling has been omitted for clarity.
//           Only administrators can execute this code
//           without being denied access to the LSA policy.
//
// Note that Michael Nelson has a tool called DCOMBRIDGE
// that will allow higher level languages like VB access
// to this functionality.
// (http://www.iapetus.com/dcom/dcp20sdk.zip)

#include <windows.h>
#include "ntsecapi.h"

// InitString is a helper function that initializes
// a UNICODE_STRING from a simple NULL terminated string.
void InitString( UNICODE_STRING& us, wchar_t* psz )
{
    USHORT cch = wcslen( psz );
    us.Length = cch * sizeof( wchar_t );
    us.MaximumLength = ( cch + 1 ) * sizeof( wchar_t );
    us.Buffer = psz;
}

// SetCOMRunAsPassword sets the corresponding password
// for the RunAs principal for a given AppID into the
// LSA as a secret. This allows the COM SCM to look it up
// and call LogonUser / CreateProcessAsUser to launch your
// COM server using the security principal of your choice.
void SetCOMRunAsPassword( const GUID& AppID, wchar_t* pszPassword )
{
    LSA_HANDLE hPolicy = 0;
    LSA_OBJECT_ATTRIBUTES oa = { sizeof oa };
    LsaOpenPolicy( 0, &oa, POLICY_CREATE_SECRET, &hPolicy );
    
    // create key formed from AppID in the following format:
    // "SCM:{00000000-0000-0000-0000-000000000000}"
    wchar_t szKey[84] = L"SCM:";
    StringFromGUID2( AppID, szKey + 4, 80 * sizeof *szKey );
    
    UNICODE_STRING usKey;   InitString( usKey,   szKey );
    UNICODE_STRING usValue; InitString( usValue, pszPassword );
    
    LsaStorePrivateData( hPolicy, &usKey, &usValue );

    LsaClose( hPolicy );
}

// This helper function demonstrates how to add a privilege
// to a user account. The privilege you will most likely
// be interested in is "SeBatchLogonRight".
void AddPrivilege( void* psid, wchar_t* pszPriv )
{
    LSA_HANDLE hPolicy = 0;
    LSA_OBJECT_ATTRIBUTES oa = { sizeof oa };
    LsaOpenPolicy( 0, &oa,
                   POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT,
                   &hPolicy );

    UNICODE_STRING usPriv; InitString( usPriv, pszPriv );

    LsaAddAccountRights( hPolicy, psid, &usPriv, 1 );

    LsaClose( hPolicy );
}