1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2016, 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.haxx.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 "system_win32.h"
29
30/* The last #include files should be: */
31#include "curl_memory.h"
32#include "memdebug.h"
33
34#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
35                                  defined(USE_WINSOCK))
36
37
38#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
39#define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
40#endif
41
42#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
43#define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
44#endif
45
46/* We use our own typedef here since some headers might lack these */
47typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
48
49/* See function definitions in winbase.h */
50#ifdef UNICODE
51#  ifdef _WIN32_WCE
52#    define LOADLIBARYEX  L"LoadLibraryExW"
53#  else
54#    define LOADLIBARYEX  "LoadLibraryExW"
55#  endif
56#else
57#  define LOADLIBARYEX    "LoadLibraryExA"
58#endif
59
60#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
61
62/*
63 * Curl_verify_windows_version()
64 *
65 * This is used to verify if we are running on a specific windows version.
66 *
67 * Parameters:
68 *
69 * majorVersion [in] - The major version number.
70 * minorVersion [in] - The minor version number.
71 * platform     [in] - The optional platform identifer.
72 * condition    [in] - The test condition used to specifier whether we are
73 *                     checking a version less then, equal to or greater than
74 *                     what is specified in the major and minor version
75 *                     numbers.
76 *
77 * Returns TRUE if matched; otherwise FALSE.
78 */
79bool Curl_verify_windows_version(const unsigned int majorVersion,
80                                 const unsigned int minorVersion,
81                                 const PlatformIdentifier platform,
82                                 const VersionCondition condition)
83{
84  bool matched = FALSE;
85
86#if defined(CURL_WINDOWS_APP)
87  /* We have no way to determine the Windows version from Windows apps,
88     so let's assume we're running on the target Windows version. */
89  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
90  const WORD targetVersion = (WORD)_WIN32_WINNT;
91
92  switch(condition) {
93  case VERSION_LESS_THAN:
94    matched = targetVersion < fullVersion;
95    break;
96
97  case VERSION_LESS_THAN_EQUAL:
98    matched = targetVersion <= fullVersion;
99    break;
100
101  case VERSION_EQUAL:
102    matched = targetVersion == fullVersion;
103    break;
104
105  case VERSION_GREATER_THAN_EQUAL:
106    matched = targetVersion >= fullVersion;
107    break;
108
109  case VERSION_GREATER_THAN:
110    matched = targetVersion > fullVersion;
111    break;
112  }
113
114  if(matched && (platform == PLATFORM_WINDOWS)) {
115    /* we're always running on PLATFORM_WINNT */
116    matched = FALSE;
117  }
118#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
119    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
120  OSVERSIONINFO osver;
121
122  memset(&osver, 0, sizeof(osver));
123  osver.dwOSVersionInfoSize = sizeof(osver);
124
125  /* Find out Windows version */
126  if(GetVersionEx(&osver)) {
127    /* Verify the Operating System version number */
128    switch(condition) {
129    case VERSION_LESS_THAN:
130      if(osver.dwMajorVersion < majorVersion ||
131        (osver.dwMajorVersion == majorVersion &&
132         osver.dwMinorVersion < minorVersion))
133        matched = TRUE;
134      break;
135
136    case VERSION_LESS_THAN_EQUAL:
137      if(osver.dwMajorVersion <= majorVersion &&
138         osver.dwMinorVersion <= minorVersion)
139        matched = TRUE;
140      break;
141
142    case VERSION_EQUAL:
143      if(osver.dwMajorVersion == majorVersion &&
144         osver.dwMinorVersion == minorVersion)
145        matched = TRUE;
146      break;
147
148    case VERSION_GREATER_THAN_EQUAL:
149      if(osver.dwMajorVersion >= majorVersion &&
150         osver.dwMinorVersion >= minorVersion)
151        matched = TRUE;
152      break;
153
154    case VERSION_GREATER_THAN:
155      if(osver.dwMajorVersion > majorVersion ||
156        (osver.dwMajorVersion == majorVersion &&
157         osver.dwMinorVersion > minorVersion))
158        matched = TRUE;
159      break;
160    }
161
162    /* Verify the platform identifier (if necessary) */
163    if(matched) {
164      switch(platform) {
165      case PLATFORM_WINDOWS:
166        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
167          matched = FALSE;
168        break;
169
170      case PLATFORM_WINNT:
171        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
172          matched = FALSE;
173
174      default: /* like platform == PLATFORM_DONT_CARE */
175        break;
176      }
177    }
178  }
179#else
180  ULONGLONG cm = 0;
181  OSVERSIONINFOEX osver;
182  BYTE majorCondition;
183  BYTE minorCondition;
184  BYTE spMajorCondition;
185  BYTE spMinorCondition;
186
187  switch(condition) {
188  case VERSION_LESS_THAN:
189    majorCondition = VER_LESS;
190    minorCondition = VER_LESS;
191    spMajorCondition = VER_LESS_EQUAL;
192    spMinorCondition = VER_LESS_EQUAL;
193    break;
194
195  case VERSION_LESS_THAN_EQUAL:
196    majorCondition = VER_LESS_EQUAL;
197    minorCondition = VER_LESS_EQUAL;
198    spMajorCondition = VER_LESS_EQUAL;
199    spMinorCondition = VER_LESS_EQUAL;
200    break;
201
202  case VERSION_EQUAL:
203    majorCondition = VER_EQUAL;
204    minorCondition = VER_EQUAL;
205    spMajorCondition = VER_GREATER_EQUAL;
206    spMinorCondition = VER_GREATER_EQUAL;
207    break;
208
209  case VERSION_GREATER_THAN_EQUAL:
210    majorCondition = VER_GREATER_EQUAL;
211    minorCondition = VER_GREATER_EQUAL;
212    spMajorCondition = VER_GREATER_EQUAL;
213    spMinorCondition = VER_GREATER_EQUAL;
214    break;
215
216  case VERSION_GREATER_THAN:
217    majorCondition = VER_GREATER;
218    minorCondition = VER_GREATER;
219    spMajorCondition = VER_GREATER_EQUAL;
220    spMinorCondition = VER_GREATER_EQUAL;
221    break;
222
223  default:
224    return FALSE;
225  }
226
227  memset(&osver, 0, sizeof(osver));
228  osver.dwOSVersionInfoSize = sizeof(osver);
229  osver.dwMajorVersion = majorVersion;
230  osver.dwMinorVersion = minorVersion;
231  if(platform == PLATFORM_WINDOWS)
232    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
233  else if(platform == PLATFORM_WINNT)
234    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
235
236  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
237  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
238  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
239  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
240  if(platform != PLATFORM_DONT_CARE)
241    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
242
243  if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
244                                VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
245                       cm))
246    matched = TRUE;
247#endif
248
249  return matched;
250}
251
252#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
253                                  defined(USE_WINSOCK))
254
255/*
256 * Curl_load_library()
257 *
258 * This is used to dynamically load DLLs using the most secure method available
259 * for the version of Windows that we are running on.
260 *
261 * Parameters:
262 *
263 * filename  [in] - The filename or full path of the DLL to load. If only the
264 *                  filename is passed then the DLL will be loaded from the
265 *                  Windows system directory.
266 *
267 * Returns the handle of the module on success; otherwise NULL.
268 */
269HMODULE Curl_load_library(LPCTSTR filename)
270{
271  HMODULE hModule = NULL;
272  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
273
274  /* Get a handle to kernel32 so we can access it's functions at runtime */
275  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
276  if(!hKernel32)
277    return NULL;
278
279  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
280     and above */
281  pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX);
282
283  /* Detect if there's already a path in the filename and load the library if
284     there is. Note: Both back slashes and forward slashes have been supported
285     since the earlier days of DOS at an API level although they are not
286     supported by command prompt */
287  if(_tcspbrk(filename, TEXT("\\/"))) {
288    /** !checksrc! disable BANNEDFUNC 1 **/
289    hModule = pLoadLibraryEx ?
290      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
291      LoadLibrary(filename);
292  }
293  /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
294     supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
295     Server 2008 R2 with this patch or natively on Windows 8 and above */
296  else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
297    /* Load the DLL from the Windows system directory */
298    hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
299  }
300  else {
301    /* Attempt to get the Windows system path */
302    UINT systemdirlen = GetSystemDirectory(NULL, 0);
303    if(systemdirlen) {
304      /* Allocate space for the full DLL path (Room for the null terminator
305         is included in systemdirlen) */
306      size_t filenamelen = _tcslen(filename);
307      TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
308      if(path && GetSystemDirectory(path, systemdirlen)) {
309        /* Calculate the full DLL path */
310        _tcscpy(path + _tcslen(path), TEXT("\\"));
311        _tcscpy(path + _tcslen(path), filename);
312
313        /* Load the DLL from the Windows system directory */
314        /** !checksrc! disable BANNEDFUNC 1 **/
315        hModule = pLoadLibraryEx ?
316          pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
317          LoadLibrary(path);
318
319      }
320      free(path);
321    }
322  }
323
324  return hModule;
325}
326
327#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
328
329#endif /* WIN32 */
330