1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #if defined(_WIN32)
28
29 #include <curl/curl.h>
30 #include "version_win32.h"
31 #include "warnless.h"
32
33 /* The last 2 #include files should be in this order */
34 #ifdef BUILDING_LIBCURL
35 #include "curl_memory.h"
36 #endif
37 #include "memdebug.h"
38
39 /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
40 and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
41 struct OUR_OSVERSIONINFOEXW {
42 ULONG dwOSVersionInfoSize;
43 ULONG dwMajorVersion;
44 ULONG dwMinorVersion;
45 ULONG dwBuildNumber;
46 ULONG dwPlatformId;
47 WCHAR szCSDVersion[128];
48 USHORT wServicePackMajor;
49 USHORT wServicePackMinor;
50 USHORT wSuiteMask;
51 UCHAR wProductType;
52 UCHAR wReserved;
53 };
54
55 /*
56 * curlx_verify_windows_version()
57 *
58 * This is used to verify if we are running on a specific Windows version.
59 *
60 * Parameters:
61 *
62 * majorVersion [in] - The major version number.
63 * minorVersion [in] - The minor version number.
64 * buildVersion [in] - The build version number. If 0, this parameter is
65 * ignored.
66 * platform [in] - The optional platform identifier.
67 * condition [in] - The test condition used to specifier whether we are
68 * checking a version less than, equal to or greater than
69 * what is specified in the major and minor version
70 * numbers.
71 *
72 * Returns TRUE if matched; otherwise FALSE.
73 */
curlx_verify_windows_version(const unsigned int majorVersion,const unsigned int minorVersion,const unsigned int buildVersion,const PlatformIdentifier platform,const VersionCondition condition)74 bool curlx_verify_windows_version(const unsigned int majorVersion,
75 const unsigned int minorVersion,
76 const unsigned int buildVersion,
77 const PlatformIdentifier platform,
78 const VersionCondition condition)
79 {
80 bool matched = FALSE;
81
82 #if defined(CURL_WINDOWS_UWP)
83 /* We have no way to determine the Windows version from Windows apps,
84 so let's assume we are running on the target Windows version. */
85 const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
86 const WORD targetVersion = (WORD)_WIN32_WINNT;
87
88 (void)buildVersion;
89
90 switch(condition) {
91 case VERSION_LESS_THAN:
92 matched = targetVersion < fullVersion;
93 break;
94
95 case VERSION_LESS_THAN_EQUAL:
96 matched = targetVersion <= fullVersion;
97 break;
98
99 case VERSION_EQUAL:
100 matched = targetVersion == fullVersion;
101 break;
102
103 case VERSION_GREATER_THAN_EQUAL:
104 matched = targetVersion >= fullVersion;
105 break;
106
107 case VERSION_GREATER_THAN:
108 matched = targetVersion > fullVersion;
109 break;
110 }
111
112 if(matched && (platform == PLATFORM_WINDOWS)) {
113 /* we are always running on PLATFORM_WINNT */
114 matched = FALSE;
115 }
116 #elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
117 (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
118 OSVERSIONINFO osver;
119
120 memset(&osver, 0, sizeof(osver));
121 osver.dwOSVersionInfoSize = sizeof(osver);
122
123 /* Find out Windows version */
124 if(GetVersionEx(&osver)) {
125 /* Verify the Operating System version number */
126 switch(condition) {
127 case VERSION_LESS_THAN:
128 if(osver.dwMajorVersion < majorVersion ||
129 (osver.dwMajorVersion == majorVersion &&
130 osver.dwMinorVersion < minorVersion) ||
131 (buildVersion != 0 &&
132 (osver.dwMajorVersion == majorVersion &&
133 osver.dwMinorVersion == minorVersion &&
134 osver.dwBuildNumber < buildVersion)))
135 matched = TRUE;
136 break;
137
138 case VERSION_LESS_THAN_EQUAL:
139 if(osver.dwMajorVersion < majorVersion ||
140 (osver.dwMajorVersion == majorVersion &&
141 osver.dwMinorVersion < minorVersion) ||
142 (osver.dwMajorVersion == majorVersion &&
143 osver.dwMinorVersion == minorVersion &&
144 (buildVersion == 0 ||
145 osver.dwBuildNumber <= buildVersion)))
146 matched = TRUE;
147 break;
148
149 case VERSION_EQUAL:
150 if(osver.dwMajorVersion == majorVersion &&
151 osver.dwMinorVersion == minorVersion &&
152 (buildVersion == 0 ||
153 osver.dwBuildNumber == buildVersion))
154 matched = TRUE;
155 break;
156
157 case VERSION_GREATER_THAN_EQUAL:
158 if(osver.dwMajorVersion > majorVersion ||
159 (osver.dwMajorVersion == majorVersion &&
160 osver.dwMinorVersion > minorVersion) ||
161 (osver.dwMajorVersion == majorVersion &&
162 osver.dwMinorVersion == minorVersion &&
163 (buildVersion == 0 ||
164 osver.dwBuildNumber >= buildVersion)))
165 matched = TRUE;
166 break;
167
168 case VERSION_GREATER_THAN:
169 if(osver.dwMajorVersion > majorVersion ||
170 (osver.dwMajorVersion == majorVersion &&
171 osver.dwMinorVersion > minorVersion) ||
172 (buildVersion != 0 &&
173 (osver.dwMajorVersion == majorVersion &&
174 osver.dwMinorVersion == minorVersion &&
175 osver.dwBuildNumber > buildVersion)))
176 matched = TRUE;
177 break;
178 }
179
180 /* Verify the platform identifier (if necessary) */
181 if(matched) {
182 switch(platform) {
183 case PLATFORM_WINDOWS:
184 if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
185 matched = FALSE;
186 break;
187
188 case PLATFORM_WINNT:
189 if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
190 matched = FALSE;
191 break;
192
193 default: /* like platform == PLATFORM_DONT_CARE */
194 break;
195 }
196 }
197 }
198 #else
199 ULONGLONG cm = 0;
200 struct OUR_OSVERSIONINFOEXW osver;
201 BYTE majorCondition;
202 BYTE minorCondition;
203 BYTE buildCondition;
204 BYTE spMajorCondition;
205 BYTE spMinorCondition;
206 DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
207 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
208
209 typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
210 (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
211 static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
212 static bool onetime = TRUE; /* safe because first call is during init */
213
214 if(onetime) {
215 pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
216 (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
217 onetime = FALSE;
218 }
219
220 switch(condition) {
221 case VERSION_LESS_THAN:
222 majorCondition = VER_LESS;
223 minorCondition = VER_LESS;
224 buildCondition = VER_LESS;
225 spMajorCondition = VER_LESS_EQUAL;
226 spMinorCondition = VER_LESS_EQUAL;
227 break;
228
229 case VERSION_LESS_THAN_EQUAL:
230 majorCondition = VER_LESS_EQUAL;
231 minorCondition = VER_LESS_EQUAL;
232 buildCondition = VER_LESS_EQUAL;
233 spMajorCondition = VER_LESS_EQUAL;
234 spMinorCondition = VER_LESS_EQUAL;
235 break;
236
237 case VERSION_EQUAL:
238 majorCondition = VER_EQUAL;
239 minorCondition = VER_EQUAL;
240 buildCondition = VER_EQUAL;
241 spMajorCondition = VER_GREATER_EQUAL;
242 spMinorCondition = VER_GREATER_EQUAL;
243 break;
244
245 case VERSION_GREATER_THAN_EQUAL:
246 majorCondition = VER_GREATER_EQUAL;
247 minorCondition = VER_GREATER_EQUAL;
248 buildCondition = VER_GREATER_EQUAL;
249 spMajorCondition = VER_GREATER_EQUAL;
250 spMinorCondition = VER_GREATER_EQUAL;
251 break;
252
253 case VERSION_GREATER_THAN:
254 majorCondition = VER_GREATER;
255 minorCondition = VER_GREATER;
256 buildCondition = VER_GREATER;
257 spMajorCondition = VER_GREATER_EQUAL;
258 spMinorCondition = VER_GREATER_EQUAL;
259 break;
260
261 default:
262 return FALSE;
263 }
264
265 memset(&osver, 0, sizeof(osver));
266 osver.dwOSVersionInfoSize = sizeof(osver);
267 osver.dwMajorVersion = majorVersion;
268 osver.dwMinorVersion = minorVersion;
269 osver.dwBuildNumber = buildVersion;
270 if(platform == PLATFORM_WINDOWS)
271 osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
272 else if(platform == PLATFORM_WINNT)
273 osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
274
275 cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
276 cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
277 cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
278 cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
279
280 if(platform != PLATFORM_DONT_CARE) {
281 cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
282 dwTypeMask |= VER_PLATFORMID;
283 }
284
285 /* Later versions of Windows have version functions that may not return the
286 real version of Windows unless the application is so manifested. We prefer
287 the real version always, so we use the Rtl variant of the function when
288 possible. Note though the function signatures have underlying fundamental
289 types that are the same, the return values are different. */
290 if(pRtlVerifyVersionInfo)
291 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
292 else
293 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
294
295 /* Compare the build number separately. VerifyVersionInfo normally compares
296 major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
297 do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
298 Build comparison is only needed when build numbers are equal (eg 1.9 is
299 always less than 2.0 so build comparison is not needed). */
300 if(matched && buildVersion &&
301 (condition == VERSION_EQUAL ||
302 ((condition == VERSION_GREATER_THAN_EQUAL ||
303 condition == VERSION_LESS_THAN_EQUAL) &&
304 curlx_verify_windows_version(majorVersion, minorVersion, 0,
305 platform, VERSION_EQUAL)))) {
306
307 cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
308 dwTypeMask = VER_BUILDNUMBER;
309 if(pRtlVerifyVersionInfo)
310 matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
311 else
312 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
313 dwTypeMask, cm);
314 }
315
316 #endif
317
318 return matched;
319 }
320
321 #endif /* _WIN32 */
322