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 #include "cfg.h"
24 #pragma comment(lib, "user32.lib")
25
26 /******************************************************************************
27 * *
28 * Function: read_registry_value *
29 * *
30 * Purpose: read value from Windows registry *
31 * *
32 ******************************************************************************/
read_registry_value(HKEY hKey,LPCTSTR name)33 static wchar_t *read_registry_value(HKEY hKey, LPCTSTR name)
34 {
35 DWORD szData;
36 wchar_t *value = NULL;
37
38 if (ERROR_SUCCESS == RegQueryValueEx(hKey, name, NULL, NULL, NULL, &szData))
39 {
40 value = zbx_malloc(NULL, szData);
41 if (ERROR_SUCCESS != RegQueryValueEx(hKey, name, NULL, NULL, (LPBYTE)value, &szData))
42 zbx_free(value);
43 }
44
45 return value;
46 }
47
48 /******************************************************************************
49 * *
50 * Function: zbx_win_getversion *
51 * *
52 * Purpose: get Windows version information *
53 * *
54 ******************************************************************************/
zbx_win_getversion(void)55 const OSVERSIONINFOEX *zbx_win_getversion(void)
56 {
57 # define ZBX_REGKEY_VERSION "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
58 # define ZBX_REGVALUE_CURRENTVERSION "CurrentVersion"
59 # define ZBX_REGVALUE_CURRENTBUILDNUMBER "CurrentBuildNumber"
60 # define ZBX_REGVALUE_CSDVERSION "CSDVersion"
61
62 # define ZBX_REGKEY_PRODUCT "System\\CurrentControlSet\\Control\\ProductOptions"
63 # define ZBX_REGVALUE_PRODUCTTYPE "ProductType"
64
65 static OSVERSIONINFOEX vi = {sizeof(OSVERSIONINFOEX)};
66
67 OSVERSIONINFOEX *pvi = NULL;
68 HKEY h_key_registry = NULL;
69 wchar_t *key_value = NULL, *ptr;
70
71 if (0 != vi.dwMajorVersion)
72 return &vi;
73
74 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(ZBX_REGKEY_VERSION), 0, KEY_READ, &h_key_registry))
75 {
76 zabbix_log(LOG_LEVEL_DEBUG, "failed to open registry key '%s'", ZBX_REGKEY_VERSION);
77 goto out;
78 }
79
80 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CURRENTVERSION))))
81 {
82 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'", ZBX_REGVALUE_CURRENTVERSION);
83 goto out;
84 }
85
86 if (NULL != (ptr = wcschr(key_value, TEXT('.'))))
87 {
88 *ptr++ = L'\0';
89 vi.dwMinorVersion = _wtoi(ptr);
90 }
91
92 vi.dwMajorVersion = _wtoi(key_value);
93
94 zbx_free(key_value);
95
96 if (6 > vi.dwMajorVersion || 2 > vi.dwMinorVersion)
97 {
98 GetVersionEx((OSVERSIONINFO *)&vi);
99 }
100 else
101 {
102 if (NULL != (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CSDVERSION))))
103 {
104 wcscpy_s(vi.szCSDVersion, sizeof(vi.szCSDVersion) / sizeof(*vi.szCSDVersion), key_value);
105
106 zbx_free(key_value);
107 }
108
109 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_CURRENTBUILDNUMBER))))
110 {
111 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'",
112 ZBX_REGVALUE_CURRENTBUILDNUMBER);
113 goto out;
114 }
115
116 vi.dwBuildNumber = _wtoi(key_value);
117 zbx_free(key_value);
118
119 RegCloseKey(h_key_registry);
120 h_key_registry = NULL;
121
122 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(ZBX_REGKEY_PRODUCT), 0, KEY_READ,
123 &h_key_registry))
124 {
125 zabbix_log(LOG_LEVEL_DEBUG, "failed to open registry key '%s'", ZBX_REGKEY_PRODUCT);
126 goto out;
127 }
128
129 if (NULL == (key_value = read_registry_value(h_key_registry, TEXT(ZBX_REGVALUE_PRODUCTTYPE))))
130 {
131 zabbix_log(LOG_LEVEL_DEBUG, "failed to read registry value '%s'", ZBX_REGVALUE_PRODUCTTYPE);
132 goto out;
133 }
134
135 if (0 == wcscmp(key_value, L"WinNT"))
136 vi.wProductType = 1;
137 else if (0 == wcscmp(key_value, L"LenmanNT"))
138 vi.wProductType = 2;
139 else if (0 == wcscmp(key_value, L"ServerNT"))
140 vi.wProductType = 3;
141
142 zbx_free(key_value);
143
144 vi.dwPlatformId = VER_PLATFORM_WIN32_NT;
145 }
146
147 pvi = &vi;
148 out:
149 if (NULL != h_key_registry)
150 RegCloseKey(h_key_registry);
151
152 return pvi;
153 }
154
get_wmi_check_timeout(const char * wmi_namespace,const char * query,char ** var,double time_first_query_started,double * time_previous_query_finished)155 static void get_wmi_check_timeout(const char *wmi_namespace, const char *query, char **var,
156 double time_first_query_started, double *time_previous_query_finished)
157 {
158 double time_left = CONFIG_TIMEOUT - (*time_previous_query_finished - time_first_query_started);
159
160 if (0 >= time_left)
161 return;
162
163 zbx_wmi_get(wmi_namespace, query, time_left, var);
164 *time_previous_query_finished = zbx_time();
165 }
166
SYSTEM_UNAME(AGENT_REQUEST * request,AGENT_RESULT * result)167 int SYSTEM_UNAME(AGENT_REQUEST *request, AGENT_RESULT *result)
168 {
169 char *os = NULL;
170 size_t os_alloc = 0, os_offset = 0;
171 char *sysname = "Windows";
172 char *os_csname = NULL;
173 char *os_version = NULL;
174 char *os_caption = NULL;
175 char *os_csdversion = NULL;
176 char *proc_architecture = NULL;
177 char *proc_addresswidth = NULL;
178 char *wmi_namespace = "root\\cimv2";
179 char *arch = "<unknown architecture>";
180 int ret = SYSINFO_RET_FAIL;
181 double start_time = zbx_time();
182 double time_previous_query_finished = start_time;
183
184 /* Emulates uname(2) (POSIX) since it is not provided natively by Windows by taking */
185 /* the relevant values from Win32_OperatingSystem and Win32_Processor WMI classes. */
186 /* It was decided that in context of Windows OS ISA is more useful information than */
187 /* CPU architecture. This is contrary to POSIX and uname(2) in Unix. */
188
189 get_wmi_check_timeout(wmi_namespace, "select CSName from Win32_OperatingSystem", &os_csname, start_time,
190 &time_previous_query_finished);
191 get_wmi_check_timeout(wmi_namespace, "select Version from Win32_OperatingSystem", &os_version, start_time,
192 &time_previous_query_finished);
193 get_wmi_check_timeout(wmi_namespace, "select Caption from Win32_OperatingSystem", &os_caption, start_time,
194 &time_previous_query_finished);
195 get_wmi_check_timeout(wmi_namespace, "select CSDVersion from Win32_OperatingSystem", &os_csdversion, start_time,
196 &time_previous_query_finished);
197 get_wmi_check_timeout(wmi_namespace, "select Architecture from Win32_Processor", &proc_architecture, start_time,
198 &time_previous_query_finished);
199 get_wmi_check_timeout(wmi_namespace, "select AddressWidth from Win32_Processor", &proc_addresswidth, start_time,
200 &time_previous_query_finished);
201
202 if (0 >= CONFIG_TIMEOUT - (time_previous_query_finished - start_time))
203 {
204 SET_MSG_RESULT(result, zbx_strdup(NULL, "WMI aggregate query timeout"));
205 }
206 else
207 {
208 if (NULL != proc_architecture)
209 {
210 switch (atoi(proc_architecture))
211 {
212 case 0: arch = "x86"; break;
213 case 6: arch = "ia64"; break;
214 case 9:
215 if (NULL != proc_addresswidth)
216 {
217 if (32 == atoi(proc_addresswidth))
218 arch = "x86";
219 else
220 arch = "x64";
221 }
222
223 break;
224 }
225 }
226
227 /* The comments indicate the relevant field in struct utsname (POSIX) that is used in uname(2). */
228 zbx_snprintf_alloc(&os, &os_alloc, &os_offset, "%s %s %s %s%s%s %s",
229 sysname, /* sysname */
230 os_csname ? os_csname : "<unknown nodename>", /* nodename */
231 os_version ? os_version : "<unknown release>", /* release */
232 os_caption ? os_caption : "<unknown version>", /* version */
233 os_caption && os_csdversion ? " " : "",
234 os_caption && os_csdversion ? os_csdversion : "", /* version (cont.) */
235 arch); /* machine */
236
237 SET_STR_RESULT(result, os);
238
239 ret = SYSINFO_RET_OK;
240 }
241
242 zbx_free(os_csname);
243 zbx_free(os_version);
244 zbx_free(os_caption);
245 zbx_free(os_csdversion);
246 zbx_free(proc_architecture);
247 zbx_free(proc_addresswidth);
248
249 return ret;
250 }
251