ntlm: Coding style policing dating back to 2011
[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   if(ntlm->has_handles) {
350     s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
351     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
352     ntlm->has_handles = 0;
353   }
354   if(ntlm->p_identity) {
355     Curl_safefree(ntlm->identity.User);
356     Curl_safefree(ntlm->identity.Password);
357     Curl_safefree(ntlm->identity.Domain);
358     ntlm->p_identity = NULL;
359   }
360 }
361 #endif
362
363 #ifndef USE_WINDOWS_SSPI
364 /* copy the source to the destination and fill in zeroes in every
365    other destination byte! */
366 static void unicodecpy(unsigned char *dest, const char *src, size_t length)
367 {
368   size_t i;
369   for(i = 0; i < length; i++) {
370     dest[2 * i] = (unsigned char)src[i];
371     dest[2 * i + 1] = '\0';
372   }
373 }
374 #endif
375
376 /*
377  * Curl_ntlm_create_type1_message()
378  *
379  * This is used to generate an already encoded NTLM type-1 message ready for
380  * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
381  * or IMAP) server, using the appropriate compile time crypo API.
382  *
383  * Parameters:
384  *
385  * userp   [in]     - The user name in the format User or Domain\User.
386  * passdwp [in]     - The user's password.
387  * ntlm    [in/out] - The ntlm data struct being used and modified.
388  * outptr  [in/out] - The address where a pointer to newly allocated memory
389  *                    holding the result will be stored upon completion.
390  * outlen  [out]    - The length of the output message.
391  *
392  * Returns CURLE_OK on success.
393  */
394 CURLcode Curl_ntlm_create_type1_message(const char *userp,
395                                         const char *passwdp,
396                                         struct ntlmdata *ntlm,
397                                         char **outptr,
398                                         size_t *outlen)
399 {
400   /* NTLM type-1 message structure:
401
402        Index  Description            Content
403          0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
404                                      (0x4e544c4d53535000)
405          8    NTLM Message Type      long (0x01000000)
406         12    Flags                  long
407        (16)   Supplied Domain        security buffer (*)
408        (24)   Supplied Workstation   security buffer (*)
409        (32)   OS Version Structure   8 bytes (*)
410   (32) (40)   Start of data block    (*)
411                                      (*) -> Optional
412   */
413
414   unsigned char ntlmbuf[NTLM_BUFSIZE];
415   size_t size;
416
417 #ifdef USE_WINDOWS_SSPI
418
419   SecBuffer buf;
420   SecBufferDesc desc;
421   SECURITY_STATUS status;
422   unsigned long attrs;
423   xcharp_u useranddomain;
424   xcharp_u user, dup_user;
425   xcharp_u domain, dup_domain;
426   xcharp_u passwd, dup_passwd;
427   size_t domlen = 0;
428   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
429
430   domain.const_tchar_ptr = TEXT("");
431
432   Curl_ntlm_sspi_cleanup(ntlm);
433
434   if(userp && *userp) {
435
436     /* null initialize ntlm identity's data to allow proper cleanup */
437     ntlm->p_identity = &ntlm->identity;
438     memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
439
440     useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
441     if(!useranddomain.tchar_ptr)
442       return CURLE_OUT_OF_MEMORY;
443
444     user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
445     if(!user.const_tchar_ptr)
446       user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
447
448     if(user.tchar_ptr) {
449       domain.tchar_ptr = useranddomain.tchar_ptr;
450       domlen = user.tchar_ptr - useranddomain.tchar_ptr;
451       user.tchar_ptr++;
452     }
453     else {
454       user.tchar_ptr = useranddomain.tchar_ptr;
455       domain.const_tchar_ptr = TEXT("");
456       domlen = 0;
457     }
458
459     /* setup ntlm identity's user and length */
460     dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
461     if(!dup_user.tchar_ptr) {
462       Curl_unicodefree(useranddomain.tchar_ptr);
463       return CURLE_OUT_OF_MEMORY;
464     }
465     ntlm->identity.User = dup_user.tbyte_ptr;
466     ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
467     dup_user.tchar_ptr = NULL;
468
469     /* setup ntlm identity's domain and length */
470     dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
471     if(!dup_domain.tchar_ptr) {
472       Curl_unicodefree(useranddomain.tchar_ptr);
473       return CURLE_OUT_OF_MEMORY;
474     }
475     _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
476     *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
477     ntlm->identity.Domain = dup_domain.tbyte_ptr;
478     ntlm->identity.DomainLength = curlx_uztoul(domlen);
479     dup_domain.tchar_ptr = NULL;
480
481     Curl_unicodefree(useranddomain.tchar_ptr);
482
483     /* setup ntlm identity's password and length */
484     passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
485     if(!passwd.tchar_ptr)
486       return CURLE_OUT_OF_MEMORY;
487     dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
488     if(!dup_passwd.tchar_ptr) {
489       Curl_unicodefree(passwd.tchar_ptr);
490       return CURLE_OUT_OF_MEMORY;
491     }
492     ntlm->identity.Password = dup_passwd.tbyte_ptr;
493     ntlm->identity.PasswordLength =
494       curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
495     dup_passwd.tchar_ptr = NULL;
496
497     Curl_unicodefree(passwd.tchar_ptr);
498
499     /* setup ntlm identity's flags */
500     ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY;
501   }
502   else
503     ntlm->p_identity = NULL;
504
505   status = s_pSecFn->AcquireCredentialsHandle(NULL,
506                                               (TCHAR *) TEXT("NTLM"),
507                                               SECPKG_CRED_OUTBOUND, NULL,
508                                               ntlm->p_identity, NULL, NULL,
509                                               &ntlm->handle, &tsDummy);
510   if(status != SEC_E_OK)
511     return CURLE_OUT_OF_MEMORY;
512
513   desc.ulVersion = SECBUFFER_VERSION;
514   desc.cBuffers  = 1;
515   desc.pBuffers  = &buf;
516   buf.cbBuffer   = NTLM_BUFSIZE;
517   buf.BufferType = SECBUFFER_TOKEN;
518   buf.pvBuffer   = ntlmbuf;
519
520   status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
521                                                (TCHAR *) TEXT(""),
522                                                ISC_REQ_CONFIDENTIALITY |
523                                                ISC_REQ_REPLAY_DETECT |
524                                                ISC_REQ_CONNECTION,
525                                                0, SECURITY_NETWORK_DREP,
526                                                NULL, 0,
527                                                &ntlm->c_handle, &desc,
528                                                &attrs, &tsDummy);
529
530   if(status == SEC_I_COMPLETE_AND_CONTINUE ||
531      status == SEC_I_CONTINUE_NEEDED)
532     s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
533   else if(status != SEC_E_OK) {
534     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
535     return CURLE_RECV_ERROR;
536   }
537
538   ntlm->has_handles = 1;
539   size = buf.cbBuffer;
540
541 #else
542
543   const char *host = "";              /* empty */
544   const char *domain = "";            /* empty */
545   size_t hostlen = 0;
546   size_t domlen = 0;
547   size_t hostoff = 0;
548   size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
549                                          domain are empty */
550   (void)userp;
551   (void)passwdp;
552   (void)ntlm;
553
554 #if USE_NTLM2SESSION
555 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
556 #else
557 #define NTLM2FLAG 0
558 #endif
559   snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
560            NTLMSSP_SIGNATURE "%c"
561            "\x01%c%c%c" /* 32-bit type = 1 */
562            "%c%c%c%c"   /* 32-bit NTLM flag field */
563            "%c%c"       /* domain length */
564            "%c%c"       /* domain allocated space */
565            "%c%c"       /* domain name offset */
566            "%c%c"       /* 2 zeroes */
567            "%c%c"       /* host length */
568            "%c%c"       /* host allocated space */
569            "%c%c"       /* host name offset */
570            "%c%c"       /* 2 zeroes */
571            "%s"         /* host name */
572            "%s",        /* domain string */
573            0,           /* trailing zero */
574            0, 0, 0,     /* part of type-1 long */
575
576            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
577                        NTLMFLAG_REQUEST_TARGET |
578                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
579                        NTLM2FLAG |
580                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
581            SHORTPAIR(domlen),
582            SHORTPAIR(domlen),
583            SHORTPAIR(domoff),
584            0, 0,
585            SHORTPAIR(hostlen),
586            SHORTPAIR(hostlen),
587            SHORTPAIR(hostoff),
588            0, 0,
589            host,  /* this is empty */
590            domain /* this is empty */);
591
592   /* Initial packet length */
593   size = 32 + hostlen + domlen;
594
595 #endif
596
597   DEBUG_OUT({
598     fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
599             "0x%08.8x ",
600             LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
601                         NTLMFLAG_REQUEST_TARGET |
602                         NTLMFLAG_NEGOTIATE_NTLM_KEY |
603                         NTLM2FLAG |
604                         NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
605             NTLMFLAG_NEGOTIATE_OEM |
606             NTLMFLAG_REQUEST_TARGET |
607             NTLMFLAG_NEGOTIATE_NTLM_KEY |
608             NTLM2FLAG |
609             NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
610     ntlm_print_flags(stderr,
611                      NTLMFLAG_NEGOTIATE_OEM |
612                      NTLMFLAG_REQUEST_TARGET |
613                      NTLMFLAG_NEGOTIATE_NTLM_KEY |
614                      NTLM2FLAG |
615                      NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
616     fprintf(stderr, "\n****\n");
617   });
618
619   /* Return with binary blob encoded into base64 */
620   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
621 }
622
623 /*
624  * Curl_ntlm_create_type3_message()
625  *
626  * This is used to generate an already encoded NTLM type-3 message ready for
627  * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
628  * or IMAP) server, using the appropriate compile time crypo API.
629  *
630  * Parameters:
631  *
632  * data    [in]     - The session handle.
633  * userp   [in]     - The user name in the format User or Domain\User.
634  * passdwp [in]     - The user's password.
635  * ntlm    [in/out] - The ntlm data struct being used and modified.
636  * outptr  [in/out] - The address where a pointer to newly allocated memory
637  *                    holding the result will be stored upon completion.
638  * outlen  [out]    - The length of the output message.
639  *
640  * Returns CURLE_OK on success.
641  */
642 CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
643                                         const char *userp,
644                                         const char *passwdp,
645                                         struct ntlmdata *ntlm,
646                                         char **outptr,
647                                         size_t *outlen)
648 {
649   /* NTLM type-3 message structure:
650
651           Index  Description            Content
652             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
653                                         (0x4e544c4d53535000)
654             8    NTLM Message Type      long (0x03000000)
655            12    LM/LMv2 Response       security buffer
656            20    NTLM/NTLMv2 Response   security buffer
657            28    Target Name            security buffer
658            36    User Name              security buffer
659            44    Workstation Name       security buffer
660           (52)   Session Key            security buffer (*)
661           (60)   Flags                  long (*)
662           (64)   OS Version Structure   8 bytes (*)
663   52 (64) (72)   Start of data block
664                                           (*) -> Optional
665   */
666
667   unsigned char ntlmbuf[NTLM_BUFSIZE];
668   size_t size;
669
670 #ifdef USE_WINDOWS_SSPI
671   SecBuffer type_2;
672   SecBuffer type_3;
673   SecBufferDesc type_2_desc;
674   SecBufferDesc type_3_desc;
675   SECURITY_STATUS status;
676   unsigned long attrs;
677   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
678
679   (void)passwdp;
680   (void)userp;
681   (void)data;
682
683   type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
684   type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
685   type_2_desc.pBuffers  = &type_2;
686   type_3_desc.pBuffers  = &type_3;
687
688   type_2.BufferType = SECBUFFER_TOKEN;
689   type_2.pvBuffer   = ntlm->type_2;
690   type_2.cbBuffer   = ntlm->n_type_2;
691   type_3.BufferType = SECBUFFER_TOKEN;
692   type_3.pvBuffer   = ntlmbuf;
693   type_3.cbBuffer   = NTLM_BUFSIZE;
694
695   status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
696                                                &ntlm->c_handle,
697                                                (TCHAR *) TEXT(""),
698                                                ISC_REQ_CONFIDENTIALITY |
699                                                ISC_REQ_REPLAY_DETECT |
700                                                ISC_REQ_CONNECTION,
701                                                0, SECURITY_NETWORK_DREP,
702                                                &type_2_desc,
703                                                0, &ntlm->c_handle,
704                                                &type_3_desc,
705                                                &attrs, &tsDummy);
706   if(status != SEC_E_OK)
707     return CURLE_RECV_ERROR;
708
709   size = type_3.cbBuffer;
710
711   Curl_ntlm_sspi_cleanup(ntlm);
712
713 #else
714   int lmrespoff;
715   unsigned char lmresp[24]; /* fixed-size */
716 #if USE_NTRESPONSES
717   int ntrespoff;
718   unsigned int ntresplen = 24;
719   unsigned char ntresp[24]; /* fixed-size */
720   unsigned char *ptr_ntresp = &ntresp[0];
721   unsigned char *ntlmv2resp = NULL;
722 #endif
723   bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
724   char host[HOSTNAME_MAX + 1] = "";
725   const char *user;
726   const char *domain = "";
727   size_t hostoff = 0;
728   size_t useroff = 0;
729   size_t domoff = 0;
730   size_t hostlen = 0;
731   size_t userlen = 0;
732   size_t domlen = 0;
733   CURLcode res = CURLE_OK;
734
735   user = strchr(userp, '\\');
736   if(!user)
737     user = strchr(userp, '/');
738
739   if(user) {
740     domain = userp;
741     domlen = (user - domain);
742     user++;
743   }
744   else
745     user = userp;
746
747   if(user)
748     userlen = strlen(user);
749
750   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
751      qualified domain name */
752   if(Curl_gethostname(host, sizeof(host))) {
753     infof(data, "gethostname() failed, continuing without!\n");
754     hostlen = 0;
755   }
756   else {
757     hostlen = strlen(host);
758   }
759
760 #if USE_NTRESPONSES
761   if(ntlm->target_info_len) {
762     unsigned char ntbuffer[0x18];
763     unsigned char entropy[8];
764     unsigned char ntlmv2hash[0x18];
765
766     /* Need to create 8 bytes random client nonce */
767     Curl_ssl_random(data, entropy, sizeof(entropy));
768
769     res = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
770     if(res)
771       return res;
772
773     res = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
774                                         ntbuffer, ntlmv2hash);
775     if(res)
776       return res;
777
778     /* LMv2 response */
779     res = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, &ntlm->nonce[0],
780                                       lmresp);
781     if(res)
782       return res;
783
784     /* NTLMv2 response */
785     res = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, ntlm, &ntlmv2resp,
786                                         &ntresplen);
787     if(res)
788       return res;
789
790     ptr_ntresp = ntlmv2resp;
791   }
792   else
793 #endif
794
795 #if USE_NTLM2SESSION
796   /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
797   if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
798     unsigned char ntbuffer[0x18];
799     unsigned char tmp[0x18];
800     unsigned char md5sum[MD5_DIGEST_LENGTH];
801     unsigned char entropy[8];
802
803     /* Need to create 8 bytes random data */
804     Curl_ssl_random(data, entropy, sizeof(entropy));
805
806     /* 8 bytes random data as challenge in lmresp */
807     memcpy(lmresp, entropy, 8);
808
809     /* Pad with zeros */
810     memset(lmresp + 8, 0, 0x10);
811
812     /* Fill tmp with challenge(nonce?) + entropy */
813     memcpy(tmp, &ntlm->nonce[0], 8);
814     memcpy(tmp + 8, entropy, 8);
815
816     Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
817
818     /* We shall only use the first 8 bytes of md5sum, but the des
819        code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
820     if(CURLE_OUT_OF_MEMORY ==
821        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
822       return CURLE_OUT_OF_MEMORY;
823
824     Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
825
826     /* End of NTLM2 Session code */
827
828   }
829   else
830 #endif
831   {
832
833 #if USE_NTRESPONSES
834     unsigned char ntbuffer[0x18];
835 #endif
836     unsigned char lmbuffer[0x18];
837
838 #if USE_NTRESPONSES
839     if(CURLE_OUT_OF_MEMORY ==
840        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
841       return CURLE_OUT_OF_MEMORY;
842     Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
843 #endif
844
845     Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
846     Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
847     /* A safer but less compatible alternative is:
848      *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
849      * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
850   }
851
852   if(unicode) {
853     domlen = domlen * 2;
854     userlen = userlen * 2;
855     hostlen = hostlen * 2;
856   }
857
858   lmrespoff = 64; /* size of the message header */
859 #if USE_NTRESPONSES
860   ntrespoff = lmrespoff + 0x18;
861   domoff = ntrespoff + ntresplen;
862 #else
863   domoff = lmrespoff + 0x18;
864 #endif
865   useroff = domoff + domlen;
866   hostoff = useroff + userlen;
867
868   /* Create the big type-3 message binary blob */
869   size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
870                   NTLMSSP_SIGNATURE "%c"
871                   "\x03%c%c%c"  /* 32-bit type = 3 */
872
873                   "%c%c"  /* LanManager length */
874                   "%c%c"  /* LanManager allocated space */
875                   "%c%c"  /* LanManager offset */
876                   "%c%c"  /* 2 zeroes */
877
878                   "%c%c"  /* NT-response length */
879                   "%c%c"  /* NT-response allocated space */
880                   "%c%c"  /* NT-response offset */
881                   "%c%c"  /* 2 zeroes */
882
883                   "%c%c"  /* domain length */
884                   "%c%c"  /* domain allocated space */
885                   "%c%c"  /* domain name offset */
886                   "%c%c"  /* 2 zeroes */
887
888                   "%c%c"  /* user length */
889                   "%c%c"  /* user allocated space */
890                   "%c%c"  /* user offset */
891                   "%c%c"  /* 2 zeroes */
892
893                   "%c%c"  /* host length */
894                   "%c%c"  /* host allocated space */
895                   "%c%c"  /* host offset */
896                   "%c%c"  /* 2 zeroes */
897
898                   "%c%c"  /* session key length (unknown purpose) */
899                   "%c%c"  /* session key allocated space (unknown purpose) */
900                   "%c%c"  /* session key offset (unknown purpose) */
901                   "%c%c"  /* 2 zeroes */
902
903                   "%c%c%c%c",  /* flags */
904
905                   /* domain string */
906                   /* user string */
907                   /* host string */
908                   /* LanManager response */
909                   /* NT response */
910
911                   0,                /* zero termination */
912                   0, 0, 0,          /* type-3 long, the 24 upper bits */
913
914                   SHORTPAIR(0x18),  /* LanManager response length, twice */
915                   SHORTPAIR(0x18),
916                   SHORTPAIR(lmrespoff),
917                   0x0, 0x0,
918
919 #if USE_NTRESPONSES
920                   SHORTPAIR(ntresplen),  /* NT-response length, twice */
921                   SHORTPAIR(ntresplen),
922                   SHORTPAIR(ntrespoff),
923                   0x0, 0x0,
924 #else
925                   0x0, 0x0,
926                   0x0, 0x0,
927                   0x0, 0x0,
928                   0x0, 0x0,
929 #endif
930                   SHORTPAIR(domlen),
931                   SHORTPAIR(domlen),
932                   SHORTPAIR(domoff),
933                   0x0, 0x0,
934
935                   SHORTPAIR(userlen),
936                   SHORTPAIR(userlen),
937                   SHORTPAIR(useroff),
938                   0x0, 0x0,
939
940                   SHORTPAIR(hostlen),
941                   SHORTPAIR(hostlen),
942                   SHORTPAIR(hostoff),
943                   0x0, 0x0,
944
945                   0x0, 0x0,
946                   0x0, 0x0,
947                   0x0, 0x0,
948                   0x0, 0x0,
949
950                   LONGQUARTET(ntlm->flags));
951
952   DEBUGASSERT(size == 64);
953   DEBUGASSERT(size == (size_t)lmrespoff);
954
955   /* We append the binary hashes */
956   if(size < (NTLM_BUFSIZE - 0x18)) {
957     memcpy(&ntlmbuf[size], lmresp, 0x18);
958     size += 0x18;
959   }
960
961   DEBUG_OUT({
962     fprintf(stderr, "**** TYPE3 header lmresp=");
963     ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
964   });
965
966 #if USE_NTRESPONSES
967   if(size < (NTLM_BUFSIZE - ntresplen)) {
968     DEBUGASSERT(size == (size_t)ntrespoff);
969     memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
970     size += ntresplen;
971   }
972
973   DEBUG_OUT({
974     fprintf(stderr, "\n   ntresp=");
975     ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
976   });
977
978   Curl_safefree(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
979
980 #endif
981
982   DEBUG_OUT({
983     fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
984             LONGQUARTET(ntlm->flags), ntlm->flags);
985     ntlm_print_flags(stderr, ntlm->flags);
986     fprintf(stderr, "\n****\n");
987   });
988
989   /* Make sure that the domain, user and host strings fit in the
990      buffer before we copy them there. */
991   if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
992     failf(data, "user + domain + host name too big");
993     return CURLE_OUT_OF_MEMORY;
994   }
995
996   DEBUGASSERT(size == domoff);
997   if(unicode)
998     unicodecpy(&ntlmbuf[size], domain, domlen / 2);
999   else
1000     memcpy(&ntlmbuf[size], domain, domlen);
1001
1002   size += domlen;
1003
1004   DEBUGASSERT(size == useroff);
1005   if(unicode)
1006     unicodecpy(&ntlmbuf[size], user, userlen / 2);
1007   else
1008     memcpy(&ntlmbuf[size], user, userlen);
1009
1010   size += userlen;
1011
1012   DEBUGASSERT(size == hostoff);
1013   if(unicode)
1014     unicodecpy(&ntlmbuf[size], host, hostlen / 2);
1015   else
1016     memcpy(&ntlmbuf[size], host, hostlen);
1017
1018   size += hostlen;
1019
1020   /* Convert domain, user, and host to ASCII but leave the rest as-is */
1021   res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
1022                                 size - domoff);
1023   if(res)
1024     return CURLE_CONV_FAILED;
1025
1026 #endif
1027
1028   /* Return with binary blob encoded into base64 */
1029   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
1030 }
1031
1032 #endif /* USE_NTLM */