Annotation of embedaddon/curl/lib/vauth/ntlm.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, 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_NTLM) && !defined(USE_WINDOWS_SSPI)
26:
27: /*
28: * NTLM details:
29: *
30: * https://davenport.sourceforge.io/ntlm.html
31: * https://www.innovation.ch/java/ntlm.html
32: */
33:
34: #define DEBUG_ME 0
35:
36: #include "urldata.h"
37: #include "non-ascii.h"
38: #include "sendf.h"
39: #include "curl_base64.h"
40: #include "curl_ntlm_core.h"
41: #include "curl_gethostname.h"
42: #include "curl_multibyte.h"
43: #include "curl_md5.h"
44: #include "warnless.h"
45: #include "rand.h"
46: #include "vtls/vtls.h"
47:
48: /* SSL backend-specific #if branches in this file must be kept in the order
49: documented in curl_ntlm_core. */
50: #if defined(NTLM_NEEDS_NSS_INIT)
51: #include "vtls/nssg.h" /* for Curl_nss_force_init() */
52: #endif
53:
54: #define BUILDING_CURL_NTLM_MSGS_C
55: #include "vauth/vauth.h"
56: #include "vauth/ntlm.h"
57: #include "curl_endian.h"
58: #include "curl_printf.h"
59:
60: /* The last #include files should be: */
61: #include "curl_memory.h"
62: #include "memdebug.h"
63:
64: /* "NTLMSSP" signature is always in ASCII regardless of the platform */
65: #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
66:
67: #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
68: #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
69: ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
70:
71: #if DEBUG_ME
72: # define DEBUG_OUT(x) x
73: static void ntlm_print_flags(FILE *handle, unsigned long flags)
74: {
75: if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
76: fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
77: if(flags & NTLMFLAG_NEGOTIATE_OEM)
78: fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
79: if(flags & NTLMFLAG_REQUEST_TARGET)
80: fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
81: if(flags & (1<<3))
82: fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
83: if(flags & NTLMFLAG_NEGOTIATE_SIGN)
84: fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
85: if(flags & NTLMFLAG_NEGOTIATE_SEAL)
86: fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
87: if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
88: fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
89: if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
90: fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
91: if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
92: fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
93: if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
94: fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
95: if(flags & (1<<10))
96: fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
97: if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
98: fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
99: if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
100: fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
101: if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
102: fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
103: if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
104: fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
105: if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
106: fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
107: if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
108: fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
109: if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
110: fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
111: if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
112: fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
113: if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
114: fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
115: if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
116: fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
117: if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
118: fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
119: if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
120: fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
121: if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
122: fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
123: if(flags & (1<<24))
124: fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
125: if(flags & (1<<25))
126: fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
127: if(flags & (1<<26))
128: fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
129: if(flags & (1<<27))
130: fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
131: if(flags & (1<<28))
132: fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
133: if(flags & NTLMFLAG_NEGOTIATE_128)
134: fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
135: if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
136: fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
137: if(flags & NTLMFLAG_NEGOTIATE_56)
138: fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
139: }
140:
141: static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
142: {
143: const char *p = buf;
144:
145: (void) handle;
146:
147: fprintf(stderr, "0x");
148: while(len-- > 0)
149: fprintf(stderr, "%02.2x", (unsigned int)*p++);
150: }
151: #else
152: # define DEBUG_OUT(x) Curl_nop_stmt
153: #endif
154:
155: /*
156: * ntlm_decode_type2_target()
157: *
158: * This is used to decode the "target info" in the NTLM type-2 message
159: * received.
160: *
161: * Parameters:
162: *
163: * data [in] - The session handle.
164: * buffer [in] - The decoded type-2 message.
165: * size [in] - The input buffer size, at least 32 bytes.
166: * ntlm [in/out] - The NTLM data struct being used and modified.
167: *
168: * Returns CURLE_OK on success.
169: */
170: static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
171: unsigned char *buffer,
172: size_t size,
173: struct ntlmdata *ntlm)
174: {
175: unsigned short target_info_len = 0;
176: unsigned int target_info_offset = 0;
177:
178: #if defined(CURL_DISABLE_VERBOSE_STRINGS)
179: (void) data;
180: #endif
181:
182: if(size >= 48) {
183: target_info_len = Curl_read16_le(&buffer[40]);
184: target_info_offset = Curl_read32_le(&buffer[44]);
185: if(target_info_len > 0) {
186: if((target_info_offset >= size) ||
187: ((target_info_offset + target_info_len) > size) ||
188: (target_info_offset < 48)) {
189: infof(data, "NTLM handshake failure (bad type-2 message). "
190: "Target Info Offset Len is set incorrect by the peer\n");
191: return CURLE_BAD_CONTENT_ENCODING;
192: }
193:
194: ntlm->target_info = malloc(target_info_len);
195: if(!ntlm->target_info)
196: return CURLE_OUT_OF_MEMORY;
197:
198: memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len);
199: }
200: }
201:
202: ntlm->target_info_len = target_info_len;
203:
204: return CURLE_OK;
205: }
206:
207: /*
208: NTLM message structure notes:
209:
210: A 'short' is a 'network short', a little-endian 16-bit unsigned value.
211:
212: A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
213:
214: A 'security buffer' represents a triplet used to point to a buffer,
215: consisting of two shorts and one long:
216:
217: 1. A 'short' containing the length of the buffer content in bytes.
218: 2. A 'short' containing the allocated space for the buffer in bytes.
219: 3. A 'long' containing the offset to the start of the buffer in bytes,
220: from the beginning of the NTLM message.
221: */
222:
223: /*
224: * Curl_auth_is_ntlm_supported()
225: *
226: * This is used to evaluate if NTLM is supported.
227: *
228: * Parameters: None
229: *
230: * Returns TRUE as NTLM as handled by libcurl.
231: */
232: bool Curl_auth_is_ntlm_supported(void)
233: {
234: return TRUE;
235: }
236:
237: /*
238: * Curl_auth_decode_ntlm_type2_message()
239: *
240: * This is used to decode an already encoded NTLM type-2 message. The message
241: * is first decoded from a base64 string into a raw NTLM message and checked
242: * for validity before the appropriate data for creating a type-3 message is
243: * written to the given NTLM data structure.
244: *
245: * Parameters:
246: *
247: * data [in] - The session handle.
248: * type2msg [in] - The base64 encoded type-2 message.
249: * ntlm [in/out] - The NTLM data struct being used and modified.
250: *
251: * Returns CURLE_OK on success.
252: */
253: CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
254: const char *type2msg,
255: struct ntlmdata *ntlm)
256: {
257: static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
258:
259: /* NTLM type-2 message structure:
260:
261: Index Description Content
262: 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
263: (0x4e544c4d53535000)
264: 8 NTLM Message Type long (0x02000000)
265: 12 Target Name security buffer
266: 20 Flags long
267: 24 Challenge 8 bytes
268: (32) Context 8 bytes (two consecutive longs) (*)
269: (40) Target Information security buffer (*)
270: (48) OS Version Structure 8 bytes (*)
271: 32 (48) (56) Start of data block (*)
272: (*) -> Optional
273: */
274:
275: CURLcode result = CURLE_OK;
276: unsigned char *type2 = NULL;
277: size_t type2_len = 0;
278:
279: #if defined(NTLM_NEEDS_NSS_INIT)
280: /* Make sure the crypto backend is initialized */
281: result = Curl_nss_force_init(data);
282: if(result)
283: return result;
284: #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
285: (void)data;
286: #endif
287:
288: /* Decode the base-64 encoded type-2 message */
289: if(strlen(type2msg) && *type2msg != '=') {
290: result = Curl_base64_decode(type2msg, &type2, &type2_len);
291: if(result)
292: return result;
293: }
294:
295: /* Ensure we have a valid type-2 message */
296: if(!type2) {
297: infof(data, "NTLM handshake failure (empty type-2 message)\n");
298: return CURLE_BAD_CONTENT_ENCODING;
299: }
300:
301: ntlm->flags = 0;
302:
303: if((type2_len < 32) ||
304: (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
305: (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
306: /* This was not a good enough type-2 message */
307: free(type2);
308: infof(data, "NTLM handshake failure (bad type-2 message)\n");
309: return CURLE_BAD_CONTENT_ENCODING;
310: }
311:
312: ntlm->flags = Curl_read32_le(&type2[20]);
313: memcpy(ntlm->nonce, &type2[24], 8);
314:
315: if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
316: result = ntlm_decode_type2_target(data, type2, type2_len, ntlm);
317: if(result) {
318: free(type2);
319: infof(data, "NTLM handshake failure (bad type-2 message)\n");
320: return result;
321: }
322: }
323:
324: DEBUG_OUT({
325: fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
326: ntlm_print_flags(stderr, ntlm->flags);
327: fprintf(stderr, "\n nonce=");
328: ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
329: fprintf(stderr, "\n****\n");
330: fprintf(stderr, "**** Header %s\n ", header);
331: });
332:
333: free(type2);
334:
335: return result;
336: }
337:
338: /* copy the source to the destination and fill in zeroes in every
339: other destination byte! */
340: static void unicodecpy(unsigned char *dest, const char *src, size_t length)
341: {
342: size_t i;
343: for(i = 0; i < length; i++) {
344: dest[2 * i] = (unsigned char)src[i];
345: dest[2 * i + 1] = '\0';
346: }
347: }
348:
349: /*
350: * Curl_auth_create_ntlm_type1_message()
351: *
352: * This is used to generate an already encoded NTLM type-1 message ready for
353: * sending to the recipient using the appropriate compile time crypto API.
354: *
355: * Parameters:
356: *
357: * data [in] - The session handle.
358: * userp [in] - The user name in the format User or Domain\User.
359: * passwdp [in] - The user's password.
360: * service [in] - The service type such as http, smtp, pop or imap.
361: * host [in] - The host name.
362: * ntlm [in/out] - The NTLM data struct being used and modified.
363: * outptr [in/out] - The address where a pointer to newly allocated memory
364: * holding the result will be stored upon completion.
365: * outlen [out] - The length of the output message.
366: *
367: * Returns CURLE_OK on success.
368: */
369: CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
370: const char *userp,
371: const char *passwdp,
372: const char *service,
373: const char *hostname,
374: struct ntlmdata *ntlm,
375: char **outptr, size_t *outlen)
376: {
377: /* NTLM type-1 message structure:
378:
379: Index Description Content
380: 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
381: (0x4e544c4d53535000)
382: 8 NTLM Message Type long (0x01000000)
383: 12 Flags long
384: (16) Supplied Domain security buffer (*)
385: (24) Supplied Workstation security buffer (*)
386: (32) OS Version Structure 8 bytes (*)
387: (32) (40) Start of data block (*)
388: (*) -> Optional
389: */
390:
391: size_t size;
392:
393: unsigned char ntlmbuf[NTLM_BUFSIZE];
394: const char *host = ""; /* empty */
395: const char *domain = ""; /* empty */
396: size_t hostlen = 0;
397: size_t domlen = 0;
398: size_t hostoff = 0;
399: size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
400: domain are empty */
401: (void)userp;
402: (void)passwdp;
403: (void)service,
404: (void)hostname,
405:
406: /* Clean up any former leftovers and initialise to defaults */
407: Curl_auth_cleanup_ntlm(ntlm);
408:
409: #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
410: #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
411: #else
412: #define NTLM2FLAG 0
413: #endif
414: msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
415: NTLMSSP_SIGNATURE "%c"
416: "\x01%c%c%c" /* 32-bit type = 1 */
417: "%c%c%c%c" /* 32-bit NTLM flag field */
418: "%c%c" /* domain length */
419: "%c%c" /* domain allocated space */
420: "%c%c" /* domain name offset */
421: "%c%c" /* 2 zeroes */
422: "%c%c" /* host length */
423: "%c%c" /* host allocated space */
424: "%c%c" /* host name offset */
425: "%c%c" /* 2 zeroes */
426: "%s" /* host name */
427: "%s", /* domain string */
428: 0, /* trailing zero */
429: 0, 0, 0, /* part of type-1 long */
430:
431: LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
432: NTLMFLAG_REQUEST_TARGET |
433: NTLMFLAG_NEGOTIATE_NTLM_KEY |
434: NTLM2FLAG |
435: NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
436: SHORTPAIR(domlen),
437: SHORTPAIR(domlen),
438: SHORTPAIR(domoff),
439: 0, 0,
440: SHORTPAIR(hostlen),
441: SHORTPAIR(hostlen),
442: SHORTPAIR(hostoff),
443: 0, 0,
444: host, /* this is empty */
445: domain /* this is empty */);
446:
447: /* Initial packet length */
448: size = 32 + hostlen + domlen;
449:
450: DEBUG_OUT({
451: fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
452: "0x%08.8x ",
453: LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
454: NTLMFLAG_REQUEST_TARGET |
455: NTLMFLAG_NEGOTIATE_NTLM_KEY |
456: NTLM2FLAG |
457: NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
458: NTLMFLAG_NEGOTIATE_OEM |
459: NTLMFLAG_REQUEST_TARGET |
460: NTLMFLAG_NEGOTIATE_NTLM_KEY |
461: NTLM2FLAG |
462: NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
463: ntlm_print_flags(stderr,
464: NTLMFLAG_NEGOTIATE_OEM |
465: NTLMFLAG_REQUEST_TARGET |
466: NTLMFLAG_NEGOTIATE_NTLM_KEY |
467: NTLM2FLAG |
468: NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
469: fprintf(stderr, "\n****\n");
470: });
471:
472: /* Return with binary blob encoded into base64 */
473: return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
474: }
475:
476: /*
477: * Curl_auth_create_ntlm_type3_message()
478: *
479: * This is used to generate an already encoded NTLM type-3 message ready for
480: * sending to the recipient using the appropriate compile time crypto API.
481: *
482: * Parameters:
483: *
484: * data [in] - The session handle.
485: * userp [in] - The user name in the format User or Domain\User.
486: * passwdp [in] - The user's password.
487: * ntlm [in/out] - The NTLM data struct being used and modified.
488: * outptr [in/out] - The address where a pointer to newly allocated memory
489: * holding the result will be stored upon completion.
490: * outlen [out] - The length of the output message.
491: *
492: * Returns CURLE_OK on success.
493: */
494: CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
495: const char *userp,
496: const char *passwdp,
497: struct ntlmdata *ntlm,
498: char **outptr, size_t *outlen)
499:
500: {
501: /* NTLM type-3 message structure:
502:
503: Index Description Content
504: 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
505: (0x4e544c4d53535000)
506: 8 NTLM Message Type long (0x03000000)
507: 12 LM/LMv2 Response security buffer
508: 20 NTLM/NTLMv2 Response security buffer
509: 28 Target Name security buffer
510: 36 User Name security buffer
511: 44 Workstation Name security buffer
512: (52) Session Key security buffer (*)
513: (60) Flags long (*)
514: (64) OS Version Structure 8 bytes (*)
515: 52 (64) (72) Start of data block
516: (*) -> Optional
517: */
518:
519: CURLcode result = CURLE_OK;
520: size_t size;
521: unsigned char ntlmbuf[NTLM_BUFSIZE];
522: int lmrespoff;
523: unsigned char lmresp[24]; /* fixed-size */
524: #ifdef USE_NTRESPONSES
525: int ntrespoff;
526: unsigned int ntresplen = 24;
527: unsigned char ntresp[24]; /* fixed-size */
528: unsigned char *ptr_ntresp = &ntresp[0];
529: unsigned char *ntlmv2resp = NULL;
530: #endif
531: bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
532: char host[HOSTNAME_MAX + 1] = "";
533: const char *user;
534: const char *domain = "";
535: size_t hostoff = 0;
536: size_t useroff = 0;
537: size_t domoff = 0;
538: size_t hostlen = 0;
539: size_t userlen = 0;
540: size_t domlen = 0;
541:
542: user = strchr(userp, '\\');
543: if(!user)
544: user = strchr(userp, '/');
545:
546: if(user) {
547: domain = userp;
548: domlen = (user - domain);
549: user++;
550: }
551: else
552: user = userp;
553:
554: userlen = strlen(user);
555:
556: /* Get the machine's un-qualified host name as NTLM doesn't like the fully
557: qualified domain name */
558: if(Curl_gethostname(host, sizeof(host))) {
559: infof(data, "gethostname() failed, continuing without!\n");
560: hostlen = 0;
561: }
562: else {
563: hostlen = strlen(host);
564: }
565:
566: #if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
567: if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
568: unsigned char ntbuffer[0x18];
569: unsigned char entropy[8];
570: unsigned char ntlmv2hash[0x18];
571:
572: result = Curl_rand(data, entropy, 8);
573: if(result)
574: return result;
575:
576: result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
577: if(result)
578: return result;
579:
580: result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
581: ntbuffer, ntlmv2hash);
582: if(result)
583: return result;
584:
585: /* LMv2 response */
586: result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
587: &ntlm->nonce[0], lmresp);
588: if(result)
589: return result;
590:
591: /* NTLMv2 response */
592: result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
593: ntlm, &ntlmv2resp, &ntresplen);
594: if(result)
595: return result;
596:
597: ptr_ntresp = ntlmv2resp;
598: }
599: else
600: #endif
601:
602: #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
603: /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
604: if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
605: unsigned char ntbuffer[0x18];
606: unsigned char tmp[0x18];
607: unsigned char md5sum[MD5_DIGEST_LENGTH];
608: unsigned char entropy[8];
609:
610: /* Need to create 8 bytes random data */
611: result = Curl_rand(data, entropy, 8);
612: if(result)
613: return result;
614:
615: /* 8 bytes random data as challenge in lmresp */
616: memcpy(lmresp, entropy, 8);
617:
618: /* Pad with zeros */
619: memset(lmresp + 8, 0, 0x10);
620:
621: /* Fill tmp with challenge(nonce?) + entropy */
622: memcpy(tmp, &ntlm->nonce[0], 8);
623: memcpy(tmp + 8, entropy, 8);
624:
625: Curl_md5it(md5sum, tmp, 16);
626:
627: /* We shall only use the first 8 bytes of md5sum, but the des code in
628: Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
629: result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
630: if(result)
631: return result;
632:
633: Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
634:
635: /* End of NTLM2 Session code */
636: /* NTLM v2 session security is a misnomer because it is not NTLM v2.
637: It is NTLM v1 using the extended session security that is also
638: in NTLM v2 */
639: }
640: else
641: #endif
642: {
643:
644: #ifdef USE_NTRESPONSES
645: unsigned char ntbuffer[0x18];
646: #endif
647: unsigned char lmbuffer[0x18];
648:
649: #ifdef USE_NTRESPONSES
650: result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
651: if(result)
652: return result;
653:
654: Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
655: #endif
656:
657: result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
658: if(result)
659: return result;
660:
661: Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
662:
663: /* A safer but less compatible alternative is:
664: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
665: * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */
666: }
667:
668: if(unicode) {
669: domlen = domlen * 2;
670: userlen = userlen * 2;
671: hostlen = hostlen * 2;
672: }
673:
674: lmrespoff = 64; /* size of the message header */
675: #ifdef USE_NTRESPONSES
676: ntrespoff = lmrespoff + 0x18;
677: domoff = ntrespoff + ntresplen;
678: #else
679: domoff = lmrespoff + 0x18;
680: #endif
681: useroff = domoff + domlen;
682: hostoff = useroff + userlen;
683:
684: /* Create the big type-3 message binary blob */
685: size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
686: NTLMSSP_SIGNATURE "%c"
687: "\x03%c%c%c" /* 32-bit type = 3 */
688:
689: "%c%c" /* LanManager length */
690: "%c%c" /* LanManager allocated space */
691: "%c%c" /* LanManager offset */
692: "%c%c" /* 2 zeroes */
693:
694: "%c%c" /* NT-response length */
695: "%c%c" /* NT-response allocated space */
696: "%c%c" /* NT-response offset */
697: "%c%c" /* 2 zeroes */
698:
699: "%c%c" /* domain length */
700: "%c%c" /* domain allocated space */
701: "%c%c" /* domain name offset */
702: "%c%c" /* 2 zeroes */
703:
704: "%c%c" /* user length */
705: "%c%c" /* user allocated space */
706: "%c%c" /* user offset */
707: "%c%c" /* 2 zeroes */
708:
709: "%c%c" /* host length */
710: "%c%c" /* host allocated space */
711: "%c%c" /* host offset */
712: "%c%c" /* 2 zeroes */
713:
714: "%c%c" /* session key length (unknown purpose) */
715: "%c%c" /* session key allocated space (unknown purpose) */
716: "%c%c" /* session key offset (unknown purpose) */
717: "%c%c" /* 2 zeroes */
718:
719: "%c%c%c%c", /* flags */
720:
721: /* domain string */
722: /* user string */
723: /* host string */
724: /* LanManager response */
725: /* NT response */
726:
727: 0, /* zero termination */
728: 0, 0, 0, /* type-3 long, the 24 upper bits */
729:
730: SHORTPAIR(0x18), /* LanManager response length, twice */
731: SHORTPAIR(0x18),
732: SHORTPAIR(lmrespoff),
733: 0x0, 0x0,
734:
735: #ifdef USE_NTRESPONSES
736: SHORTPAIR(ntresplen), /* NT-response length, twice */
737: SHORTPAIR(ntresplen),
738: SHORTPAIR(ntrespoff),
739: 0x0, 0x0,
740: #else
741: 0x0, 0x0,
742: 0x0, 0x0,
743: 0x0, 0x0,
744: 0x0, 0x0,
745: #endif
746: SHORTPAIR(domlen),
747: SHORTPAIR(domlen),
748: SHORTPAIR(domoff),
749: 0x0, 0x0,
750:
751: SHORTPAIR(userlen),
752: SHORTPAIR(userlen),
753: SHORTPAIR(useroff),
754: 0x0, 0x0,
755:
756: SHORTPAIR(hostlen),
757: SHORTPAIR(hostlen),
758: SHORTPAIR(hostoff),
759: 0x0, 0x0,
760:
761: 0x0, 0x0,
762: 0x0, 0x0,
763: 0x0, 0x0,
764: 0x0, 0x0,
765:
766: LONGQUARTET(ntlm->flags));
767:
768: DEBUGASSERT(size == 64);
769: DEBUGASSERT(size == (size_t)lmrespoff);
770:
771: /* We append the binary hashes */
772: if(size < (NTLM_BUFSIZE - 0x18)) {
773: memcpy(&ntlmbuf[size], lmresp, 0x18);
774: size += 0x18;
775: }
776:
777: DEBUG_OUT({
778: fprintf(stderr, "**** TYPE3 header lmresp=");
779: ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
780: });
781:
782: #ifdef USE_NTRESPONSES
783: /* ntresplen + size should not be risking an integer overflow here */
784: if(ntresplen + size > sizeof(ntlmbuf)) {
785: failf(data, "incoming NTLM message too big");
786: return CURLE_OUT_OF_MEMORY;
787: }
788: DEBUGASSERT(size == (size_t)ntrespoff);
789: memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
790: size += ntresplen;
791:
792: DEBUG_OUT({
793: fprintf(stderr, "\n ntresp=");
794: ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
795: });
796:
797: free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
798:
799: #endif
800:
801: DEBUG_OUT({
802: fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
803: LONGQUARTET(ntlm->flags), ntlm->flags);
804: ntlm_print_flags(stderr, ntlm->flags);
805: fprintf(stderr, "\n****\n");
806: });
807:
808: /* Make sure that the domain, user and host strings fit in the
809: buffer before we copy them there. */
810: if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
811: failf(data, "user + domain + host name too big");
812: return CURLE_OUT_OF_MEMORY;
813: }
814:
815: DEBUGASSERT(size == domoff);
816: if(unicode)
817: unicodecpy(&ntlmbuf[size], domain, domlen / 2);
818: else
819: memcpy(&ntlmbuf[size], domain, domlen);
820:
821: size += domlen;
822:
823: DEBUGASSERT(size == useroff);
824: if(unicode)
825: unicodecpy(&ntlmbuf[size], user, userlen / 2);
826: else
827: memcpy(&ntlmbuf[size], user, userlen);
828:
829: size += userlen;
830:
831: DEBUGASSERT(size == hostoff);
832: if(unicode)
833: unicodecpy(&ntlmbuf[size], host, hostlen / 2);
834: else
835: memcpy(&ntlmbuf[size], host, hostlen);
836:
837: size += hostlen;
838:
839: /* Convert domain, user, and host to ASCII but leave the rest as-is */
840: result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
841: size - domoff);
842: if(result)
843: return CURLE_CONV_FAILED;
844:
845: /* Return with binary blob encoded into base64 */
846: result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
847:
848: Curl_auth_cleanup_ntlm(ntlm);
849:
850: return result;
851: }
852:
853: /*
854: * Curl_auth_cleanup_ntlm()
855: *
856: * This is used to clean up the NTLM specific data.
857: *
858: * Parameters:
859: *
860: * ntlm [in/out] - The NTLM data struct being cleaned up.
861: *
862: */
863: void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
864: {
865: /* Free the target info */
866: Curl_safefree(ntlm->target_info);
867:
868: /* Reset any variables */
869: ntlm->target_info_len = 0;
870: }
871:
872: #endif /* USE_NTLM && !USE_WINDOWS_SSPI */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>