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