Module: check_mk
Branch: master
Commit: aa5c32a3b85f4f488b41ad3a464ad848632f488f
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=aa5c32a3b85f4f…
Author: Sebastian Herbord <sh(a)mathias-kettner.de>
Date: Fri Nov 20 08:43:36 2015 +0100
windows agent: improvements and bugfixes to the wmi interface
---
agents/windows/stringutil.cc | 31 +++++++++++
agents/windows/stringutil.h | 3 ++
agents/windows/wmiHelper.cc | 120 ++++++++++++++++++++++++++----------------
agents/windows/wmiHelper.h | 5 +-
4 files changed, 112 insertions(+), 47 deletions(-)
diff --git a/agents/windows/stringutil.cc b/agents/windows/stringutil.cc
index 04efb36..2f1c01a 100644
--- a/agents/windows/stringutil.cc
+++ b/agents/windows/stringutil.cc
@@ -10,6 +10,7 @@
using std::string;
+using std::wstring;
char *lstrip(char *s)
@@ -154,6 +155,13 @@ int parse_boolean(char *value)
}
+string to_utf8(const char *input)
+{
+ // this isn't right, the input is most likely in locat 8-bit encoding
+ return std::string(input);
+}
+
+
string to_utf8(const wchar_t *input)
{
string result;
@@ -176,6 +184,29 @@ string to_utf8(const wchar_t *input)
}
+
+wstring to_utf16(const char *input)
+{
+ wstring result;
+ // preflight: how many bytes to we need?
+ int required_size = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
+ if (required_size == 0) {
+ // conversion failure. What to do?
+ return wstring();
+ }
+ result.resize(required_size);
+
+ // real conversion
+ MultiByteToWideChar(CP_UTF8, 0, input, -1, &result[0], required_size);
+
+ // strip away the zero termination. This is necessary, otherwise the stored string
length
+ // in the string is wrong
+ result.resize(required_size - 1);
+
+ return result;
+}
+
+
bool ci_compare_pred(unsigned char lhs, unsigned char rhs)
{
return std::tolower(lhs) == std::tolower(rhs);
diff --git a/agents/windows/stringutil.h b/agents/windows/stringutil.h
index 8c4376a..dbd4466 100644
--- a/agents/windows/stringutil.h
+++ b/agents/windows/stringutil.h
@@ -55,8 +55,11 @@ void lowercase(char *s);
int parse_boolean(char *value);
+std::string to_utf8(const char *input);
std::string to_utf8(const wchar_t *input);
+std::wstring to_utf16(const char *input);
+
// case insensitive compare
bool ci_equal(const std::string &lhs, const std::string &rhs);
diff --git a/agents/windows/wmiHelper.cc b/agents/windows/wmiHelper.cc
index 6dfe9e6..9137e07 100644
--- a/agents/windows/wmiHelper.cc
+++ b/agents/windows/wmiHelper.cc
@@ -36,22 +36,23 @@ using namespace wmi;
using namespace std;
-#ifdef UNICODE
-ComException::ComException(const string &message, HRESULT result)
- : runtime_error(message + ": " + to_utf8(_com_error(result,
getErrorInfo()).ErrorMessage())
- + " (" + toStringHex(result) + ")")
-{
+std::string ComException::resolveError(HRESULT result)
+{
+ switch (static_cast<ULONG>(result)) {
+ case WBEM_E_INVALID_NAMESPACE: return "Invalid Namespace";
+ case WBEM_E_ACCESS_DENIED: return "Access Denied";
+ case WBEM_E_INVALID_CLASS: return "Invalid Class";
+ case WBEM_E_INVALID_QUERY: return "Invalid Query";
+ default: return to_utf8(_com_error(result, getErrorInfo()).ErrorMessage());
+ }
}
-#else
+
ComException::ComException(const string &message, HRESULT result)
- : runtime_error(message + ": " + _com_error(result,
getErrorInfo()).ErrorMessage()
- + " (" + toStringHex(result) + ")")
+ : runtime_error(message + ": " + resolveError(result) + " (" +
toStringHex(result) + ")")
{
}
-#endif
-
ComTypeException::ComTypeException(const string &message)
: runtime_error(message)
@@ -268,6 +269,15 @@ template <> int Variant::get()
}
+template <> bool Variant::get()
+{
+ switch (_value.vt) {
+ case VT_BOOL: return _value.boolVal;
+ default: throw ComTypeException(string("wrong value type requested: ")
+ to_string(_value.vt));
+ }
+}
+
+
template <> ULONG Variant::get()
{
switch (_value.vt) {
@@ -300,17 +310,70 @@ template <> string Variant::get()
template <> wstring Variant::get()
{
switch (_value.vt) {
- case VT_BSTR: return wstring(_value.bstrVal);
- default: throw ComTypeException(string("wrong value type requested: ")
+ to_string(_value.vt));
+ case VT_BSTR:
+ return wstring(_value.bstrVal);
+ case VT_I1:
+ case VT_I2:
+ case VT_I4:
+ case VT_UI1:
+ case VT_UI2:
+ case VT_UI4:
+ return std::to_wstring(get<int>());
+ case VT_UI8:
+ return std::to_wstring(get<ULONGLONG>());
+ case VT_BOOL:
+ return std::to_wstring(get<bool>());
+ case VT_NULL:
+ return L"<null>";
+ default:
+ throw ComTypeException(string("wrong value type requested: ") +
to_string(_value.vt));
}
}
+class COMManager {
+public:
+ static void init() {
+ // this is apparently thread safe in C++11 and in gcc even before that
+ // see §6.4 in C++11 standard or §6.7 in C++14
+ static COMManager s_Instance;
+ }
+
+ ~COMManager() {
+ CoUninitialize();
+ }
+private:
+ COMManager() {
+ HRESULT res = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(res)) {
+ throw ComException("Failed to initialize COM", res);
+ }
+
+ res = CoInitializeSecurity(
+ NULL, // security descriptor
+ -1, // authentication
+ NULL, // authentication services
+ NULL, // reserved
+ RPC_C_AUTHN_LEVEL_DEFAULT, // authentication level
+ RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
+ NULL, // authentication info
+ EOAC_NONE, // additional capabilities
+ NULL // reserved
+ );
+ if (FAILED(res)) {
+ throw ComException("Failed to initialize COM security", res);
+ }
+ }
+private:
+};
+
+
Helper::Helper(LPCWSTR path)
: _locator(NULL)
, _path(path)
{
- initCOM();
+ COMManager::init();
+
_locator = getWBEMLocator();
_services = connectServer(_locator);
}
@@ -324,37 +387,6 @@ Helper::~Helper()
if (_services != NULL) {
_services->Release();
}
- deinitCOM();
-}
-
-
-void Helper::initCOM()
-{
- HRESULT res = CoInitializeEx(0, COINIT_MULTITHREADED);
- if (FAILED(res)) {
- throw ComException("Failed to initialize COM", res);
- }
-
- res = CoInitializeSecurity(
- NULL, // security descriptor
- -1, // authentication
- NULL, // authentication services
- NULL, // reserved
- RPC_C_AUTHN_LEVEL_DEFAULT, // authentication level
- RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
- NULL, // authentication info
- EOAC_NONE, // additional capabilities
- NULL // reserved
- );
- if (FAILED(res)) {
- throw ComException("Failed to initialize COM security", res);
- }
-}
-
-
-void Helper::deinitCOM()
-{
- CoUninitialize();
}
diff --git a/agents/windows/wmiHelper.h b/agents/windows/wmiHelper.h
index 4baf86a..48ed235 100644
--- a/agents/windows/wmiHelper.h
+++ b/agents/windows/wmiHelper.h
@@ -43,6 +43,7 @@ namespace wmi {
struct ComException : public std::runtime_error {
ComException(const std::string &message, HRESULT result);
private:
+ std::string resolveError(HRESULT result);
IErrorInfo *getErrorInfo();
std::string toStringHex(HRESULT res);
};
@@ -70,6 +71,7 @@ private:
template <> int Variant::get();
+template <> bool Variant::get();
template <> ULONG Variant::get();
template <> ULONGLONG Variant::get();
template <> std::string Variant::get();
@@ -173,9 +175,6 @@ public:
private:
- void initCOM();
- void deinitCOM();
-
// get a locator that is used to look up WMI namespaces
IWbemLocator *getWBEMLocator();