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