xref: /third_party/curl/lib/version_win32.c (revision 13498266)
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) */
39struct 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 */
72bool 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