Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/vauth/ntlm_sspi.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 #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 /* Release the package buffer as it is not required anymore */ | |
| 60 if(status == SEC_E_OK) { | |
| 61 s_pSecFn->FreeContextBuffer(SecurityPackage); | |
| 62 } | |
| 63 | |
| 64 return (status == SEC_E_OK ? TRUE : FALSE); | |
| 65 } | |
| 66 | |
| 67 /* | |
| 68 * Curl_auth_create_ntlm_type1_message() | |
| 69 * | |
| 70 * This is used to generate an already encoded NTLM type-1 message ready for | |
| 71 * sending to the recipient. | |
| 72 * | |
| 73 * Parameters: | |
| 74 * | |
| 75 * data [in] - The session handle. | |
| 76 * userp [in] - The user name in the format User or Domain\User. | |
| 77 * passwdp [in] - The user's password. | |
| 78 * service [in] - The service type such as http, smtp, pop or imap. | |
| 79 * host [in] - The host name. | |
| 80 * ntlm [in/out] - The NTLM data struct being used and modified. | |
| 81 * outptr [in/out] - The address where a pointer to newly allocated memory | |
| 82 * holding the result will be stored upon completion. | |
| 83 * outlen [out] - The length of the output message. | |
| 84 * | |
| 85 * Returns CURLE_OK on success. | |
| 86 */ | |
| 87 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, | |
| 88 const char *userp, | |
| 89 const char *passwdp, | |
| 90 const char *service, | |
| 91 const char *host, | |
| 92 struct ntlmdata *ntlm, | |
| 93 char **outptr, size_t *outlen) | |
| 94 { | |
| 95 PSecPkgInfo SecurityPackage; | |
| 96 SecBuffer type_1_buf; | |
| 97 SecBufferDesc type_1_desc; | |
| 98 SECURITY_STATUS status; | |
| 99 unsigned long attrs; | |
| 100 TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ | |
| 101 | |
| 102 /* Clean up any former leftovers and initialise to defaults */ | |
| 103 Curl_auth_cleanup_ntlm(ntlm); | |
| 104 | |
| 105 /* Query the security package for NTLM */ | |
| 106 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), | |
| 107 &SecurityPackage); | |
| 108 if(status != SEC_E_OK) | |
| 109 return CURLE_NOT_BUILT_IN; | |
| 110 | |
| 111 ntlm->token_max = SecurityPackage->cbMaxToken; | |
| 112 | |
| 113 /* Release the package buffer as it is not required anymore */ | |
| 114 s_pSecFn->FreeContextBuffer(SecurityPackage); | |
| 115 | |
| 116 /* Allocate our output buffer */ | |
| 117 ntlm->output_token = malloc(ntlm->token_max); | |
| 118 if(!ntlm->output_token) | |
| 119 return CURLE_OUT_OF_MEMORY; | |
| 120 | |
| 121 if(userp && *userp) { | |
| 122 CURLcode result; | |
| 123 | |
| 124 /* Populate our identity structure */ | |
| 125 result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); | |
| 126 if(result) | |
| 127 return result; | |
| 128 | |
| 129 /* Allow proper cleanup of the identity structure */ | |
| 130 ntlm->p_identity = &ntlm->identity; | |
| 131 } | |
| 132 else | |
| 133 /* Use the current Windows user */ | |
| 134 ntlm->p_identity = NULL; | |
| 135 | |
| 136 /* Allocate our credentials handle */ | |
| 137 ntlm->credentials = calloc(1, sizeof(CredHandle)); | |
| 138 if(!ntlm->credentials) | |
| 139 return CURLE_OUT_OF_MEMORY; | |
| 140 | |
| 141 /* Acquire our credentials handle */ | |
| 142 status = s_pSecFn->AcquireCredentialsHandle(NULL, | |
| 143 (TCHAR *) TEXT(SP_NAME_NTLM), | |
| 144 SECPKG_CRED_OUTBOUND, NULL, | |
| 145 ntlm->p_identity, NULL, NULL, | |
| 146 ntlm->credentials, &expiry); | |
| 147 if(status != SEC_E_OK) | |
| 148 return CURLE_LOGIN_DENIED; | |
| 149 | |
| 150 /* Allocate our new context handle */ | |
| 151 ntlm->context = calloc(1, sizeof(CtxtHandle)); | |
| 152 if(!ntlm->context) | |
| 153 return CURLE_OUT_OF_MEMORY; | |
| 154 | |
| 155 ntlm->spn = Curl_auth_build_spn(service, host, NULL); | |
| 156 if(!ntlm->spn) | |
| 157 return CURLE_OUT_OF_MEMORY; | |
| 158 | |
| 159 /* Setup the type-1 "output" security buffer */ | |
| 160 type_1_desc.ulVersion = SECBUFFER_VERSION; | |
| 161 type_1_desc.cBuffers = 1; | |
| 162 type_1_desc.pBuffers = &type_1_buf; | |
| 163 type_1_buf.BufferType = SECBUFFER_TOKEN; | |
| 164 type_1_buf.pvBuffer = ntlm->output_token; | |
| 165 type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); | |
| 166 | |
| 167 /* Generate our type-1 message */ | |
| 168 status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, | |
| 169 ntlm->spn, | |
| 170 0, 0, SECURITY_NETWORK_DREP, | |
| 171 NULL, 0, | |
| 172 ntlm->context, &type_1_desc, | |
| 173 &attrs, &expiry); | |
| 174 if(status == SEC_I_COMPLETE_NEEDED || | |
| 175 status == SEC_I_COMPLETE_AND_CONTINUE) | |
| 176 s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); | |
| 177 else if(status == SEC_E_INSUFFICIENT_MEMORY) | |
| 178 return CURLE_OUT_OF_MEMORY; | |
| 179 else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) | |
| 180 return CURLE_AUTH_ERROR; | |
| 181 | |
| 182 /* Base64 encode the response */ | |
| 183 return Curl_base64_encode(data, (char *) ntlm->output_token, | |
| 184 type_1_buf.cbBuffer, outptr, outlen); | |
| 185 } | |
| 186 | |
| 187 /* | |
| 188 * Curl_auth_decode_ntlm_type2_message() | |
| 189 * | |
| 190 * This is used to decode an already encoded NTLM type-2 message. | |
| 191 * | |
| 192 * Parameters: | |
| 193 * | |
| 194 * data [in] - The session handle. | |
| 195 * type2msg [in] - The base64 encoded type-2 message. | |
| 196 * ntlm [in/out] - The NTLM data struct being used and modified. | |
| 197 * | |
| 198 * Returns CURLE_OK on success. | |
| 199 */ | |
| 200 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, | |
| 201 const char *type2msg, | |
| 202 struct ntlmdata *ntlm) | |
| 203 { | |
| 204 CURLcode result = CURLE_OK; | |
| 205 unsigned char *type2 = NULL; | |
| 206 size_t type2_len = 0; | |
| 207 | |
| 208 #if defined(CURL_DISABLE_VERBOSE_STRINGS) | |
| 209 (void) data; | |
| 210 #endif | |
| 211 | |
| 212 /* Decode the base-64 encoded type-2 message */ | |
| 213 if(strlen(type2msg) && *type2msg != '=') { | |
| 214 result = Curl_base64_decode(type2msg, &type2, &type2_len); | |
| 215 if(result) | |
| 216 return result; | |
| 217 } | |
| 218 | |
| 219 /* Ensure we have a valid type-2 message */ | |
| 220 if(!type2) { | |
| 221 infof(data, "NTLM handshake failure (empty type-2 message)\n"); | |
| 222 | |
| 223 return CURLE_BAD_CONTENT_ENCODING; | |
| 224 } | |
| 225 | |
| 226 /* Simply store the challenge for use later */ | |
| 227 ntlm->input_token = type2; | |
| 228 ntlm->input_token_len = type2_len; | |
| 229 | |
| 230 return result; | |
| 231 } | |
| 232 | |
| 233 /* | |
| 234 * Curl_auth_create_ntlm_type3_message() | |
| 235 * Curl_auth_create_ntlm_type3_message() | |
| 236 * | |
| 237 * This is used to generate an already encoded NTLM type-3 message ready for | |
| 238 * sending to the recipient. | |
| 239 * | |
| 240 * Parameters: | |
| 241 * | |
| 242 * data [in] - The session handle. | |
| 243 * userp [in] - The user name in the format User or Domain\User. | |
| 244 * passwdp [in] - The user's password. | |
| 245 * ntlm [in/out] - The NTLM data struct being used and modified. | |
| 246 * outptr [in/out] - The address where a pointer to newly allocated memory | |
| 247 * holding the result will be stored upon completion. | |
| 248 * outlen [out] - The length of the output message. | |
| 249 * | |
| 250 * Returns CURLE_OK on success. | |
| 251 */ | |
| 252 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, | |
| 253 const char *userp, | |
| 254 const char *passwdp, | |
| 255 struct ntlmdata *ntlm, | |
| 256 char **outptr, size_t *outlen) | |
| 257 { | |
| 258 CURLcode result = CURLE_OK; | |
| 259 SecBuffer type_2_bufs[2]; | |
| 260 SecBuffer type_3_buf; | |
| 261 SecBufferDesc type_2_desc; | |
| 262 SecBufferDesc type_3_desc; | |
| 263 SECURITY_STATUS status; | |
| 264 unsigned long attrs; | |
| 265 TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ | |
| 266 | |
| 267 (void) passwdp; | |
| 268 (void) userp; | |
| 269 | |
| 270 /* Setup the type-2 "input" security buffer */ | |
| 271 type_2_desc.ulVersion = SECBUFFER_VERSION; | |
| 272 type_2_desc.cBuffers = 1; | |
| 273 type_2_desc.pBuffers = &type_2_bufs[0]; | |
| 274 type_2_bufs[0].BufferType = SECBUFFER_TOKEN; | |
| 275 type_2_bufs[0].pvBuffer = ntlm->input_token; | |
| 276 type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len); | |
| 277 | |
| 278 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS | |
| 279 /* ssl context comes from schannel. | |
| 280 * When extended protection is used in IIS server, | |
| 281 * we have to pass a second SecBuffer to the SecBufferDesc | |
| 282 * otherwise IIS will not pass the authentication (401 response). | |
| 283 * Minimum supported version is Windows 7. | |
| 284 * https://docs.microsoft.com/en-us/security-updates | |
| 285 * /SecurityAdvisories/2009/973811 | |
| 286 */ | |
| 287 if(ntlm->sslContext) { | |
| 288 SEC_CHANNEL_BINDINGS channelBindings; | |
| 289 SecPkgContext_Bindings pkgBindings; | |
| 290 pkgBindings.Bindings = &channelBindings; | |
| 291 status = s_pSecFn->QueryContextAttributes( | |
| 292 ntlm->sslContext, | |
| 293 SECPKG_ATTR_ENDPOINT_BINDINGS, | |
| 294 &pkgBindings | |
| 295 ); | |
| 296 if(status == SEC_E_OK) { | |
| 297 type_2_desc.cBuffers++; | |
| 298 type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; | |
| 299 type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength; | |
| 300 type_2_bufs[1].pvBuffer = pkgBindings.Bindings; | |
| 301 } | |
| 302 } | |
| 303 #endif | |
| 304 | |
| 305 /* Setup the type-3 "output" security buffer */ | |
| 306 type_3_desc.ulVersion = SECBUFFER_VERSION; | |
| 307 type_3_desc.cBuffers = 1; | |
| 308 type_3_desc.pBuffers = &type_3_buf; | |
| 309 type_3_buf.BufferType = SECBUFFER_TOKEN; | |
| 310 type_3_buf.pvBuffer = ntlm->output_token; | |
| 311 type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); | |
| 312 | |
| 313 /* Generate our type-3 message */ | |
| 314 status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, | |
| 315 ntlm->context, | |
| 316 ntlm->spn, | |
| 317 0, 0, SECURITY_NETWORK_DREP, | |
| 318 &type_2_desc, | |
| 319 0, ntlm->context, | |
| 320 &type_3_desc, | |
| 321 &attrs, &expiry); | |
| 322 if(status != SEC_E_OK) { | |
| 323 infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", | |
| 324 status); | |
| 325 | |
| 326 if(status == SEC_E_INSUFFICIENT_MEMORY) | |
| 327 return CURLE_OUT_OF_MEMORY; | |
| 328 | |
| 329 return CURLE_AUTH_ERROR; | |
| 330 } | |
| 331 | |
| 332 /* Base64 encode the response */ | |
| 333 result = Curl_base64_encode(data, (char *) ntlm->output_token, | |
| 334 type_3_buf.cbBuffer, outptr, outlen); | |
| 335 | |
| 336 Curl_auth_cleanup_ntlm(ntlm); | |
| 337 | |
| 338 return result; | |
| 339 } | |
| 340 | |
| 341 /* | |
| 342 * Curl_auth_cleanup_ntlm() | |
| 343 * | |
| 344 * This is used to clean up the NTLM specific data. | |
| 345 * | |
| 346 * Parameters: | |
| 347 * | |
| 348 * ntlm [in/out] - The NTLM data struct being cleaned up. | |
| 349 * | |
| 350 */ | |
| 351 void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) | |
| 352 { | |
| 353 /* Free our security context */ | |
| 354 if(ntlm->context) { | |
| 355 s_pSecFn->DeleteSecurityContext(ntlm->context); | |
| 356 free(ntlm->context); | |
| 357 ntlm->context = NULL; | |
| 358 } | |
| 359 | |
| 360 /* Free our credentials handle */ | |
| 361 if(ntlm->credentials) { | |
| 362 s_pSecFn->FreeCredentialsHandle(ntlm->credentials); | |
| 363 free(ntlm->credentials); | |
| 364 ntlm->credentials = NULL; | |
| 365 } | |
| 366 | |
| 367 /* Free our identity */ | |
| 368 Curl_sspi_free_identity(ntlm->p_identity); | |
| 369 ntlm->p_identity = NULL; | |
| 370 | |
| 371 /* Free the input and output tokens */ | |
| 372 Curl_safefree(ntlm->input_token); | |
| 373 Curl_safefree(ntlm->output_token); | |
| 374 | |
| 375 /* Reset any variables */ | |
| 376 ntlm->token_max = 0; | |
| 377 | |
| 378 Curl_safefree(ntlm->spn); | |
| 379 } | |
| 380 | |
| 381 #endif /* USE_WINDOWS_SSPI && USE_NTLM */ |
