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