• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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