/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see .
**/
#include "zbxsysinc.h"
#include
#include
extern "C"
{
# include "../sysinfo.h"
# include "zbxstr.h"
# include "zbxlog.h"
# include "zbxalgo.h"
# include "zbxjson.h"
}
#pragma comment(lib, "wbemuuid.lib")
typedef struct
{
BSTR name;
VARIANT *value;
}
zbx_wmi_prop_t;
ZBX_VECTOR_DECL(wmi_prop, zbx_wmi_prop_t)
ZBX_VECTOR_IMPL(wmi_prop, zbx_wmi_prop_t)
ZBX_PTR_VECTOR_DECL(wmi_instance, zbx_vector_wmi_prop_t *)
ZBX_PTR_VECTOR_IMPL(wmi_instance, zbx_vector_wmi_prop_t *)
extern "C" static void wmi_prop_clear(zbx_wmi_prop_t *prop)
{
SysFreeString(prop->name);
VariantClear(prop->value);
zbx_free(prop->value);
}
extern "C" static void wmi_instance_clear(zbx_vector_wmi_prop_t *wmi_inst_value)
{
for (int i = 0; i < wmi_inst_value->values_num; i++)
wmi_prop_clear(&wmi_inst_value->values[i]);
zbx_vector_wmi_prop_destroy(wmi_inst_value);
zbx_free(wmi_inst_value);
}
typedef int (*zbx_parse_wmi_t)(IEnumWbemClassObject *pEnumerator, double timeout,
zbx_vector_wmi_instance_t *wmi_values, char **error);
extern "C" int put_variant_json(const char *prop_json, const char *prop_err, VARIANT *vtProp, struct zbx_json *jdoc,
char **error);
static ZBX_THREAD_LOCAL int com_initialized = 0;
extern "C" int zbx_co_initialize()
{
if (0 == com_initialized)
{
HRESULT hres;
/* must be called once per each thread */
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
zabbix_log(LOG_LEVEL_DEBUG, "cannot initialized COM library");
return FAIL;
}
/* must be called once per process, subsequent calls return RPC_E_TOO_LATE */
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hres) && RPC_E_TOO_LATE != hres)
{
zabbix_log(LOG_LEVEL_DEBUG, "cannot set default security levels for COM library");
CoUninitialize();
return FAIL;
}
com_initialized = 1;
}
return SUCCEED;
}
extern "C" void zbx_co_uninitialize()
{
if (1 == com_initialized)
CoUninitialize();
}
extern "C" static void get_error_code_text(HRESULT hres, char **error)
{
IWbemStatusCodeText *pStatus = NULL;
SCODE sc;
sc = CoCreateInstance(CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText,
(LPVOID *) &pStatus);
if (S_OK == sc)
{
BSTR bstr = 0;
sc = pStatus->GetErrorCodeText(hres, 0, 0, &bstr);
if (S_OK == sc)
{
*error = zbx_unicode_to_utf8((wchar_t *)bstr);
zbx_rtrim(*error, "\n\r");
SysFreeString(bstr);
}
else
{
*error = zbx_dsprintf(*error, "error code:" ZBX_FS_I64, hres);
zabbix_log(LOG_LEVEL_DEBUG, "GetErrorCodeText() failed with code:" ZBX_FS_I64
" when retrieving error code for " ZBX_FS_I64, sc, hres);
}
}
else
{
*error = zbx_dsprintf(*error, "error code:" ZBX_FS_I64, hres);
zabbix_log(LOG_LEVEL_DEBUG, "CoCreateInstance() failed with code:" ZBX_FS_I64
" when retrieving error code for:" ZBX_FS_I64, sc, hres);
}
if (NULL != pStatus)
pStatus->Release();
}
/******************************************************************************
* *
* Purpose: extracts only one value from search result *
* *
* Parameters: pEnumerator - [IN] search result *
* timeout - [IN] query timeout in seconds *
* wmi_values - [IN/OUT] vector with found value *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - wmi_values contains the retrieved value *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
* Comments: one value is value from the first property of first instance *
* from search result *
* *
******************************************************************************/
extern "C" static int parse_first_first(IEnumWbemClassObject *pEnumerator, double timeout,
zbx_vector_wmi_instance_t *wmi_values, char **error)
{
int ret = SYSINFO_RET_FAIL;
VARIANT *vtProp = NULL;
IWbemClassObject *pclsObj = 0;
ULONG uReturn = 0;
HRESULT hres;
zbx_vector_wmi_prop_t *inst_val;
zbx_wmi_prop_t prop;
hres = pEnumerator->Next((long)(1000 * timeout), 1, &pclsObj, &uReturn);
if (WBEM_S_TIMEDOUT == hres)
{
*error = zbx_strdup(*error, "WMI query timeout.");
goto out2;
}
if (FAILED(hres))
{
get_error_code_text(hres, error);
goto out2;
}
if (0 == uReturn)
goto out2;
hres = pclsObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
if (FAILED(hres))
{
*error = zbx_strdup(*error, "Cannot start WMI query result enumeration.");
goto out1;
}
vtProp = (VARIANT*) zbx_malloc(NULL, sizeof(VARIANT));
VariantInit(vtProp);
hres = pclsObj->Next(0, NULL, vtProp, 0, 0);
if (FAILED(hres))
{
*error = zbx_strdup(*error, "Cannot parse WMI result field.");
zbx_free(vtProp);
goto out1;
}
pclsObj->EndEnumeration();
if (hres == WBEM_S_NO_MORE_DATA || VT_EMPTY == V_VT(vtProp) || VT_NULL == V_VT(vtProp))
{
zbx_free(vtProp);
goto out1;
}
else
ret = SYSINFO_RET_OK;
prop.name = NULL;
prop.value = vtProp;
inst_val = (zbx_vector_wmi_prop_t*) zbx_malloc(NULL, sizeof(zbx_vector_wmi_prop_t));
zbx_vector_wmi_prop_create(inst_val);
zbx_vector_wmi_prop_append(inst_val, prop);
zbx_vector_wmi_instance_append(wmi_values, inst_val);
out1:
pclsObj->Release();
out2:
return ret;
}
/******************************************************************************
* *
* Purpose: extracts all values from the search result *
* *
* Parameters: pEnumerator - [IN] search result *
* timeout - [IN] query timeout in seconds *
* wmi_values - [IN/OUT] vector with found values *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - wmi_values contains retrieved values *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
******************************************************************************/
extern "C" static int parse_all(IEnumWbemClassObject *pEnumerator, double timeout,
zbx_vector_wmi_instance_t *wmi_values, char **error)
{
int ret = SYSINFO_RET_FAIL;
VARIANT *vtProp;
HRESULT hres = S_OK;
while (pEnumerator && SUCCEEDED(hres))
{
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
zbx_vector_wmi_prop_t *inst_val = NULL;
hres = pEnumerator->Next((long)(1000 * timeout), 1, &pclsObj, &uReturn);
if (WBEM_S_TIMEDOUT == hres)
{
ret = SYSINFO_RET_FAIL;
*error = zbx_strdup(*error, "WMI query timeout.");
return ret;
}
if (WBEM_S_FALSE == hres && 0 == uReturn)
return SYSINFO_RET_OK;
if (FAILED(hres))
{
get_error_code_text(hres, error);
return ret;
}
if (0 == uReturn)
return ret;
hres = pclsObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
if (FAILED(hres))
{
*error = zbx_strdup(*error, "Cannot start WMI query result enumeration.");
pclsObj->Release();
break;
}
inst_val = (zbx_vector_wmi_prop_t*)zbx_malloc(NULL, sizeof(zbx_vector_wmi_prop_t));
zbx_vector_wmi_prop_create(inst_val);
zbx_vector_wmi_instance_append(wmi_values, inst_val);
while (!(FAILED(hres) || WBEM_S_NO_MORE_DATA == hres))
{
zbx_wmi_prop_t prop = {NULL, NULL};
vtProp = (VARIANT*)zbx_malloc(NULL, sizeof(VARIANT));
VariantInit(vtProp);
hres = pclsObj->Next(0, &prop.name, vtProp, 0, 0);
if (FAILED(hres) || WBEM_S_NO_MORE_DATA == hres || VT_EMPTY == V_VT(vtProp) ||
VT_NULL == V_VT(vtProp))
{
if (FAILED(hres))
*error = zbx_strdup(*error, "Cannot parse WMI result field.");
SysFreeString(prop.name);
zbx_free(vtProp);
continue;
}
prop.value = vtProp;
zbx_vector_wmi_prop_append(inst_val, prop);
ret = SYSINFO_RET_OK;
}
pclsObj->EndEnumeration();
pclsObj->Release();
}
return ret;
}
/******************************************************************************
* *
* Purpose: retrieves WMI value and stores it in provided memory location *
* *
* Parameters: wmi_namespace - [IN] object path of WMI namespace (UTF-8) *
* wmi_query - [IN] WQL query (UTF-8) *
* parse_value_cb - [IN] callback parsing function *
* timeout - [IN] query timeout in seconds *
* wmi_values - [OUT] pointer to memory for queried values *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - *vtProp contains retrieved WMI value *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
* Comments: *vtProp must be initialized with VariantInit(), *
* wmi_* must not be NULL. The callers must convert value to the *
* intended format using VariantChangeType() *
* *
******************************************************************************/
extern "C" int zbx_wmi_get_variant(const char *wmi_namespace, const char *wmi_query, zbx_parse_wmi_t parse_value_cb,
double timeout, zbx_vector_wmi_instance_t *wmi_values, char **error)
{
IWbemLocator *pLoc = 0;
IWbemServices *pService = 0;
IEnumWbemClassObject *pEnumerator = 0;
int ret = SYSINFO_RET_FAIL;
HRESULT hres;
wchar_t *wmi_namespace_wide;
wchar_t *wmi_query_wide;
/* obtain the initial locator to Windows Management on a particular host computer */
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
*error = zbx_strdup(*error, "Cannot obtain WMI locator service.");
goto exit;
}
wmi_namespace_wide = zbx_utf8_to_unicode(wmi_namespace);
hres = pLoc->ConnectServer(_bstr_t(wmi_namespace_wide), NULL, NULL, 0, NULL, 0, 0, &pService);
zbx_free(wmi_namespace_wide);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot obtain %s WMI service.", wmi_namespace);
goto exit;
}
/* set the IWbemServices proxy so that impersonation of the user (client) occurs */
hres = CoSetProxyBlanket(pService, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres))
{
*error = zbx_strdup(*error, "Cannot set IWbemServices proxy.");
goto exit;
}
wmi_query_wide = zbx_utf8_to_unicode(wmi_query);
hres = pService->ExecQuery(_bstr_t("WQL"), _bstr_t(wmi_query_wide),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
zbx_free(wmi_query_wide);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Failed to execute WMI query %s.", wmi_query);
goto exit;
}
if (NULL != pEnumerator)
ret = parse_value_cb(pEnumerator, timeout, wmi_values, error);
if (SYSINFO_RET_FAIL == ret && NULL == *error)
*error = zbx_strdup(*error, "Empty WMI search result.");
exit:
if (0 != pEnumerator)
{
while (WBEM_S_NO_ERROR == pEnumerator->Skip((long)(1000 * timeout), 1)) {}
pEnumerator->Release();
}
if (0 != pService)
pService->Release();
if (0 != pLoc)
pLoc->Release();
return ret;
}
/******************************************************************************
* *
* Purpose: Wrapper function for zbx_wmi_get_variant(), stores the retrieved *
* WMI value as UTF-8 encoded string. *
* *
* Parameters: wmi_namespace - [IN] object path of WMI namespace (UTF-8) *
* wmi_query - [IN] WQL query (UTF-8) *
* timeout - [IN] query timeout in seconds *
* utf8_value - [OUT] address of pointer to retrieved value *
* (dynamically allocated) *
* *
* Comments: If either retrieval or type conversion failed then *utf8_value *
* remains unchanged (set it to NULL before calling this function *
* to check for this condition). Callers must free *utf8_value. *
* *
******************************************************************************/
extern "C" void zbx_wmi_get(const char *wmi_namespace, const char *wmi_query, double timeout, char **utf8_value)
{
VARIANT *vtProp;
HRESULT hres;
zbx_vector_wmi_instance_t wmi_values;
char *error = NULL;
zbx_vector_wmi_instance_create(&wmi_values);
if (SUCCEED != zbx_co_initialize())
{
zabbix_log(LOG_LEVEL_DEBUG, "cannot initialize COM library for querying WMI");
goto out;
}
if (SYSINFO_RET_FAIL == zbx_wmi_get_variant(wmi_namespace, wmi_query, parse_first_first, timeout, &wmi_values,
&error))
{
zabbix_log(LOG_LEVEL_DEBUG, error);
goto out;
}
vtProp = wmi_values.values[0]->values[0].value;
hres = VariantChangeType(vtProp, vtProp, VARIANT_ALPHABOOL, VT_BSTR);
if (FAILED(hres))
{
zabbix_log(LOG_LEVEL_DEBUG, "cannot convert WMI result of type %d to VT_BSTR", V_VT(vtProp));
goto out;
}
*utf8_value = zbx_unicode_to_utf8((wchar_t *)_bstr_t(vtProp->bstrVal));
out:
zbx_vector_wmi_instance_clear_ext(&wmi_values, wmi_instance_clear);
zbx_vector_wmi_instance_destroy(&wmi_values);
zbx_free(error);
}
/******************************************************************************
* *
* Purpose: wrapper function for wmi.get metric *
* *
* Parameters: request - [IN] WMI request parameters *
* result - [OUT] one value of property from WMI Class *
* *
* Return value: SYSINFO_RET_OK - result contains retrieved WMI value *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
******************************************************************************/
extern "C" int wmi_get(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *wmi_namespace, *wmi_query, *error = NULL;
VARIANT *vtProp;
HRESULT hres;
int ret = SYSINFO_RET_FAIL;
zbx_vector_wmi_instance_t wmi_values;
if (2 != request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
return SYSINFO_RET_FAIL;
}
wmi_namespace = get_rparam(request, 0);
wmi_query = get_rparam(request, 1);
if (SUCCEED != zbx_co_initialize())
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot initialize COM library."));
return SYSINFO_RET_FAIL;
}
zbx_vector_wmi_instance_create(&wmi_values);
if (SYSINFO_RET_FAIL == zbx_wmi_get_variant(wmi_namespace, wmi_query, parse_first_first,
sysinfo_get_config_timeout(), &wmi_values, &error))
{
goto out;
}
vtProp = wmi_values.values[0]->values[0].value;
if (V_ISARRAY(vtProp))
{
error = zbx_strdup(error, "Cannot convert WMI array result.");
goto out;
}
switch (V_VT(vtProp))
{
case VT_EMPTY:
case VT_NULL:
goto out;
case VT_I8:
case VT_I4:
case VT_UI1:
case VT_I2:
case VT_I1:
case VT_UI2:
case VT_UI4:
case VT_UI8:
case VT_INT:
case VT_UINT:
hres = VariantChangeType(vtProp, vtProp, 0, VT_I8);
if (FAILED(hres))
{
error = zbx_dsprintf(error, "Cannot convert WMI result of type %d to VT_I8",
V_VT(vtProp));
goto out;
}
SET_UI64_RESULT(result, vtProp->llVal);
ret = SYSINFO_RET_OK;
break;
case VT_R4:
case VT_R8:
hres = VariantChangeType(vtProp, vtProp, 0, VT_R8);
if (FAILED(hres))
{
error = zbx_dsprintf(error, "Cannot convert WMI result of type %d to VT_R8",
V_VT(vtProp));
goto out;
}
SET_DBL_RESULT(result, vtProp->dblVal);
ret = SYSINFO_RET_OK;
break;
default:
hres = VariantChangeType(vtProp, vtProp, VARIANT_ALPHABOOL, VT_BSTR);
if (FAILED(hres))
{
error = zbx_dsprintf(error, "Cannot convert WMI result of type %d to VT_BSTR",
V_VT(vtProp));
goto out;
}
SET_TEXT_RESULT(result, zbx_unicode_to_utf8((wchar_t *)_bstr_t(V_BSTR(vtProp))));
ret = SYSINFO_RET_OK;
break;
}
out:
zbx_vector_wmi_instance_clear_ext(&wmi_values, wmi_instance_clear);
zbx_vector_wmi_instance_destroy(&wmi_values);
if (SYSINFO_RET_FAIL == ret)
SET_MSG_RESULT(result, error);
return ret;
}
extern "C" static void get_idispatch_value(VARIANT *arProp, BYTE *pbData)
{
HRESULT hres;
IDispatch *pDispatch = *((IDispatch**)pbData);
if (pDispatch)
{
DISPID dispid;
OLECHAR *propName = L"Value";
hres = pDispatch->GetIDsOfNames(IID_NULL, &propName, 1, LOCALE_USER_DEFAULT, &dispid);
if (SUCCEEDED(hres))
{
DISPPARAMS dispParams = {NULL, NULL, 0, 0};
hres = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
&dispParams, arProp, NULL, NULL);
}
else
{
VariantClear(arProp);
V_VT(arProp) = VT_EMPTY;
}
pDispatch->Release();
}
else
V_VT(arProp) = VT_EMPTY;
}
/******************************************************************************
* *
* Purpose: takes one element from array and puts value to JSON document *
* *
* Parameters: sa - [IN] SafeArray from WMI property *
* index - [IN] ID of element in array *
* prop_err - [IN] json attribute name *
* jdoc - [IN/OUT] JSON document *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - json document contains array element *
* SYSINFO_RET_FAIL - transformation of variant array failed *
* *
******************************************************************************/
extern "C" int proc_arr_element(SAFEARRAY *sa, LONG *index, const char *prop_err, struct zbx_json *jdoc,
char **error)
{
HRESULT hres;
BYTE *pbData;
int ret = SYSINFO_RET_OK;
VARTYPE pvt;
VARIANT arProp;
pbData = (BYTE*)zbx_malloc(NULL, (size_t)SafeArrayGetElemsize(sa));
hres = SafeArrayGetElement(sa, index, pbData);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot get element from WMI array '%s'", prop_err);
zbx_free(pbData);
return SYSINFO_RET_FAIL;
}
hres = SafeArrayGetVartype(sa, &pvt);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot get element type from WMI array '%s'", prop_err);
zbx_free(pbData);
return SYSINFO_RET_FAIL;
}
VariantInit(&arProp);
V_VT(&arProp) = pvt;
switch(pvt &(~VT_ARRAY))
{
case VT_BOOL:
V_BOOL(&arProp) = *((VARIANT_BOOL*)pbData);
break;
case VT_I1:
V_I1(&arProp) = *((char*)pbData);
break;
case VT_I2:
V_I2(&arProp) = *((short*)pbData);
break;
case VT_I4:
V_I4(&arProp) = *((long*)pbData);
break;
case VT_I8:
V_I8(&arProp) = *((LONGLONG*)pbData);
break;
case VT_UI1:
V_UI1(&arProp) = *((BYTE*)pbData);
break;
case VT_UI2:
V_UI2(&arProp) = *((WORD*)pbData);
break;
case VT_UI4:
V_UI4(&arProp) = *((DWORD*)pbData);
break;
case VT_UI8:
V_UI8(&arProp) = *((ULONGLONG*)pbData);
break;
case VT_R4:
V_R4(&arProp) = *((float*)pbData);
break;
case VT_R8:
V_R8(&arProp) = *((double*)pbData);
break;
case VT_CY:
V_CY(&arProp) = *((CY*)pbData);
hres = VariantChangeType(&arProp, &arProp, 0, VT_BSTR);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot convert WMI property '%s' of "
"type %d to VT_BSTR", prop_err, pvt);
ret = SYSINFO_RET_FAIL;
}
break;
case VT_DATE:
V_DATE(&arProp) = *((DATE*)pbData);
hres = VariantChangeType(&arProp, &arProp, 0, VT_BSTR);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot convert WMI property '%s' of "
"type %d to VT_BSTR", prop_err, pvt);
ret = SYSINFO_RET_FAIL;
}
break;
case VT_BSTR:
V_BSTR(&arProp) = *((BSTR*)pbData);
break;
case VT_UNKNOWN:
V_VT(&arProp) = VT_EMPTY;
break;
case VT_DISPATCH:
get_idispatch_value(&arProp, pbData);
break;
case VT_VARIANT:
hres = VariantCopy(&arProp, (VARIANT*)pbData);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot copy array element of WMI property '%s'",
prop_err);
ret = SYSINFO_RET_FAIL;
}
break;
default:
*error = zbx_dsprintf(*error, "Unsupported type %d for array element of WMI property '%s'",
pvt, prop_err);
ret = SYSINFO_RET_FAIL;
break;
}
if (SYSINFO_RET_OK == ret)
ret = put_variant_json(NULL, prop_err, &arProp, jdoc, error);
VariantClear(&arProp);
zbx_free(pbData);
return ret;
}
/******************************************************************************
* *
* Purpose: transformation of variant array from WMI search result to JSON *
* *
* Parameters: vtProp - [IN] variant WMI property value *
* prop_name - [IN] json attribute name *
* dim - [IN] dimension of array *
* offset_dim - [IN] index of dimension for processing *
* index - [IN/OUT] index of element in the array *
* jdoc - [IN/OUT] JSON document *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - json document contains the WMI array *
* SYSINFO_RET_FAIL - transformation of variant array failed *
* *
******************************************************************************/
extern "C" int convert_wmiarray_json(VARIANT *vtProp, const char *prop_name, ULONG dim, ULONG offset_dim,
LONG **index, struct zbx_json *jdoc, char **error)
{
HRESULT hres;
LONG lBound, uBound;
int ret = SYSINFO_RET_OK;
SAFEARRAY *sa = V_ARRAY(vtProp);
if (0 == dim)
{
dim = SafeArrayGetDim(sa);
*index = (LONG*) zbx_malloc(*index, (size_t)(sizeof(LONG) * dim));
offset_dim = 1;
zbx_json_addarray(jdoc, prop_name);
}
else
zbx_json_addarray(jdoc, NULL);
hres = SafeArrayGetLBound(sa, offset_dim, &lBound);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot get index of first element from WMI array '%s'", prop_name);
return SYSINFO_RET_FAIL;
}
hres = SafeArrayGetUBound(sa, offset_dim, &uBound);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot get index of last element from WMI array '%s'", prop_name);
return SYSINFO_RET_FAIL;
}
for (LONG i = lBound; i <= uBound && SYSINFO_RET_OK == ret; i++)
{
(*index)[offset_dim-1] = i;
if (offset_dim < dim)
{
ret = convert_wmiarray_json(vtProp, prop_name, dim, offset_dim + 1, index, jdoc, error);
continue;
}
ret = proc_arr_element(sa, *index, prop_name, jdoc, error);
}
zbx_json_close(jdoc);
return ret;
}
/******************************************************************************
* *
* Purpose: copies value of VARIANT type to JSON document *
* *
* Parameters: prop_json - [IN] json attribute name *
* prop_err - [IN] json attribute name *
* vtProp - [IN] variant WMI property value *
* jdoc - [IN/OUT] JSON document *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - json document contains the WMI property *
* SYSINFO_RET_FAIL - transformation of variant failed *
* *
******************************************************************************/
extern "C" int put_variant_json(const char *prop_json, const char *prop_err, VARIANT *vtProp, struct zbx_json *jdoc,
char **error)
{
HRESULT hres;
int ret = SYSINFO_RET_OK;
switch (V_VT(vtProp))
{
case VT_I8:
case VT_I4:
case VT_UI1:
case VT_I2:
case VT_I1:
case VT_UI2:
case VT_UI4:
case VT_UI8:
case VT_INT:
case VT_UINT:
hres = VariantChangeType(vtProp, vtProp, 0, VT_I8);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot convert WMI property '%s' of "
"type %d to VT_I8", prop_err, V_VT(vtProp));
ret = SYSINFO_RET_FAIL;
}
else
zbx_json_adduint64(jdoc, prop_json, vtProp->llVal);
break;
case VT_R4:
case VT_R8:
hres = VariantChangeType(vtProp, vtProp, 0, VT_R8);
if (FAILED(hres))
{
*error = zbx_dsprintf(*error, "Cannot convert WMI property '%s' of "
"type %d to VT_R8", prop_err, V_VT(vtProp));
ret = SYSINFO_RET_FAIL;
}
else
zbx_json_addfloat(jdoc, prop_json, vtProp->dblVal);
break;
case VT_EMPTY:
zbx_json_addraw(jdoc, prop_json, "null");
break;
default:
char *str;
if (V_ISARRAY(vtProp))
{
LONG *index = NULL;
ret = convert_wmiarray_json(vtProp, prop_json, 0, 0, &index, jdoc, error);
zbx_free(index);
break;
}
hres = VariantChangeType(vtProp, vtProp, VARIANT_ALPHABOOL, VT_BSTR);
if (FAILED(hres))
{
zbx_json_addraw(jdoc, prop_json, "null");
}
else
{
str = zbx_unicode_to_utf8((wchar_t *)_bstr_t(V_BSTR(vtProp)));
zbx_json_escape(&str);
zbx_json_addstring(jdoc, prop_json, str, ZBX_JSON_TYPE_STRING);
zbx_free(str);
}
break;
}
return ret;
}
/******************************************************************************
* *
* Purpose: transformation of WMI search result to JSON *
* *
* Parameters: wmi_values - [IN] WMI search result *
* json_data - [OUT] JSON document with WMI search result *
* error - [OUT] error description *
* *
* Return value: SYSINFO_RET_OK - result contains retrieved WMI value *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
******************************************************************************/
extern "C" int convert_wmi_json(zbx_vector_wmi_instance_t *wmi_values, char **json_data, char **error)
{
struct zbx_json j;
int ret = SYSINFO_RET_OK;
zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
for (int inst_i = 0; inst_i < wmi_values->values_num && SYSINFO_RET_OK == ret; inst_i++)
{
zbx_json_addobject(&j, NULL);
for (int prop_i = 0; prop_i < wmi_values->values[inst_i]->values_num && SYSINFO_RET_OK == ret; prop_i++)
{
VARIANT *vtProp = wmi_values->values[inst_i]->values[prop_i].value;
char *prop_name = zbx_unicode_to_utf8(
(wchar_t *)_bstr_t(wmi_values->values[inst_i]->values[prop_i].name));
zbx_json_escape(&prop_name);
ret = put_variant_json(prop_name, prop_name, vtProp, &j, error);
zbx_free(prop_name);
}
zbx_json_close(&j);
}
zbx_json_close(&j);
if (SYSINFO_RET_OK == ret)
{
size_t offset, len = 0;
zbx_str_memcpy_alloc(json_data, &len, &offset, j.buffer, j.buffer_size);
}
zbx_json_free(&j);
return ret;
}
/******************************************************************************
* *
* Purpose: wrapper function for wmi.getall metric *
* *
* Parameters: request - [IN] WMI request parameters *
* result - [OUT] all values from WMI Class in JSON format *
* *
* Return value: SYSINFO_RET_OK - result contains retrieved WMI value *
* SYSINFO_RET_FAIL - retrieving WMI value failed *
* *
******************************************************************************/
extern "C" int wmi_getall(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *wmi_namespace, *wmi_query, *jd = NULL, *error = NULL;
int ret = SYSINFO_RET_FAIL;
zbx_vector_wmi_instance_t wmi_values;
if (2 != request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
return SYSINFO_RET_FAIL;
}
wmi_namespace = get_rparam(request, 0);
wmi_query = get_rparam(request, 1);
if (SUCCEED != zbx_co_initialize())
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot initialize COM library."));
return SYSINFO_RET_FAIL;
}
zbx_vector_wmi_instance_create(&wmi_values);
if (SYSINFO_RET_OK == zbx_wmi_get_variant(wmi_namespace, wmi_query, parse_all, sysinfo_get_config_timeout(),
&wmi_values, &error))
{
ret = convert_wmi_json(&wmi_values, &jd, &error);
}
zbx_vector_wmi_instance_clear_ext(&wmi_values, wmi_instance_clear);
zbx_vector_wmi_instance_destroy(&wmi_values);
if (SYSINFO_RET_OK == ret)
SET_TEXT_RESULT(result,jd);
else
SET_MSG_RESULT(result, error);
return ret;
}