xref: /third_party/curl/lib/system_win32.c (revision 13498266)
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 "system_win32.h"
31#include "version_win32.h"
32#include "curl_sspi.h"
33#include "warnless.h"
34
35/* The last #include files should be: */
36#include "curl_memory.h"
37#include "memdebug.h"
38
39LARGE_INTEGER Curl_freq;
40bool Curl_isVistaOrGreater;
41bool Curl_isWindows8OrGreater;
42
43/* Handle of iphlpapp.dll */
44static HMODULE s_hIpHlpApiDll = NULL;
45
46/* Function pointers */
47IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
48FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW = NULL;
49GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel = NULL;
50GETADDRINFOEXW_FN Curl_GetAddrInfoExW = NULL;
51
52/* Curl_win32_init() performs win32 global initialization */
53CURLcode Curl_win32_init(long flags)
54{
55#ifdef USE_WINSOCK
56  HMODULE ws2_32Dll;
57#endif
58  /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
59     is just for Winsock at the moment. Any required win32 initialization
60     should take place after this block. */
61  if(flags & CURL_GLOBAL_WIN32) {
62#ifdef USE_WINSOCK
63    WORD wVersionRequested;
64    WSADATA wsaData;
65    int res;
66
67    wVersionRequested = MAKEWORD(2, 2);
68    res = WSAStartup(wVersionRequested, &wsaData);
69
70    if(res)
71      /* Tell the user that we couldn't find a usable */
72      /* winsock.dll.     */
73      return CURLE_FAILED_INIT;
74
75    /* Confirm that the Windows Sockets DLL supports what we need.*/
76    /* Note that if the DLL supports versions greater */
77    /* than wVersionRequested, it will still return */
78    /* wVersionRequested in wVersion. wHighVersion contains the */
79    /* highest supported version. */
80
81    if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
82       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
83      /* Tell the user that we couldn't find a usable */
84
85      /* winsock.dll. */
86      WSACleanup();
87      return CURLE_FAILED_INIT;
88    }
89    /* The Windows Sockets DLL is acceptable. Proceed. */
90#elif defined(USE_LWIPSOCK)
91    lwip_init();
92#endif
93  } /* CURL_GLOBAL_WIN32 */
94
95#ifdef USE_WINDOWS_SSPI
96  {
97    CURLcode result = Curl_sspi_global_init();
98    if(result)
99      return result;
100  }
101#endif
102
103  s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll"));
104  if(s_hIpHlpApiDll) {
105    /* Get the address of the if_nametoindex function */
106    IF_NAMETOINDEX_FN pIfNameToIndex =
107      CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN,
108                          (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));
109
110    if(pIfNameToIndex)
111      Curl_if_nametoindex = pIfNameToIndex;
112  }
113
114#ifdef USE_WINSOCK
115  ws2_32Dll = GetModuleHandleA("ws2_32");
116  if(ws2_32Dll) {
117    Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN,
118      GetProcAddress(ws2_32Dll, "FreeAddrInfoExW"));
119    Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN,
120      GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel"));
121    Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN,
122      GetProcAddress(ws2_32Dll, "GetAddrInfoExW"));
123  }
124#endif
125
126  /* curlx_verify_windows_version must be called during init at least once
127     because it has its own initialization routine. */
128  if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
129                                  VERSION_GREATER_THAN_EQUAL)) {
130    Curl_isVistaOrGreater = TRUE;
131  }
132  else
133    Curl_isVistaOrGreater = FALSE;
134
135  if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
136                                  VERSION_GREATER_THAN_EQUAL)) {
137    Curl_isWindows8OrGreater = TRUE;
138  }
139  else
140    Curl_isWindows8OrGreater = FALSE;
141
142  QueryPerformanceFrequency(&Curl_freq);
143  return CURLE_OK;
144}
145
146/* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
147void Curl_win32_cleanup(long init_flags)
148{
149  Curl_FreeAddrInfoExW = NULL;
150  Curl_GetAddrInfoExCancel = NULL;
151  Curl_GetAddrInfoExW = NULL;
152  if(s_hIpHlpApiDll) {
153    FreeLibrary(s_hIpHlpApiDll);
154    s_hIpHlpApiDll = NULL;
155    Curl_if_nametoindex = NULL;
156  }
157
158#ifdef USE_WINDOWS_SSPI
159  Curl_sspi_global_cleanup();
160#endif
161
162  if(init_flags & CURL_GLOBAL_WIN32) {
163#ifdef USE_WINSOCK
164    WSACleanup();
165#endif
166  }
167}
168
169#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
170#define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
171#endif
172
173#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
174#define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
175#endif
176
177/* We use our own typedef here since some headers might lack these */
178typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
179
180/* See function definitions in winbase.h */
181#ifdef UNICODE
182#  ifdef _WIN32_WCE
183#    define LOADLIBARYEX  L"LoadLibraryExW"
184#  else
185#    define LOADLIBARYEX  "LoadLibraryExW"
186#  endif
187#else
188#  define LOADLIBARYEX    "LoadLibraryExA"
189#endif
190
191/*
192 * Curl_load_library()
193 *
194 * This is used to dynamically load DLLs using the most secure method available
195 * for the version of Windows that we are running on.
196 *
197 * Parameters:
198 *
199 * filename  [in] - The filename or full path of the DLL to load. If only the
200 *                  filename is passed then the DLL will be loaded from the
201 *                  Windows system directory.
202 *
203 * Returns the handle of the module on success; otherwise NULL.
204 */
205HMODULE Curl_load_library(LPCTSTR filename)
206{
207#ifndef CURL_WINDOWS_APP
208  HMODULE hModule = NULL;
209  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
210
211  /* Get a handle to kernel32 so we can access it's functions at runtime */
212  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
213  if(!hKernel32)
214    return NULL;
215
216  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
217     and above */
218  pLoadLibraryEx =
219    CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
220                        (GetProcAddress(hKernel32, LOADLIBARYEX)));
221
222  /* Detect if there's already a path in the filename and load the library if
223     there is. Note: Both back slashes and forward slashes have been supported
224     since the earlier days of DOS at an API level although they are not
225     supported by command prompt */
226  if(_tcspbrk(filename, TEXT("\\/"))) {
227    /** !checksrc! disable BANNEDFUNC 1 **/
228    hModule = pLoadLibraryEx ?
229      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
230      LoadLibrary(filename);
231  }
232  /* Detect if KB2533623 is installed, as LOAD_LIBRARY_SEARCH_SYSTEM32 is only
233     supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
234     Server 2008 R2 with this patch or natively on Windows 8 and above */
235  else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
236    /* Load the DLL from the Windows system directory */
237    hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
238  }
239  else {
240    /* Attempt to get the Windows system path */
241    UINT systemdirlen = GetSystemDirectory(NULL, 0);
242    if(systemdirlen) {
243      /* Allocate space for the full DLL path (Room for the null terminator
244         is included in systemdirlen) */
245      size_t filenamelen = _tcslen(filename);
246      TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
247      if(path && GetSystemDirectory(path, systemdirlen)) {
248        /* Calculate the full DLL path */
249        _tcscpy(path + _tcslen(path), TEXT("\\"));
250        _tcscpy(path + _tcslen(path), filename);
251
252        /* Load the DLL from the Windows system directory */
253        /** !checksrc! disable BANNEDFUNC 1 **/
254        hModule = pLoadLibraryEx ?
255          pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
256          LoadLibrary(path);
257
258      }
259      free(path);
260    }
261  }
262  return hModule;
263#else
264  /* the Universal Windows Platform (UWP) can't do this */
265  (void)filename;
266  return NULL;
267#endif
268}
269
270#endif /* _WIN32 */
271