1384 lines
40 KiB
C++

//----------------------------------------------------------------------------
//
// Copyright (C) 2003 Intel Corporation
//
// File: CimWsman.h
//
// Contents: Library independent interface to WS-Management transport
//
//----------------------------------------------------------------------------
#include <atlbase.h>
#include <atlconv.h>
#include <sstream>
#include "CimWinRMClient.h"
#include "CimException.h"
using namespace std;
namespace Intel
{
namespace WSManagement
{
using Intel::Manageability::Exceptions::WSManException;
using Intel::Manageability::Exceptions::HTTPException;
using Intel::Manageability::Exceptions::ConversionException;
const SCODE WSMAN_ERROR1 = 0x803380f5;
const SCODE WSMAN_ERROR2 = 0x8033803D;
const SCODE WSMAN_ERROR3 = 0x80338013;
// Copy constructor
CimWinRMClient::CimWinRMClient(const CimWinRMClient& Other)
: connection(Other.connection)
{
}
// operator =
CimWinRMClient& CimWinRMClient::operator=(const CimWinRMClient& other)
{
if(this != &other)
{
connection = other.connection;
}
return *this;
}
// Constructor from params.
CimWinRMClient::CimWinRMClient(const string &host,
const int port,
bool secure,
AuthMethod auth_method,
const string &username,
const string &password
)
{
connection.authmethod = auth_method;
connection.host = host;
connection.port = port;
connection.username = username;
connection.password = password;
connection.secure = secure;
if(!Init())
{
ReleaseDisps();
throw WSManException("ERROR: Failed to create winrm client.\n"
"Make Sure your system supports WS-MAN COM development and that CoInitialize() was called.");
}
}
// Constructor from ConnectionInfo.
CimWinRMClient::CimWinRMClient(const ConnectionInfo &Connection)
: connection(Connection)
{
if(!Init())
{
ReleaseDisps();
throw WSManException(
"ERROR: Failed to create winrm client.\n"
"Make Sure your system supports WS-MAN COM development and that CoInitialize() was called.");
}
}
// Initialize the WinRM client.
bool CimWinRMClient::Init()
{
if(connection.proxy_host.length() > 0)
{
throw invalid_argument("WinRM does not support proxy connections");
}
if(connection.certificate.length() > 0)
{
throw invalid_argument("WinRM does not support mutual authentication.");
}
HRESULT res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(0 > res)
{
return false;
}
_pWsmanSessionDispatch = NULL;
_pWsmanDispatch = NULL;
_pWsmanConnectionOptions = NULL;
_getDispid = 0;
_putDispid = 0;
_createDispid = 0;
_enumerateDispid = 0;
_invokeDispid = 0;
_deleteDispid = 0;
_createSessionDispid = 0;
_createConnectionOptionsDispid = 0;
_createResourceLocatorDispid = 0;
_dispPropertyPut = DISPID_PROPERTYPUT;
_connectionFlags = 0;
HRESULT hr = E_FAIL;
// get wsman.automation object
hr = CLSIDFromProgID(L"wsman.automation", &_wsmanOleClsid);
if (FAILED(hr))
{
return false;
}
hr = CoCreateInstance(_wsmanOleClsid, 0, CLSCTX_INPROC_SERVER, IID_IDispatch, (LPVOID *)&_pWsmanDispatch);
if (FAILED(hr))
{
return false;
}
// create connection
return CreateSession() && GetFunctionIds() && GetDispId(_pWsmanDispatch, &_createResourceLocatorDispid, L"createresourcelocator");
}
// Destructor.
CimWinRMClient::~CimWinRMClient()
{
ReleaseDisps();
CoUninitialize();
}
// ConnectionInfo
ConnectionInfo CimWinRMClient::Connection() const
{
return connection;
}
// Creates a new instance of a resource.
string CimWinRMClient::Create(const string &resourceUri, const string &data) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, resourceUri, NULL))
{
throw WSManException("ERROR: Failed to perform Create function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS createArgs = {0};
createArgs.cArgs = 3;
createArgs.rgvarg = new VARIANTARG[createArgs.cArgs]; // parameters are passed in reverse order
createArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
createArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
createArgs.rgvarg[1].vt = VT_BSTR;
int len = MultiByteToWideChar(CP_ACP, 0, data.c_str(), data.length()+1,0,0);
wchar_t* resource = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, data.c_str(), data.length()+1, resource, len);
createArgs.rgvarg[1].bstrVal = SysAllocString(resource);
delete[] resource;
createArgs.rgvarg[2].vt = VT_VARIANT | VT_BYREF;
createArgs.rgvarg[2].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_createDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &createArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
VariantClear(&(createArgs.rgvarg[1]));
delete [] createArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Create function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if (w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
auto w2ca = W2CA(var.bstrVal);
string ret(w2ca != nullptr ? w2ca : "");
VariantClear(&var);
return ret;
}
// Identify.
string CimWinRMClient::Identify() const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
DISPPARAMS getArgs = {0};
getArgs.cArgs = 1;
getArgs.rgvarg = new VARIANTARG[getArgs.cArgs]; // parameters are passed in reverse order
getArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
getArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_identifyDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &getArgs, &var, &excepinfo, &argNum);
delete [] getArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Identify function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if (w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
auto w2ca = W2CA(var.bstrVal);
string ret(w2ca != nullptr ? w2ca : "");
VariantClear(&var);
return ret;
}
// Delete a resource.
void CimWinRMClient::Delete(const string &resourceUri, const NameValuePairs *s) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, resourceUri, s))
{
throw WSManException("ERROR: Failed to perform Delete function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS deleteArgs = {0};
deleteArgs.cArgs = 2;
deleteArgs.rgvarg = new VARIANTARG[deleteArgs.cArgs]; // parameters are passed in reverse order
deleteArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
deleteArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
deleteArgs.rgvarg[1].vt = VT_VARIANT | VT_BYREF;
deleteArgs.rgvarg[1].pvarVal = &uri;
unsigned int argNum = 0;
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_deleteDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &deleteArgs, NULL, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
delete [] deleteArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Delete function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
}
// Enumerate resource.
void CimWinRMClient::Enumerate(const string &resourceUri, vector<string> &enumRes, const NameValuePairs *s) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, resourceUri, NULL))
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS enumArgs = {0};
enumArgs.cArgs = 4;
enumArgs.rgvarg = new VARIANTARG[enumArgs.cArgs]; // parameters are passed in reverse order
if(s) //Adding the selectors to the body of the enumeration
{
const LPTSTR test = TEXT("http://schemas.dmtf.org/wbem/wsman/1/wsman/SelectorFilter");
const BSTR dialect = T2BSTR(test);
string input("<SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">");
for (const auto& p : *s)
{
input += "<Selector Name=\""+ p.first+"\">"+ p.second+"</Selector>";
}
input += "</SelectorSet>";
wchar_t *ws = new wchar_t[input.length() + 1];
size_t charsConverted = 0;
if (mbstowcs_s(&charsConverted, ws, input.length(), input.c_str(), input.length())) {
delete[] ws;
throw ConversionException(string("could not convert multibyte characters to wide characters.").c_str());
}
ws[input.length()] = L'\0';
const auto in = ws;
// SysAlloc inside, how allocation is released ?
const BSTR filter1 = T2BSTR(in);
delete[] ws;
// Adding the WSManEnumFlags
enumArgs.rgvarg[0].vt = VT_UI4;
enumArgs.rgvarg[0].lVal = 0; //WSManFlagReturnObject
// Adding dialect
enumArgs.rgvarg[1].vt = VT_BSTR;
enumArgs.rgvarg[1].bstrVal = dialect;
// Adding filter
enumArgs.rgvarg[2].vt = VT_BSTR;
enumArgs.rgvarg[2].bstrVal = filter1;
}
else
{
enumArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
enumArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
enumArgs.rgvarg[1].vt = VT_ERROR; // skip optional param
enumArgs.rgvarg[1].scode = DISP_E_PARAMNOTFOUND;
enumArgs.rgvarg[2].vt = VT_ERROR; // skip optional param
enumArgs.rgvarg[2].scode = DISP_E_PARAMNOTFOUND;
}
enumArgs.rgvarg[3].vt = VT_VARIANT | VT_BYREF;
enumArgs.rgvarg[3].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_enumerateDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &enumArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
delete [] enumArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Enumerate function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
IDispatch* enumerator = nullptr;
hr = var.punkVal->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID *>(&enumerator));
VariantClear(&var);
if (FAILED(hr))
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
const auto ret = GetEnumerationItems(enumerator, enumRes);
enumerator->Release();
if(!ret)
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
}
// Retrieve a resource.
string CimWinRMClient::Get(const string &resourceUri, const NameValuePairs *s) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, resourceUri, s))
{
throw WSManException("ERROR: Failed to perform Get function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS getArgs = {0};
getArgs.cArgs = 2;
getArgs.rgvarg = new VARIANTARG[getArgs.cArgs]; // parameters are passed in reverse order
getArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
getArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
getArgs.rgvarg[1].vt = VT_VARIANT | VT_BYREF;
getArgs.rgvarg[1].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_getDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &getArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
delete [] getArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Get function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
auto w2ca = W2CA(var.bstrVal);
string ret(w2ca != nullptr ? w2ca : "");
VariantClear(&var);
return ret;
}
// Update a resource.
string CimWinRMClient::Put(const string &resourceUri, const string &content, const NameValuePairs *s) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, resourceUri, s))
{
throw WSManException("ERROR: Failed to perform Get function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS putArgs = {0};
putArgs.cArgs = 3;
putArgs.rgvarg = new VARIANTARG[putArgs.cArgs]; // parameters are passed in reverse order
putArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
putArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
putArgs.rgvarg[1].vt = VT_BSTR;
int len = MultiByteToWideChar(CP_ACP, 0, content.c_str(), content.length()+1,0,0);
wchar_t* resource = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, content.c_str(), content.length()+1, resource, len);
putArgs.rgvarg[1].bstrVal = SysAllocString(resource);
delete[] resource;
putArgs.rgvarg[2].vt = VT_VARIANT | VT_BYREF;
putArgs.rgvarg[2].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_putDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &putArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
VariantClear(&(putArgs.rgvarg[1]));
delete [] putArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Put function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
auto w2ca = W2CA(var.bstrVal);
string ret(w2ca != nullptr ? w2ca : "");
VariantClear(&var);
return ret;
}
// Invokes a method and returns the results of the method call.
string CimWinRMClient::Invoke(const string &resourceUri, const string &methodName, const string &content, const NameValuePairs *s) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
IDispatch* resourceLocator = nullptr;
if(!CreateResourceLocator(&resourceLocator, resourceUri, s))
{
string msg = "ERROR: Failed to perform Invoke " + methodName + " function.";
throw WSManException(msg);
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
DISPPARAMS invokeArgs = {0};
invokeArgs.cArgs = 4;
invokeArgs.rgvarg = new VARIANTARG[invokeArgs.cArgs]; // parameters are passed in reverse order
invokeArgs.rgvarg[0].vt = VT_ERROR; // skip optional param
invokeArgs.rgvarg[0].scode = DISP_E_PARAMNOTFOUND;
invokeArgs.rgvarg[1].vt = VT_BSTR;
int len = MultiByteToWideChar(CP_ACP, 0, content.c_str(), content.length()+1,0,0);
wchar_t* resource = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, content.c_str(), content.length()+1, resource, len);
invokeArgs.rgvarg[1].bstrVal = SysAllocString(resource);
delete[] resource;
invokeArgs.rgvarg[2].vt = VT_VARIANT | VT_BYREF;
invokeArgs.rgvarg[2].pvarVal = &uri;
invokeArgs.rgvarg[3].vt = VT_BSTR;
len = MultiByteToWideChar(CP_ACP, 0, methodName.c_str(), methodName.length()+1,0,0);
wchar_t* meth = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, methodName.c_str(), methodName.length()+1, meth, len);
invokeArgs.rgvarg[3].bstrVal = SysAllocString(meth);
delete[] meth;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_invokeDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &invokeArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
VariantClear(&(invokeArgs.rgvarg[1]));
VariantClear(&(invokeArgs.rgvarg[3]));
delete [] invokeArgs.rgvarg;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Invoke " + methodName + "function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
auto w2ca = W2CA(var.bstrVal);
string ret( w2ca != nullptr ? w2ca :"");
VariantClear(&var);
return ret;
}
// "Special" Enumerate
void CimWinRMClient::Enumerate(vector<string> &enumRes, const EnumerateFilter &filter) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
string enumerateURI = "http://schemas.dmtf.org/wbem/wscim/1/*";
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, enumerateURI, NULL))
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
LPTSTR test = TEXT("http://schemas.dmtf.org/wbem/wsman/1/cimbinding/associationFilter");
BSTR dialect = T2BSTR(test);
string input = "";
if(filter.assocType == EnumerateFilter::AssociatedInstance)
input += "<AssociatedInstances xmlns=\""+CIMBINDING_NS+"\">";
else if(filter.assocType == EnumerateFilter::AssociationInstance)
input += "<AssociationInstances xmlns=\""+CIMBINDING_NS+"\">";
input += "<Object xmlns=\""+CIMBINDING_NS+"\">" + filter.reference.Serialize() + "</Object>";
if (filter.associationClass.length() > 0)
input += "<AssociationClassName xmlns=\""+CIMBINDING_NS+"\">"+ filter.associationClass +"</AssociationClassName>";
if (filter.role.length() > 0)
input += "<Role xmlns=\""+CIMBINDING_NS+"\">"+ filter.role+"</Role>";
if (filter.resultClass.length() > 0)
input += "<ResultClassName xmlns=\""+CIMBINDING_NS+"\">"+ filter.resultClass +"</ResultClassName>";
if (filter.resultRole.length() > 0)
input += "<ResultRole xmlns=\""+CIMBINDING_NS+"\">"+ filter.resultRole +"</ResultRole>";
vector<string>::const_iterator iter;
for(iter = filter.resultProperties.begin(); iter != filter.resultProperties.end(); iter++)
{
input += "<IncludeResultProperty xmlns=\""+CIMBINDING_NS+"\">"+ *iter +"</IncludeResultProperty>";
filter.resultProperties;
}
if(filter.assocType == EnumerateFilter::AssociatedInstance)
input += "</AssociatedInstances>";
else if(filter.assocType == EnumerateFilter::AssociationInstance)
input += "</AssociationInstances>";
size_t charsConverted = 0;
wchar_t *ws = new wchar_t[input.length() + 1];
if (mbstowcs_s(&charsConverted, ws, input.length(), input.c_str(), input.length())) {
delete[] ws;
::SysFreeString(dialect);
throw ConversionException(string("could not convert multibyte characters to wide characters.").c_str());
}
ws[input.length()] = L'\0';
LPTSTR in = ws;
BSTR filter1 = T2BSTR(in);
DISPPARAMS enumArgs = {0};
enumArgs.cArgs = 4;
enumArgs.rgvarg = new VARIANTARG[enumArgs.cArgs]; // parameters are passed in reverse order
// Adding the WSManEnumFlags
enumArgs.rgvarg[0].vt = VT_UI4;
enumArgs.rgvarg[0].lVal = 0; //WSManFlagReturnObject
// Adding dialect
enumArgs.rgvarg[1].vt = VT_BSTR;
enumArgs.rgvarg[1].bstrVal = dialect;
// Adding filter
enumArgs.rgvarg[2].vt = VT_BSTR;
enumArgs.rgvarg[2].bstrVal = filter1;
enumArgs.rgvarg[3].vt = VT_VARIANT | VT_BYREF;
enumArgs.rgvarg[3].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_enumerateDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &enumArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
delete [] enumArgs.rgvarg;
delete [] ws;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Enumerate function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if (excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3) {
::SysFreeString(dialect);
::SysFreeString(filter1);
throw WSManException(msg.str());
}
else {
::SysFreeString(dialect);
::SysFreeString(filter1);
throw HTTPException(msg.str());
}
}
IDispatch* enumerator = nullptr;
hr = var.punkVal->QueryInterface(IID_IDispatch, (LPVOID *)&enumerator);
VariantClear(&var);
if (FAILED(hr))
{
::SysFreeString(dialect);
::SysFreeString(filter1);
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
bool ret = GetEnumerationItems(enumerator, enumRes);
enumerator->Release();
if(!ret)
{
::SysFreeString(dialect);
::SysFreeString(filter1);
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
::SysFreeString(dialect);
::SysFreeString(filter1);
}
// "Special" Enumerate of references
void CimWinRMClient::EnumerateRef(vector<string> &enumRes, const EnumerateFilter &filter) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
string enumerateURI = "http://schemas.dmtf.org/wbem/wscim/1/*";
IDispatch* resourceLocator = 0;
if(!CreateResourceLocator(&resourceLocator, enumerateURI, NULL))
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
VARIANT uri;
VariantInit(&uri);
uri.vt = VT_DISPATCH;
uri.pdispVal = resourceLocator;
LPTSTR test = TEXT("http://schemas.dmtf.org/wbem/wsman/1/cimbinding/associationFilter");
BSTR dialect = T2BSTR(test);
string input = "";
if(filter.assocType == EnumerateFilter::AssociatedInstance)
input += "<AssociatedInstances xmlns=\""+CIMBINDING_NS+"\">";
else if(filter.assocType == EnumerateFilter::AssociationInstance)
input += "<AssociationInstances xmlns=\""+CIMBINDING_NS+"\">";
input += "<Object xmlns=\""+CIMBINDING_NS+"\">" + filter.reference.Serialize() + "</Object>";
if (filter.associationClass.length() > 0)
input += "<AssociationClassName xmlns=\""+CIMBINDING_NS+"\">"+ filter.associationClass +"</AssociationClassName>";
if (filter.role.length() > 0)
input += "<Role xmlns=\""+CIMBINDING_NS+"\">"+ filter.role+"</Role>";
if (filter.resultClass.length() > 0)
input += "<ResultClassName xmlns=\""+CIMBINDING_NS+"\">"+ filter.resultClass +"</ResultClassName>";
if (filter.resultRole.length() > 0)
input += "<ResultRole xmlns=\""+CIMBINDING_NS+"\">"+ filter.resultRole +"</ResultRole>";
vector<string>::const_iterator iter;
for(iter = filter.resultProperties.begin(); iter != filter.resultProperties.end(); iter++)
{
input += "<IncludeResultProperty xmlns=\""+CIMBINDING_NS+"\">"+ *iter +"</IncludeResultProperty>";
filter.resultProperties;
}
if(filter.assocType == EnumerateFilter::AssociatedInstance)
input += "</AssociatedInstances>";
else if(filter.assocType == EnumerateFilter::AssociationInstance)
input += "</AssociationInstances>";
size_t charsConverted = 0;
wchar_t *ws = new wchar_t[input.length() + 1];
if (mbstowcs_s(&charsConverted, ws, input.length(), input.c_str(), input.length())) {
delete[] ws;
::SysFreeString(dialect);
throw ConversionException(string("could not convert multibyte characters to wide characters.").c_str());
}
ws[input.length()] = L'\0';
LPTSTR in = ws;
BSTR filter1 = T2BSTR(in);
DISPPARAMS enumArgs = {0};
enumArgs.cArgs = 4;
enumArgs.rgvarg = new VARIANTARG[enumArgs.cArgs]; // parameters are passed in reverse order
// Adding the WSManEnumFlags
enumArgs.rgvarg[0].vt = VT_UI4;
enumArgs.rgvarg[0].lVal = 2; //EnumerationFlagReturnEPR
// Adding dialect
enumArgs.rgvarg[1].vt = VT_BSTR;
enumArgs.rgvarg[1].bstrVal = dialect;
// Adding filter
enumArgs.rgvarg[2].vt = VT_BSTR;
enumArgs.rgvarg[2].bstrVal = filter1;
enumArgs.rgvarg[3].vt = VT_VARIANT | VT_BYREF;
enumArgs.rgvarg[3].pvarVal = &uri;
unsigned int argNum = 0;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanSessionDispatch->Invoke(_enumerateDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &enumArgs, &var, &excepinfo, &argNum);
resourceLocator->Release();
VariantClear(&uri);
::SysFreeString(dialect);
delete [] enumArgs.rgvarg;
delete [] ws;
if (FAILED(hr))
{
stringstream msg;
msg << "ERROR: Failed to perform Enumerate function." << endl;
msg << "Winrm error code: " << excepinfo.scode;
const auto w2ca_e = (excepinfo.bstrDescription != nullptr) ? (W2CA(excepinfo.bstrDescription)) : nullptr;
if(w2ca_e)
{
msg << endl << endl << "Error Description: " << w2ca_e;
}
if(excepinfo.scode == WSMAN_ERROR1 || excepinfo.scode == WSMAN_ERROR2 || excepinfo.scode == WSMAN_ERROR3)
throw WSManException(msg.str());
else
throw HTTPException(msg.str());
}
IDispatch* enumerator = nullptr;
hr = var.punkVal->QueryInterface(IID_IDispatch, (LPVOID *)&enumerator);
VariantClear(&var);
if (FAILED(hr))
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
bool ret = GetEnumerationItems(enumerator, enumRes);
enumerator->Release();
if(!ret)
{
throw WSManException("ERROR: Failed to perform Enumerate function.");
}
}
// Submit a subscription
string CimWinRMClient::Subscribe(const string &resourceUri, const SubscribeInfo &info, string &identifier) const
{
throw WSManException("Subscribe: not implemented in WinRM client");
}
// Renew a subscription
string CimWinRMClient::Renew(const string &resourceUri, const string &identifier, float expire, const NameValuePairs *s) const
{
throw WSManException("Renew: not implemented in WinRM client");
}
// Terminate a subscription
void CimWinRMClient::Unsubscribe(const string &resourceUri, const string &identifier, const NameValuePairs *s) const
{
throw WSManException("Unsubscribe: not implemented in WinRM client");
}
// Set auth method
void CimWinRMClient::SetAuth(const char *auth_method)
{
throw WSManException("SetAuth: WinRM client does not support SetAuth after creation");
//connection.authmethod = (strcmp(auth_method, "digest") == 0) ? DIGEST : KERBEROS;
}
// Set user name
void CimWinRMClient::SetUserName(const char *user_name)
{
connection.username = user_name;
SetConnectionOptions(L"username", connection.username);
}
// Set passsword
void CimWinRMClient::SetPassword(const char *password)
{
connection.password = password;
SetConnectionOptions(L"password", connection.password);
}
// Set encoding
void CimWinRMClient::SetEncoding(const char *encoding)
{
// Do nothing - always use encoding type utf-8
}
// Set CIM namespace
void CimWinRMClient::SetNamespace(const char *ns)
{
// Do nothing - the client sets its own Namespace
}
// Set client certificate params
void CimWinRMClient::SetClientCert(const char *caOid, const char *caName, const bool localCert)
{
throw WSManException("SetClientCert: mutual authentication not implemented in WinRM client");
}
void CimWinRMClient::SetProxy(const char *proxy, const char *proxy_username, const char *proxy_password)
{
throw WSManException("SetProxy: not implemented in WinRM client");
}
// Return the ID of all of the functions.
bool CimWinRMClient::GetFunctionIds()
{
return GetDispId(_pWsmanSessionDispatch, &_getDispid, L"get") &&
GetDispId(_pWsmanSessionDispatch, &_putDispid, L"put") &&
GetDispId(_pWsmanSessionDispatch, &_identifyDispid, L"identify") &&
GetDispId(_pWsmanSessionDispatch, &_createDispid, L"create") &&
GetDispId(_pWsmanSessionDispatch, &_invokeDispid, L"invoke") &&
GetDispId(_pWsmanSessionDispatch, &_deleteDispid, L"delete") &&
GetDispId(_pWsmanSessionDispatch, &_enumerateDispid, L"enumerate");
}
// Return the ID of a specified function.
bool CimWinRMClient::GetDispId(IDispatch* disp, DISPID* id, wchar_t* name)
{
HRESULT hr = E_FAIL;
OLECHAR FAR* idName = name;
hr = disp->GetIDsOfNames(IID_NULL, &idName, 1, LOCALE_USER_DEFAULT, id);
if (FAILED(hr))
{
return false;
}
return true;
}
// Function to release Dispatch resources.
void CimWinRMClient::ReleaseDisps()
{
ULONG ret = 0;
if (_pWsmanSessionDispatch)
{
ret = _pWsmanSessionDispatch->Release();
_pWsmanSessionDispatch = NULL;
}
if (_pWsmanConnectionOptions)
{
ret = _pWsmanConnectionOptions->Release();
_pWsmanConnectionOptions = NULL;
}
if(_pWsmanDispatch)
{
ret = _pWsmanDispatch->Release();
_pWsmanDispatch = NULL;
}
}
// Set the connection options.
bool CimWinRMClient::SetConnectionOptions(wchar_t* fieldName, const string& fieldValue)
{
HRESULT hr = E_FAIL;
// set password
DISPID paramDispid;
if(!GetDispId(_pWsmanConnectionOptions, &paramDispid, fieldName))
{
return false;
}
DISPPARAMS paramArgs = {0};
paramArgs.cArgs = 1;
paramArgs.rgvarg = new VARIANTARG[paramArgs.cArgs]; // parameters are passed in reverse order
paramArgs.cNamedArgs = 1;
paramArgs.rgdispidNamedArgs = &_dispPropertyPut;
paramArgs.rgvarg[0].vt = VT_BSTR;
int len = MultiByteToWideChar(CP_ACP, 0, fieldValue.c_str(), fieldValue.length()+1,0,0);
wchar_t* tmp = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, fieldValue.c_str(), fieldValue.length()+1, tmp, len);
paramArgs.rgvarg[0].bstrVal = SysAllocString(tmp);
delete[] tmp;
hr = _pWsmanConnectionOptions->Invoke(paramDispid, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &paramArgs, NULL, NULL, NULL);
VariantClear(&(paramArgs.rgvarg[0]));
delete [] paramArgs.rgvarg;
if (FAILED(hr))
{
return false;
}
return true;
}
// Create the connction options.
bool CimWinRMClient::CreateConnectionOptions()
{
HRESULT hr = E_FAIL;
// create connection parameters
// get dispid for createconnectionoptions
if(!GetDispId(_pWsmanDispatch, &_createConnectionOptionsDispid, L"createconnectionoptions"))
{
return false;
}
DISPPARAMS connectionOptionsArgs = {0};
connectionOptionsArgs.cArgs = 0;
connectionOptionsArgs.rgvarg = 0; // parameters are passed in reverse order
VARIANT opt;
VariantInit(&opt);
hr = _pWsmanDispatch->Invoke(_createConnectionOptionsDispid, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_METHOD, &connectionOptionsArgs, &opt, NULL, NULL);
if (FAILED(hr))
{
return false;
}
hr = opt.punkVal->QueryInterface(IID_IDispatch, (LPVOID *)&_pWsmanConnectionOptions);
VariantClear(&opt);
if (FAILED(hr))
{
return false;
}
if(connection.authmethod == DIGEST)
return SetConnectionOptions(L"password", connection.password) && SetConnectionOptions(L"username", connection.username);
else
return true;
}
// Add the flags to the session.
bool CimWinRMClient::AddSessionFlag(wchar_t* fName)
{
HRESULT hr = E_FAIL;
long flag = 0;
DISPID flagDisp = 0;
if(!GetDispId(_pWsmanDispatch, &flagDisp, fName))
{
return false;
}
DISPPARAMS dispArgs = {0};
dispArgs.cArgs = 0;
dispArgs.rgvarg = 0; // parameters are passed in reverse order
VARIANT opt;
VariantInit(&opt);
hr = _pWsmanDispatch->Invoke(flagDisp, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispArgs, &opt, NULL, NULL);
if (FAILED(hr))
{
return false;
}
flag = opt.lVal;
VariantClear(&opt);
_connectionFlags |= flag;
return true;
}
// Create the flags for the session.
bool CimWinRMClient::CreateSessionFlags()
{
// set SessionFlagUTF8
if(AddSessionFlag(L"sessionflagutf8") == false)
return false;
if(connection.authmethod == DIGEST)
{
if (!AddSessionFlag(L"SessionFlagCredUsernamePassword") || !AddSessionFlag(L"SessionFlagUseDigest"))
return false;
}
else // Kerberos
{
if (!AddSessionFlag(L"SessionFlagEnableSPNServerPort") || !AddSessionFlag(L"SessionFlagUseKerberos"))
return false;
}
if (!connection.secure && connection.authmethod == KERBEROS)
if (!AddSessionFlag(L"SessionFlagNoEncryption"))
return false;
return true;
}
bool CimWinRMClient::CreateSession()
{
if(!CreateConnectionOptions() || !CreateSessionFlags())
{
return false;
}
// get dispid for createsession
if(!GetDispId(_pWsmanDispatch, &_createSessionDispid, L"createsession"))
{
return false;
}
HRESULT hr = E_FAIL;
DISPPARAMS connectArgs = {0};
connectArgs.cArgs = 3;
connectArgs.rgvarg = new VARIANTARG[connectArgs.cArgs]; // parameters are passed in reverse order
string endpoint = "";
endpoint += connection.secure ? "https" : "http";
endpoint += "://";
endpoint += connection.host;
endpoint += ":";
// convert port int to string
ostringstream buffer;
buffer << connection.port;
endpoint += buffer.str();
endpoint += "/wsman";
int len = MultiByteToWideChar(CP_ACP, 0, endpoint.c_str(), endpoint.length()+1,0,0);
wchar_t* tmp = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, endpoint.c_str(), endpoint.length()+1, tmp, len);
connectArgs.rgvarg[0].vt = VT_DISPATCH;
connectArgs.rgvarg[0].pdispVal = _pWsmanConnectionOptions;
connectArgs.rgvarg[1].vt = VT_I4;
connectArgs.rgvarg[1].lVal = _connectionFlags;
connectArgs.rgvarg[2].vt = VT_BSTR;
connectArgs.rgvarg[2].bstrVal = SysAllocString(tmp);
delete[] tmp;
VARIANT var;
VariantInit(&var);
EXCEPINFO excepinfo = {0};
hr = _pWsmanDispatch->Invoke(_createSessionDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &connectArgs, &var, &excepinfo, NULL);
VariantClear(&(connectArgs.rgvarg[2]));
delete [] connectArgs.rgvarg;
if (FAILED(hr))
{
return false;
}
hr = var.punkVal->QueryInterface(IID_IDispatch, (LPVOID *)&_pWsmanSessionDispatch);
VariantClear(&var);
if (FAILED(hr))
{
return false;
}
return true;
}
// Add the given list of selectors to the wsman call header.
bool CimWinRMClient::AddSelectors(IDispatch* disp, const NameValuePairs *selectors) const
{
DISPID addsel = 0;
HRESULT hr = E_FAIL;
OLECHAR FAR* idName = L"addselector";
hr = disp->GetIDsOfNames(IID_NULL, &idName, 1, LOCALE_USER_DEFAULT, &addsel);
if (FAILED(hr))
{
return false;
}
for (PairsIterator p = selectors->begin(); p != selectors->end(); ++p)
{
if(!p->second.empty())
{
if(!AddSelector(disp, addsel, p->first, p->second))
{
return false;
}
}
}
return true;
}
// Add the given selector.
bool CimWinRMClient::AddSelector(IDispatch* disp, DISPID& selID, const string& name, const string& value) const
{
HRESULT hr = E_FAIL;
DISPPARAMS selArgs = {0};
selArgs.cArgs = 2;
selArgs.rgvarg = new VARIANTARG[selArgs.cArgs];
VARIANT val;
VariantInit(&val);
val.vt = VT_BSTR;
int len0 = MultiByteToWideChar(CP_ACP, 0, value.c_str(), value.length()+1,0,0);
wchar_t* tmp0 = new wchar_t[len0];
MultiByteToWideChar(CP_ACP, 0, value.c_str(), value.length()+1, tmp0, len0);
val.bstrVal = SysAllocString(tmp0);
selArgs.rgvarg[0].vt = VT_VARIANT | VT_BYREF;
selArgs.rgvarg[0].pvarVal = &val;
delete[] tmp0;
int len1 = MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length()+1,0,0);
wchar_t* tmp1 = new wchar_t[len1];
MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length()+1, tmp1, len1);
selArgs.rgvarg[1].vt = VT_BSTR;
selArgs.rgvarg[1].bstrVal = SysAllocString(tmp1);
delete[] tmp1;
hr = disp->Invoke(selID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &selArgs, NULL, NULL, NULL);
/// clean up
VariantClear(&(selArgs.rgvarg[1]));
VariantClear(&val);
delete [] selArgs.rgvarg;
if (FAILED(hr))
{
return false;
}
return true;
}
// Create the resource using the given uri & selectors.
bool CimWinRMClient::CreateResourceLocator(IDispatch **disp, const string& uri, const NameValuePairs *s) const
{
HRESULT hr = E_FAIL;
DISPPARAMS uriArgs = {0};
uriArgs.cArgs = 1;
uriArgs.rgvarg = new VARIANTARG[uriArgs.cArgs]; // parameters are passed in reverse order
int len = MultiByteToWideChar(CP_ACP, 0, uri.c_str(), uri.length()+1,0,0);
wchar_t* tmp = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, uri.c_str(), uri.length()+1, tmp, len);
uriArgs.rgvarg[0].vt = VT_BSTR;
uriArgs.rgvarg[0].bstrVal = SysAllocString(tmp);
delete[] tmp;
VARIANT var;
VariantInit(&var);
hr = _pWsmanDispatch->Invoke(_createResourceLocatorDispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &uriArgs, &var, NULL, NULL);
VariantClear(&(uriArgs.rgvarg[0]));
delete [] uriArgs.rgvarg;
if (FAILED(hr))
{
return false;
}
hr = var.punkVal->QueryInterface(IID_IDispatch, (LPVOID *)disp);
if (FAILED(hr))
{
VariantClear(&var);
return false;
}
if(!s)
{
return true;
}
return AddSelectors(*disp, s);
}
// Check if there are more items in the enumeration Dispatcher.
bool CimWinRMClient::CheckForMoreItems(IDispatch* disp, DISPID& id, bool& hasItems) const
{
DISPPARAMS dispArgs = {0};
dispArgs.cArgs = 0;
dispArgs.rgvarg = nullptr;
VARIANT var;
VariantInit(&var);
HRESULT hr = disp->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispArgs, &var, NULL, NULL);
if (FAILED(hr))
{
return false;
}
hasItems = !var.boolVal;
VariantClear(&var);
return true;
}
// Return a vector of items from the enumeration Dispatcher.
bool CimWinRMClient::GetEnumerationItems(IDispatch* disp, vector<string> &enumRes) const
{
USES_CONVERSION;
HRESULT hr = E_FAIL;
DISPID getItemId = 0;
DISPID eosId = 0;
OLECHAR FAR* getItemName = L"readitem";
OLECHAR FAR* eosName = L"atendofstream";
hr = disp->GetIDsOfNames(IID_NULL, &getItemName, 1, LOCALE_USER_DEFAULT, &getItemId);
if (FAILED(hr))
{
return false;
}
hr = disp->GetIDsOfNames(IID_NULL, &eosName, 1, LOCALE_USER_DEFAULT, &eosId);
if (FAILED(hr))
{
return false;
}
bool hasItem = false;
if(!CheckForMoreItems(disp, eosId, hasItem))
{
return false;
}
DISPPARAMS dispArgs = {0};
dispArgs.cArgs = 0;
dispArgs.rgvarg = nullptr;
EXCEPINFO excepinfo = {0};
unsigned int argNum = 0;
while(hasItem)
{
VARIANT var;
VariantInit(&var);
hr = disp->Invoke(getItemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispArgs, &var, &excepinfo, &argNum);
if (FAILED(hr))
{
return false;
}
auto w2ca = W2CA(var.bstrVal);
string item(( w2ca != nullptr ) ? w2ca :"");
VariantClear(&var);
enumRes.push_back(item);
if(!CheckForMoreItems(disp, eosId, hasItem))
{
return false;
}
}
return true;
}
//------------
} // namespace WSManagement
} // namespace Intel