/* ** 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 <https://www.gnu.org/licenses/>. **/ #include "zbxsysinc.h" #include <comdef.h> #include <Wbemidl.h> 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; }