307 lines
9.6 KiB
C++
307 lines
9.6 KiB
C++
//***************************************************************************
|
|
//
|
|
// KERBTEST.CPP
|
|
//
|
|
// Module: WBEM kerberos provider sample code
|
|
//
|
|
// Purpose: Defines the CKerbTestPro class. An object of this class is
|
|
// created by the class factory for each connection.
|
|
//
|
|
// Copyright (c)1998-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
#define _WIN32_WINNT 0x0400
|
|
|
|
#include <objbase.h>
|
|
#include "kerbtest.h"
|
|
#include <process.h>
|
|
#include <wbemidl.h>
|
|
#include <stdio.h>
|
|
#include <objbase.h>
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CKerbTestPro::CKerbTestPro
|
|
// CKerbTestPro::~CKerbTestPro
|
|
//
|
|
//***************************************************************************
|
|
|
|
CKerbTestPro::CKerbTestPro()
|
|
{
|
|
InterlockedIncrement(&g_cObj);
|
|
return;
|
|
|
|
}
|
|
|
|
CKerbTestPro::~CKerbTestPro(void)
|
|
{
|
|
InterlockedDecrement(&g_cObj);
|
|
return;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CKerbTestPro::QueryInterface
|
|
// CKerbTestPro::AddRef
|
|
// CKerbTestPro::Release
|
|
//
|
|
// Purpose: IUnknown members for CKerbTestPro object.
|
|
//***************************************************************************
|
|
|
|
|
|
STDMETHODIMP CKerbTestPro::QueryInterface(REFIID riid, PPVOID ppv)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if (IID_IUnknown==riid || IID_IWbemServices == riid || IID_IWbemProviderInit==riid)
|
|
if(riid== IID_IWbemServices){
|
|
*ppv=(IWbemServices*)this;
|
|
}
|
|
|
|
if(IID_IUnknown==riid || riid== IID_IWbemProviderInit){
|
|
*ppv=(IWbemProviderInit*)this;
|
|
}
|
|
|
|
|
|
if (NULL!=*ppv) {
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CKerbTestPro::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CKerbTestPro::Release(void)
|
|
{
|
|
ULONG nNewCount = InterlockedDecrement((long *)&m_cRef);
|
|
if (0L == nNewCount)
|
|
delete this;
|
|
|
|
return nNewCount;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* *
|
|
*CKerbTestPro::Initialize *
|
|
* *
|
|
*Purpose: This is the implementation of IWbemProviderInit. The method *
|
|
* is need to initialize with CIMOM. *
|
|
* *
|
|
***********************************************************************/
|
|
STDMETHODIMP CKerbTestPro::Initialize(LPWSTR pszUser, LONG lFlags,
|
|
LPWSTR pszNamespace, LPWSTR pszLocale,
|
|
IWbemServices *pNamespace,
|
|
IWbemContext *pCtx,
|
|
IWbemProviderInitSink *pInitSink)
|
|
{
|
|
|
|
|
|
m_pWbemSvcs=pNamespace;
|
|
m_pWbemSvcs->AddRef();
|
|
|
|
//Let CIMOM know your initialized
|
|
//===============================
|
|
pInitSink->SetStatus(WBEM_S_INITIALIZED,0);
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* *
|
|
*CKerbTestPro::ExecMethodAsync *
|
|
* *
|
|
*Purpose: This is the Async function implementation. *
|
|
* The only method supported in this sample is named . It *
|
|
* takes an input string, copies it to the output and returns the*
|
|
* length. The mof definition is *
|
|
* *
|
|
* [dynamic: ToInstance, provider("KerbTest")]class KerbTest *
|
|
* { *
|
|
* [implemented, static] *
|
|
* uint32 RemoteGetObject([IN]string sObjPath= "__win32provider" ,*
|
|
* [IN]string sNamespace= "\\\\a-khint3\\root" , *
|
|
* [IN]string sPrincipal="a-davjdom\\a-khint3", *
|
|
* [out] object OutArg); }; *
|
|
* *
|
|
************************************************************************/
|
|
|
|
STDMETHODIMP CKerbTestPro::ExecMethodAsync(const BSTR ObjectPath, const BSTR MethodName,
|
|
long lFlags, IWbemContext* pCtx, IWbemClassObject* pInParams,
|
|
IWbemObjectSink* pResultSink)
|
|
{
|
|
HRESULT hr;
|
|
IWbemClassObject * pClass = NULL;
|
|
IWbemClassObject * pOutClass = NULL;
|
|
IWbemClassObject* pOutParams = NULL;
|
|
|
|
|
|
// Do some minimal error checking. This code only support the
|
|
// method "RemoteGetObject".
|
|
|
|
if(_wcsicmp(MethodName, L"RemoteGetObject") || pInParams == NULL)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
// Get the class object and spawn an instance of the return parameters
|
|
|
|
BSTR ClassName = SysAllocString(L"KerbTest");
|
|
hr = m_pWbemSvcs->GetObject(ClassName, 0, pCtx, &pClass, NULL);
|
|
SysFreeString(ClassName);
|
|
if(hr != S_OK)
|
|
{
|
|
pResultSink->SetStatus(0,hr, NULL, NULL);
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
hr = pClass->GetMethod(MethodName, 0, NULL, &pOutClass);
|
|
pClass->Release();
|
|
pOutClass->SpawnInstance(0, &pOutParams);
|
|
pOutClass->Release();
|
|
|
|
|
|
// Copy the input arguments into variants
|
|
// The first argument is the object path and should be an instance or class
|
|
// The second is the remote namespace. It should be "\\machine\root" etc,
|
|
// The last is the pricipal. For Kerberos, it should be a combination of
|
|
// the domain and machine name. Ex; "a-davjdom\machine"
|
|
|
|
VARIANT varObjPath;
|
|
VariantInit(&varObjPath); // Get the input argument
|
|
pInParams->Get(L"sObjPath", 0, &varObjPath, NULL, NULL);
|
|
|
|
VARIANT varNamespace;
|
|
VariantInit(&varNamespace); // Get the input argument
|
|
pInParams->Get(L"sNamespace", 0, &varNamespace, NULL, NULL);
|
|
|
|
VARIANT varPrincipal;
|
|
VariantInit(&varPrincipal); // Get the input argument
|
|
pInParams->Get(L"sPrincipal", 0, &varPrincipal, NULL, NULL);
|
|
|
|
// Get the remote machine name. Extract it from the namespace name. Note that
|
|
// production code would do a few checks here!
|
|
|
|
WCHAR wMachineName[30];
|
|
WCHAR * pTo = wMachineName;
|
|
WCHAR * pFrom = varNamespace.bstrVal + 2; // The 2 is for skipping around the leading slashes
|
|
for(; *pFrom != L'\\' ; pTo++, pFrom++)
|
|
*pTo = *pFrom;
|
|
*pTo = 0;
|
|
|
|
// Impersonate
|
|
|
|
hr = CoImpersonateClient();
|
|
|
|
|
|
// The following code replaces a ConnectServer call!!!
|
|
// Start of by getting the Login object on the remote machine.
|
|
|
|
COSERVERINFO csi, *pcsi=NULL;
|
|
MULTI_QI mq;
|
|
COAUTHINFO AuthInfo;
|
|
|
|
IWbemServices *pNamespace = 0;
|
|
|
|
memset(&csi, 0, sizeof(COSERVERINFO));
|
|
csi.pwszName = wMachineName;
|
|
pcsi = &csi;
|
|
|
|
AuthInfo.dwAuthnSvc = 16;
|
|
AuthInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
AuthInfo.pwszServerPrincName = varPrincipal.bstrVal;
|
|
AuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
|
|
AuthInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_DELEGATE;
|
|
AuthInfo.pAuthIdentityData = NULL;
|
|
AuthInfo.dwCapabilities = 0X20;
|
|
pcsi->pAuthInfo = &AuthInfo;
|
|
|
|
// create a remote instance of the Login object on the remote machine
|
|
mq.pIID = &IID_IWbemLevel1Login;
|
|
mq.pItf = NULL;
|
|
mq.hr = S_OK;
|
|
hr = CoCreateInstanceEx(CLSID_WbemLevel1Login, NULL, CLSCTX_REMOTE_SERVER, pcsi, 1, &mq);
|
|
IWbemLevel1Login * m_pLevel1 = (IWbemLevel1Login*)mq.pItf;
|
|
|
|
if ((hr == S_OK))
|
|
{
|
|
hr = CoSetProxyBlanket(
|
|
m_pLevel1,
|
|
16,
|
|
RPC_C_AUTHZ_NONE,
|
|
varPrincipal.bstrVal,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
0x20);
|
|
|
|
// Use the remote login object to create a services pointer
|
|
|
|
hr = m_pLevel1->NTLMLogin(varNamespace.bstrVal, NULL, 0, NULL, &pNamespace);
|
|
if(hr == S_OK)
|
|
hr = CoSetProxyBlanket(
|
|
pNamespace,
|
|
16,
|
|
RPC_C_AUTHZ_NONE,
|
|
varPrincipal.bstrVal,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
0x20);
|
|
hr = m_pLevel1->Release();
|
|
}
|
|
|
|
if(hr == S_OK)
|
|
{
|
|
|
|
// At this point we have a services interface to a remote machine
|
|
// Call get object and revert to self.
|
|
|
|
IWbemClassObject * pObj = NULL;
|
|
hr = pNamespace->GetObject(varObjPath.bstrVal, 0, NULL, &pObj, NULL);
|
|
CoRevertToSelf();
|
|
|
|
if(hr == S_OK)
|
|
{
|
|
// This code is mainly for demo purposes. This embeds the returned object
|
|
// in the return object of the method and has nothing to do with Kerberos!
|
|
|
|
VARIANT var;
|
|
VariantInit(&var); // Get the input argument
|
|
var.punkVal = (IUnknown *)pObj;
|
|
var.vt = VT_UNKNOWN;
|
|
pOutParams->Put(L"OutArg" , 0, &var, 0);
|
|
long lLen = wcslen(var.bstrVal);
|
|
var.vt = VT_I4;
|
|
var.lVal = 0;
|
|
pOutParams->Put(L"ReturnValue" , 0, &var, 0);
|
|
|
|
// Send the output object back to the client via the sink. Then
|
|
// release the pointers and free the strings.
|
|
|
|
hr = pResultSink->Indicate(1, &pOutParams);
|
|
pObj->Release();
|
|
}
|
|
pNamespace->Release();
|
|
}
|
|
|
|
// Free up stuff
|
|
|
|
VariantClear(&varObjPath);
|
|
VariantClear(&varNamespace);
|
|
VariantClear(&varPrincipal);
|
|
pOutParams->Release();
|
|
|
|
// all done now, set the status
|
|
|
|
pResultSink->SetStatus(0,hr, NULL, NULL);
|
|
return WBEM_S_NO_ERROR;
|
|
}
|