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