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