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 );
}