1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2016 - 2021, 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 ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #if defined(WIN32)
26
27 #include <curl/curl.h>
28 #include "version_win32.h"
29 #include "warnless.h"
30
31 /* The last #include files should be: */
32 #include "curl_memory.h"
33 #include "memdebug.h"
34
35 /* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
36 and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
37 struct OUR_OSVERSIONINFOEXW {
38 ULONG dwOSVersionInfoSize;
39 ULONG dwMajorVersion;
40 ULONG dwMinorVersion;
41 ULONG dwBuildNumber;
42 ULONG dwPlatformId;
43 WCHAR szCSDVersion[128];
44 USHORT wServicePackMajor;
45 USHORT wServicePackMinor;
46 USHORT wSuiteMask;
47 UCHAR wProductType;
48 UCHAR wReserved;
49 };
50
51 /*
52 * curlx_verify_windows_version()
53 *
54 * This is used to verify if we are running on a specific windows version.
55 *
56 * Parameters:
57 *
58 * majorVersion [in] - The major version number.
59 * minorVersion [in] - The minor version number.
60 * platform [in] - The optional platform identifier.
61 * condition [in] - The test condition used to specifier whether we are
62 * checking a version less then, equal to or greater than
63 * what is specified in the major and minor version
64 * numbers.
65 *
66 * Returns TRUE if matched; otherwise FALSE.
67 */
curlx_verify_windows_version(const unsigned int majorVersion,const unsigned int minorVersion,const PlatformIdentifier platform,const VersionCondition condition)68 bool curlx_verify_windows_version(const unsigned int majorVersion,
69 const unsigned int minorVersion,
70 const PlatformIdentifier platform,
71 const VersionCondition condition)
72 {
73 bool matched = FALSE;
74
75 #if defined(CURL_WINDOWS_APP)
76 /* We have no way to determine the Windows version from Windows apps,
77 so let's assume we're running on the target Windows version. */
78 const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
79 const WORD targetVersion = (WORD)_WIN32_WINNT;
80
81 switch(condition) {
82 case VERSION_LESS_THAN:
83 matched = targetVersion < fullVersion;
84 break;
85
86 case VERSION_LESS_THAN_EQUAL:
87 matched = targetVersion <= fullVersion;
88 break;
89
90 case VERSION_EQUAL:
91 matched = targetVersion == fullVersion;
92 break;
93
94 case VERSION_GREATER_THAN_EQUAL:
95 matched = targetVersion >= fullVersion;
96 break;
97
98 case VERSION_GREATER_THAN:
99 matched = targetVersion > fullVersion;
100 break;
101 }
102
103 if(matched && (platform == PLATFORM_WINDOWS)) {
104 /* we're always running on PLATFORM_WINNT */
105 matched = FALSE;
106 }
107 #elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
108 (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
109 OSVERSIONINFO osver;
110
111 memset(&osver, 0, sizeof(osver));
112 osver.dwOSVersionInfoSize = sizeof(osver);
113
114 /* Find out Windows version */
115 if(GetVersionEx(&osver)) {
116 /* Verify the Operating System version number */
117 switch(condition) {
118 case VERSION_LESS_THAN:
119 if(osver.dwMajorVersion < majorVersion ||
120 (osver.dwMajorVersion == majorVersion &&
121 osver.dwMinorVersion < minorVersion))
122 matched = TRUE;
123 break;
124
125 case VERSION_LESS_THAN_EQUAL:
126 if(osver.dwMajorVersion < majorVersion ||
127 (osver.dwMajorVersion == majorVersion &&
128 osver.dwMinorVersion <= minorVersion))
129 matched = TRUE;
130 break;
131
132 case VERSION_EQUAL:
133 if(osver.dwMajorVersion == majorVersion &&
134 osver.dwMinorVersion == minorVersion)
135 matched = TRUE;
136 break;
137
138 case VERSION_GREATER_THAN_EQUAL:
139 if(osver.dwMajorVersion > majorVersion ||
140 (osver.dwMajorVersion == majorVersion &&
141 osver.dwMinorVersion >= minorVersion))
142 matched = TRUE;
143 break;
144
145 case VERSION_GREATER_THAN:
146 if(osver.dwMajorVersion > majorVersion ||
147 (osver.dwMajorVersion == majorVersion &&
148 osver.dwMinorVersion > minorVersion))
149 matched = TRUE;
150 break;
151 }
152
153 /* Verify the platform identifier (if necessary) */
154 if(matched) {
155 switch(platform) {
156 case PLATFORM_WINDOWS:
157 if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
158 matched = FALSE;
159 break;
160
161 case PLATFORM_WINNT:
162 if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
163 matched = FALSE;
164
165 default: /* like platform == PLATFORM_DONT_CARE */
166 break;
167 }
168 }
169 }
170 #else
171 ULONGLONG cm = 0;
172 struct OUR_OSVERSIONINFOEXW osver;
173 BYTE majorCondition;
174 BYTE minorCondition;
175 BYTE spMajorCondition;
176 BYTE spMinorCondition;
177
178 typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
179 (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
180 static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
181 static bool onetime = true; /* safe because first call is during init */
182
183 if(onetime) {
184 pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
185 (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
186 onetime = false;
187 }
188
189 switch(condition) {
190 case VERSION_LESS_THAN:
191 majorCondition = VER_LESS;
192 minorCondition = VER_LESS;
193 spMajorCondition = VER_LESS_EQUAL;
194 spMinorCondition = VER_LESS_EQUAL;
195 break;
196
197 case VERSION_LESS_THAN_EQUAL:
198 majorCondition = VER_LESS_EQUAL;
199 minorCondition = VER_LESS_EQUAL;
200 spMajorCondition = VER_LESS_EQUAL;
201 spMinorCondition = VER_LESS_EQUAL;
202 break;
203
204 case VERSION_EQUAL:
205 majorCondition = VER_EQUAL;
206 minorCondition = VER_EQUAL;
207 spMajorCondition = VER_GREATER_EQUAL;
208 spMinorCondition = VER_GREATER_EQUAL;
209 break;
210
211 case VERSION_GREATER_THAN_EQUAL:
212 majorCondition = VER_GREATER_EQUAL;
213 minorCondition = VER_GREATER_EQUAL;
214 spMajorCondition = VER_GREATER_EQUAL;
215 spMinorCondition = VER_GREATER_EQUAL;
216 break;
217
218 case VERSION_GREATER_THAN:
219 majorCondition = VER_GREATER;
220 minorCondition = VER_GREATER;
221 spMajorCondition = VER_GREATER_EQUAL;
222 spMinorCondition = VER_GREATER_EQUAL;
223 break;
224
225 default:
226 return FALSE;
227 }
228
229 memset(&osver, 0, sizeof(osver));
230 osver.dwOSVersionInfoSize = sizeof(osver);
231 osver.dwMajorVersion = majorVersion;
232 osver.dwMinorVersion = minorVersion;
233 if(platform == PLATFORM_WINDOWS)
234 osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
235 else if(platform == PLATFORM_WINNT)
236 osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
237
238 cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
239 cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
240 cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
241 cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
242 if(platform != PLATFORM_DONT_CARE)
243 cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
244
245 /* Later versions of Windows have version functions that may not return the
246 real version of Windows unless the application is so manifested. We prefer
247 the real version always, so we use the Rtl variant of the function when
248 possible. Note though the function signatures have underlying fundamental
249 types that are the same, the return values are different. */
250 if(pRtlVerifyVersionInfo) {
251 matched = !pRtlVerifyVersionInfo(&osver,
252 (VER_MAJORVERSION | VER_MINORVERSION |
253 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
254 cm);
255 }
256 else {
257 matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
258 (VER_MAJORVERSION | VER_MINORVERSION |
259 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
260 cm);
261 }
262 #endif
263
264 return matched;
265 }
266
267 #endif /* WIN32 */
268