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