1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "sysinfo.h"
21 #include "log.h"
22 #include "perfmon.h"
23 #pragma comment(lib, "user32.lib")
24
25 /******************************************************************************
26 * *
27 * Function: read_registry_value *
28 * *
29 * Purpose: read value from Windows registry *
30 * *
31 ******************************************************************************/
read_registry_value(HKEY hKey,LPCTSTR name)32 static wchar_t *read_registry_value(HKEY hKey, LPCTSTR name)
33 {
34 DWORD szData;
35 wchar_t *value = NULL;
36
37 if (ERROR_SUCCESS == RegQueryValueEx(hKey, name, NULL, NULL, NULL, &szData))
38 {
39 value = zbx_malloc(NULL, szData);
40 if (ERROR_SUCCESS != RegQueryValueEx(hKey, name, NULL, NULL, (LPBYTE)value, &szData))
41 zbx_free(value);
42 }
43
44 return value;
45 }
46
47 /******************************************************************************
48 * *
49 * Function: zbx_win_getversion *
50 * *
51 * Purpose: get Windows version information *
52 * *
53 ******************************************************************************/
zbx_win_getversion()54 const OSVERSIONINFOEX *zbx_win_getversion()
55 {
56 # define ZBX_REGKEY_VERSION "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
57 # define ZBX_REGVALUE_CURRENTVERSION "CurrentVersion"
58 # define ZBX_REGVALUE_CURRENTBUILDNUMBER "CurrentBuildNumber"
59 # define ZBX_REGVALUE_CSDVERSION "CSDVersion"
60
61 # define ZBX_REGKEY_PRODUCT "System\\CurrentControlSet\\Control\\ProductOptions"
62 # define ZBX_REGVALUE_PRODUCTTYPE "ProductType"
63
64 static OSVERSIONINFOEX vi = {sizeof(OSVERSIONINFOEX)};
65
66 OSVERSIONINFOEX *pvi = NULL;
67 HKEY h_key_registry = NULL;
68 wchar_t *key_value = NULL, *ptr;
69
70 if (0 != vi.dwMajorVersion)
71 return &vi;
72
73 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(ZBX_REGKEY_VERSION), 0, KEY_READ, &h_key_registry))
74 {
75 zabbix_log(LOG_LEVEL_DEBUG, "failed to open registry key '%s'", ZBX_REGKEY_VERSION);
76 goto out;
77 }
78
79 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CURRENTVERSION))))
80 {
81 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'", ZBX_REGVALUE_CURRENTVERSION);
82 goto out;
83 }
84
85 if (NULL != (ptr = wcschr(key_value, TEXT('.'))))
86 {
87 *ptr++ = L'\0';
88 vi.dwMinorVersion = _wtoi(ptr);
89 }
90
91 vi.dwMajorVersion = _wtoi(key_value);
92
93 zbx_free(key_value);
94
95 if (6 > vi.dwMajorVersion || 2 > vi.dwMinorVersion)
96 {
97 GetVersionEx((OSVERSIONINFO *)&vi);
98 }
99 else
100 {
101 if (NULL != (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CSDVERSION))))
102 {
103 wcscpy_s(vi.szCSDVersion, sizeof(vi.szCSDVersion) / sizeof(*vi.szCSDVersion), key_value);
104
105 zbx_free(key_value);
106 }
107
108 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CURRENTBUILDNUMBER))))
109 {
110 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'",
111 ZBX_REGVALUE_CURRENTBUILDNUMBER);
112 goto out;
113 }
114
115 vi.dwBuildNumber = _wtoi(key_value);
116 zbx_free(key_value);
117
118 RegCloseKey(h_key_registry);
119 h_key_registry = NULL;
120
121 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(ZBX_REGKEY_PRODUCT), 0, KEY_READ,
122 &h_key_registry))
123 {
124 zabbix_log(LOG_LEVEL_DEBUG, "failed to open registry key '%s'", ZBX_REGKEY_PRODUCT);
125 goto out;
126 }
127
128 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_PRODUCTTYPE))))
129 {
130 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'", ZBX_REGVALUE_PRODUCTTYPE);
131 goto out;
132 }
133
134 if (0 == wcscmp(key_value, L"WinNT"))
135 vi.wProductType = 1;
136 else if (0 == wcscmp(key_value, L"LenmanNT"))
137 vi.wProductType = 2;
138 else if (0 == wcscmp(key_value, L"ServerNT"))
139 vi.wProductType = 3;
140
141 zbx_free(key_value);
142
143 vi.dwPlatformId = VER_PLATFORM_WIN32_NT;
144 }
145
146 pvi = &vi;
147 out:
148 if (NULL != h_key_registry)
149 RegCloseKey(h_key_registry);
150
151 return pvi;
152 }
153
SYSTEM_UNAME(AGENT_REQUEST * request,AGENT_RESULT * result)154 int SYSTEM_UNAME(AGENT_REQUEST *request, AGENT_RESULT *result)
155 {
156 char *os = NULL;
157 size_t os_alloc = 0, os_offset = 0;
158 char *sysname = "Windows";
159 char *os_csname = NULL;
160 char *os_version = NULL;
161 char *os_caption = NULL;
162 char *os_csdversion = NULL;
163 char *proc_architecture = NULL;
164 char *proc_addresswidth = NULL;
165 char *wmi_namespace = "root\\cimv2";
166 char *arch = "<unknown architecture>";
167
168 /* Emulates uname(2) (POSIX) since it is not provided natively by Windows by taking */
169 /* the relevant values from Win32_OperatingSystem and Win32_Processor WMI classes. */
170 /* It was decided that in context of Windows OS ISA is more useful information than */
171 /* CPU architecture. This is contrary to POSIX and uname(2) in Unix. */
172
173 zbx_wmi_get(wmi_namespace, "select CSName from Win32_OperatingSystem", &os_csname);
174 zbx_wmi_get(wmi_namespace, "select Version from Win32_OperatingSystem", &os_version);
175 zbx_wmi_get(wmi_namespace, "select Caption from Win32_OperatingSystem", &os_caption);
176 zbx_wmi_get(wmi_namespace, "select CSDVersion from Win32_OperatingSystem", &os_csdversion);
177 zbx_wmi_get(wmi_namespace, "select Architecture from Win32_Processor", &proc_architecture);
178 zbx_wmi_get(wmi_namespace, "select AddressWidth from Win32_Processor", &proc_addresswidth);
179
180 if (NULL != proc_architecture)
181 {
182 switch (atoi(proc_architecture))
183 {
184 case 0: arch = "x86"; break;
185 case 6: arch = "ia64"; break;
186 case 9:
187 if (NULL != proc_addresswidth)
188 {
189 if (32 == atoi(proc_addresswidth))
190 arch = "x86";
191 else
192 arch = "x64";
193 }
194
195 break;
196 }
197 }
198
199 /* The comments indicate the relevant field in struct utsname (POSIX) that is used in uname(2). */
200 zbx_snprintf_alloc(&os, &os_alloc, &os_offset, "%s %s %s %s%s%s %s",
201 sysname, /* sysname */
202 os_csname ? os_csname : "<unknown nodename>", /* nodename */
203 os_version ? os_version : "<unknown release>", /* release */
204 os_caption ? os_caption : "<unknown version>", /* version */
205 os_caption && os_csdversion ? " " : "",
206 os_caption && os_csdversion ? os_csdversion : "", /* version (cont.) */
207 arch); /* machine */
208
209 zbx_free(os_csname);
210 zbx_free(os_version);
211 zbx_free(os_caption);
212 zbx_free(os_csdversion);
213 zbx_free(proc_architecture);
214
215 SET_STR_RESULT(result, os);
216
217 return SYSINFO_RET_OK;
218 }
219