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