1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, 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 "sslgen.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#endif
162
163/*
164  NTLM message structure notes:
165
166  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
167
168  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
169
170  A 'security buffer' represents a triplet used to point to a buffer,
171  consisting of two shorts and one long:
172
173    1. A 'short' containing the length of the buffer content in bytes.
174    2. A 'short' containing the allocated space for the buffer in bytes.
175    3. A 'long' containing the offset to the start of the buffer in bytes,
176       from the beginning of the NTLM message.
177*/
178
179/*
180 * Curl_ntlm_decode_type2_message()
181 *
182 * This is used to decode a ntlm type-2 message received from a HTTP or SASL
183 * based (such as SMTP, POP3 or IMAP) server. The message is first decoded
184 * from a base64 string into a raw ntlm message and checked for validity
185 * before the appropriate data for creating a type-3 message is written to
186 * the given ntlm data structure.
187 *
188 * Parameters:
189 *
190 * data    [in]     - Pointer to session handle.
191 * header  [in]     - Pointer to the input buffer.
192 * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
193 *
194 * Returns CURLE_OK on success.
195 */
196CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
197                                        const char* header,
198                                        struct ntlmdata* ntlm)
199{
200#ifndef USE_WINDOWS_SSPI
201  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
202#endif
203
204  /* NTLM type-2 message structure:
205
206          Index  Description            Content
207            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
208                                        (0x4e544c4d53535000)
209            8    NTLM Message Type      long (0x02000000)
210           12    Target Name            security buffer
211           20    Flags                  long
212           24    Challenge              8 bytes
213          (32)   Context                8 bytes (two consecutive longs) (*)
214          (40)   Target Information     security buffer (*)
215          (48)   OS Version Structure   8 bytes (*)
216  32 (48) (56)   Start of data block    (*)
217                                        (*) -> Optional
218  */
219
220  size_t size = 0;
221  unsigned char *buffer = NULL;
222  CURLcode error;
223
224#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
225  (void)data;
226#endif
227
228  error = Curl_base64_decode(header, &buffer, &size);
229  if(error)
230    return error;
231
232  if(!buffer) {
233    infof(data, "NTLM handshake failure (unhandled condition)\n");
234    return CURLE_REMOTE_ACCESS_DENIED;
235  }
236
237#ifdef USE_WINDOWS_SSPI
238  ntlm->type_2 = malloc(size + 1);
239  if(ntlm->type_2 == NULL) {
240    free(buffer);
241    return CURLE_OUT_OF_MEMORY;
242  }
243  ntlm->n_type_2 = curlx_uztoul(size);
244  memcpy(ntlm->type_2, buffer, size);
245#else
246  ntlm->flags = 0;
247
248  if((size < 32) ||
249     (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
250     (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
251    /* This was not a good enough type-2 message */
252    free(buffer);
253    infof(data, "NTLM handshake failure (bad type-2 message)\n");
254    return CURLE_REMOTE_ACCESS_DENIED;
255  }
256
257  ntlm->flags = readint_le(&buffer[20]);
258  memcpy(ntlm->nonce, &buffer[24], 8);
259
260  DEBUG_OUT({
261    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
262    ntlm_print_flags(stderr, ntlm->flags);
263    fprintf(stderr, "\n                  nonce=");
264    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
265    fprintf(stderr, "\n****\n");
266    fprintf(stderr, "**** Header %s\n ", header);
267  });
268#endif
269  free(buffer);
270
271  return CURLE_OK;
272}
273
274#ifdef USE_WINDOWS_SSPI
275void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
276{
277  Curl_safefree(ntlm->type_2);
278  if(ntlm->has_handles) {
279    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
280    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
281    ntlm->has_handles = 0;
282  }
283  if(ntlm->p_identity) {
284    Curl_safefree(ntlm->identity.User);
285    Curl_safefree(ntlm->identity.Password);
286    Curl_safefree(ntlm->identity.Domain);
287    ntlm->p_identity = NULL;
288  }
289}
290#endif
291
292#ifndef USE_WINDOWS_SSPI
293/* copy the source to the destination and fill in zeroes in every
294   other destination byte! */
295static void unicodecpy(unsigned char *dest,
296                       const char *src, size_t length)
297{
298  size_t i;
299  for(i = 0; i < length; i++) {
300    dest[2 * i] = (unsigned char)src[i];
301    dest[2 * i + 1] = '\0';
302  }
303}
304#endif
305
306/*
307 * Curl_ntlm_create_type1_message()
308 *
309 * This is used to generate an already encoded NTLM type-1 message ready for
310 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
311 * or IMAP) server, using the appropriate compile time crypo API.
312 *
313 * Parameters:
314 *
315 * userp   [in]     - The user name in the format User or Domain\User.
316 * passdwp [in]     - The user's password.
317 * ntlm    [in/out] - The ntlm data struct being used and modified.
318 * outptr  [in/out] - The address where a pointer to newly allocated memory
319 *                    holding the result will be stored upon completion.
320 * outlen  [out]    - The length of the output message.
321 *
322 * Returns CURLE_OK on success.
323 */
324CURLcode Curl_ntlm_create_type1_message(const char *userp,
325                                        const char *passwdp,
326                                        struct ntlmdata *ntlm,
327                                        char **outptr,
328                                        size_t *outlen)
329{
330  /* NTLM type-1 message structure:
331
332       Index  Description            Content
333         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
334                                     (0x4e544c4d53535000)
335         8    NTLM Message Type      long (0x01000000)
336        12    Flags                  long
337       (16)   Supplied Domain        security buffer (*)
338       (24)   Supplied Workstation   security buffer (*)
339       (32)   OS Version Structure   8 bytes (*)
340  (32) (40)   Start of data block    (*)
341                                     (*) -> Optional
342  */
343
344  unsigned char ntlmbuf[NTLM_BUFSIZE];
345  size_t size;
346
347#ifdef USE_WINDOWS_SSPI
348
349  SecBuffer buf;
350  SecBufferDesc desc;
351  SECURITY_STATUS status;
352  unsigned long attrs;
353  xcharp_u useranddomain;
354  xcharp_u user, dup_user;
355  xcharp_u domain, dup_domain;
356  xcharp_u passwd, dup_passwd;
357  size_t domlen = 0;
358  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
359
360  domain.const_tchar_ptr = TEXT("");
361
362  Curl_ntlm_sspi_cleanup(ntlm);
363
364  if(userp && *userp) {
365
366    /* null initialize ntlm identity's data to allow proper cleanup */
367    ntlm->p_identity = &ntlm->identity;
368    memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
369
370    useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
371    if(!useranddomain.tchar_ptr)
372      return CURLE_OUT_OF_MEMORY;
373
374    user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
375    if(!user.const_tchar_ptr)
376      user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
377
378    if(user.tchar_ptr) {
379      domain.tchar_ptr = useranddomain.tchar_ptr;
380      domlen = user.tchar_ptr - useranddomain.tchar_ptr;
381      user.tchar_ptr++;
382    }
383    else {
384      user.tchar_ptr = useranddomain.tchar_ptr;
385      domain.const_tchar_ptr = TEXT("");
386      domlen = 0;
387    }
388
389    /* setup ntlm identity's user and length */
390    dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
391    if(!dup_user.tchar_ptr) {
392      Curl_unicodefree(useranddomain.tchar_ptr);
393      return CURLE_OUT_OF_MEMORY;
394    }
395    ntlm->identity.User = dup_user.tbyte_ptr;
396    ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
397    dup_user.tchar_ptr = NULL;
398
399    /* setup ntlm identity's domain and length */
400    dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
401    if(!dup_domain.tchar_ptr) {
402      Curl_unicodefree(useranddomain.tchar_ptr);
403      return CURLE_OUT_OF_MEMORY;
404    }
405    _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
406    *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
407    ntlm->identity.Domain = dup_domain.tbyte_ptr;
408    ntlm->identity.DomainLength = curlx_uztoul(domlen);
409    dup_domain.tchar_ptr = NULL;
410
411    Curl_unicodefree(useranddomain.tchar_ptr);
412
413    /* setup ntlm identity's password and length */
414    passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
415    if(!passwd.tchar_ptr)
416      return CURLE_OUT_OF_MEMORY;
417    dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
418    if(!dup_passwd.tchar_ptr) {
419      Curl_unicodefree(passwd.tchar_ptr);
420      return CURLE_OUT_OF_MEMORY;
421    }
422    ntlm->identity.Password = dup_passwd.tbyte_ptr;
423    ntlm->identity.PasswordLength =
424      curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
425    dup_passwd.tchar_ptr = NULL;
426
427    Curl_unicodefree(passwd.tchar_ptr);
428
429    /* setup ntlm identity's flags */
430    ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY;
431  }
432  else
433    ntlm->p_identity = NULL;
434
435  status = s_pSecFn->AcquireCredentialsHandle(NULL,
436                                              (TCHAR *) TEXT("NTLM"),
437                                              SECPKG_CRED_OUTBOUND, NULL,
438                                              ntlm->p_identity, NULL, NULL,
439                                              &ntlm->handle, &tsDummy);
440  if(status != SEC_E_OK)
441    return CURLE_OUT_OF_MEMORY;
442
443  desc.ulVersion = SECBUFFER_VERSION;
444  desc.cBuffers  = 1;
445  desc.pBuffers  = &buf;
446  buf.cbBuffer   = NTLM_BUFSIZE;
447  buf.BufferType = SECBUFFER_TOKEN;
448  buf.pvBuffer   = ntlmbuf;
449
450  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
451                                               (TCHAR *) TEXT(""),
452                                               ISC_REQ_CONFIDENTIALITY |
453                                               ISC_REQ_REPLAY_DETECT |
454                                               ISC_REQ_CONNECTION,
455                                               0, SECURITY_NETWORK_DREP,
456                                               NULL, 0,
457                                               &ntlm->c_handle, &desc,
458                                               &attrs, &tsDummy);
459
460  if(status == SEC_I_COMPLETE_AND_CONTINUE ||
461     status == SEC_I_CONTINUE_NEEDED)
462    s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
463  else if(status != SEC_E_OK) {
464    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
465    return CURLE_RECV_ERROR;
466  }
467
468  ntlm->has_handles = 1;
469  size = buf.cbBuffer;
470
471#else
472
473  const char *host = "";              /* empty */
474  const char *domain = "";            /* empty */
475  size_t hostlen = 0;
476  size_t domlen = 0;
477  size_t hostoff = 0;
478  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
479                                         domain are empty */
480  (void)userp;
481  (void)passwdp;
482  (void)ntlm;
483
484#if USE_NTLM2SESSION
485#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
486#else
487#define NTLM2FLAG 0
488#endif
489  snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
490           NTLMSSP_SIGNATURE "%c"
491           "\x01%c%c%c" /* 32-bit type = 1 */
492           "%c%c%c%c"   /* 32-bit NTLM flag field */
493           "%c%c"       /* domain length */
494           "%c%c"       /* domain allocated space */
495           "%c%c"       /* domain name offset */
496           "%c%c"       /* 2 zeroes */
497           "%c%c"       /* host length */
498           "%c%c"       /* host allocated space */
499           "%c%c"       /* host name offset */
500           "%c%c"       /* 2 zeroes */
501           "%s"         /* host name */
502           "%s",        /* domain string */
503           0,           /* trailing zero */
504           0, 0, 0,     /* part of type-1 long */
505
506           LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
507                       NTLMFLAG_REQUEST_TARGET |
508                       NTLMFLAG_NEGOTIATE_NTLM_KEY |
509                       NTLM2FLAG |
510                       NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
511           SHORTPAIR(domlen),
512           SHORTPAIR(domlen),
513           SHORTPAIR(domoff),
514           0, 0,
515           SHORTPAIR(hostlen),
516           SHORTPAIR(hostlen),
517           SHORTPAIR(hostoff),
518           0, 0,
519           host,  /* this is empty */
520           domain /* this is empty */);
521
522  /* Initial packet length */
523  size = 32 + hostlen + domlen;
524
525#endif
526
527  DEBUG_OUT({
528    fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
529            "0x%08.8x ",
530            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
531                        NTLMFLAG_REQUEST_TARGET |
532                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
533                        NTLM2FLAG |
534                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
535            NTLMFLAG_NEGOTIATE_OEM |
536            NTLMFLAG_REQUEST_TARGET |
537            NTLMFLAG_NEGOTIATE_NTLM_KEY |
538            NTLM2FLAG |
539            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
540    ntlm_print_flags(stderr,
541                     NTLMFLAG_NEGOTIATE_OEM |
542                     NTLMFLAG_REQUEST_TARGET |
543                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
544                     NTLM2FLAG |
545                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
546    fprintf(stderr, "\n****\n");
547  });
548
549  /* Return with binary blob encoded into base64 */
550  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
551}
552
553/*
554 * Curl_ntlm_create_type3_message()
555 *
556 * This is used to generate an already encoded NTLM type-3 message ready for
557 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
558 * or IMAP) server, using the appropriate compile time crypo API.
559 *
560 * Parameters:
561 *
562 * data    [in]     - The session handle.
563 * userp   [in]     - The user name in the format User or Domain\User.
564 * passdwp [in]     - The user's password.
565 * ntlm    [in/out] - The ntlm data struct being used and modified.
566 * outptr  [in/out] - The address where a pointer to newly allocated memory
567 *                    holding the result will be stored upon completion.
568 * outlen  [out]    - The length of the output message.
569 *
570 * Returns CURLE_OK on success.
571 */
572CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
573                                        const char *userp,
574                                        const char *passwdp,
575                                        struct ntlmdata *ntlm,
576                                        char **outptr,
577                                        size_t *outlen)
578{
579  /* NTLM type-3 message structure:
580
581          Index  Description            Content
582            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
583                                        (0x4e544c4d53535000)
584            8    NTLM Message Type      long (0x03000000)
585           12    LM/LMv2 Response       security buffer
586           20    NTLM/NTLMv2 Response   security buffer
587           28    Target Name            security buffer
588           36    User Name              security buffer
589           44    Workstation Name       security buffer
590          (52)   Session Key            security buffer (*)
591          (60)   Flags                  long (*)
592          (64)   OS Version Structure   8 bytes (*)
593  52 (64) (72)   Start of data block
594                                          (*) -> Optional
595  */
596
597  unsigned char ntlmbuf[NTLM_BUFSIZE];
598  size_t size;
599
600#ifdef USE_WINDOWS_SSPI
601  SecBuffer type_2;
602  SecBuffer type_3;
603  SecBufferDesc type_2_desc;
604  SecBufferDesc type_3_desc;
605  SECURITY_STATUS status;
606  unsigned long attrs;
607  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
608
609  (void)passwdp;
610  (void)userp;
611  (void)data;
612
613  type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
614  type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
615  type_2_desc.pBuffers  = &type_2;
616  type_3_desc.pBuffers  = &type_3;
617
618  type_2.BufferType = SECBUFFER_TOKEN;
619  type_2.pvBuffer   = ntlm->type_2;
620  type_2.cbBuffer   = ntlm->n_type_2;
621  type_3.BufferType = SECBUFFER_TOKEN;
622  type_3.pvBuffer   = ntlmbuf;
623  type_3.cbBuffer   = NTLM_BUFSIZE;
624
625  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
626                                               &ntlm->c_handle,
627                                               (TCHAR *) TEXT(""),
628                                               ISC_REQ_CONFIDENTIALITY |
629                                               ISC_REQ_REPLAY_DETECT |
630                                               ISC_REQ_CONNECTION,
631                                               0, SECURITY_NETWORK_DREP,
632                                               &type_2_desc,
633                                               0, &ntlm->c_handle,
634                                               &type_3_desc,
635                                               &attrs, &tsDummy);
636  if(status != SEC_E_OK)
637    return CURLE_RECV_ERROR;
638
639  size = type_3.cbBuffer;
640
641  Curl_ntlm_sspi_cleanup(ntlm);
642
643#else
644  int lmrespoff;
645  unsigned char lmresp[24]; /* fixed-size */
646#if USE_NTRESPONSES
647  int ntrespoff;
648  unsigned char ntresp[24]; /* fixed-size */
649#endif
650  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
651  char host[HOSTNAME_MAX + 1] = "";
652  const char *user;
653  const char *domain = "";
654  size_t hostoff = 0;
655  size_t useroff = 0;
656  size_t domoff = 0;
657  size_t hostlen = 0;
658  size_t userlen = 0;
659  size_t domlen = 0;
660  CURLcode res;
661
662  user = strchr(userp, '\\');
663  if(!user)
664    user = strchr(userp, '/');
665
666  if(user) {
667    domain = userp;
668    domlen = (user - domain);
669    user++;
670  }
671  else
672    user = userp;
673
674  if(user)
675    userlen = strlen(user);
676
677  /* Get the machine's un-qualified host name as NTLM doesn't like the fully
678     qualified domain name */
679  if(Curl_gethostname(host, sizeof(host))) {
680    infof(data, "gethostname() failed, continuing without!\n");
681    hostlen = 0;
682  }
683  else {
684    hostlen = strlen(host);
685  }
686
687  if(unicode) {
688    domlen = domlen * 2;
689    userlen = userlen * 2;
690    hostlen = hostlen * 2;
691  }
692
693#if USE_NTLM2SESSION
694  /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
695  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
696    unsigned char ntbuffer[0x18];
697    unsigned char tmp[0x18];
698    unsigned char md5sum[MD5_DIGEST_LENGTH];
699    unsigned char entropy[8];
700
701    /* Need to create 8 bytes random data */
702    Curl_ssl_random(data, entropy, sizeof(entropy));
703
704    /* 8 bytes random data as challenge in lmresp */
705    memcpy(lmresp, entropy, 8);
706
707    /* Pad with zeros */
708    memset(lmresp + 8, 0, 0x10);
709
710    /* Fill tmp with challenge(nonce?) + entropy */
711    memcpy(tmp, &ntlm->nonce[0], 8);
712    memcpy(tmp + 8, entropy, 8);
713
714    Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
715
716    /* We shall only use the first 8 bytes of md5sum, but the des
717       code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
718    if(CURLE_OUT_OF_MEMORY ==
719       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
720      return CURLE_OUT_OF_MEMORY;
721    Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
722
723    /* End of NTLM2 Session code */
724  }
725  else
726#endif
727  {
728
729#if USE_NTRESPONSES
730    unsigned char ntbuffer[0x18];
731#endif
732    unsigned char lmbuffer[0x18];
733
734#if USE_NTRESPONSES
735    if(CURLE_OUT_OF_MEMORY ==
736       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
737      return CURLE_OUT_OF_MEMORY;
738    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
739#endif
740
741    Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
742    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
743    /* A safer but less compatible alternative is:
744     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
745     * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
746  }
747
748  lmrespoff = 64; /* size of the message header */
749#if USE_NTRESPONSES
750  ntrespoff = lmrespoff + 0x18;
751  domoff = ntrespoff + 0x18;
752#else
753  domoff = lmrespoff + 0x18;
754#endif
755  useroff = domoff + domlen;
756  hostoff = useroff + userlen;
757
758  /* Create the big type-3 message binary blob */
759  size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
760                  NTLMSSP_SIGNATURE "%c"
761                  "\x03%c%c%c"  /* 32-bit type = 3 */
762
763                  "%c%c"  /* LanManager length */
764                  "%c%c"  /* LanManager allocated space */
765                  "%c%c"  /* LanManager offset */
766                  "%c%c"  /* 2 zeroes */
767
768                  "%c%c"  /* NT-response length */
769                  "%c%c"  /* NT-response allocated space */
770                  "%c%c"  /* NT-response offset */
771                  "%c%c"  /* 2 zeroes */
772
773                  "%c%c"  /* domain length */
774                  "%c%c"  /* domain allocated space */
775                  "%c%c"  /* domain name offset */
776                  "%c%c"  /* 2 zeroes */
777
778                  "%c%c"  /* user length */
779                  "%c%c"  /* user allocated space */
780                  "%c%c"  /* user offset */
781                  "%c%c"  /* 2 zeroes */
782
783                  "%c%c"  /* host length */
784                  "%c%c"  /* host allocated space */
785                  "%c%c"  /* host offset */
786                  "%c%c"  /* 2 zeroes */
787
788                  "%c%c"  /* session key length (unknown purpose) */
789                  "%c%c"  /* session key allocated space (unknown purpose) */
790                  "%c%c"  /* session key offset (unknown purpose) */
791                  "%c%c"  /* 2 zeroes */
792
793                  "%c%c%c%c",  /* flags */
794
795                  /* domain string */
796                  /* user string */
797                  /* host string */
798                  /* LanManager response */
799                  /* NT response */
800
801                  0,                /* zero termination */
802                  0, 0, 0,          /* type-3 long, the 24 upper bits */
803
804                  SHORTPAIR(0x18),  /* LanManager response length, twice */
805                  SHORTPAIR(0x18),
806                  SHORTPAIR(lmrespoff),
807                  0x0, 0x0,
808
809#if USE_NTRESPONSES
810                  SHORTPAIR(0x18),  /* NT-response length, twice */
811                  SHORTPAIR(0x18),
812                  SHORTPAIR(ntrespoff),
813                  0x0, 0x0,
814#else
815                  0x0, 0x0,
816                  0x0, 0x0,
817                  0x0, 0x0,
818                  0x0, 0x0,
819#endif
820                  SHORTPAIR(domlen),
821                  SHORTPAIR(domlen),
822                  SHORTPAIR(domoff),
823                  0x0, 0x0,
824
825                  SHORTPAIR(userlen),
826                  SHORTPAIR(userlen),
827                  SHORTPAIR(useroff),
828                  0x0, 0x0,
829
830                  SHORTPAIR(hostlen),
831                  SHORTPAIR(hostlen),
832                  SHORTPAIR(hostoff),
833                  0x0, 0x0,
834
835                  0x0, 0x0,
836                  0x0, 0x0,
837                  0x0, 0x0,
838                  0x0, 0x0,
839
840                  LONGQUARTET(ntlm->flags));
841
842  DEBUGASSERT(size == 64);
843  DEBUGASSERT(size == (size_t)lmrespoff);
844
845  /* We append the binary hashes */
846  if(size < (NTLM_BUFSIZE - 0x18)) {
847    memcpy(&ntlmbuf[size], lmresp, 0x18);
848    size += 0x18;
849  }
850
851  DEBUG_OUT({
852    fprintf(stderr, "**** TYPE3 header lmresp=");
853    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
854  });
855
856#if USE_NTRESPONSES
857  if(size < (NTLM_BUFSIZE - 0x18)) {
858    DEBUGASSERT(size == (size_t)ntrespoff);
859    memcpy(&ntlmbuf[size], ntresp, 0x18);
860    size += 0x18;
861  }
862
863  DEBUG_OUT({
864    fprintf(stderr, "\n   ntresp=");
865    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
866  });
867
868#endif
869
870  DEBUG_OUT({
871    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
872            LONGQUARTET(ntlm->flags), ntlm->flags);
873    ntlm_print_flags(stderr, ntlm->flags);
874    fprintf(stderr, "\n****\n");
875  });
876
877  /* Make sure that the domain, user and host strings fit in the
878     buffer before we copy them there. */
879  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
880    failf(data, "user + domain + host name too big");
881    return CURLE_OUT_OF_MEMORY;
882  }
883
884  DEBUGASSERT(size == domoff);
885  if(unicode)
886    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
887  else
888    memcpy(&ntlmbuf[size], domain, domlen);
889
890  size += domlen;
891
892  DEBUGASSERT(size == useroff);
893  if(unicode)
894    unicodecpy(&ntlmbuf[size], user, userlen / 2);
895  else
896    memcpy(&ntlmbuf[size], user, userlen);
897
898  size += userlen;
899
900  DEBUGASSERT(size == hostoff);
901  if(unicode)
902    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
903  else
904    memcpy(&ntlmbuf[size], host, hostlen);
905
906  size += hostlen;
907
908  /* Convert domain, user, and host to ASCII but leave the rest as-is */
909  res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
910                                size - domoff);
911  if(res)
912    return CURLE_CONV_FAILED;
913
914#endif
915
916  /* Return with binary blob encoded into base64 */
917  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
918}
919
920#endif /* USE_NTLM */
921