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