1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, 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 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(USE_WINDOWS_SSPI) && defined(USE_NTLM) 26 27 #include <curl/curl.h> 28 29 #include "vauth/vauth.h" 30 #include "urldata.h" 31 #include "curl_base64.h" 32 #include "curl_ntlm_core.h" 33 #include "warnless.h" 34 #include "curl_multibyte.h" 35 #include "sendf.h" 36 37 /* The last #include files should be: */ 38 #include "curl_memory.h" 39 #include "memdebug.h" 40 41 /* 42 * Curl_auth_is_ntlm_supported() 43 * 44 * This is used to evaluate if NTLM is supported. 45 * 46 * Parameters: None 47 * 48 * Returns TRUE if NTLM is supported by Windows SSPI. 49 */ 50 bool Curl_auth_is_ntlm_supported(void) 51 { 52 PSecPkgInfo SecurityPackage; 53 SECURITY_STATUS status; 54 55 /* Query the security package for NTLM */ 56 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), 57 &SecurityPackage); 58 59 return (status == SEC_E_OK ? TRUE : FALSE); 60 } 61 62 /* 63 * Curl_auth_create_ntlm_type1_message() 64 * 65 * This is used to generate an already encoded NTLM type-1 message ready for 66 * sending to the recipient. 67 * 68 * Parameters: 69 * 70 * data [in] - The session handle. 71 * userp [in] - The user name in the format User or Domain\User. 72 * passdwp [in] - The user's password. 73 * ntlm [in/out] - The NTLM data struct being used and modified. 74 * outptr [in/out] - The address where a pointer to newly allocated memory 75 * holding the result will be stored upon completion. 76 * outlen [out] - The length of the output message. 77 * 78 * Returns CURLE_OK on success. 79 */ 80 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, 81 const char *userp, 82 const char *passwdp, 83 struct ntlmdata *ntlm, 84 char **outptr, size_t *outlen) 85 { 86 PSecPkgInfo SecurityPackage; 87 SecBuffer type_1_buf; 88 SecBufferDesc type_1_desc; 89 SECURITY_STATUS status; 90 unsigned long attrs; 91 TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ 92 93 /* Clean up any former leftovers and initialise to defaults */ 94 Curl_auth_ntlm_cleanup(ntlm); 95 96 /* Query the security package for NTLM */ 97 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), 98 &SecurityPackage); 99 if(status != SEC_E_OK) 100 return CURLE_NOT_BUILT_IN; 101 102 ntlm->token_max = SecurityPackage->cbMaxToken; 103 104 /* Release the package buffer as it is not required anymore */ 105 s_pSecFn->FreeContextBuffer(SecurityPackage); 106 107 /* Allocate our output buffer */ 108 ntlm->output_token = malloc(ntlm->token_max); 109 if(!ntlm->output_token) 110 return CURLE_OUT_OF_MEMORY; 111 112 if(userp && *userp) { 113 CURLcode result; 114 115 /* Populate our identity structure */ 116 result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); 117 if(result) 118 return result; 119 120 /* Allow proper cleanup of the identity structure */ 121 ntlm->p_identity = &ntlm->identity; 122 } 123 else 124 /* Use the current Windows user */ 125 ntlm->p_identity = NULL; 126 127 /* Allocate our credentials handle */ 128 ntlm->credentials = malloc(sizeof(CredHandle)); 129 if(!ntlm->credentials) 130 return CURLE_OUT_OF_MEMORY; 131 132 memset(ntlm->credentials, 0, sizeof(CredHandle)); 133 134 /* Acquire our credentials handle */ 135 status = s_pSecFn->AcquireCredentialsHandle(NULL, 136 (TCHAR *) TEXT(SP_NAME_NTLM), 137 SECPKG_CRED_OUTBOUND, NULL, 138 ntlm->p_identity, NULL, NULL, 139 ntlm->credentials, &expiry); 140 if(status != SEC_E_OK) 141 return CURLE_LOGIN_DENIED; 142 143 /* Allocate our new context handle */ 144 ntlm->context = malloc(sizeof(CtxtHandle)); 145 if(!ntlm->context) 146 return CURLE_OUT_OF_MEMORY; 147 148 memset(ntlm->context, 0, sizeof(CtxtHandle)); 149 150 /* Setup the type-1 "output" security buffer */ 151 type_1_desc.ulVersion = SECBUFFER_VERSION; 152 type_1_desc.cBuffers = 1; 153 type_1_desc.pBuffers = &type_1_buf; 154 type_1_buf.BufferType = SECBUFFER_TOKEN; 155 type_1_buf.pvBuffer = ntlm->output_token; 156 type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); 157 158 /* Generate our type-1 message */ 159 status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, 160 (TCHAR *) TEXT(""), 161 0, 0, SECURITY_NETWORK_DREP, 162 NULL, 0, 163 ntlm->context, &type_1_desc, 164 &attrs, &expiry); 165 if(status == SEC_I_COMPLETE_NEEDED || 166 status == SEC_I_COMPLETE_AND_CONTINUE) 167 s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); 168 else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) 169 return CURLE_RECV_ERROR; 170 171 /* Base64 encode the response */ 172 return Curl_base64_encode(data, (char *) ntlm->output_token, 173 type_1_buf.cbBuffer, outptr, outlen); 174 } 175 176 /* 177 * Curl_auth_decode_ntlm_type2_message() 178 * 179 * This is used to decode an already encoded NTLM type-2 message. 180 * 181 * Parameters: 182 * 183 * data [in] - The session handle. 184 * type2msg [in] - The base64 encoded type-2 message. 185 * ntlm [in/out] - The NTLM data struct being used and modified. 186 * 187 * Returns CURLE_OK on success. 188 */ 189 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, 190 const char *type2msg, 191 struct ntlmdata *ntlm) 192 { 193 CURLcode result = CURLE_OK; 194 unsigned char *type2 = NULL; 195 size_t type2_len = 0; 196 197 #if defined(CURL_DISABLE_VERBOSE_STRINGS) 198 (void) data; 199 #endif 200 201 /* Decode the base-64 encoded type-2 message */ 202 if(strlen(type2msg) && *type2msg != '=') { 203 result = Curl_base64_decode(type2msg, &type2, &type2_len); 204 if(result) 205 return result; 206 } 207 208 /* Ensure we have a valid type-2 message */ 209 if(!type2) { 210 infof(data, "NTLM handshake failure (empty type-2 message)\n"); 211 212 return CURLE_BAD_CONTENT_ENCODING; 213 } 214 215 /* Simply store the challenge for use later */ 216 ntlm->input_token = type2; 217 ntlm->input_token_len = type2_len; 218 219 return result; 220 } 221 222 /* 223 * Curl_auth_create_ntlm_type3_message() 224 * Curl_auth_create_ntlm_type3_message() 225 * 226 * This is used to generate an already encoded NTLM type-3 message ready for 227 * sending to the recipient. 228 * 229 * Parameters: 230 * 231 * data [in] - The session handle. 232 * userp [in] - The user name in the format User or Domain\User. 233 * passdwp [in] - The user's password. 234 * ntlm [in/out] - The NTLM data struct being used and modified. 235 * outptr [in/out] - The address where a pointer to newly allocated memory 236 * holding the result will be stored upon completion. 237 * outlen [out] - The length of the output message. 238 * 239 * Returns CURLE_OK on success. 240 */ 241 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, 242 const char *userp, 243 const char *passwdp, 244 struct ntlmdata *ntlm, 245 char **outptr, size_t *outlen) 246 { 247 CURLcode result = CURLE_OK; 248 SecBuffer type_2_buf; 249 SecBuffer type_3_buf; 250 SecBufferDesc type_2_desc; 251 SecBufferDesc type_3_desc; 252 SECURITY_STATUS status; 253 unsigned long attrs; 254 TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ 255 256 (void) passwdp; 257 (void) userp; 258 259 /* Setup the type-2 "input" security buffer */ 260 type_2_desc.ulVersion = SECBUFFER_VERSION; 261 type_2_desc.cBuffers = 1; 262 type_2_desc.pBuffers = &type_2_buf; 263 type_2_buf.BufferType = SECBUFFER_TOKEN; 264 type_2_buf.pvBuffer = ntlm->input_token; 265 type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); 266 267 /* Setup the type-3 "output" security buffer */ 268 type_3_desc.ulVersion = SECBUFFER_VERSION; 269 type_3_desc.cBuffers = 1; 270 type_3_desc.pBuffers = &type_3_buf; 271 type_3_buf.BufferType = SECBUFFER_TOKEN; 272 type_3_buf.pvBuffer = ntlm->output_token; 273 type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); 274 275 /* Generate our type-3 message */ 276 status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, 277 ntlm->context, 278 (TCHAR *) TEXT(""), 279 0, 0, SECURITY_NETWORK_DREP, 280 &type_2_desc, 281 0, ntlm->context, 282 &type_3_desc, 283 &attrs, &expiry); 284 if(status != SEC_E_OK) { 285 infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", 286 status); 287 288 return CURLE_RECV_ERROR; 289 } 290 291 /* Base64 encode the response */ 292 result = Curl_base64_encode(data, (char *) ntlm->output_token, 293 type_3_buf.cbBuffer, outptr, outlen); 294 295 Curl_auth_ntlm_cleanup(ntlm); 296 297 return result; 298 } 299 300 /* 301 * Curl_auth_ntlm_cleanup() 302 * 303 * This is used to clean up the NTLM specific data. 304 * 305 * Parameters: 306 * 307 * ntlm [in/out] - The NTLM data struct being cleaned up. 308 * 309 */ 310 void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) 311 { 312 /* Free our security context */ 313 if(ntlm->context) { 314 s_pSecFn->DeleteSecurityContext(ntlm->context); 315 free(ntlm->context); 316 ntlm->context = NULL; 317 } 318 319 /* Free our credentials handle */ 320 if(ntlm->credentials) { 321 s_pSecFn->FreeCredentialsHandle(ntlm->credentials); 322 free(ntlm->credentials); 323 ntlm->credentials = NULL; 324 } 325 326 /* Free our identity */ 327 Curl_sspi_free_identity(ntlm->p_identity); 328 ntlm->p_identity = NULL; 329 330 /* Free the input and output tokens */ 331 Curl_safefree(ntlm->input_token); 332 Curl_safefree(ntlm->output_token); 333 334 /* Reset any variables */ 335 ntlm->token_max = 0; 336 } 337 338 #endif /* USE_WINDOWS_SSPI && USE_NTLM */ 339