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