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