1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
30 * https://davenport.sourceforge.io/ntlm.html
31 * https://www.innovation.ch/java/ntlm.html
38 #include "curl_ntlm_core.h"
39 #include "curl_gethostname.h"
40 #include "curl_multibyte.h"
44 #include "vtls/vtls.h"
46 /* SSL backend-specific #if branches in this file must be kept in the order
47 documented in curl_ntlm_core. */
48 #if defined(NTLM_NEEDS_NSS_INIT)
49 #include "vtls/nssg.h" /* for Curl_nss_force_init() */
52 #define BUILDING_CURL_NTLM_MSGS_C
53 #include "vauth/vauth.h"
54 #include "vauth/ntlm.h"
55 #include "curl_endian.h"
56 #include "curl_printf.h"
58 /* The last #include files should be: */
59 #include "curl_memory.h"
62 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
63 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
66 # define DEBUG_OUT(x) x
67 static void ntlm_print_flags(FILE *handle, unsigned long flags)
69 if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
70 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
71 if(flags & NTLMFLAG_NEGOTIATE_OEM)
72 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
73 if(flags & NTLMFLAG_REQUEST_TARGET)
74 fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
76 fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
77 if(flags & NTLMFLAG_NEGOTIATE_SIGN)
78 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
79 if(flags & NTLMFLAG_NEGOTIATE_SEAL)
80 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
81 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
82 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
83 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
84 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
85 if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
86 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
87 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
88 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
90 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
91 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
92 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
93 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
94 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
95 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
96 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
97 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
98 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
99 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
100 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
101 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
102 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
103 if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
104 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
105 if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
106 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
107 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
108 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
109 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
110 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
111 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
112 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
113 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
114 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
115 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
116 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
118 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
120 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
122 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
124 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
126 fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
127 if(flags & NTLMFLAG_NEGOTIATE_128)
128 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
129 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
130 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
131 if(flags & NTLMFLAG_NEGOTIATE_56)
132 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
135 static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
141 fprintf(stderr, "0x");
143 fprintf(stderr, "%02.2x", (unsigned int)*p++);
146 # define DEBUG_OUT(x) Curl_nop_stmt
150 * ntlm_decode_type2_target()
152 * This is used to decode the "target info" in the NTLM type-2 message
157 * data [in] - The session handle.
158 * type2ref [in] - The type-2 message.
159 * ntlm [in/out] - The NTLM data struct being used and modified.
161 * Returns CURLE_OK on success.
163 static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
164 const struct bufref *type2ref,
165 struct ntlmdata *ntlm)
167 unsigned short target_info_len = 0;
168 unsigned int target_info_offset = 0;
169 const unsigned char *type2 = Curl_bufref_ptr(type2ref);
170 size_t type2len = Curl_bufref_len(type2ref);
172 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
177 target_info_len = Curl_read16_le(&type2[40]);
178 target_info_offset = Curl_read32_le(&type2[44]);
179 if(target_info_len > 0) {
180 if((target_info_offset > type2len) ||
181 (target_info_offset + target_info_len) > type2len ||
182 target_info_offset < 48) {
183 infof(data, "NTLM handshake failure (bad type-2 message). "
184 "Target Info Offset Len is set incorrect by the peer");
185 return CURLE_BAD_CONTENT_ENCODING;
188 free(ntlm->target_info); /* replace any previous data */
189 ntlm->target_info = malloc(target_info_len);
190 if(!ntlm->target_info)
191 return CURLE_OUT_OF_MEMORY;
193 memcpy(ntlm->target_info, &type2[target_info_offset], target_info_len);
197 ntlm->target_info_len = target_info_len;
203 NTLM message structure notes:
205 A 'short' is a 'network short', a little-endian 16-bit unsigned value.
207 A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
209 A 'security buffer' represents a triplet used to point to a buffer,
210 consisting of two shorts and one long:
212 1. A 'short' containing the length of the buffer content in bytes.
213 2. A 'short' containing the allocated space for the buffer in bytes.
214 3. A 'long' containing the offset to the start of the buffer in bytes,
215 from the beginning of the NTLM message.
219 * Curl_auth_is_ntlm_supported()
221 * This is used to evaluate if NTLM is supported.
225 * Returns TRUE as NTLM as handled by libcurl.
227 bool Curl_auth_is_ntlm_supported(void)
233 * Curl_auth_decode_ntlm_type2_message()
235 * This is used to decode an NTLM type-2 message. The raw NTLM message is
236 * checked * for validity before the appropriate data for creating a type-3
237 * message is * written to the given NTLM data structure.
241 * data [in] - The session handle.
242 * type2ref [in] - The type-2 message.
243 * ntlm [in/out] - The NTLM data struct being used and modified.
245 * Returns CURLE_OK on success.
247 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
248 const struct bufref *type2ref,
249 struct ntlmdata *ntlm)
251 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
253 /* NTLM type-2 message structure:
255 Index Description Content
256 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
258 8 NTLM Message Type long (0x02000000)
259 12 Target Name security buffer
262 (32) Context 8 bytes (two consecutive longs) (*)
263 (40) Target Information security buffer (*)
264 (48) OS Version Structure 8 bytes (*)
265 32 (48) (56) Start of data block (*)
269 CURLcode result = CURLE_OK;
270 const unsigned char *type2 = Curl_bufref_ptr(type2ref);
271 size_t type2len = Curl_bufref_len(type2ref);
273 #if defined(NTLM_NEEDS_NSS_INIT)
274 /* Make sure the crypto backend is initialized */
275 result = Curl_nss_force_init(data);
278 #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
284 if((type2len < 32) ||
285 (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
286 (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
287 /* This was not a good enough type-2 message */
288 infof(data, "NTLM handshake failure (bad type-2 message)");
289 return CURLE_BAD_CONTENT_ENCODING;
292 ntlm->flags = Curl_read32_le(&type2[20]);
293 memcpy(ntlm->nonce, &type2[24], 8);
295 if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
296 result = ntlm_decode_type2_target(data, type2ref, ntlm);
298 infof(data, "NTLM handshake failure (bad type-2 message)");
304 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
305 ntlm_print_flags(stderr, ntlm->flags);
306 fprintf(stderr, "\n nonce=");
307 ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
308 fprintf(stderr, "\n****\n");
309 fprintf(stderr, "**** Header %s\n ", header);
315 /* copy the source to the destination and fill in zeroes in every
316 other destination byte! */
317 static void unicodecpy(unsigned char *dest, const char *src, size_t length)
320 for(i = 0; i < length; i++) {
321 dest[2 * i] = (unsigned char)src[i];
322 dest[2 * i + 1] = '\0';
327 * Curl_auth_create_ntlm_type1_message()
329 * This is used to generate an NTLM type-1 message ready for sending to the
330 * recipient using the appropriate compile time crypto API.
334 * data [in] - The session handle.
335 * userp [in] - The user name in the format User or Domain\User.
336 * passwdp [in] - The user's password.
337 * service [in] - The service type such as http, smtp, pop or imap.
338 * host [in] - The host name.
339 * ntlm [in/out] - The NTLM data struct being used and modified.
340 * out [out] - The result storage.
342 * Returns CURLE_OK on success.
344 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
348 const char *hostname,
349 struct ntlmdata *ntlm,
352 /* NTLM type-1 message structure:
354 Index Description Content
355 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
357 8 NTLM Message Type long (0x01000000)
359 (16) Supplied Domain security buffer (*)
360 (24) Supplied Workstation security buffer (*)
361 (32) OS Version Structure 8 bytes (*)
362 (32) (40) Start of data block (*)
369 const char *host = ""; /* empty */
370 const char *domain = ""; /* empty */
374 size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
382 /* Clean up any former leftovers and initialise to defaults */
383 Curl_auth_cleanup_ntlm(ntlm);
385 ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c"
386 "\x01%c%c%c" /* 32-bit type = 1 */
387 "%c%c%c%c" /* 32-bit NTLM flag field */
388 "%c%c" /* domain length */
389 "%c%c" /* domain allocated space */
390 "%c%c" /* domain name offset */
391 "%c%c" /* 2 zeroes */
392 "%c%c" /* host length */
393 "%c%c" /* host allocated space */
394 "%c%c" /* host name offset */
395 "%c%c" /* 2 zeroes */
397 "%s", /* domain string */
398 0, /* trailing zero */
399 0, 0, 0, /* part of type-1 long */
401 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
402 NTLMFLAG_REQUEST_TARGET |
403 NTLMFLAG_NEGOTIATE_NTLM_KEY |
404 NTLMFLAG_NEGOTIATE_NTLM2_KEY |
405 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
414 host, /* this is empty */
415 domain /* this is empty */);
418 return CURLE_OUT_OF_MEMORY;
420 /* Initial packet length */
421 size = 32 + hostlen + domlen;
424 fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
426 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
427 NTLMFLAG_REQUEST_TARGET |
428 NTLMFLAG_NEGOTIATE_NTLM_KEY |
429 NTLMFLAG_NEGOTIATE_NTLM2_KEY |
430 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
431 NTLMFLAG_NEGOTIATE_OEM |
432 NTLMFLAG_REQUEST_TARGET |
433 NTLMFLAG_NEGOTIATE_NTLM_KEY |
434 NTLMFLAG_NEGOTIATE_NTLM2_KEY |
435 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
436 ntlm_print_flags(stderr,
437 NTLMFLAG_NEGOTIATE_OEM |
438 NTLMFLAG_REQUEST_TARGET |
439 NTLMFLAG_NEGOTIATE_NTLM_KEY |
440 NTLMFLAG_NEGOTIATE_NTLM2_KEY |
441 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
442 fprintf(stderr, "\n****\n");
445 Curl_bufref_set(out, ntlmbuf, size, curl_free);
450 * Curl_auth_create_ntlm_type3_message()
452 * This is used to generate an already encoded NTLM type-3 message ready for
453 * sending to the recipient using the appropriate compile time crypto API.
457 * data [in] - The session handle.
458 * userp [in] - The user name in the format User or Domain\User.
459 * passwdp [in] - The user's password.
460 * ntlm [in/out] - The NTLM data struct being used and modified.
461 * out [out] - The result storage.
463 * Returns CURLE_OK on success.
465 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
468 struct ntlmdata *ntlm,
471 /* NTLM type-3 message structure:
473 Index Description Content
474 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
476 8 NTLM Message Type long (0x03000000)
477 12 LM/LMv2 Response security buffer
478 20 NTLM/NTLMv2 Response security buffer
479 28 Target Name security buffer
480 36 User Name security buffer
481 44 Workstation Name security buffer
482 (52) Session Key security buffer (*)
484 (64) OS Version Structure 8 bytes (*)
485 52 (64) (72) Start of data block
489 CURLcode result = CURLE_OK;
491 unsigned char ntlmbuf[NTLM_BUFSIZE];
493 unsigned char lmresp[24]; /* fixed-size */
495 unsigned int ntresplen = 24;
496 unsigned char ntresp[24]; /* fixed-size */
497 unsigned char *ptr_ntresp = &ntresp[0];
498 unsigned char *ntlmv2resp = NULL;
499 bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
500 char host[HOSTNAME_MAX + 1] = "";
502 const char *domain = "";
510 user = strchr(userp, '\\');
512 user = strchr(userp, '/');
516 domlen = (user - domain);
522 userlen = strlen(user);
524 /* Get the machine's un-qualified host name as NTLM doesn't like the fully
525 qualified domain name */
526 if(Curl_gethostname(host, sizeof(host))) {
527 infof(data, "gethostname() failed, continuing without");
531 hostlen = strlen(host);
534 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
535 unsigned char ntbuffer[0x18];
536 unsigned char entropy[8];
537 unsigned char ntlmv2hash[0x18];
539 /* Full NTLM version 2
540 Although this cannot be negotiated, it is used here if available, as
541 servers featuring extended security are likely supporting also
543 result = Curl_rand(data, entropy, 8);
547 result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
551 result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
552 ntbuffer, ntlmv2hash);
557 result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
558 &ntlm->nonce[0], lmresp);
562 /* NTLMv2 response */
563 result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
564 ntlm, &ntlmv2resp, &ntresplen);
568 ptr_ntresp = ntlmv2resp;
572 unsigned char ntbuffer[0x18];
573 unsigned char lmbuffer[0x18];
577 result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
581 Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
583 result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
587 Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
588 ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY;
590 /* A safer but less compatible alternative is:
591 * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
592 * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */
597 userlen = userlen * 2;
598 hostlen = hostlen * 2;
601 lmrespoff = 64; /* size of the message header */
602 ntrespoff = lmrespoff + 0x18;
603 domoff = ntrespoff + ntresplen;
604 useroff = domoff + domlen;
605 hostoff = useroff + userlen;
607 /* Create the big type-3 message binary blob */
608 size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
609 NTLMSSP_SIGNATURE "%c"
610 "\x03%c%c%c" /* 32-bit type = 3 */
612 "%c%c" /* LanManager length */
613 "%c%c" /* LanManager allocated space */
614 "%c%c" /* LanManager offset */
615 "%c%c" /* 2 zeroes */
617 "%c%c" /* NT-response length */
618 "%c%c" /* NT-response allocated space */
619 "%c%c" /* NT-response offset */
620 "%c%c" /* 2 zeroes */
622 "%c%c" /* domain length */
623 "%c%c" /* domain allocated space */
624 "%c%c" /* domain name offset */
625 "%c%c" /* 2 zeroes */
627 "%c%c" /* user length */
628 "%c%c" /* user allocated space */
629 "%c%c" /* user offset */
630 "%c%c" /* 2 zeroes */
632 "%c%c" /* host length */
633 "%c%c" /* host allocated space */
634 "%c%c" /* host offset */
635 "%c%c" /* 2 zeroes */
637 "%c%c" /* session key length (unknown purpose) */
638 "%c%c" /* session key allocated space (unknown purpose) */
639 "%c%c" /* session key offset (unknown purpose) */
640 "%c%c" /* 2 zeroes */
642 "%c%c%c%c", /* flags */
647 /* LanManager response */
650 0, /* zero termination */
651 0, 0, 0, /* type-3 long, the 24 upper bits */
653 SHORTPAIR(0x18), /* LanManager response length, twice */
655 SHORTPAIR(lmrespoff),
658 SHORTPAIR(ntresplen), /* NT-response length, twice */
659 SHORTPAIR(ntresplen),
660 SHORTPAIR(ntrespoff),
683 LONGQUARTET(ntlm->flags));
685 DEBUGASSERT(size == 64);
686 DEBUGASSERT(size == (size_t)lmrespoff);
688 /* We append the binary hashes */
689 if(size < (NTLM_BUFSIZE - 0x18)) {
690 memcpy(&ntlmbuf[size], lmresp, 0x18);
695 fprintf(stderr, "**** TYPE3 header lmresp=");
696 ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
699 /* ntresplen + size should not be risking an integer overflow here */
700 if(ntresplen + size > sizeof(ntlmbuf)) {
701 failf(data, "incoming NTLM message too big");
702 return CURLE_OUT_OF_MEMORY;
704 DEBUGASSERT(size == (size_t)ntrespoff);
705 memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
709 fprintf(stderr, "\n ntresp=");
710 ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
713 free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
716 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
717 LONGQUARTET(ntlm->flags), ntlm->flags);
718 ntlm_print_flags(stderr, ntlm->flags);
719 fprintf(stderr, "\n****\n");
722 /* Make sure that the domain, user and host strings fit in the
723 buffer before we copy them there. */
724 if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
725 failf(data, "user + domain + host name too big");
726 return CURLE_OUT_OF_MEMORY;
729 DEBUGASSERT(size == domoff);
731 unicodecpy(&ntlmbuf[size], domain, domlen / 2);
733 memcpy(&ntlmbuf[size], domain, domlen);
737 DEBUGASSERT(size == useroff);
739 unicodecpy(&ntlmbuf[size], user, userlen / 2);
741 memcpy(&ntlmbuf[size], user, userlen);
745 DEBUGASSERT(size == hostoff);
747 unicodecpy(&ntlmbuf[size], host, hostlen / 2);
749 memcpy(&ntlmbuf[size], host, hostlen);
753 /* Return the binary blob. */
754 result = Curl_bufref_memdup(out, ntlmbuf, size);
756 Curl_auth_cleanup_ntlm(ntlm);
762 * Curl_auth_cleanup_ntlm()
764 * This is used to clean up the NTLM specific data.
768 * ntlm [in/out] - The NTLM data struct being cleaned up.
771 void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
773 /* Free the target info */
774 Curl_safefree(ntlm->target_info);
776 /* Reset any variables */
777 ntlm->target_info_len = 0;
780 #endif /* USE_NTLM && !USE_WINDOWS_SSPI */