1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2016 - 2019, 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 #include "curl_sspi.h"
30 #include "warnless.h"
31 
32 /* The last #include files should be: */
33 #include "curl_memory.h"
34 #include "memdebug.h"
35 
36 LARGE_INTEGER Curl_freq;
37 bool Curl_isVistaOrGreater;
38 
39 /* Handle of iphlpapp.dll */
40 static HMODULE s_hIpHlpApiDll = NULL;
41 
42 /* Pointer to the if_nametoindex function */
43 IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
44 
45 /* Curl_win32_init() performs win32 global initialization */
Curl_win32_init(long flags)46 CURLcode Curl_win32_init(long flags)
47 {
48   /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
49      is just for Winsock at the moment. Any required win32 initialization
50      should take place after this block. */
51   if(flags & CURL_GLOBAL_WIN32) {
52 #ifdef USE_WINSOCK
53     WORD wVersionRequested;
54     WSADATA wsaData;
55     int res;
56 
57 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
58 #error IPV6_requires_winsock2
59 #endif
60 
61     wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
62 
63     res = WSAStartup(wVersionRequested, &wsaData);
64 
65     if(res != 0)
66       /* Tell the user that we couldn't find a usable */
67       /* winsock.dll.     */
68       return CURLE_FAILED_INIT;
69 
70     /* Confirm that the Windows Sockets DLL supports what we need.*/
71     /* Note that if the DLL supports versions greater */
72     /* than wVersionRequested, it will still return */
73     /* wVersionRequested in wVersion. wHighVersion contains the */
74     /* highest supported version. */
75 
76     if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
77        HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
78       /* Tell the user that we couldn't find a usable */
79 
80       /* winsock.dll. */
81       WSACleanup();
82       return CURLE_FAILED_INIT;
83     }
84     /* The Windows Sockets DLL is acceptable. Proceed. */
85   #elif defined(USE_LWIPSOCK)
86     lwip_init();
87   #endif
88   } /* CURL_GLOBAL_WIN32 */
89 
90 #ifdef USE_WINDOWS_SSPI
91   {
92     CURLcode result = Curl_sspi_global_init();
93     if(result)
94       return result;
95   }
96 #endif
97 
98   s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll"));
99   if(s_hIpHlpApiDll) {
100     /* Get the address of the if_nametoindex function */
101     IF_NAMETOINDEX_FN pIfNameToIndex =
102       CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN,
103                           (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));
104 
105     if(pIfNameToIndex)
106       Curl_if_nametoindex = pIfNameToIndex;
107   }
108 
109   if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
110                                  VERSION_GREATER_THAN_EQUAL)) {
111     Curl_isVistaOrGreater = TRUE;
112     QueryPerformanceFrequency(&Curl_freq);
113   }
114   else
115     Curl_isVistaOrGreater = FALSE;
116 
117   return CURLE_OK;
118 }
119 
120 /* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
Curl_win32_cleanup(long init_flags)121 void Curl_win32_cleanup(long init_flags)
122 {
123   if(s_hIpHlpApiDll) {
124     FreeLibrary(s_hIpHlpApiDll);
125     s_hIpHlpApiDll = NULL;
126     Curl_if_nametoindex = NULL;
127   }
128 
129 #ifdef USE_WINDOWS_SSPI
130   Curl_sspi_global_cleanup();
131 #endif
132 
133   if(init_flags & CURL_GLOBAL_WIN32) {
134 #ifdef USE_WINSOCK
135     WSACleanup();
136 #endif
137   }
138 }
139 
140 #if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
141 #define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
142 #endif
143 
144 #if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
145 #define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
146 #endif
147 
148 /* We use our own typedef here since some headers might lack these */
149 typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
150 
151 /* See function definitions in winbase.h */
152 #ifdef UNICODE
153 #  ifdef _WIN32_WCE
154 #    define LOADLIBARYEX  L"LoadLibraryExW"
155 #  else
156 #    define LOADLIBARYEX  "LoadLibraryExW"
157 #  endif
158 #else
159 #  define LOADLIBARYEX    "LoadLibraryExA"
160 #endif
161 
162 /*
163  * Curl_verify_windows_version()
164  *
165  * This is used to verify if we are running on a specific windows version.
166  *
167  * Parameters:
168  *
169  * majorVersion [in] - The major version number.
170  * minorVersion [in] - The minor version number.
171  * platform     [in] - The optional platform identifier.
172  * condition    [in] - The test condition used to specifier whether we are
173  *                     checking a version less then, equal to or greater than
174  *                     what is specified in the major and minor version
175  *                     numbers.
176  *
177  * Returns TRUE if matched; otherwise FALSE.
178  */
Curl_verify_windows_version(const unsigned int majorVersion,const unsigned int minorVersion,const PlatformIdentifier platform,const VersionCondition condition)179 bool Curl_verify_windows_version(const unsigned int majorVersion,
180                                  const unsigned int minorVersion,
181                                  const PlatformIdentifier platform,
182                                  const VersionCondition condition)
183 {
184   bool matched = FALSE;
185 
186 #if defined(CURL_WINDOWS_APP)
187   /* We have no way to determine the Windows version from Windows apps,
188      so let's assume we're running on the target Windows version. */
189   const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
190   const WORD targetVersion = (WORD)_WIN32_WINNT;
191 
192   switch(condition) {
193   case VERSION_LESS_THAN:
194     matched = targetVersion < fullVersion;
195     break;
196 
197   case VERSION_LESS_THAN_EQUAL:
198     matched = targetVersion <= fullVersion;
199     break;
200 
201   case VERSION_EQUAL:
202     matched = targetVersion == fullVersion;
203     break;
204 
205   case VERSION_GREATER_THAN_EQUAL:
206     matched = targetVersion >= fullVersion;
207     break;
208 
209   case VERSION_GREATER_THAN:
210     matched = targetVersion > fullVersion;
211     break;
212   }
213 
214   if(matched && (platform == PLATFORM_WINDOWS)) {
215     /* we're always running on PLATFORM_WINNT */
216     matched = FALSE;
217   }
218 #elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
219     (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
220   OSVERSIONINFO osver;
221 
222   memset(&osver, 0, sizeof(osver));
223   osver.dwOSVersionInfoSize = sizeof(osver);
224 
225   /* Find out Windows version */
226   if(GetVersionEx(&osver)) {
227     /* Verify the Operating System version number */
228     switch(condition) {
229     case VERSION_LESS_THAN:
230       if(osver.dwMajorVersion < majorVersion ||
231         (osver.dwMajorVersion == majorVersion &&
232          osver.dwMinorVersion < minorVersion))
233         matched = TRUE;
234       break;
235 
236     case VERSION_LESS_THAN_EQUAL:
237       if(osver.dwMajorVersion < majorVersion ||
238         (osver.dwMajorVersion == majorVersion &&
239          osver.dwMinorVersion <= minorVersion))
240         matched = TRUE;
241       break;
242 
243     case VERSION_EQUAL:
244       if(osver.dwMajorVersion == majorVersion &&
245          osver.dwMinorVersion == minorVersion)
246         matched = TRUE;
247       break;
248 
249     case VERSION_GREATER_THAN_EQUAL:
250       if(osver.dwMajorVersion > majorVersion ||
251         (osver.dwMajorVersion == majorVersion &&
252          osver.dwMinorVersion >= minorVersion))
253         matched = TRUE;
254       break;
255 
256     case VERSION_GREATER_THAN:
257       if(osver.dwMajorVersion > majorVersion ||
258         (osver.dwMajorVersion == majorVersion &&
259          osver.dwMinorVersion > minorVersion))
260         matched = TRUE;
261       break;
262     }
263 
264     /* Verify the platform identifier (if necessary) */
265     if(matched) {
266       switch(platform) {
267       case PLATFORM_WINDOWS:
268         if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
269           matched = FALSE;
270         break;
271 
272       case PLATFORM_WINNT:
273         if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
274           matched = FALSE;
275 
276       default: /* like platform == PLATFORM_DONT_CARE */
277         break;
278       }
279     }
280   }
281 #else
282   ULONGLONG cm = 0;
283   OSVERSIONINFOEX osver;
284   BYTE majorCondition;
285   BYTE minorCondition;
286   BYTE spMajorCondition;
287   BYTE spMinorCondition;
288 
289   switch(condition) {
290   case VERSION_LESS_THAN:
291     majorCondition = VER_LESS;
292     minorCondition = VER_LESS;
293     spMajorCondition = VER_LESS_EQUAL;
294     spMinorCondition = VER_LESS_EQUAL;
295     break;
296 
297   case VERSION_LESS_THAN_EQUAL:
298     majorCondition = VER_LESS_EQUAL;
299     minorCondition = VER_LESS_EQUAL;
300     spMajorCondition = VER_LESS_EQUAL;
301     spMinorCondition = VER_LESS_EQUAL;
302     break;
303 
304   case VERSION_EQUAL:
305     majorCondition = VER_EQUAL;
306     minorCondition = VER_EQUAL;
307     spMajorCondition = VER_GREATER_EQUAL;
308     spMinorCondition = VER_GREATER_EQUAL;
309     break;
310 
311   case VERSION_GREATER_THAN_EQUAL:
312     majorCondition = VER_GREATER_EQUAL;
313     minorCondition = VER_GREATER_EQUAL;
314     spMajorCondition = VER_GREATER_EQUAL;
315     spMinorCondition = VER_GREATER_EQUAL;
316     break;
317 
318   case VERSION_GREATER_THAN:
319     majorCondition = VER_GREATER;
320     minorCondition = VER_GREATER;
321     spMajorCondition = VER_GREATER_EQUAL;
322     spMinorCondition = VER_GREATER_EQUAL;
323     break;
324 
325   default:
326     return FALSE;
327   }
328 
329   memset(&osver, 0, sizeof(osver));
330   osver.dwOSVersionInfoSize = sizeof(osver);
331   osver.dwMajorVersion = majorVersion;
332   osver.dwMinorVersion = minorVersion;
333   if(platform == PLATFORM_WINDOWS)
334     osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
335   else if(platform == PLATFORM_WINNT)
336     osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
337 
338   cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
339   cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
340   cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
341   cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
342   if(platform != PLATFORM_DONT_CARE)
343     cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
344 
345   if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
346                                 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
347                        cm))
348     matched = TRUE;
349 #endif
350 
351   return matched;
352 }
353 
354 /*
355  * Curl_load_library()
356  *
357  * This is used to dynamically load DLLs using the most secure method available
358  * for the version of Windows that we are running on.
359  *
360  * Parameters:
361  *
362  * filename  [in] - The filename or full path of the DLL to load. If only the
363  *                  filename is passed then the DLL will be loaded from the
364  *                  Windows system directory.
365  *
366  * Returns the handle of the module on success; otherwise NULL.
367  */
Curl_load_library(LPCTSTR filename)368 HMODULE Curl_load_library(LPCTSTR filename)
369 {
370 #ifndef CURL_WINDOWS_APP
371   HMODULE hModule = NULL;
372   LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
373 
374   /* Get a handle to kernel32 so we can access it's functions at runtime */
375   HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
376   if(!hKernel32)
377     return NULL;
378 
379   /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
380      and above */
381   pLoadLibraryEx =
382     CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
383                         (GetProcAddress(hKernel32, LOADLIBARYEX)));
384 
385   /* Detect if there's already a path in the filename and load the library if
386      there is. Note: Both back slashes and forward slashes have been supported
387      since the earlier days of DOS at an API level although they are not
388      supported by command prompt */
389   if(_tcspbrk(filename, TEXT("\\/"))) {
390     /** !checksrc! disable BANNEDFUNC 1 **/
391     hModule = pLoadLibraryEx ?
392       pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
393       LoadLibrary(filename);
394   }
395   /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
396      supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
397      Server 2008 R2 with this patch or natively on Windows 8 and above */
398   else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
399     /* Load the DLL from the Windows system directory */
400     hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
401   }
402   else {
403     /* Attempt to get the Windows system path */
404     UINT systemdirlen = GetSystemDirectory(NULL, 0);
405     if(systemdirlen) {
406       /* Allocate space for the full DLL path (Room for the null terminator
407          is included in systemdirlen) */
408       size_t filenamelen = _tcslen(filename);
409       TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
410       if(path && GetSystemDirectory(path, systemdirlen)) {
411         /* Calculate the full DLL path */
412         _tcscpy(path + _tcslen(path), TEXT("\\"));
413         _tcscpy(path + _tcslen(path), filename);
414 
415         /* Load the DLL from the Windows system directory */
416         /** !checksrc! disable BANNEDFUNC 1 **/
417         hModule = pLoadLibraryEx ?
418           pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
419           LoadLibrary(path);
420 
421       }
422       free(path);
423     }
424   }
425   return hModule;
426 #else
427   /* the Universal Windows Platform (UWP) can't do this */
428   (void)filename;
429   return NULL;
430 #endif
431 }
432 
433 #endif /* WIN32 */
434