113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#if defined(_WIN32)
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include <curl/curl.h>
3013498266Sopenharmony_ci#include "version_win32.h"
3113498266Sopenharmony_ci#include "warnless.h"
3213498266Sopenharmony_ci
3313498266Sopenharmony_ci/* The last #include files should be: */
3413498266Sopenharmony_ci#include "curl_memory.h"
3513498266Sopenharmony_ci#include "memdebug.h"
3613498266Sopenharmony_ci
3713498266Sopenharmony_ci/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
3813498266Sopenharmony_ci   and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
3913498266Sopenharmony_cistruct OUR_OSVERSIONINFOEXW {
4013498266Sopenharmony_ci  ULONG  dwOSVersionInfoSize;
4113498266Sopenharmony_ci  ULONG  dwMajorVersion;
4213498266Sopenharmony_ci  ULONG  dwMinorVersion;
4313498266Sopenharmony_ci  ULONG  dwBuildNumber;
4413498266Sopenharmony_ci  ULONG  dwPlatformId;
4513498266Sopenharmony_ci  WCHAR  szCSDVersion[128];
4613498266Sopenharmony_ci  USHORT wServicePackMajor;
4713498266Sopenharmony_ci  USHORT wServicePackMinor;
4813498266Sopenharmony_ci  USHORT wSuiteMask;
4913498266Sopenharmony_ci  UCHAR  wProductType;
5013498266Sopenharmony_ci  UCHAR  wReserved;
5113498266Sopenharmony_ci};
5213498266Sopenharmony_ci
5313498266Sopenharmony_ci/*
5413498266Sopenharmony_ci * curlx_verify_windows_version()
5513498266Sopenharmony_ci *
5613498266Sopenharmony_ci * This is used to verify if we are running on a specific windows version.
5713498266Sopenharmony_ci *
5813498266Sopenharmony_ci * Parameters:
5913498266Sopenharmony_ci *
6013498266Sopenharmony_ci * majorVersion [in] - The major version number.
6113498266Sopenharmony_ci * minorVersion [in] - The minor version number.
6213498266Sopenharmony_ci * buildVersion [in] - The build version number. If 0, this parameter is
6313498266Sopenharmony_ci *                     ignored.
6413498266Sopenharmony_ci * platform     [in] - The optional platform identifier.
6513498266Sopenharmony_ci * condition    [in] - The test condition used to specifier whether we are
6613498266Sopenharmony_ci *                     checking a version less then, equal to or greater than
6713498266Sopenharmony_ci *                     what is specified in the major and minor version
6813498266Sopenharmony_ci *                     numbers.
6913498266Sopenharmony_ci *
7013498266Sopenharmony_ci * Returns TRUE if matched; otherwise FALSE.
7113498266Sopenharmony_ci */
7213498266Sopenharmony_cibool curlx_verify_windows_version(const unsigned int majorVersion,
7313498266Sopenharmony_ci                                  const unsigned int minorVersion,
7413498266Sopenharmony_ci                                  const unsigned int buildVersion,
7513498266Sopenharmony_ci                                  const PlatformIdentifier platform,
7613498266Sopenharmony_ci                                  const VersionCondition condition)
7713498266Sopenharmony_ci{
7813498266Sopenharmony_ci  bool matched = FALSE;
7913498266Sopenharmony_ci
8013498266Sopenharmony_ci#if defined(CURL_WINDOWS_APP)
8113498266Sopenharmony_ci  (void)buildVersion;
8213498266Sopenharmony_ci
8313498266Sopenharmony_ci  /* We have no way to determine the Windows version from Windows apps,
8413498266Sopenharmony_ci     so let's assume we're running on the target Windows version. */
8513498266Sopenharmony_ci  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
8613498266Sopenharmony_ci  const WORD targetVersion = (WORD)_WIN32_WINNT;
8713498266Sopenharmony_ci
8813498266Sopenharmony_ci  switch(condition) {
8913498266Sopenharmony_ci  case VERSION_LESS_THAN:
9013498266Sopenharmony_ci    matched = targetVersion < fullVersion;
9113498266Sopenharmony_ci    break;
9213498266Sopenharmony_ci
9313498266Sopenharmony_ci  case VERSION_LESS_THAN_EQUAL:
9413498266Sopenharmony_ci    matched = targetVersion <= fullVersion;
9513498266Sopenharmony_ci    break;
9613498266Sopenharmony_ci
9713498266Sopenharmony_ci  case VERSION_EQUAL:
9813498266Sopenharmony_ci    matched = targetVersion == fullVersion;
9913498266Sopenharmony_ci    break;
10013498266Sopenharmony_ci
10113498266Sopenharmony_ci  case VERSION_GREATER_THAN_EQUAL:
10213498266Sopenharmony_ci    matched = targetVersion >= fullVersion;
10313498266Sopenharmony_ci    break;
10413498266Sopenharmony_ci
10513498266Sopenharmony_ci  case VERSION_GREATER_THAN:
10613498266Sopenharmony_ci    matched = targetVersion > fullVersion;
10713498266Sopenharmony_ci    break;
10813498266Sopenharmony_ci  }
10913498266Sopenharmony_ci
11013498266Sopenharmony_ci  if(matched && (platform == PLATFORM_WINDOWS)) {
11113498266Sopenharmony_ci    /* we're always running on PLATFORM_WINNT */
11213498266Sopenharmony_ci    matched = FALSE;
11313498266Sopenharmony_ci  }
11413498266Sopenharmony_ci#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
11513498266Sopenharmony_ci    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
11613498266Sopenharmony_ci  OSVERSIONINFO osver;
11713498266Sopenharmony_ci
11813498266Sopenharmony_ci  memset(&osver, 0, sizeof(osver));
11913498266Sopenharmony_ci  osver.dwOSVersionInfoSize = sizeof(osver);
12013498266Sopenharmony_ci
12113498266Sopenharmony_ci  /* Find out Windows version */
12213498266Sopenharmony_ci  if(GetVersionEx(&osver)) {
12313498266Sopenharmony_ci    /* Verify the Operating System version number */
12413498266Sopenharmony_ci    switch(condition) {
12513498266Sopenharmony_ci    case VERSION_LESS_THAN:
12613498266Sopenharmony_ci      if(osver.dwMajorVersion < majorVersion ||
12713498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
12813498266Sopenharmony_ci         osver.dwMinorVersion < minorVersion) ||
12913498266Sopenharmony_ci        (buildVersion != 0 &&
13013498266Sopenharmony_ci         (osver.dwMajorVersion == majorVersion &&
13113498266Sopenharmony_ci          osver.dwMinorVersion == minorVersion &&
13213498266Sopenharmony_ci          osver.dwBuildNumber < buildVersion)))
13313498266Sopenharmony_ci        matched = TRUE;
13413498266Sopenharmony_ci      break;
13513498266Sopenharmony_ci
13613498266Sopenharmony_ci    case VERSION_LESS_THAN_EQUAL:
13713498266Sopenharmony_ci      if(osver.dwMajorVersion < majorVersion ||
13813498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
13913498266Sopenharmony_ci         osver.dwMinorVersion < minorVersion) ||
14013498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
14113498266Sopenharmony_ci         osver.dwMinorVersion == minorVersion &&
14213498266Sopenharmony_ci         (buildVersion == 0 ||
14313498266Sopenharmony_ci          osver.dwBuildNumber <= buildVersion)))
14413498266Sopenharmony_ci        matched = TRUE;
14513498266Sopenharmony_ci      break;
14613498266Sopenharmony_ci
14713498266Sopenharmony_ci    case VERSION_EQUAL:
14813498266Sopenharmony_ci      if(osver.dwMajorVersion == majorVersion &&
14913498266Sopenharmony_ci         osver.dwMinorVersion == minorVersion &&
15013498266Sopenharmony_ci        (buildVersion == 0 ||
15113498266Sopenharmony_ci         osver.dwBuildNumber == buildVersion))
15213498266Sopenharmony_ci        matched = TRUE;
15313498266Sopenharmony_ci      break;
15413498266Sopenharmony_ci
15513498266Sopenharmony_ci    case VERSION_GREATER_THAN_EQUAL:
15613498266Sopenharmony_ci      if(osver.dwMajorVersion > majorVersion ||
15713498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
15813498266Sopenharmony_ci         osver.dwMinorVersion > minorVersion) ||
15913498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
16013498266Sopenharmony_ci         osver.dwMinorVersion == minorVersion &&
16113498266Sopenharmony_ci         (buildVersion == 0 ||
16213498266Sopenharmony_ci          osver.dwBuildNumber >= buildVersion)))
16313498266Sopenharmony_ci        matched = TRUE;
16413498266Sopenharmony_ci      break;
16513498266Sopenharmony_ci
16613498266Sopenharmony_ci    case VERSION_GREATER_THAN:
16713498266Sopenharmony_ci      if(osver.dwMajorVersion > majorVersion ||
16813498266Sopenharmony_ci        (osver.dwMajorVersion == majorVersion &&
16913498266Sopenharmony_ci         osver.dwMinorVersion > minorVersion) ||
17013498266Sopenharmony_ci        (buildVersion != 0 &&
17113498266Sopenharmony_ci         (osver.dwMajorVersion == majorVersion &&
17213498266Sopenharmony_ci          osver.dwMinorVersion == minorVersion &&
17313498266Sopenharmony_ci          osver.dwBuildNumber > buildVersion)))
17413498266Sopenharmony_ci        matched = TRUE;
17513498266Sopenharmony_ci      break;
17613498266Sopenharmony_ci    }
17713498266Sopenharmony_ci
17813498266Sopenharmony_ci    /* Verify the platform identifier (if necessary) */
17913498266Sopenharmony_ci    if(matched) {
18013498266Sopenharmony_ci      switch(platform) {
18113498266Sopenharmony_ci      case PLATFORM_WINDOWS:
18213498266Sopenharmony_ci        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
18313498266Sopenharmony_ci          matched = FALSE;
18413498266Sopenharmony_ci        break;
18513498266Sopenharmony_ci
18613498266Sopenharmony_ci      case PLATFORM_WINNT:
18713498266Sopenharmony_ci        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
18813498266Sopenharmony_ci          matched = FALSE;
18913498266Sopenharmony_ci        break;
19013498266Sopenharmony_ci
19113498266Sopenharmony_ci      default: /* like platform == PLATFORM_DONT_CARE */
19213498266Sopenharmony_ci        break;
19313498266Sopenharmony_ci      }
19413498266Sopenharmony_ci    }
19513498266Sopenharmony_ci  }
19613498266Sopenharmony_ci#else
19713498266Sopenharmony_ci  ULONGLONG cm = 0;
19813498266Sopenharmony_ci  struct OUR_OSVERSIONINFOEXW osver;
19913498266Sopenharmony_ci  BYTE majorCondition;
20013498266Sopenharmony_ci  BYTE minorCondition;
20113498266Sopenharmony_ci  BYTE buildCondition;
20213498266Sopenharmony_ci  BYTE spMajorCondition;
20313498266Sopenharmony_ci  BYTE spMinorCondition;
20413498266Sopenharmony_ci  DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
20513498266Sopenharmony_ci                     VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
20613498266Sopenharmony_ci
20713498266Sopenharmony_ci  typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
20813498266Sopenharmony_ci    (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
20913498266Sopenharmony_ci  static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
21013498266Sopenharmony_ci  static bool onetime = true; /* safe because first call is during init */
21113498266Sopenharmony_ci
21213498266Sopenharmony_ci  if(onetime) {
21313498266Sopenharmony_ci    pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
21413498266Sopenharmony_ci      (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
21513498266Sopenharmony_ci    onetime = false;
21613498266Sopenharmony_ci  }
21713498266Sopenharmony_ci
21813498266Sopenharmony_ci  switch(condition) {
21913498266Sopenharmony_ci  case VERSION_LESS_THAN:
22013498266Sopenharmony_ci    majorCondition = VER_LESS;
22113498266Sopenharmony_ci    minorCondition = VER_LESS;
22213498266Sopenharmony_ci    buildCondition = VER_LESS;
22313498266Sopenharmony_ci    spMajorCondition = VER_LESS_EQUAL;
22413498266Sopenharmony_ci    spMinorCondition = VER_LESS_EQUAL;
22513498266Sopenharmony_ci    break;
22613498266Sopenharmony_ci
22713498266Sopenharmony_ci  case VERSION_LESS_THAN_EQUAL:
22813498266Sopenharmony_ci    majorCondition = VER_LESS_EQUAL;
22913498266Sopenharmony_ci    minorCondition = VER_LESS_EQUAL;
23013498266Sopenharmony_ci    buildCondition = VER_LESS_EQUAL;
23113498266Sopenharmony_ci    spMajorCondition = VER_LESS_EQUAL;
23213498266Sopenharmony_ci    spMinorCondition = VER_LESS_EQUAL;
23313498266Sopenharmony_ci    break;
23413498266Sopenharmony_ci
23513498266Sopenharmony_ci  case VERSION_EQUAL:
23613498266Sopenharmony_ci    majorCondition = VER_EQUAL;
23713498266Sopenharmony_ci    minorCondition = VER_EQUAL;
23813498266Sopenharmony_ci    buildCondition = VER_EQUAL;
23913498266Sopenharmony_ci    spMajorCondition = VER_GREATER_EQUAL;
24013498266Sopenharmony_ci    spMinorCondition = VER_GREATER_EQUAL;
24113498266Sopenharmony_ci    break;
24213498266Sopenharmony_ci
24313498266Sopenharmony_ci  case VERSION_GREATER_THAN_EQUAL:
24413498266Sopenharmony_ci    majorCondition = VER_GREATER_EQUAL;
24513498266Sopenharmony_ci    minorCondition = VER_GREATER_EQUAL;
24613498266Sopenharmony_ci    buildCondition = VER_GREATER_EQUAL;
24713498266Sopenharmony_ci    spMajorCondition = VER_GREATER_EQUAL;
24813498266Sopenharmony_ci    spMinorCondition = VER_GREATER_EQUAL;
24913498266Sopenharmony_ci    break;
25013498266Sopenharmony_ci
25113498266Sopenharmony_ci  case VERSION_GREATER_THAN:
25213498266Sopenharmony_ci    majorCondition = VER_GREATER;
25313498266Sopenharmony_ci    minorCondition = VER_GREATER;
25413498266Sopenharmony_ci    buildCondition = VER_GREATER;
25513498266Sopenharmony_ci    spMajorCondition = VER_GREATER_EQUAL;
25613498266Sopenharmony_ci    spMinorCondition = VER_GREATER_EQUAL;
25713498266Sopenharmony_ci    break;
25813498266Sopenharmony_ci
25913498266Sopenharmony_ci  default:
26013498266Sopenharmony_ci    return FALSE;
26113498266Sopenharmony_ci  }
26213498266Sopenharmony_ci
26313498266Sopenharmony_ci  memset(&osver, 0, sizeof(osver));
26413498266Sopenharmony_ci  osver.dwOSVersionInfoSize = sizeof(osver);
26513498266Sopenharmony_ci  osver.dwMajorVersion = majorVersion;
26613498266Sopenharmony_ci  osver.dwMinorVersion = minorVersion;
26713498266Sopenharmony_ci  osver.dwBuildNumber = buildVersion;
26813498266Sopenharmony_ci  if(platform == PLATFORM_WINDOWS)
26913498266Sopenharmony_ci    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
27013498266Sopenharmony_ci  else if(platform == PLATFORM_WINNT)
27113498266Sopenharmony_ci    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
27213498266Sopenharmony_ci
27313498266Sopenharmony_ci  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
27413498266Sopenharmony_ci  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
27513498266Sopenharmony_ci  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
27613498266Sopenharmony_ci  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
27713498266Sopenharmony_ci
27813498266Sopenharmony_ci  if(platform != PLATFORM_DONT_CARE) {
27913498266Sopenharmony_ci    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
28013498266Sopenharmony_ci    dwTypeMask |= VER_PLATFORMID;
28113498266Sopenharmony_ci  }
28213498266Sopenharmony_ci
28313498266Sopenharmony_ci  /* Later versions of Windows have version functions that may not return the
28413498266Sopenharmony_ci     real version of Windows unless the application is so manifested. We prefer
28513498266Sopenharmony_ci     the real version always, so we use the Rtl variant of the function when
28613498266Sopenharmony_ci     possible. Note though the function signatures have underlying fundamental
28713498266Sopenharmony_ci     types that are the same, the return values are different. */
28813498266Sopenharmony_ci  if(pRtlVerifyVersionInfo)
28913498266Sopenharmony_ci    matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
29013498266Sopenharmony_ci  else
29113498266Sopenharmony_ci    matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
29213498266Sopenharmony_ci
29313498266Sopenharmony_ci  /* Compare the build number separately. VerifyVersionInfo normally compares
29413498266Sopenharmony_ci     major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
29513498266Sopenharmony_ci     do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
29613498266Sopenharmony_ci     Build comparison is only needed when build numbers are equal (eg 1.9 is
29713498266Sopenharmony_ci     always less than 2.0 so build comparison is not needed). */
29813498266Sopenharmony_ci  if(matched && buildVersion &&
29913498266Sopenharmony_ci     (condition == VERSION_EQUAL ||
30013498266Sopenharmony_ci      ((condition == VERSION_GREATER_THAN_EQUAL ||
30113498266Sopenharmony_ci        condition == VERSION_LESS_THAN_EQUAL) &&
30213498266Sopenharmony_ci        curlx_verify_windows_version(majorVersion, minorVersion, 0,
30313498266Sopenharmony_ci                                     platform, VERSION_EQUAL)))) {
30413498266Sopenharmony_ci
30513498266Sopenharmony_ci    cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
30613498266Sopenharmony_ci    dwTypeMask = VER_BUILDNUMBER;
30713498266Sopenharmony_ci    if(pRtlVerifyVersionInfo)
30813498266Sopenharmony_ci      matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
30913498266Sopenharmony_ci    else
31013498266Sopenharmony_ci      matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
31113498266Sopenharmony_ci                                      dwTypeMask, cm);
31213498266Sopenharmony_ci  }
31313498266Sopenharmony_ci
31413498266Sopenharmony_ci#endif
31513498266Sopenharmony_ci
31613498266Sopenharmony_ci  return matched;
31713498266Sopenharmony_ci}
31813498266Sopenharmony_ci
31913498266Sopenharmony_ci#endif /* _WIN32 */
320