| 1 | /*************************************************************************** | 
|---|
| 2 | *                                  _   _ ____  _ | 
|---|
| 3 | *  Project                     ___| | | |  _ \| | | 
|---|
| 4 | *                             / __| | | | |_) | | | 
|---|
| 5 | *                            | (__| |_| |  _ <| |___ | 
|---|
| 6 | *                             \___|\___/|_| \_\_____| | 
|---|
| 7 | * | 
|---|
| 8 | * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. | 
|---|
| 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 | #ifdef USE_WINDOWS_SSPI | 
|---|
| 26 |  | 
|---|
| 27 | #include <curl/curl.h> | 
|---|
| 28 | #include "curl_sspi.h" | 
|---|
| 29 | #include "curl_multibyte.h" | 
|---|
| 30 | #include "system_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 | /* We use our own typedef here since some headers might lack these */ | 
|---|
| 38 | typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); | 
|---|
| 39 |  | 
|---|
| 40 | /* See definition of SECURITY_ENTRYPOINT in sspi.h */ | 
|---|
| 41 | #ifdef UNICODE | 
|---|
| 42 | #  ifdef _WIN32_WCE | 
|---|
| 43 | #    define SECURITYENTRYPOINT L"InitSecurityInterfaceW" | 
|---|
| 44 | #  else | 
|---|
| 45 | #    define SECURITYENTRYPOINT "InitSecurityInterfaceW" | 
|---|
| 46 | #  endif | 
|---|
| 47 | #else | 
|---|
| 48 | #  define SECURITYENTRYPOINT "InitSecurityInterfaceA" | 
|---|
| 49 | #endif | 
|---|
| 50 |  | 
|---|
| 51 | /* Handle of security.dll or secur32.dll, depending on Windows version */ | 
|---|
| 52 | HMODULE s_hSecDll = NULL; | 
|---|
| 53 |  | 
|---|
| 54 | /* Pointer to SSPI dispatch table */ | 
|---|
| 55 | PSecurityFunctionTable s_pSecFn = NULL; | 
|---|
| 56 |  | 
|---|
| 57 | /* | 
|---|
| 58 | * Curl_sspi_global_init() | 
|---|
| 59 | * | 
|---|
| 60 | * This is used to load the Security Service Provider Interface (SSPI) | 
|---|
| 61 | * dynamic link library portably across all Windows versions, without | 
|---|
| 62 | * the need to directly link libcurl, nor the application using it, at | 
|---|
| 63 | * build time. | 
|---|
| 64 | * | 
|---|
| 65 | * Once this function has been executed, Windows SSPI functions can be | 
|---|
| 66 | * called through the Security Service Provider Interface dispatch table. | 
|---|
| 67 | * | 
|---|
| 68 | * Parameters: | 
|---|
| 69 | * | 
|---|
| 70 | * None. | 
|---|
| 71 | * | 
|---|
| 72 | * Returns CURLE_OK on success. | 
|---|
| 73 | */ | 
|---|
| 74 | CURLcode Curl_sspi_global_init(void) | 
|---|
| 75 | { | 
|---|
| 76 | INITSECURITYINTERFACE_FN pInitSecurityInterface; | 
|---|
| 77 |  | 
|---|
| 78 | /* If security interface is not yet initialized try to do this */ | 
|---|
| 79 | if(!s_hSecDll) { | 
|---|
| 80 | /* Security Service Provider Interface (SSPI) functions are located in | 
|---|
| 81 | * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP | 
|---|
| 82 | * have both these DLLs (security.dll forwards calls to secur32.dll) */ | 
|---|
| 83 |  | 
|---|
| 84 | /* Load SSPI dll into the address space of the calling process */ | 
|---|
| 85 | if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) | 
|---|
| 86 | s_hSecDll = Curl_load_library(TEXT( "security.dll")); | 
|---|
| 87 | else | 
|---|
| 88 | s_hSecDll = Curl_load_library(TEXT( "secur32.dll")); | 
|---|
| 89 | if(!s_hSecDll) | 
|---|
| 90 | return CURLE_FAILED_INIT; | 
|---|
| 91 |  | 
|---|
| 92 | /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ | 
|---|
| 93 | pInitSecurityInterface = | 
|---|
| 94 | CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN, | 
|---|
| 95 | (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT))); | 
|---|
| 96 | if(!pInitSecurityInterface) | 
|---|
| 97 | return CURLE_FAILED_INIT; | 
|---|
| 98 |  | 
|---|
| 99 | /* Get pointer to Security Service Provider Interface dispatch table */ | 
|---|
| 100 | s_pSecFn = pInitSecurityInterface(); | 
|---|
| 101 | if(!s_pSecFn) | 
|---|
| 102 | return CURLE_FAILED_INIT; | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | return CURLE_OK; | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | /* | 
|---|
| 109 | * Curl_sspi_global_cleanup() | 
|---|
| 110 | * | 
|---|
| 111 | * This deinitializes the Security Service Provider Interface from libcurl. | 
|---|
| 112 | * | 
|---|
| 113 | * Parameters: | 
|---|
| 114 | * | 
|---|
| 115 | * None. | 
|---|
| 116 | */ | 
|---|
| 117 | void Curl_sspi_global_cleanup(void) | 
|---|
| 118 | { | 
|---|
| 119 | if(s_hSecDll) { | 
|---|
| 120 | FreeLibrary(s_hSecDll); | 
|---|
| 121 | s_hSecDll = NULL; | 
|---|
| 122 | s_pSecFn = NULL; | 
|---|
| 123 | } | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | /* | 
|---|
| 127 | * Curl_create_sspi_identity() | 
|---|
| 128 | * | 
|---|
| 129 | * This is used to populate a SSPI identity structure based on the supplied | 
|---|
| 130 | * username and password. | 
|---|
| 131 | * | 
|---|
| 132 | * Parameters: | 
|---|
| 133 | * | 
|---|
| 134 | * userp    [in]     - The user name in the format User or Domain\User. | 
|---|
| 135 | * passwdp  [in]     - The user's password. | 
|---|
| 136 | * identity [in/out] - The identity structure. | 
|---|
| 137 | * | 
|---|
| 138 | * Returns CURLE_OK on success. | 
|---|
| 139 | */ | 
|---|
| 140 | CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, | 
|---|
| 141 | SEC_WINNT_AUTH_IDENTITY *identity) | 
|---|
| 142 | { | 
|---|
| 143 | xcharp_u useranddomain; | 
|---|
| 144 | xcharp_u user, dup_user; | 
|---|
| 145 | xcharp_u domain, dup_domain; | 
|---|
| 146 | xcharp_u passwd, dup_passwd; | 
|---|
| 147 | size_t domlen = 0; | 
|---|
| 148 |  | 
|---|
| 149 | domain.const_tchar_ptr = TEXT( ""); | 
|---|
| 150 |  | 
|---|
| 151 | /* Initialize the identity */ | 
|---|
| 152 | memset(identity, 0, sizeof(*identity)); | 
|---|
| 153 |  | 
|---|
| 154 | useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); | 
|---|
| 155 | if(!useranddomain.tchar_ptr) | 
|---|
| 156 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 157 |  | 
|---|
| 158 | user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); | 
|---|
| 159 | if(!user.const_tchar_ptr) | 
|---|
| 160 | user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); | 
|---|
| 161 |  | 
|---|
| 162 | if(user.tchar_ptr) { | 
|---|
| 163 | domain.tchar_ptr = useranddomain.tchar_ptr; | 
|---|
| 164 | domlen = user.tchar_ptr - useranddomain.tchar_ptr; | 
|---|
| 165 | user.tchar_ptr++; | 
|---|
| 166 | } | 
|---|
| 167 | else { | 
|---|
| 168 | user.tchar_ptr = useranddomain.tchar_ptr; | 
|---|
| 169 | domain.const_tchar_ptr = TEXT( ""); | 
|---|
| 170 | domlen = 0; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | /* Setup the identity's user and length */ | 
|---|
| 174 | dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); | 
|---|
| 175 | if(!dup_user.tchar_ptr) { | 
|---|
| 176 | Curl_unicodefree(useranddomain.tchar_ptr); | 
|---|
| 177 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 178 | } | 
|---|
| 179 | identity->User = dup_user.tbyte_ptr; | 
|---|
| 180 | identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); | 
|---|
| 181 | dup_user.tchar_ptr = NULL; | 
|---|
| 182 |  | 
|---|
| 183 | /* Setup the identity's domain and length */ | 
|---|
| 184 | dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); | 
|---|
| 185 | if(!dup_domain.tchar_ptr) { | 
|---|
| 186 | Curl_unicodefree(useranddomain.tchar_ptr); | 
|---|
| 187 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 188 | } | 
|---|
| 189 | _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); | 
|---|
| 190 | *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); | 
|---|
| 191 | identity->Domain = dup_domain.tbyte_ptr; | 
|---|
| 192 | identity->DomainLength = curlx_uztoul(domlen); | 
|---|
| 193 | dup_domain.tchar_ptr = NULL; | 
|---|
| 194 |  | 
|---|
| 195 | Curl_unicodefree(useranddomain.tchar_ptr); | 
|---|
| 196 |  | 
|---|
| 197 | /* Setup the identity's password and length */ | 
|---|
| 198 | passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); | 
|---|
| 199 | if(!passwd.tchar_ptr) | 
|---|
| 200 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 201 | dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); | 
|---|
| 202 | if(!dup_passwd.tchar_ptr) { | 
|---|
| 203 | Curl_unicodefree(passwd.tchar_ptr); | 
|---|
| 204 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 205 | } | 
|---|
| 206 | identity->Password = dup_passwd.tbyte_ptr; | 
|---|
| 207 | identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); | 
|---|
| 208 | dup_passwd.tchar_ptr = NULL; | 
|---|
| 209 |  | 
|---|
| 210 | Curl_unicodefree(passwd.tchar_ptr); | 
|---|
| 211 |  | 
|---|
| 212 | /* Setup the identity's flags */ | 
|---|
| 213 | identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; | 
|---|
| 214 |  | 
|---|
| 215 | return CURLE_OK; | 
|---|
| 216 | } | 
|---|
| 217 |  | 
|---|
| 218 | /* | 
|---|
| 219 | * Curl_sspi_free_identity() | 
|---|
| 220 | * | 
|---|
| 221 | * This is used to free the contents of a SSPI identifier structure. | 
|---|
| 222 | * | 
|---|
| 223 | * Parameters: | 
|---|
| 224 | * | 
|---|
| 225 | * identity [in/out] - The identity structure. | 
|---|
| 226 | */ | 
|---|
| 227 | void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) | 
|---|
| 228 | { | 
|---|
| 229 | if(identity) { | 
|---|
| 230 | Curl_safefree(identity->User); | 
|---|
| 231 | Curl_safefree(identity->Password); | 
|---|
| 232 | Curl_safefree(identity->Domain); | 
|---|
| 233 | } | 
|---|
| 234 | } | 
|---|
| 235 |  | 
|---|
| 236 | #endif /* USE_WINDOWS_SSPI */ | 
|---|
| 237 |  | 
|---|