1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2014, 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 http://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#ifdef USE_NTLM
26
27/*
28 * NTLM details:
29 *
30 * http://davenport.sourceforge.net/ntlm.html
31 * http://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 "warnless.h"
44#include "curl_memory.h"
45
46#ifdef USE_WINDOWS_SSPI
47#  include "curl_sspi.h"
48#endif
49
50#include "vtls/vtls.h"
51
52#define BUILDING_CURL_NTLM_MSGS_C
53#include "curl_ntlm_msgs.h"
54
55#define _MPRINTF_REPLACE /* use our functions only */
56#include <curl/mprintf.h>
57
58/* The last #include file should be: */
59#include "memdebug.h"
60
61/* "NTLMSSP" signature is always in ASCII regardless of the platform */
62#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
63
64#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
65#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
66  (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
67
68#if DEBUG_ME
69# define DEBUG_OUT(x) x
70static void ntlm_print_flags(FILE *handle, unsigned long flags)
71{
72  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
73    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
74  if(flags & NTLMFLAG_NEGOTIATE_OEM)
75    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
76  if(flags & NTLMFLAG_REQUEST_TARGET)
77    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
78  if(flags & (1<<3))
79    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
80  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
81    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
82  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
83    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
84  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
85    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
86  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
87    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
88  if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
89    fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
90  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
91    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
92  if(flags & (1<<10))
93    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
94  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
95    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
96  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
97    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
98  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
99    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
100  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
101    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
102  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
103    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
104  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
105    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
106  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
107    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
108  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
109    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
110  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
111    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
112  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
113    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
114  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
115    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
116  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
117    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
118  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
119    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
120  if(flags & (1<<24))
121    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
122  if(flags & (1<<25))
123    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
124  if(flags & (1<<26))
125    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
126  if(flags & (1<<27))
127    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
128  if(flags & (1<<28))
129    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
130  if(flags & NTLMFLAG_NEGOTIATE_128)
131    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
132  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
133    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
134  if(flags & NTLMFLAG_NEGOTIATE_56)
135    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
136}
137
138static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
139{
140  const char *p = buf;
141  (void)handle;
142  fprintf(stderr, "0x");
143  while(len-- > 0)
144    fprintf(stderr, "%02.2x", (unsigned int)*p++);
145}
146#else
147# define DEBUG_OUT(x) Curl_nop_stmt
148#endif
149
150#ifndef USE_WINDOWS_SSPI
151/*
152 * This function converts from the little endian format used in the
153 * incoming package to whatever endian format we're using natively.
154 * Argument is a pointer to a 4 byte buffer.
155 */
156static unsigned int readint_le(unsigned char *buf)
157{
158  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
159    ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
160}
161
162/*
163 * This function converts from the little endian format used in the incoming
164 * package to whatever endian format we're using natively. Argument is a
165 * pointer to a 2 byte buffer.
166 */
167static unsigned int readshort_le(unsigned char *buf)
168{
169  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8);
170}
171
172/*
173 * Curl_ntlm_decode_type2_target()
174 *
175 * This is used to decode the "target info" in the ntlm type-2 message
176 * received.
177 *
178 * Parameters:
179 *
180 * data      [in]    - Pointer to the session handle
181 * buffer    [in]    - The decoded base64 ntlm header of Type 2
182 * size      [in]    - The input buffer size, atleast 32 bytes
183 * ntlm      [in]    - Pointer to ntlm data struct being used and modified.
184 *
185 * Returns CURLE_OK on success.
186 */
187CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data,
188                                       unsigned char *buffer,
189                                       size_t size,
190                                       struct ntlmdata *ntlm)
191{
192  unsigned int target_info_len = 0;
193  unsigned int target_info_offset = 0;
194
195  Curl_safefree(ntlm->target_info);
196  ntlm->target_info_len = 0;
197
198  if(size >= 48) {
199    target_info_len = readshort_le(&buffer[40]);
200    target_info_offset = readint_le(&buffer[44]);
201    if(target_info_len > 0) {
202      if(((target_info_offset + target_info_len) > size) ||
203         (target_info_offset < 48)) {
204        infof(data, "NTLM handshake failure (bad type-2 message). "
205                    "Target Info Offset Len is set incorrect by the peer\n");
206        return CURLE_REMOTE_ACCESS_DENIED;
207      }
208
209      ntlm->target_info = malloc(target_info_len);
210      if(!ntlm->target_info)
211        return CURLE_OUT_OF_MEMORY;
212
213      memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len);
214      ntlm->target_info_len = target_info_len;
215
216    }
217
218  }
219
220  return CURLE_OK;
221}
222
223#endif
224
225/*
226  NTLM message structure notes:
227
228  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
229
230  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
231
232  A 'security buffer' represents a triplet used to point to a buffer,
233  consisting of two shorts and one long:
234
235    1. A 'short' containing the length of the buffer content in bytes.
236    2. A 'short' containing the allocated space for the buffer in bytes.
237    3. A 'long' containing the offset to the start of the buffer in bytes,
238       from the beginning of the NTLM message.
239*/
240
241/*
242 * Curl_ntlm_decode_type2_message()
243 *
244 * This is used to decode a ntlm type-2 message received from a HTTP or SASL
245 * based (such as SMTP, POP3 or IMAP) server. The message is first decoded
246 * from a base64 string into a raw ntlm message and checked for validity
247 * before the appropriate data for creating a type-3 message is written to
248 * the given ntlm data structure.
249 *
250 * Parameters:
251 *
252 * data    [in]     - Pointer to session handle.
253 * header  [in]     - Pointer to the input buffer.
254 * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
255 *
256 * Returns CURLE_OK on success.
257 */
258CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
259                                        const char *header,
260                                        struct ntlmdata *ntlm)
261{
262#ifndef USE_WINDOWS_SSPI
263  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
264#endif
265
266  /* NTLM type-2 message structure:
267
268          Index  Description            Content
269            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
270                                        (0x4e544c4d53535000)
271            8    NTLM Message Type      long (0x02000000)
272           12    Target Name            security buffer
273           20    Flags                  long
274           24    Challenge              8 bytes
275          (32)   Context                8 bytes (two consecutive longs) (*)
276          (40)   Target Information     security buffer (*)
277          (48)   OS Version Structure   8 bytes (*)
278  32 (48) (56)   Start of data block    (*)
279                                        (*) -> Optional
280  */
281
282  size_t size = 0;
283  unsigned char *buffer = NULL;
284  CURLcode error;
285
286#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
287  (void)data;
288#endif
289
290  error = Curl_base64_decode(header, &buffer, &size);
291  if(error)
292    return error;
293
294  if(!buffer) {
295    infof(data, "NTLM handshake failure (unhandled condition)\n");
296    return CURLE_REMOTE_ACCESS_DENIED;
297  }
298
299#ifdef USE_WINDOWS_SSPI
300  ntlm->type_2 = malloc(size + 1);
301  if(ntlm->type_2 == NULL) {
302    free(buffer);
303    return CURLE_OUT_OF_MEMORY;
304  }
305  ntlm->n_type_2 = curlx_uztoul(size);
306  memcpy(ntlm->type_2, buffer, size);
307#else
308  ntlm->flags = 0;
309
310  if((size < 32) ||
311     (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
312     (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
313    /* This was not a good enough type-2 message */
314    free(buffer);
315    infof(data, "NTLM handshake failure (bad type-2 message)\n");
316    return CURLE_REMOTE_ACCESS_DENIED;
317  }
318
319  ntlm->flags = readint_le(&buffer[20]);
320  memcpy(ntlm->nonce, &buffer[24], 8);
321
322  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
323    error = Curl_ntlm_decode_type2_target(data, buffer, size, ntlm);
324    if(error) {
325      free(buffer);
326      infof(data, "NTLM handshake failure (bad type-2 message)\n");
327      return error;
328    }
329  }
330
331  DEBUG_OUT({
332    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
333    ntlm_print_flags(stderr, ntlm->flags);
334    fprintf(stderr, "\n                  nonce=");
335    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
336    fprintf(stderr, "\n****\n");
337    fprintf(stderr, "**** Header %s\n ", header);
338  });
339#endif
340  free(buffer);
341
342  return CURLE_OK;
343}
344
345#ifdef USE_WINDOWS_SSPI
346void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
347{
348  Curl_safefree(ntlm->type_2);
349  if(ntlm->has_handles) {
350    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
351    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
352    ntlm->has_handles = 0;
353  }
354  if(ntlm->p_identity) {
355    Curl_safefree(ntlm->identity.User);
356    Curl_safefree(ntlm->identity.Password);
357    Curl_safefree(ntlm->identity.Domain);
358    ntlm->p_identity = NULL;
359  }
360}
361#endif
362
363#ifndef USE_WINDOWS_SSPI
364/* copy the source to the destination and fill in zeroes in every
365   other destination byte! */
366static void unicodecpy(unsigned char *dest, const char *src, size_t length)
367{
368  size_t i;
369  for(i = 0; i < length; i++) {
370    dest[2 * i] = (unsigned char)src[i];
371    dest[2 * i + 1] = '\0';
372  }
373}
374#endif
375
376/*
377 * Curl_ntlm_create_type1_message()
378 *
379 * This is used to generate an already encoded NTLM type-1 message ready for
380 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
381 * or IMAP) server, using the appropriate compile time crypo API.
382 *
383 * Parameters:
384 *
385 * userp   [in]     - The user name in the format User or Domain\User.
386 * passdwp [in]     - The user's password.
387 * ntlm    [in/out] - The ntlm data struct being used and modified.
388 * outptr  [in/out] - The address where a pointer to newly allocated memory
389 *                    holding the result will be stored upon completion.
390 * outlen  [out]    - The length of the output message.
391 *
392 * Returns CURLE_OK on success.
393 */
394CURLcode Curl_ntlm_create_type1_message(const char *userp,
395                                        const char *passwdp,
396                                        struct ntlmdata *ntlm,
397                                        char **outptr,
398                                        size_t *outlen)
399{
400  /* NTLM type-1 message structure:
401
402       Index  Description            Content
403         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
404                                     (0x4e544c4d53535000)
405         8    NTLM Message Type      long (0x01000000)
406        12    Flags                  long
407       (16)   Supplied Domain        security buffer (*)
408       (24)   Supplied Workstation   security buffer (*)
409       (32)   OS Version Structure   8 bytes (*)
410  (32) (40)   Start of data block    (*)
411                                     (*) -> Optional
412  */
413
414  unsigned char ntlmbuf[NTLM_BUFSIZE];
415  size_t size;
416
417#ifdef USE_WINDOWS_SSPI
418
419  SecBuffer buf;
420  SecBufferDesc desc;
421  SECURITY_STATUS status;
422  unsigned long attrs;
423  xcharp_u useranddomain;
424  xcharp_u user, dup_user;
425  xcharp_u domain, dup_domain;
426  xcharp_u passwd, dup_passwd;
427  size_t domlen = 0;
428  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
429
430  domain.const_tchar_ptr = TEXT("");
431
432  Curl_ntlm_sspi_cleanup(ntlm);
433
434  if(userp && *userp) {
435
436    /* null initialize ntlm identity's data to allow proper cleanup */
437    ntlm->p_identity = &ntlm->identity;
438    memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
439
440    useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
441    if(!useranddomain.tchar_ptr)
442      return CURLE_OUT_OF_MEMORY;
443
444    user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
445    if(!user.const_tchar_ptr)
446      user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
447
448    if(user.tchar_ptr) {
449      domain.tchar_ptr = useranddomain.tchar_ptr;
450      domlen = user.tchar_ptr - useranddomain.tchar_ptr;
451      user.tchar_ptr++;
452    }
453    else {
454      user.tchar_ptr = useranddomain.tchar_ptr;
455      domain.const_tchar_ptr = TEXT("");
456      domlen = 0;
457    }
458
459    /* setup ntlm identity's user and length */
460    dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
461    if(!dup_user.tchar_ptr) {
462      Curl_unicodefree(useranddomain.tchar_ptr);
463      return CURLE_OUT_OF_MEMORY;
464    }
465    ntlm->identity.User = dup_user.tbyte_ptr;
466    ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
467    dup_user.tchar_ptr = NULL;
468
469    /* setup ntlm identity's domain and length */
470    dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
471    if(!dup_domain.tchar_ptr) {
472      Curl_unicodefree(useranddomain.tchar_ptr);
473      return CURLE_OUT_OF_MEMORY;
474    }
475    _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
476    *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
477    ntlm->identity.Domain = dup_domain.tbyte_ptr;
478    ntlm->identity.DomainLength = curlx_uztoul(domlen);
479    dup_domain.tchar_ptr = NULL;
480
481    Curl_unicodefree(useranddomain.tchar_ptr);
482
483    /* setup ntlm identity's password and length */
484    passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
485    if(!passwd.tchar_ptr)
486      return CURLE_OUT_OF_MEMORY;
487    dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
488    if(!dup_passwd.tchar_ptr) {
489      Curl_unicodefree(passwd.tchar_ptr);
490      return CURLE_OUT_OF_MEMORY;
491    }
492    ntlm->identity.Password = dup_passwd.tbyte_ptr;
493    ntlm->identity.PasswordLength =
494      curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
495    dup_passwd.tchar_ptr = NULL;
496
497    Curl_unicodefree(passwd.tchar_ptr);
498
499    /* setup ntlm identity's flags */
500    ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY;
501  }
502  else
503    ntlm->p_identity = NULL;
504
505  status = s_pSecFn->AcquireCredentialsHandle(NULL,
506                                              (TCHAR *) TEXT("NTLM"),
507                                              SECPKG_CRED_OUTBOUND, NULL,
508                                              ntlm->p_identity, NULL, NULL,
509                                              &ntlm->handle, &tsDummy);
510  if(status != SEC_E_OK)
511    return CURLE_OUT_OF_MEMORY;
512
513  desc.ulVersion = SECBUFFER_VERSION;
514  desc.cBuffers  = 1;
515  desc.pBuffers  = &buf;
516  buf.cbBuffer   = NTLM_BUFSIZE;
517  buf.BufferType = SECBUFFER_TOKEN;
518  buf.pvBuffer   = ntlmbuf;
519
520  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
521                                               (TCHAR *) TEXT(""),
522                                               ISC_REQ_CONFIDENTIALITY |
523                                               ISC_REQ_REPLAY_DETECT |
524                                               ISC_REQ_CONNECTION,
525                                               0, SECURITY_NETWORK_DREP,
526                                               NULL, 0,
527                                               &ntlm->c_handle, &desc,
528                                               &attrs, &tsDummy);
529
530  if(status == SEC_I_COMPLETE_AND_CONTINUE ||
531     status == SEC_I_CONTINUE_NEEDED)
532    s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
533  else if(status != SEC_E_OK) {
534    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
535    return CURLE_RECV_ERROR;
536  }
537
538  ntlm->has_handles = 1;
539  size = buf.cbBuffer;
540
541#else
542
543  const char *host = "";              /* empty */
544  const char *domain = "";            /* empty */
545  size_t hostlen = 0;
546  size_t domlen = 0;
547  size_t hostoff = 0;
548  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
549                                         domain are empty */
550  (void)userp;
551  (void)passwdp;
552  (void)ntlm;
553
554#if USE_NTLM2SESSION
555#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
556#else
557#define NTLM2FLAG 0
558#endif
559  snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
560           NTLMSSP_SIGNATURE "%c"
561           "\x01%c%c%c" /* 32-bit type = 1 */
562           "%c%c%c%c"   /* 32-bit NTLM flag field */
563           "%c%c"       /* domain length */
564           "%c%c"       /* domain allocated space */
565           "%c%c"       /* domain name offset */
566           "%c%c"       /* 2 zeroes */
567           "%c%c"       /* host length */
568           "%c%c"       /* host allocated space */
569           "%c%c"       /* host name offset */
570           "%c%c"       /* 2 zeroes */
571           "%s"         /* host name */
572           "%s",        /* domain string */
573           0,           /* trailing zero */
574           0, 0, 0,     /* part of type-1 long */
575
576           LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
577                       NTLMFLAG_REQUEST_TARGET |
578                       NTLMFLAG_NEGOTIATE_NTLM_KEY |
579                       NTLM2FLAG |
580                       NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
581           SHORTPAIR(domlen),
582           SHORTPAIR(domlen),
583           SHORTPAIR(domoff),
584           0, 0,
585           SHORTPAIR(hostlen),
586           SHORTPAIR(hostlen),
587           SHORTPAIR(hostoff),
588           0, 0,
589           host,  /* this is empty */
590           domain /* this is empty */);
591
592  /* Initial packet length */
593  size = 32 + hostlen + domlen;
594
595#endif
596
597  DEBUG_OUT({
598    fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
599            "0x%08.8x ",
600            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
601                        NTLMFLAG_REQUEST_TARGET |
602                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
603                        NTLM2FLAG |
604                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
605            NTLMFLAG_NEGOTIATE_OEM |
606            NTLMFLAG_REQUEST_TARGET |
607            NTLMFLAG_NEGOTIATE_NTLM_KEY |
608            NTLM2FLAG |
609            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
610    ntlm_print_flags(stderr,
611                     NTLMFLAG_NEGOTIATE_OEM |
612                     NTLMFLAG_REQUEST_TARGET |
613                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
614                     NTLM2FLAG |
615                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
616    fprintf(stderr, "\n****\n");
617  });
618
619  /* Return with binary blob encoded into base64 */
620  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
621}
622
623/*
624 * Curl_ntlm_create_type3_message()
625 *
626 * This is used to generate an already encoded NTLM type-3 message ready for
627 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
628 * or IMAP) server, using the appropriate compile time crypo API.
629 *
630 * Parameters:
631 *
632 * data    [in]     - The session handle.
633 * userp   [in]     - The user name in the format User or Domain\User.
634 * passdwp [in]     - The user's password.
635 * ntlm    [in/out] - The ntlm data struct being used and modified.
636 * outptr  [in/out] - The address where a pointer to newly allocated memory
637 *                    holding the result will be stored upon completion.
638 * outlen  [out]    - The length of the output message.
639 *
640 * Returns CURLE_OK on success.
641 */
642CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
643                                        const char *userp,
644                                        const char *passwdp,
645                                        struct ntlmdata *ntlm,
646                                        char **outptr,
647                                        size_t *outlen)
648{
649  /* NTLM type-3 message structure:
650
651          Index  Description            Content
652            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
653                                        (0x4e544c4d53535000)
654            8    NTLM Message Type      long (0x03000000)
655           12    LM/LMv2 Response       security buffer
656           20    NTLM/NTLMv2 Response   security buffer
657           28    Target Name            security buffer
658           36    User Name              security buffer
659           44    Workstation Name       security buffer
660          (52)   Session Key            security buffer (*)
661          (60)   Flags                  long (*)
662          (64)   OS Version Structure   8 bytes (*)
663  52 (64) (72)   Start of data block
664                                          (*) -> Optional
665  */
666
667  unsigned char ntlmbuf[NTLM_BUFSIZE];
668  size_t size;
669
670#ifdef USE_WINDOWS_SSPI
671  SecBuffer type_2;
672  SecBuffer type_3;
673  SecBufferDesc type_2_desc;
674  SecBufferDesc type_3_desc;
675  SECURITY_STATUS status;
676  unsigned long attrs;
677  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
678
679  (void)passwdp;
680  (void)userp;
681  (void)data;
682
683  type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
684  type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
685  type_2_desc.pBuffers  = &type_2;
686  type_3_desc.pBuffers  = &type_3;
687
688  type_2.BufferType = SECBUFFER_TOKEN;
689  type_2.pvBuffer   = ntlm->type_2;
690  type_2.cbBuffer   = ntlm->n_type_2;
691  type_3.BufferType = SECBUFFER_TOKEN;
692  type_3.pvBuffer   = ntlmbuf;
693  type_3.cbBuffer   = NTLM_BUFSIZE;
694
695  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
696                                               &ntlm->c_handle,
697                                               (TCHAR *) TEXT(""),
698                                               ISC_REQ_CONFIDENTIALITY |
699                                               ISC_REQ_REPLAY_DETECT |
700                                               ISC_REQ_CONNECTION,
701                                               0, SECURITY_NETWORK_DREP,
702                                               &type_2_desc,
703                                               0, &ntlm->c_handle,
704                                               &type_3_desc,
705                                               &attrs, &tsDummy);
706  if(status != SEC_E_OK)
707    return CURLE_RECV_ERROR;
708
709  size = type_3.cbBuffer;
710
711  Curl_ntlm_sspi_cleanup(ntlm);
712
713#else
714  int lmrespoff;
715  unsigned char lmresp[24]; /* fixed-size */
716#if USE_NTRESPONSES
717  int ntrespoff;
718  unsigned int ntresplen = 24;
719  unsigned char ntresp[24]; /* fixed-size */
720  unsigned char *ptr_ntresp = &ntresp[0];
721  unsigned char *ntlmv2resp = NULL;
722#endif
723  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
724  char host[HOSTNAME_MAX + 1] = "";
725  const char *user;
726  const char *domain = "";
727  size_t hostoff = 0;
728  size_t useroff = 0;
729  size_t domoff = 0;
730  size_t hostlen = 0;
731  size_t userlen = 0;
732  size_t domlen = 0;
733  CURLcode res = CURLE_OK;
734
735  user = strchr(userp, '\\');
736  if(!user)
737    user = strchr(userp, '/');
738
739  if(user) {
740    domain = userp;
741    domlen = (user - domain);
742    user++;
743  }
744  else
745    user = userp;
746
747  if(user)
748    userlen = strlen(user);
749
750  /* Get the machine's un-qualified host name as NTLM doesn't like the fully
751     qualified domain name */
752  if(Curl_gethostname(host, sizeof(host))) {
753    infof(data, "gethostname() failed, continuing without!\n");
754    hostlen = 0;
755  }
756  else {
757    hostlen = strlen(host);
758  }
759
760#if USE_NTRESPONSES
761  if(ntlm->target_info_len) {
762    unsigned char ntbuffer[0x18];
763    unsigned char entropy[8];
764    unsigned char ntlmv2hash[0x18];
765
766#if defined(DEBUGBUILD)
767    /* Use static client nonce in debug (Test Suite) builds */
768    memcpy(entropy, "12345678", sizeof(entropy));
769#else
770    /* Create an 8 byte random client nonce */
771    Curl_ssl_random(data, entropy, sizeof(entropy));
772#endif
773
774    res = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
775    if(res)
776      return res;
777
778    res = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
779                                        ntbuffer, ntlmv2hash);
780    if(res)
781      return res;
782
783    /* LMv2 response */
784    res = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, &ntlm->nonce[0],
785                                      lmresp);
786    if(res)
787      return res;
788
789    /* NTLMv2 response */
790    res = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, ntlm, &ntlmv2resp,
791                                        &ntresplen);
792    if(res)
793      return res;
794
795    ptr_ntresp = ntlmv2resp;
796  }
797  else
798#endif
799
800#if USE_NTLM2SESSION
801  /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
802  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
803    unsigned char ntbuffer[0x18];
804    unsigned char tmp[0x18];
805    unsigned char md5sum[MD5_DIGEST_LENGTH];
806    unsigned char entropy[8];
807
808    /* Need to create 8 bytes random data */
809    Curl_ssl_random(data, entropy, sizeof(entropy));
810
811    /* 8 bytes random data as challenge in lmresp */
812    memcpy(lmresp, entropy, 8);
813
814    /* Pad with zeros */
815    memset(lmresp + 8, 0, 0x10);
816
817    /* Fill tmp with challenge(nonce?) + entropy */
818    memcpy(tmp, &ntlm->nonce[0], 8);
819    memcpy(tmp + 8, entropy, 8);
820
821    Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
822
823    /* We shall only use the first 8 bytes of md5sum, but the des
824       code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
825    if(CURLE_OUT_OF_MEMORY ==
826       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
827      return CURLE_OUT_OF_MEMORY;
828
829    Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
830
831    /* End of NTLM2 Session code */
832
833  }
834  else
835#endif
836  {
837
838#if USE_NTRESPONSES
839    unsigned char ntbuffer[0x18];
840#endif
841    unsigned char lmbuffer[0x18];
842
843#if USE_NTRESPONSES
844    if(CURLE_OUT_OF_MEMORY ==
845       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
846      return CURLE_OUT_OF_MEMORY;
847    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
848#endif
849
850    Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
851    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
852    /* A safer but less compatible alternative is:
853     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
854     * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
855  }
856
857  if(unicode) {
858    domlen = domlen * 2;
859    userlen = userlen * 2;
860    hostlen = hostlen * 2;
861  }
862
863  lmrespoff = 64; /* size of the message header */
864#if USE_NTRESPONSES
865  ntrespoff = lmrespoff + 0x18;
866  domoff = ntrespoff + ntresplen;
867#else
868  domoff = lmrespoff + 0x18;
869#endif
870  useroff = domoff + domlen;
871  hostoff = useroff + userlen;
872
873  /* Create the big type-3 message binary blob */
874  size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
875                  NTLMSSP_SIGNATURE "%c"
876                  "\x03%c%c%c"  /* 32-bit type = 3 */
877
878                  "%c%c"  /* LanManager length */
879                  "%c%c"  /* LanManager allocated space */
880                  "%c%c"  /* LanManager offset */
881                  "%c%c"  /* 2 zeroes */
882
883                  "%c%c"  /* NT-response length */
884                  "%c%c"  /* NT-response allocated space */
885                  "%c%c"  /* NT-response offset */
886                  "%c%c"  /* 2 zeroes */
887
888                  "%c%c"  /* domain length */
889                  "%c%c"  /* domain allocated space */
890                  "%c%c"  /* domain name offset */
891                  "%c%c"  /* 2 zeroes */
892
893                  "%c%c"  /* user length */
894                  "%c%c"  /* user allocated space */
895                  "%c%c"  /* user offset */
896                  "%c%c"  /* 2 zeroes */
897
898                  "%c%c"  /* host length */
899                  "%c%c"  /* host allocated space */
900                  "%c%c"  /* host offset */
901                  "%c%c"  /* 2 zeroes */
902
903                  "%c%c"  /* session key length (unknown purpose) */
904                  "%c%c"  /* session key allocated space (unknown purpose) */
905                  "%c%c"  /* session key offset (unknown purpose) */
906                  "%c%c"  /* 2 zeroes */
907
908                  "%c%c%c%c",  /* flags */
909
910                  /* domain string */
911                  /* user string */
912                  /* host string */
913                  /* LanManager response */
914                  /* NT response */
915
916                  0,                /* zero termination */
917                  0, 0, 0,          /* type-3 long, the 24 upper bits */
918
919                  SHORTPAIR(0x18),  /* LanManager response length, twice */
920                  SHORTPAIR(0x18),
921                  SHORTPAIR(lmrespoff),
922                  0x0, 0x0,
923
924#if USE_NTRESPONSES
925                  SHORTPAIR(ntresplen),  /* NT-response length, twice */
926                  SHORTPAIR(ntresplen),
927                  SHORTPAIR(ntrespoff),
928                  0x0, 0x0,
929#else
930                  0x0, 0x0,
931                  0x0, 0x0,
932                  0x0, 0x0,
933                  0x0, 0x0,
934#endif
935                  SHORTPAIR(domlen),
936                  SHORTPAIR(domlen),
937                  SHORTPAIR(domoff),
938                  0x0, 0x0,
939
940                  SHORTPAIR(userlen),
941                  SHORTPAIR(userlen),
942                  SHORTPAIR(useroff),
943                  0x0, 0x0,
944
945                  SHORTPAIR(hostlen),
946                  SHORTPAIR(hostlen),
947                  SHORTPAIR(hostoff),
948                  0x0, 0x0,
949
950                  0x0, 0x0,
951                  0x0, 0x0,
952                  0x0, 0x0,
953                  0x0, 0x0,
954
955                  LONGQUARTET(ntlm->flags));
956
957  DEBUGASSERT(size == 64);
958  DEBUGASSERT(size == (size_t)lmrespoff);
959
960  /* We append the binary hashes */
961  if(size < (NTLM_BUFSIZE - 0x18)) {
962    memcpy(&ntlmbuf[size], lmresp, 0x18);
963    size += 0x18;
964  }
965
966  DEBUG_OUT({
967    fprintf(stderr, "**** TYPE3 header lmresp=");
968    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
969  });
970
971#if USE_NTRESPONSES
972  if(size < (NTLM_BUFSIZE - ntresplen)) {
973    DEBUGASSERT(size == (size_t)ntrespoff);
974    memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
975    size += ntresplen;
976  }
977
978  DEBUG_OUT({
979    fprintf(stderr, "\n   ntresp=");
980    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
981  });
982
983  Curl_safefree(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
984
985#endif
986
987  DEBUG_OUT({
988    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
989            LONGQUARTET(ntlm->flags), ntlm->flags);
990    ntlm_print_flags(stderr, ntlm->flags);
991    fprintf(stderr, "\n****\n");
992  });
993
994  /* Make sure that the domain, user and host strings fit in the
995     buffer before we copy them there. */
996  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
997    failf(data, "user + domain + host name too big");
998    return CURLE_OUT_OF_MEMORY;
999  }
1000
1001  DEBUGASSERT(size == domoff);
1002  if(unicode)
1003    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
1004  else
1005    memcpy(&ntlmbuf[size], domain, domlen);
1006
1007  size += domlen;
1008
1009  DEBUGASSERT(size == useroff);
1010  if(unicode)
1011    unicodecpy(&ntlmbuf[size], user, userlen / 2);
1012  else
1013    memcpy(&ntlmbuf[size], user, userlen);
1014
1015  size += userlen;
1016
1017  DEBUGASSERT(size == hostoff);
1018  if(unicode)
1019    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
1020  else
1021    memcpy(&ntlmbuf[size], host, hostlen);
1022
1023  size += hostlen;
1024
1025  /* Convert domain, user, and host to ASCII but leave the rest as-is */
1026  res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
1027                                size - domoff);
1028  if(res)
1029    return CURLE_CONV_FAILED;
1030
1031#endif
1032
1033  /* Return with binary blob encoded into base64 */
1034  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
1035}
1036
1037#endif /* USE_NTLM */
1038