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