Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-77321
-rw-r--r--build/win32/project/Makefile_agent1
-rw-r--r--build/win32/project/Makefile_common.inc2
-rw-r--r--include/sysinfo.h3
-rw-r--r--src/go/plugins/plugins_windows.go1
-rw-r--r--src/go/plugins/windows/registry/registry.go311
-rw-r--r--src/libs/zbxsysinfo/win32/registry.c471
-rw-r--r--src/libs/zbxsysinfo/win32/win32.c3
-rw-r--r--ui/include/classes/data/CItemData.php12
9 files changed, 803 insertions, 2 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-7732 b/ChangeLog.d/feature/ZBXNEXT-7732
new file mode 100644
index 00000000000..dd958553a63
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-7732
@@ -0,0 +1 @@
+..FG...... [ZBXNEXT-7732] added metrics for Windows Registry monitoring (dgoloscapov, rdetlavs, wiper)
diff --git a/build/win32/project/Makefile_agent b/build/win32/project/Makefile_agent
index 2f117d25886..773fbdb88c4 100644
--- a/build/win32/project/Makefile_agent
+++ b/build/win32/project/Makefile_agent
@@ -85,6 +85,7 @@ OBJS = \
..\..\..\src\libs\zbxsysinfo\win32\memory.o \
..\..\..\src\libs\zbxsysinfo\win32\net.o \
..\..\..\src\libs\zbxsysinfo\win32\pdhmon.o \
+ ..\..\..\src\libs\zbxsysinfo\win32\registry.o \
..\..\..\src\libs\zbxsysinfo\win32\proc.o \
..\..\..\src\libs\zbxsysinfo\win32\services.o \
..\..\..\src\libs\zbxsysinfo\win32\swap.o \
diff --git a/build/win32/project/Makefile_common.inc b/build/win32/project/Makefile_common.inc
index 944baa9420a..f4288b2e778 100644
--- a/build/win32/project/Makefile_common.inc
+++ b/build/win32/project/Makefile_common.inc
@@ -13,7 +13,7 @@ RESOURCE_RES = $(PROJECTNAME).res
INCS = /I $(PROJECTDIR) /I .\ /I ..\include /I ..\include\common /I ..\..\..\include /I ..\..\..\include\common
!IF "$(CPU)" == "i386" || "$(CPU)" == "x86"
-COMMON_FLAGS = /D _WIN32_WINNT=0x0501
+COMMON_FLAGS = /D _WIN32_WINNT=0x0502
ADD_LFLAGS = $(ADD_LFLAGS) /SUBSYSTEM:"CONSOLE,5.01"
!ELSEIF "$(CPU)" == "AMD64"
COMMON_FLAGS = /D _WIN32_WINNT=0x0502
diff --git a/include/sysinfo.h b/include/sysinfo.h
index 87963ffccbd..bd0d06c27d5 100644
--- a/include/sysinfo.h
+++ b/include/sysinfo.h
@@ -314,6 +314,8 @@ int NET_IF_LIST(AGENT_REQUEST *request, AGENT_RESULT *result);
int WMI_GET(AGENT_REQUEST *request, AGENT_RESULT *result);
int WMI_GETALL(AGENT_REQUEST *request, AGENT_RESULT *result);
int VM_VMEMORY_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result);
+int REGISTRY_DATA(AGENT_REQUEST *request, AGENT_RESULT *result);
+int REGISTRY_GET(AGENT_REQUEST *request, AGENT_RESULT *result);
#endif
#ifdef _AIX
@@ -412,4 +414,3 @@ void zbx_alias_list_free(void);
const char *zbx_alias_get(const char *orig);
#endif
-
diff --git a/src/go/plugins/plugins_windows.go b/src/go/plugins/plugins_windows.go
index 95b9060aaae..d0a88c01c66 100644
--- a/src/go/plugins/plugins_windows.go
+++ b/src/go/plugins/plugins_windows.go
@@ -52,6 +52,7 @@ import (
_ "zabbix.com/plugins/windows/eventlog"
_ "zabbix.com/plugins/windows/perfinstance"
_ "zabbix.com/plugins/windows/perfmon"
+ _ "zabbix.com/plugins/windows/registry"
_ "zabbix.com/plugins/windows/services"
_ "zabbix.com/plugins/windows/wmi"
_ "zabbix.com/plugins/zabbix/async"
diff --git a/src/go/plugins/windows/registry/registry.go b/src/go/plugins/windows/registry/registry.go
new file mode 100644
index 00000000000..f8b519af487
--- /dev/null
+++ b/src/go/plugins/windows/registry/registry.go
@@ -0,0 +1,311 @@
+//go:build windows
+// +build windows
+
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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 General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+package registry
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "regexp"
+ "strings"
+
+ "git.zabbix.com/ap/plugin-support/plugin"
+ "git.zabbix.com/ap/plugin-support/zbxerr"
+ "golang.org/x/sys/windows/registry"
+)
+
+// Plugin -
+type Plugin struct {
+ plugin.Base
+}
+
+var impl Plugin
+
+type registryKey struct {
+ Fullkey string `json:"fullkey"`
+ Lastsubkey string `json:"lastsubkey"`
+}
+
+type registryValue struct {
+ Fullkey string `json:"fullkey"`
+ Lastsubkey string `json:"lastsubkey"`
+ Name string `json:"name"`
+ Data interface{} `json:"data"`
+ Type string `json:"type"`
+}
+
+const (
+ RegistryDiscoveryModeValues = iota
+ RegistryDiscoveryModeKeys
+)
+
+func getHive(key string) (hive registry.Key, e error) {
+ switch key {
+ case "HKLM", "HKEY_LOCAL_MACHINE":
+ return registry.LOCAL_MACHINE, nil
+ case "HKCU", "HKEY_CURRENT_USER":
+ return registry.CURRENT_USER, nil
+ case "HKCR", "HKEY_CLASSES_ROOT":
+ return registry.CLASSES_ROOT, nil
+ case "HKU", "HKEY_USERS":
+ return registry.USERS, nil
+ case "HKPD", "HKEY_PERFORMANCE_DATA":
+ return registry.PERFORMANCE_DATA, nil
+ }
+
+ return 0, errors.New("Failed to parse registry key.")
+}
+
+func convertValue(k registry.Key, value string) (result interface{}, stype string, err error) {
+ _, valueType, err := k.GetValue(value, nil)
+ if err != nil {
+ return nil, "", err
+ }
+
+ switch valueType {
+ case registry.NONE:
+ return "", "REG_NONE", nil
+ case registry.EXPAND_SZ:
+ stype = "REG_EXPAND_SZ"
+ result, _, err = k.GetStringValue(value)
+ case registry.SZ:
+ stype = "REG_SZ"
+ result, _, err = k.GetStringValue(value)
+ case registry.BINARY:
+ stype = "REG_BINARY"
+ if val, _, err := k.GetBinaryValue(value); err == nil {
+ result = base64.StdEncoding.EncodeToString(val)
+ } else {
+ return nil, "", err
+ }
+ case registry.QWORD:
+ stype = "REG_QWORD"
+ result, _, err = k.GetIntegerValue(value)
+ case registry.DWORD:
+ stype = "REG_DWORD"
+ result, _, err = k.GetIntegerValue(value)
+ case registry.MULTI_SZ:
+ stype = "REG_MULTI_SZ"
+ result, _, err = k.GetStringsValue(value)
+ default:
+ return nil, "", errors.New("Unsupported registry data type.")
+ }
+
+ return result, stype, err
+}
+
+func discoverValues(hive registry.Key, fullkey string, discovered_values []registryValue, current_key string,
+ re *regexp.Regexp, shive string) (result []registryValue, e error) {
+
+ k, err := registry.OpenKey(hive, fullkey, registry.READ)
+ if err != nil {
+ return nil, err
+ }
+ defer k.Close()
+
+ subkeys, err := k.ReadSubKeyNames(0)
+ if err != nil {
+ return []registryValue{}, err
+ }
+
+ values, err := k.ReadValueNames(0)
+ if err != nil {
+ return []registryValue{}, err
+ }
+
+ for _, v := range values {
+ data, valtype, err := convertValue(k, v)
+
+ if err != nil {
+ continue
+ }
+
+ if re != nil {
+ if re.MatchString(v) {
+ discovered_values = append(discovered_values,
+ registryValue{shive + "\\" + fullkey, current_key, v, data, valtype})
+ }
+ } else {
+ discovered_values = append(discovered_values,
+ registryValue{shive + "\\" + fullkey, current_key, v, data, valtype})
+ }
+ }
+
+ for _, subkey := range subkeys {
+ new_fullkey := fullkey + "\\" + subkey
+ discovered_values, _ = discoverValues(hive, new_fullkey, discovered_values, subkey, re, shive)
+ }
+
+ return discovered_values, nil
+}
+
+func discoverKeys(hive registry.Key, fullkey string, subkeys []registryKey, shive string) (result []registryKey, e error) {
+ k, err := registry.OpenKey(hive, fullkey, registry.ENUMERATE_SUB_KEYS)
+ if err != nil {
+ return nil, err
+ }
+
+ s, err := k.ReadSubKeyNames(0)
+ defer k.Close()
+
+ if err != nil {
+ return nil, err
+ }
+
+ for _, i := range s {
+ current_key := fullkey + "\\" + i
+ subkeys = append(subkeys, registryKey{shive + "\\" + current_key, i})
+ subkeys, _ = discoverKeys(hive, current_key, subkeys, shive)
+ }
+
+ return subkeys, nil
+}
+
+func splitFullkey(fullkey string) (hive registry.Key, key string, shive string, e error) {
+ idx := strings.Index(fullkey, "\\")
+
+ if idx == -1 {
+ return 0, "", "", errors.New("Failed to parse registry key.")
+ }
+
+ shive = fullkey[:idx]
+ hive, e = getHive(shive)
+ key = fullkey[idx+1:]
+
+ return
+}
+
+func getValue(params []string) (result interface{}, err error) {
+ if len(params) > 2 {
+ return nil, zbxerr.ErrorTooManyParameters
+ }
+
+ if len(params) < 1 || params[0] == "" {
+ return nil, errors.New("Registry key is not supplied.")
+ }
+
+ fullkey := params[0]
+
+ hive, key, _, e := splitFullkey(fullkey)
+ if e != nil {
+ return nil, e
+ }
+
+ var value string
+
+ if len(params) == 2 {
+ value = params[1]
+ }
+
+ handle, err := registry.OpenKey(hive, key, registry.QUERY_VALUE)
+ if err != nil {
+ return nil, err
+ }
+ defer handle.Close()
+
+ result, _, err = convertValue(handle, value)
+ if err != nil {
+ return nil, err
+ }
+
+ if x, ok := result.([]string); ok {
+ var j []byte
+ j, err = json.Marshal(x)
+ result = string(j)
+ }
+
+ return
+}
+
+func discover(params []string) (result string, err error) {
+ var j []byte
+ var re *regexp.Regexp
+
+ if len(params) > 3 {
+ return "", zbxerr.ErrorTooManyParameters
+ }
+
+ if len(params) < 1 || params[0] == "" {
+ return "", errors.New("Registry key is not supplied.")
+ }
+
+ fullkey := params[0]
+
+ hive, key, shive, e := splitFullkey(fullkey)
+ if e != nil {
+ return "", e
+ }
+
+ mode := RegistryDiscoveryModeValues
+
+ if len(params) > 1 {
+ switch params[1] {
+ case "values", "":
+ // default mode - RegistryDiscoveryModeValues
+ case "keys":
+ mode = RegistryDiscoveryModeKeys
+ default:
+ return "", errors.New("Invalid 'mode' parameter.")
+ }
+
+ if len(params) == 3 {
+ if mode != RegistryDiscoveryModeValues {
+ return "", zbxerr.ErrorTooManyParameters
+ }
+ if re, err = regexp.Compile(params[2]); err != nil {
+ return "", err
+ }
+ }
+ }
+ switch mode {
+ case RegistryDiscoveryModeKeys:
+ results := make([]registryKey, 0)
+ results, err = discoverKeys(hive, key, results, shive)
+ j, _ = json.Marshal(results)
+ case RegistryDiscoveryModeValues:
+ results := make([]registryValue, 0)
+ results, err = discoverValues(hive, key, results, "", re, shive)
+ j, _ = json.Marshal(results)
+ }
+
+ return string(j), err
+}
+
+// Export -
+func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) {
+ switch key {
+ case "registry.data":
+ return getValue(params)
+ case "registry.get":
+ return discover(params)
+ default:
+ return nil, plugin.UnsupportedMetricError
+ }
+}
+
+func init() {
+ plugin.RegisterMetrics(&impl, "Registry",
+ "registry.data", "Return value of the registry key.",
+ "registry.get", "Discover registry key and its subkeys.",
+ )
+}
diff --git a/src/libs/zbxsysinfo/win32/registry.c b/src/libs/zbxsysinfo/win32/registry.c
new file mode 100644
index 00000000000..c0f4396e368
--- /dev/null
+++ b/src/libs/zbxsysinfo/win32/registry.c
@@ -0,0 +1,471 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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 General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "sysinfo.h"
+#include "base64.h"
+#include "zbxjson.h"
+#include "zbxalgo.h"
+#include "zbxregexp.h"
+#include <locale.h>
+#include <winreg.h>
+
+#define ZBX_SYSINFO_REGISTRY_TAG_FULLKEY "fullkey"
+#define ZBX_SYSINFO_REGISTRY_TAG_LASTKEY "lastsubkey"
+#define ZBX_SYSINFO_REGISTRY_TAG_NAME "name"
+#define ZBX_SYSINFO_REGISTRY_TAG_DATA "data"
+#define ZBX_SYSINFO_REGISTRY_TAG_TYPE "type"
+
+#define MAX_KEY_LENGTH 255
+#define MAX_DATA_LENGTH 65534
+#define MAX_VALUE_NAME 16383
+#define MAX_FULLKEY_LENGTH 4096
+
+#define REGISTRY_DISCOVERY_MODE_KEYS 0
+#define REGISTRY_DISCOVERY_MODE_VALUES 1
+
+static HKEY get_hkey_from_fullkey(char *fullkey)
+{
+ if (0 == strcmp("HKEY_CLASSES_ROOT", fullkey) || 0 == strcmp("HKCR", fullkey))
+ return HKEY_CLASSES_ROOT;
+ else if (0 == strcmp("HKEY_CURRENT_CONFIG", fullkey) || 0 == strcmp("HKCC", fullkey))
+ return HKEY_CURRENT_CONFIG;
+ else if (0 == strcmp("HKEY_CURRENT_USER", fullkey) || 0 == strcmp("HKCU", fullkey))
+ return HKEY_CURRENT_USER;
+ else if (0 == strcmp("HKEY_CURRENT_USER_LOCAL_SETTINGS", fullkey) || 0 == strcmp("HKCULS", fullkey))
+ return HKEY_CURRENT_USER_LOCAL_SETTINGS;
+ else if (0 == strcmp("HKEY_LOCAL_MACHINE", fullkey) || 0 == strcmp("HKLM", fullkey))
+ return HKEY_LOCAL_MACHINE;
+ else if (0 == strcmp("HKEY_PERFORMANCE_DATA", fullkey) || 0 == strcmp("HKPD", fullkey))
+ return HKEY_PERFORMANCE_DATA;
+ else if (0 == strcmp("HKEY_PERFORMANCE_NLSTEXT", fullkey) || 0 == strcmp("HKPN", fullkey))
+ return HKEY_PERFORMANCE_NLSTEXT;
+ else if (0 == strcmp("HKEY_PERFORMANCE_TEXT", fullkey) || 0 == strcmp("HKPT", fullkey))
+ return HKEY_PERFORMANCE_TEXT;
+ else if (0 == strcmp("HKEY_USERS", fullkey) || 0 == strcmp("HKU", fullkey))
+ return HKEY_USERS;
+
+ return 0;
+}
+
+static const char *registry_type_to_string(DWORD type)
+{
+ switch (type)
+ {
+ case REG_BINARY:
+ return "REG_BINARY";
+ case REG_DWORD:
+ return "REG_DWORD";
+ case REG_EXPAND_SZ:
+ return "REG_EXPAND_SZ";
+ case REG_LINK:
+ return "REG_LINK";
+ case REG_MULTI_SZ:
+ return "REG_MULTI_SZ";
+ case REG_NONE:
+ return "REG_NONE";
+ case REG_QWORD:
+ return "REG_QWORD";
+ case REG_SZ:
+ return "REG_SZ";
+ }
+
+ return "Unknown";
+}
+
+static void registry_get_multistring_value(const wchar_t *wbuffer, struct zbx_json *j)
+{
+ char *buffer;
+
+ while (L'\0' != *wbuffer)
+ {
+ buffer = zbx_unicode_to_utf8(wbuffer);
+ zbx_json_addstring(j, NULL, buffer, ZBX_JSON_TYPE_STRING);
+ zbx_free(buffer);
+ wbuffer += wcslen(wbuffer) + 1 ;
+ }
+}
+
+static int convert_value(DWORD type, const char *value, DWORD value_len, char **out)
+{
+ struct zbx_json j;
+
+ switch (type) {
+ case REG_BINARY:
+ str_base64_encode_dyn(value, out, (int)value_len);
+ return SUCCEED;
+ case REG_DWORD:
+ *out = zbx_dsprintf(NULL, "%u", *(DWORD *)value);
+ return SUCCEED;
+ case REG_QWORD:
+ *out = zbx_dsprintf(NULL, "%lu", *(DWORDLONG *)value);
+ return SUCCEED;
+ case REG_MULTI_SZ:
+ zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
+ zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
+
+ registry_get_multistring_value((wchar_t *)value, &j);
+
+ zbx_json_close(&j);
+ *out = zbx_strdup(NULL, j.buffer);
+ zbx_json_free(&j);
+ return SUCCEED;
+ case REG_NONE:
+ *out = NULL;
+ return SUCCEED;
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ *out = zbx_unicode_to_utf8((wchar_t *)value);
+ return SUCCEED;
+ default:
+ return FAIL;
+ }
+}
+
+ZBX_PTR_VECTOR_DECL(wchar_ptr, wchar_t *)
+ZBX_PTR_VECTOR_IMPL(wchar_ptr, wchar_t *)
+
+static void discovery_get_regkey_values(HKEY hKey, wchar_t *current_subkey, struct zbx_json *j, int mode,
+ wchar_t *root, const char *regexp)
+{
+ wchar_t achClass[MAX_PATH] = TEXT(""), achValue[MAX_VALUE_NAME];
+ DWORD cchClassName = MAX_PATH, cSubKeys=0, cValues, cbName, i, retCode,
+ cchValue = MAX_VALUE_NAME;
+ char *uroot, *usubkey;
+ zbx_vector_wchar_ptr_t wsubkeys;
+
+ retCode = RegQueryInfoKey(hKey, achClass, &cchClassName, NULL, &cSubKeys, NULL, NULL, &cValues, NULL, NULL,
+ NULL, NULL);
+
+ zbx_vector_wchar_ptr_create(&wsubkeys);
+
+ uroot = zbx_unicode_to_utf8(root);
+ usubkey = zbx_unicode_to_utf8(current_subkey);
+
+ if (REGISTRY_DISCOVERY_MODE_KEYS == mode)
+ {
+ if (*usubkey != '\0')
+ {
+ zbx_json_addobject(j, NULL);
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_FULLKEY, uroot, ZBX_JSON_TYPE_STRING);
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_LASTKEY, usubkey, ZBX_JSON_TYPE_STRING);
+ zbx_json_close(j);
+ }
+
+ zbx_free(uroot);
+ zbx_free(usubkey);
+ }
+
+ for (i = 0; i < cSubKeys; i++)
+ {
+ cbName = MAX_KEY_LENGTH;
+ retCode = RegEnumKeyEx(hKey, i, achClass, &cbName, NULL, NULL, NULL, NULL);
+
+ if (ERROR_SUCCESS == retCode)
+ zbx_vector_wchar_ptr_append(&wsubkeys, wcsdup(achClass));
+ }
+
+ for (i = 0; i < (DWORD)wsubkeys.values_num; i++)
+ {
+ HKEY hSubkey;
+ wchar_t wnew_root[MAX_FULLKEY_LENGTH];
+ wchar_t *wsubkey;
+
+ wsubkey = wsubkeys.values[i];
+
+ if (0 == wcscmp(wsubkey, L""))
+ continue;
+
+ _snwprintf_s(wnew_root, MAX_FULLKEY_LENGTH, MAX_FULLKEY_LENGTH, L"%s\\%s", root, wsubkey);
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(hKey, wsubkey, 0, KEY_READ, &hSubkey))
+ discovery_get_regkey_values(hSubkey, wsubkey, j, mode, wnew_root, regexp);
+
+ RegCloseKey(hSubkey);
+ }
+
+ zbx_vector_wchar_ptr_clear_ext(&wsubkeys, zbx_ptr_free);
+ zbx_vector_wchar_ptr_destroy(&wsubkeys);
+
+ if (REGISTRY_DISCOVERY_MODE_VALUES == mode && 0 != cValues)
+ {
+ DWORD buffer_alloc = 1024;
+ char *buffer;
+
+ buffer = zbx_malloc(NULL, buffer_alloc);
+
+ for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
+ {
+ DWORD valueType, value_len = buffer_alloc;
+ char *uvaluename, *out = NULL;
+
+ cchValue = MAX_VALUE_NAME;
+ achValue[0] = L'\0';
+
+ if (ERROR_MORE_DATA == (retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, &valueType,
+ buffer, &value_len)))
+ {
+ buffer = zbx_realloc(buffer, value_len);
+ buffer_alloc = value_len;
+
+ cchValue = MAX_VALUE_NAME;
+ retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, &valueType, buffer, &value_len);
+ }
+
+ if (ERROR_SUCCESS != retCode)
+ continue;
+
+ uvaluename = zbx_unicode_to_utf8(achValue);
+
+ if (NULL != regexp && '\0' != *regexp)
+ {
+ if (NULL == zbx_regexp_match(uvaluename, regexp, NULL))
+ {
+ zbx_free(uvaluename);
+ continue;
+ }
+ }
+
+ if (SUCCEED != convert_value(valueType, buffer, value_len, &out))
+ continue;
+
+ zbx_json_addobject(j, NULL);
+
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_FULLKEY, uroot,
+ ZBX_JSON_TYPE_STRING);
+
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_LASTKEY, usubkey,
+ ZBX_JSON_TYPE_STRING);
+
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_NAME, uvaluename, ZBX_JSON_TYPE_STRING);
+ zbx_free(uvaluename);
+
+ switch (valueType)
+ {
+ case REG_DWORD:
+ case REG_QWORD:
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_DATA, out, ZBX_JSON_TYPE_INT);
+ break;
+ case REG_NONE:
+ zbx_json_adduint64(j, ZBX_SYSINFO_REGISTRY_TAG_DATA, 0);
+ break;
+ case REG_MULTI_SZ:
+ zbx_json_addraw(j, ZBX_SYSINFO_REGISTRY_TAG_DATA, out);
+ break;
+ default:
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_DATA, out, ZBX_JSON_TYPE_STRING);
+ }
+
+ zbx_free(out);
+
+ zbx_json_addstring(j, ZBX_SYSINFO_REGISTRY_TAG_TYPE,
+ registry_type_to_string(valueType), ZBX_JSON_TYPE_STRING);
+
+ zbx_json_close(j);
+ }
+
+ zbx_free(buffer);
+ }
+
+ zbx_free(uroot);
+ zbx_free(usubkey);
+}
+
+static int split_fullkey(char **fullkey, HKEY *hive_handle, char **hive_str)
+{
+ char *end;
+
+ if (NULL == (end = strchr(*fullkey, '\\')))
+ return FAIL;
+
+ *end = '\0';
+
+ if (NULL == (*hive_handle = get_hkey_from_fullkey(*fullkey)))
+ return FAIL;
+
+ if (NULL != hive_str)
+ *hive_str = *fullkey;
+
+ *fullkey = *fullkey + (end - *fullkey) + 1;
+
+ return SUCCEED;
+}
+
+static int registry_discover(char *key, int mode, AGENT_RESULT *result, const char *regexp)
+{
+ wchar_t *wkey, *wfullkey = NULL;;
+ HKEY hkey, hive_handle;
+ struct zbx_json j;
+ DWORD retCode;
+ int ret = SUCCEED;
+ char *hive_str, *fullkey = NULL;
+
+ if (FAIL == split_fullkey(&key, &hive_handle, &hive_str))
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Failed to parse registry key."));
+ return FAIL;
+ }
+
+ zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
+
+ wkey = zbx_utf8_to_unicode(key);
+
+ if (ERROR_SUCCESS == (retCode = RegOpenKeyEx(hive_handle, wkey, 0, KEY_READ, &hkey)))
+ {
+ fullkey = zbx_dsprintf(fullkey, "%s\\%s", hive_str, key);
+ wfullkey = zbx_utf8_to_unicode(fullkey);
+ discovery_get_regkey_values(hkey, L"", &j, mode, wfullkey, regexp);
+ }
+ else
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, strerror_from_system(retCode)));
+ ret = FAIL;
+ goto out;
+ }
+
+ RegCloseKey(hkey);
+
+ zbx_json_close(&j);
+ SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
+out:
+ zbx_json_free(&j);
+ zbx_free(wkey);
+ zbx_free(fullkey);
+ zbx_free(wfullkey);
+
+ return ret;
+}
+
+static int registry_get_value(char *key, const char *value, AGENT_RESULT *result)
+{
+ wchar_t *wkey, *wvalue;
+ char *data = NULL, *bin_value = NULL, *value_str = NULL;
+ DWORD BufferSize = 0, type;
+ LSTATUS errCode;
+ HKEY hive_handle;
+ int ret = SUCCEED;
+
+ if (FAIL == split_fullkey(&key, &hive_handle, NULL))
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Failed to parse registry key."));
+ return FAIL;
+ }
+
+ wkey = zbx_utf8_to_unicode(key);
+ wvalue = (NULL != value ? zbx_utf8_to_unicode(value) : NULL);
+
+ errCode = RegGetValue(hive_handle, wkey, wvalue, RRF_RT_ANY, &type, NULL, &BufferSize);
+ if (ERROR_SUCCESS == errCode)
+ {
+ data = zbx_malloc(NULL, (size_t)BufferSize);
+ errCode = RegGetValue(hive_handle, wkey, wvalue, RRF_RT_ANY, &type, (PVOID)data, &BufferSize);
+ }
+
+ if (ERROR_SUCCESS != errCode)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, strerror_from_system(errCode)));
+ ret = FAIL;
+ goto out;
+ }
+
+ if (SUCCEED == (ret = convert_value(type, data, BufferSize, &value_str)))
+ SET_STR_RESULT(result, value_str);
+ else
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported registry data type."));
+out:
+ zbx_free(wkey);
+ zbx_free(wvalue);
+ zbx_free(data);
+
+ return ret;
+}
+
+int REGISTRY_DATA(AGENT_REQUEST *request, AGENT_RESULT *result)
+{
+ char *regkey, *value_name;
+
+ if (2 < request->nparam)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
+ return SYSINFO_RET_FAIL;
+ }
+
+ regkey = get_rparam(request, 0);
+
+ if (NULL == regkey || '\0' == *regkey)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Registry key is not supplied."));
+ return SYSINFO_RET_FAIL;
+ }
+
+ value_name = get_rparam(request, 1);
+
+ if (FAIL == registry_get_value(regkey, value_name, result))
+ return SYSINFO_RET_FAIL;
+
+ return SYSINFO_RET_OK;
+}
+
+int REGISTRY_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
+{
+ char *pkey, *pmode, *regexp;
+ int mode;
+
+ if (3 < request->nparam)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
+ return SYSINFO_RET_FAIL;
+ }
+
+ pkey = get_rparam(request, 0);
+
+ if (NULL == pkey || '\0' == *pkey)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Registry key is not supplied."));
+ return SYSINFO_RET_FAIL;
+ }
+
+ pmode = get_rparam(request, 1);
+
+ if (NULL == pmode || '\0' == *pmode || 0 == strcmp(pmode, "values"))
+ {
+ mode = REGISTRY_DISCOVERY_MODE_VALUES;
+ }
+ else if (0 == strcmp(pmode, "keys"))
+ {
+ mode = REGISTRY_DISCOVERY_MODE_KEYS;
+
+ if (2 < request->nparam)
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
+ return SYSINFO_RET_FAIL;
+ }
+ }
+ else
+ {
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid 'mode' parameter."));
+ return SYSINFO_RET_FAIL;
+ }
+
+ regexp = get_rparam(request, 2);
+
+ if (FAIL == registry_discover(pkey, mode, result, regexp))
+ return SYSINFO_RET_FAIL;
+
+ return SYSINFO_RET_OK;
+}
diff --git a/src/libs/zbxsysinfo/win32/win32.c b/src/libs/zbxsysinfo/win32/win32.c
index f4fce3d7cbc..f366657c564 100644
--- a/src/libs/zbxsysinfo/win32/win32.c
+++ b/src/libs/zbxsysinfo/win32/win32.c
@@ -71,5 +71,8 @@ ZBX_METRIC parameters_specific[] =
{"wmi.get", CF_HAVEPARAMS, WMI_GET, "root\\cimv2,select Caption from Win32_OperatingSystem"},
{"wmi.getall", CF_HAVEPARAMS, WMI_GETALL, "root\\cimv2,select * from Win32_OperatingSystem"},
+ {"registry.data", CF_HAVEPARAMS, REGISTRY_DATA, NULL},
+ {"registry.get", CF_HAVEPARAMS, REGISTRY_GET, NULL},
+
{NULL}
};
diff --git a/ui/include/classes/data/CItemData.php b/ui/include/classes/data/CItemData.php
index ae67b8298e5..a516b9842e2 100644
--- a/ui/include/classes/data/CItemData.php
+++ b/ui/include/classes/data/CItemData.php
@@ -61,6 +61,8 @@ final class CItemData {
'proc.mem[<name>,<user>,<mode>,<cmdline>,<memtype>]',
'proc.num[<name>,<user>,<state>,<cmdline>,<zone>]',
'proc_info[process,<attribute>,<type>]',
+ 'registry.data[key,<value name>]',
+ 'registry.get[key,<mode>,<name regexp>]',
'sensor[device,sensor,<mode>]',
'service.info[service,<param>]',
'services[<type>,<state>,<exclude>]',
@@ -161,6 +163,8 @@ final class CItemData {
'proc.mem[<name>,<user>,<mode>,<cmdline>,<memtype>]',
'proc.num[<name>,<user>,<state>,<cmdline>,<zone>]',
'proc_info[process,<attribute>,<type>]',
+ 'registry.data[key,<value name>]',
+ 'registry.get[key,<mode>,<name regexp>]',
'sensor[device,sensor,<mode>]',
'service.info[service,<param>]',
'services[<type>,<state>,<exclude>]',
@@ -1009,6 +1013,14 @@ final class CItemData {
'description' => _('Various information about specific process(es). Returns float'),
'value_type' => ITEM_VALUE_TYPE_FLOAT
],
+ 'registry.data[key,<value name>]' => [
+ 'description' => _('Value data for value name in Windows Registry key.'),
+ 'value_type' => null
+ ],
+ 'registry.get[key,<mode>,<name regexp>]' => [
+ 'description' => _('List of Windows Registry values or keys located at given key. Returns JSON.'),
+ 'value_type' => ITEM_VALUE_TYPE_TEXT
+ ],
'sensor[device,sensor,<mode>]' => [
'description' => _('Hardware sensor reading. Returns float'),
'value_type' => ITEM_VALUE_TYPE_FLOAT