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