//---------------------------------------------------------------------------- // // Copyright (C) 2003 Intel Corporation // // File: CimWsman.h // // Contents: Library independent interface to WS-Management transport // //---------------------------------------------------------------------------- #include #include #include #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 &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(""); for (const auto& p : *s) { input += ""+ p.second+""; } input += ""; 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(&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 &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 += ""; else if(filter.assocType == EnumerateFilter::AssociationInstance) input += ""; input += "" + filter.reference.Serialize() + ""; if (filter.associationClass.length() > 0) input += ""+ filter.associationClass +""; if (filter.role.length() > 0) input += ""+ filter.role+""; if (filter.resultClass.length() > 0) input += ""+ filter.resultClass +""; if (filter.resultRole.length() > 0) input += ""+ filter.resultRole +""; vector::const_iterator iter; for(iter = filter.resultProperties.begin(); iter != filter.resultProperties.end(); iter++) { input += ""+ *iter +""; filter.resultProperties; } if(filter.assocType == EnumerateFilter::AssociatedInstance) input += ""; else if(filter.assocType == EnumerateFilter::AssociationInstance) input += ""; 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 &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 += ""; else if(filter.assocType == EnumerateFilter::AssociationInstance) input += ""; input += "" + filter.reference.Serialize() + ""; if (filter.associationClass.length() > 0) input += ""+ filter.associationClass +""; if (filter.role.length() > 0) input += ""+ filter.role+""; if (filter.resultClass.length() > 0) input += ""+ filter.resultClass +""; if (filter.resultRole.length() > 0) input += ""+ filter.resultRole +""; vector::const_iterator iter; for(iter = filter.resultProperties.begin(); iter != filter.resultProperties.end(); iter++) { input += ""+ *iter +""; filter.resultProperties; } if(filter.assocType == EnumerateFilter::AssociatedInstance) input += ""; else if(filter.assocType == EnumerateFilter::AssociationInstance) input += ""; 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, ¶mDispid, 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, ¶mArgs, 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 &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