- Constantine Sapuntzakis filed bug report #2042430
[platform/upstream/curl.git] / lib / http_ntlm.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2008, 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  * $Id$
22  ***************************************************************************/
23 #include "setup.h"
24
25 /* NTLM details:
26
27    http://davenport.sourceforge.net/ntlm.html
28    http://www.innovation.ch/java/ntlm.html
29
30    Another implementation:
31    http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
32
33 */
34
35 #ifndef CURL_DISABLE_HTTP
36 #ifdef USE_NTLM
37
38 #define DEBUG_ME 0
39
40 /* -- WIN32 approved -- */
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
52 #include <netdb.h>
53 #endif
54
55 #include "urldata.h"
56 #include "easyif.h"  /* for Curl_convert_... prototypes */
57 #include "sendf.h"
58 #include "strequal.h"
59 #include "base64.h"
60 #include "http_ntlm.h"
61 #include "url.h"
62 #include "memory.h"
63 #include "ssluse.h"
64
65 #define _MPRINTF_REPLACE /* use our functions only */
66 #include <curl/mprintf.h>
67
68 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
69 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
70
71 #ifndef USE_WINDOWS_SSPI
72
73 #include <openssl/des.h>
74 #include <openssl/md4.h>
75 #include <openssl/md5.h>
76 #include <openssl/ssl.h>
77 #include <openssl/rand.h>
78
79 #if OPENSSL_VERSION_NUMBER < 0x00907001L
80 #define DES_key_schedule des_key_schedule
81 #define DES_cblock des_cblock
82 #define DES_set_odd_parity des_set_odd_parity
83 #define DES_set_key des_set_key
84 #define DES_ecb_encrypt des_ecb_encrypt
85
86 /* This is how things were done in the old days */
87 #define DESKEY(x) x
88 #define DESKEYARG(x) x
89 #else
90 /* Modern version */
91 #define DESKEYARG(x) *x
92 #define DESKEY(x) &x
93 #endif
94
95 #else
96
97 #include <rpc.h>
98
99 /* Handle of security.dll or secur32.dll, depending on Windows version */
100 static HMODULE s_hSecDll = NULL;
101 /* Pointer to SSPI dispatch table */
102 static PSecurityFunctionTable s_pSecFn = NULL;
103
104 #endif
105
106 /* The last #include file should be: */
107 #include "memdebug.h"
108
109 /* Define this to make the type-3 message include the NT response message */
110 #define USE_NTRESPONSES 1
111
112 /* Define this to make the type-3 message include the NTLM2Session response
113    message, requires USE_NTRESPONSES. */
114 #define USE_NTLM2SESSION 1
115
116 #ifndef USE_WINDOWS_SSPI
117 /* this function converts from the little endian format used in the incoming
118    package to whatever endian format we're using natively */
119 static unsigned int readint_le(unsigned char *buf) /* must point to a
120                                                       4 bytes buffer*/
121 {
122   return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
123     ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
124 }
125 #endif
126
127 #if DEBUG_ME
128 # define DEBUG_OUT(x) x
129 static void print_flags(FILE *handle, unsigned long flags)
130 {
131   if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
132     fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
133   if(flags & NTLMFLAG_NEGOTIATE_OEM)
134     fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
135   if(flags & NTLMFLAG_REQUEST_TARGET)
136     fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
137   if(flags & (1<<3))
138     fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
139   if(flags & NTLMFLAG_NEGOTIATE_SIGN)
140     fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
141   if(flags & NTLMFLAG_NEGOTIATE_SEAL)
142     fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
143   if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
144     fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
145   if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
146     fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
147   if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
148     fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
149   if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
150     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
151   if(flags & (1<<10))
152     fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
153   if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
154     fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
155   if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
156     fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
157   if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
158     fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
159   if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
160     fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
161   if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
162     fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
163   if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
164     fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
165   if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
166     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
167   if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
168     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
169   if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
170     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
171   if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
172     fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
173   if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
174     fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
175   if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
176     fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
177   if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
178     fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
179   if(flags & (1<<24))
180     fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
181   if(flags & (1<<25))
182     fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
183   if(flags & (1<<26))
184     fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
185   if(flags & (1<<27))
186     fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
187   if(flags & (1<<28))
188     fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
189   if(flags & NTLMFLAG_NEGOTIATE_128)
190     fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
191   if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
192     fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
193   if(flags & NTLMFLAG_NEGOTIATE_56)
194     fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
195 }
196
197 static void print_hex(FILE *handle, const char *buf, size_t len)
198 {
199   const char *p = buf;
200   fprintf(stderr, "0x");
201   while(len-- > 0)
202     fprintf(stderr, "%02.2x", (unsigned int)*p++);
203 }
204 #else
205 # define DEBUG_OUT(x)
206 #endif
207
208 /*
209   (*) = A "security buffer" is a triplet consisting of two shorts and one
210   long:
211
212   1. a 'short' containing the length of the buffer in bytes
213   2. a 'short' containing the allocated space for the buffer in bytes
214   3. a 'long' containing the offset to the start of the buffer from the
215      beginning of the NTLM message, in bytes.
216 */
217
218
219 CURLntlm Curl_input_ntlm(struct connectdata *conn,
220                          bool proxy,   /* if proxy or not */
221                          const char *header) /* rest of the www-authenticate:
222                                                 header */
223 {
224   /* point to the correct struct with this */
225   struct ntlmdata *ntlm;
226 #ifndef USE_WINDOWS_SSPI
227   static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
228 #endif
229
230   ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
231
232   /* skip initial whitespaces */
233   while(*header && ISSPACE(*header))
234     header++;
235
236   if(checkprefix("NTLM", header)) {
237     header += strlen("NTLM");
238
239     while(*header && ISSPACE(*header))
240       header++;
241
242     if(*header) {
243       /* We got a type-2 message here:
244
245          Index   Description         Content
246          0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
247                                      (0x4e544c4d53535000)
248          8       NTLM Message Type   long (0x02000000)
249          12      Target Name         security buffer(*)
250          20      Flags               long
251          24      Challenge           8 bytes
252          (32)    Context (optional)  8 bytes (two consecutive longs)
253          (40)    Target Information  (optional) security buffer(*)
254          32 (48) start of data block
255       */
256       size_t size;
257       unsigned char *buffer;
258       size = Curl_base64_decode(header, &buffer);
259       if(!buffer)
260         return CURLNTLM_BAD;
261
262       ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
263
264 #ifdef USE_WINDOWS_SSPI
265       ntlm->type_2 = malloc(size+1);
266       if(ntlm->type_2 == NULL) {
267         free(buffer);
268         return CURLE_OUT_OF_MEMORY;
269       }
270       ntlm->n_type_2 = size;
271       memcpy(ntlm->type_2, buffer, size);
272 #else
273       ntlm->flags = 0;
274
275       if((size < 32) ||
276          (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
277          (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
278         /* This was not a good enough type-2 message */
279         free(buffer);
280         return CURLNTLM_BAD;
281       }
282
283       ntlm->flags = readint_le(&buffer[20]);
284       memcpy(ntlm->nonce, &buffer[24], 8);
285
286       DEBUG_OUT({
287         fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
288         print_flags(stderr, ntlm->flags);
289         fprintf(stderr, "\n                  nonce=");
290         print_hex(stderr, (char *)ntlm->nonce, 8);
291         fprintf(stderr, "\n****\n");
292         fprintf(stderr, "**** Header %s\n ", header);
293       });
294
295       free(buffer);
296 #endif
297     }
298     else {
299       if(ntlm->state >= NTLMSTATE_TYPE1)
300         return CURLNTLM_BAD;
301
302       ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
303     }
304   }
305   return CURLNTLM_FINE;
306 }
307
308 #ifndef USE_WINDOWS_SSPI
309
310 /*
311  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
312  * key schedule ks is also set.
313  */
314 static void setup_des_key(unsigned char *key_56,
315                           DES_key_schedule DESKEYARG(ks))
316 {
317   DES_cblock key;
318
319   key[0] = key_56[0];
320   key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
321   key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
322   key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
323   key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
324   key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
325   key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
326   key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
327
328   DES_set_odd_parity(&key);
329   DES_set_key(&key, ks);
330 }
331
332  /*
333   * takes a 21 byte array and treats it as 3 56-bit DES keys. The
334   * 8 byte plaintext is encrypted with each key and the resulting 24
335   * bytes are stored in the results array.
336   */
337 static void lm_resp(unsigned char *keys,
338                       unsigned char *plaintext,
339                       unsigned char *results)
340 {
341   DES_key_schedule ks;
342
343   setup_des_key(keys, DESKEY(ks));
344   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
345                   DESKEY(ks), DES_ENCRYPT);
346
347   setup_des_key(keys+7, DESKEY(ks));
348   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
349                   DESKEY(ks), DES_ENCRYPT);
350
351   setup_des_key(keys+14, DESKEY(ks));
352   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
353                   DESKEY(ks), DES_ENCRYPT);
354 }
355
356
357 /*
358  * Set up lanmanager hashed password
359  */
360 static void mk_lm_hash(struct SessionHandle *data,
361                        char *password,
362                        unsigned char *lmbuffer /* 21 bytes */)
363 {
364   unsigned char pw[14];
365   static const unsigned char magic[] = {
366     0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
367   };
368   unsigned int i;
369   size_t len = strlen(password);
370
371   if(len > 14)
372     len = 14;
373
374   for (i=0; i<len; i++)
375     pw[i] = (unsigned char)toupper(password[i]);
376
377   for (; i<14; i++)
378     pw[i] = 0;
379
380 #ifdef CURL_DOES_CONVERSIONS
381   /*
382    * The LanManager hashed password needs to be created using the
383    * password in the network encoding not the host encoding.
384    */
385   if(data)
386     Curl_convert_to_network(data, (char *)pw, 14);
387 #else
388   (void)data;
389 #endif
390
391   {
392     /* Create LanManager hashed password. */
393
394     DES_key_schedule ks;
395
396     setup_des_key(pw, DESKEY(ks));
397     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
398                     DESKEY(ks), DES_ENCRYPT);
399
400     setup_des_key(pw+7, DESKEY(ks));
401     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
402                     DESKEY(ks), DES_ENCRYPT);
403
404     memset(lmbuffer + 16, 0, 21 - 16);
405   }
406   }
407
408 #if USE_NTRESPONSES
409 static void utf8_to_unicode_le(unsigned char *dest, const char *src,
410                                size_t srclen)
411 {
412   size_t i;
413   for (i=0; i<srclen; i++) {
414     dest[2*i]   = (unsigned char)src[i];
415     dest[2*i+1] =   '\0';
416   }
417 }
418
419 /*
420  * Set up nt hashed passwords
421  */
422 static CURLcode mk_nt_hash(struct SessionHandle *data,
423                            char *password,
424                            unsigned char *ntbuffer /* 21 bytes */)
425 {
426   size_t len = strlen(password);
427   unsigned char *pw = malloc(len*2);
428   if(!pw)
429     return CURLE_OUT_OF_MEMORY;
430
431   utf8_to_unicode_le(pw, password, len);
432
433 #ifdef CURL_DOES_CONVERSIONS
434   /*
435    * The NT hashed password needs to be created using the
436    * password in the network encoding not the host encoding.
437    */
438   if(data)
439     Curl_convert_to_network(data, (char *)pw, len*2);
440 #else
441   (void)data;
442 #endif
443
444   {
445     /* Create NT hashed password. */
446     MD4_CTX MD4pw;
447
448     MD4_Init(&MD4pw);
449     MD4_Update(&MD4pw, pw, 2*len);
450     MD4_Final(ntbuffer, &MD4pw);
451
452     memset(ntbuffer + 16, 0, 21 - 16);
453   }
454
455   free(pw);
456   return CURLE_OK;
457 }
458 #endif
459
460
461 #endif
462
463 #ifdef USE_WINDOWS_SSPI
464
465 static void
466 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
467 {
468   if(ntlm->type_2) {
469     free(ntlm->type_2);
470     ntlm->type_2 = NULL;
471   }
472   if(ntlm->has_handles) {
473     s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
474     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
475     ntlm->has_handles = 0;
476   }
477   if(ntlm->p_identity) {
478     if(ntlm->identity.User) free(ntlm->identity.User);
479     if(ntlm->identity.Password) free(ntlm->identity.Password);
480     if(ntlm->identity.Domain) free(ntlm->identity.Domain);
481     ntlm->p_identity = NULL;
482   }
483 }
484
485 #endif
486
487 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
488 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
489   (((x) >>16)&0xff), (((x)>>24) & 0xff)
490
491 #define HOSTNAME_MAX 1024
492
493 /* this is for creating ntlm header output */
494 CURLcode Curl_output_ntlm(struct connectdata *conn,
495                           bool proxy)
496 {
497   const char *domain=""; /* empty */
498   char host [HOSTNAME_MAX+ 1] = ""; /* empty */
499 #ifndef USE_WINDOWS_SSPI
500   size_t domlen = strlen(domain);
501   size_t hostlen = strlen(host);
502   size_t hostoff; /* host name offset */
503   size_t domoff;  /* domain name offset */
504 #endif
505   size_t size;
506   char *base64=NULL;
507   unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
508                                   long */
509
510   /* point to the address of the pointer that holds the string to sent to the
511      server, which is for a plain host or for a HTTP proxy */
512   char **allocuserpwd;
513
514   /* point to the name and password for this */
515   char *userp;
516   char *passwdp;
517   /* point to the correct struct with this */
518   struct ntlmdata *ntlm;
519   struct auth *authp;
520
521   DEBUGASSERT(conn);
522   DEBUGASSERT(conn->data);
523
524   if(proxy) {
525     allocuserpwd = &conn->allocptr.proxyuserpwd;
526     userp = conn->proxyuser;
527     passwdp = conn->proxypasswd;
528     ntlm = &conn->proxyntlm;
529     authp = &conn->data->state.authproxy;
530   }
531   else {
532     allocuserpwd = &conn->allocptr.userpwd;
533     userp = conn->user;
534     passwdp = conn->passwd;
535     ntlm = &conn->ntlm;
536     authp = &conn->data->state.authhost;
537   }
538   authp->done = FALSE;
539
540   /* not set means empty */
541   if(!userp)
542     userp=(char *)"";
543
544   if(!passwdp)
545     passwdp=(char *)"";
546
547 #ifdef USE_WINDOWS_SSPI
548   if (s_hSecDll == NULL) {
549     /* not thread safe and leaks - use curl_global_init() to avoid */
550     CURLcode err = Curl_ntlm_global_init();
551     if (s_hSecDll == NULL)
552       return err;
553   }
554 #endif
555
556   switch(ntlm->state) {
557   case NTLMSTATE_TYPE1:
558   default: /* for the weird cases we (re)start here */
559 #ifdef USE_WINDOWS_SSPI
560   {
561     SecBuffer buf;
562     SecBufferDesc desc;
563     SECURITY_STATUS status;
564     ULONG attrs;
565     const char *user;
566     int domlen;
567     TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
568
569     ntlm_sspi_cleanup(ntlm);
570
571     user = strchr(userp, '\\');
572     if(!user)
573       user = strchr(userp, '/');
574
575     if(user) {
576       domain = userp;
577       domlen = user - userp;
578       user++;
579     }
580     else {
581       user = userp;
582       domain = "";
583       domlen = 0;
584     }
585
586     if(user && *user) {
587       /* note: initialize all of this before doing the mallocs so that
588        * it can be cleaned up later without leaking memory.
589        */
590       ntlm->p_identity = &ntlm->identity;
591       memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
592       if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
593         return CURLE_OUT_OF_MEMORY;
594       ntlm->identity.UserLength = strlen(user);
595       if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
596         return CURLE_OUT_OF_MEMORY;
597       ntlm->identity.PasswordLength = strlen(passwdp);
598       if((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
599         return CURLE_OUT_OF_MEMORY;
600       strncpy((char *)ntlm->identity.Domain, domain, domlen);
601       ntlm->identity.Domain[domlen] = '\0';
602       ntlm->identity.DomainLength = domlen;
603       ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
604     }
605     else {
606       ntlm->p_identity = NULL;
607     }
608
609     if(s_pSecFn->AcquireCredentialsHandle(
610           NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
611           NULL, NULL, &ntlm->handle, &tsDummy
612           ) != SEC_E_OK) {
613       return CURLE_OUT_OF_MEMORY;
614     }
615
616     desc.ulVersion = SECBUFFER_VERSION;
617     desc.cBuffers  = 1;
618     desc.pBuffers  = &buf;
619     buf.cbBuffer   = sizeof(ntlmbuf);
620     buf.BufferType = SECBUFFER_TOKEN;
621     buf.pvBuffer   = ntlmbuf;
622
623     status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
624                                                  (char *) host,
625                                                  ISC_REQ_CONFIDENTIALITY |
626                                                  ISC_REQ_REPLAY_DETECT |
627                                                  ISC_REQ_CONNECTION,
628                                                  0, SECURITY_NETWORK_DREP,
629                                                  NULL, 0,
630                                                  &ntlm->c_handle, &desc,
631                                                  &attrs, &tsDummy);
632
633     if(status == SEC_I_COMPLETE_AND_CONTINUE ||
634         status == SEC_I_CONTINUE_NEEDED) {
635       s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
636     }
637     else if(status != SEC_E_OK) {
638       s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
639       return CURLE_RECV_ERROR;
640     }
641
642     ntlm->has_handles = 1;
643     size = buf.cbBuffer;
644   }
645 #else
646     hostoff = 0;
647     domoff = hostoff + hostlen; /* This is 0: remember that host and domain
648                                    are empty */
649
650     /* Create and send a type-1 message:
651
652     Index Description          Content
653     0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
654                                (0x4e544c4d53535000)
655     8     NTLM Message Type    long (0x01000000)
656     12    Flags                long
657     16    Supplied Domain      security buffer(*)
658     24    Supplied Workstation security buffer(*)
659     32    start of data block
660
661     */
662 #if USE_NTLM2SESSION
663 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
664 #else
665 #define NTLM2FLAG 0
666 #endif
667     snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c"
668              "\x01%c%c%c" /* 32-bit type = 1 */
669              "%c%c%c%c"   /* 32-bit NTLM flag field */
670              "%c%c"  /* domain length */
671              "%c%c"  /* domain allocated space */
672              "%c%c"  /* domain name offset */
673              "%c%c"  /* 2 zeroes */
674              "%c%c"  /* host length */
675              "%c%c"  /* host allocated space */
676              "%c%c"  /* host name offset */
677              "%c%c"  /* 2 zeroes */
678              "%s"   /* host name */
679              "%s",  /* domain string */
680              0,     /* trailing zero */
681              0,0,0, /* part of type-1 long */
682
683              LONGQUARTET(
684                NTLMFLAG_NEGOTIATE_OEM|
685                NTLMFLAG_REQUEST_TARGET|
686                NTLMFLAG_NEGOTIATE_NTLM_KEY|
687                NTLM2FLAG|
688                NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
689                ),
690              SHORTPAIR(domlen),
691              SHORTPAIR(domlen),
692              SHORTPAIR(domoff),
693              0,0,
694              SHORTPAIR(hostlen),
695              SHORTPAIR(hostlen),
696              SHORTPAIR(hostoff),
697              0,0,
698              host /* this is empty */, domain /* this is empty */);
699
700     /* initial packet length */
701     size = 32 + hostlen + domlen;
702 #endif
703
704     DEBUG_OUT({
705       fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
706               LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
707                           NTLMFLAG_REQUEST_TARGET|
708                           NTLMFLAG_NEGOTIATE_NTLM_KEY|
709                           NTLM2FLAG|
710                           NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
711               NTLMFLAG_NEGOTIATE_OEM|
712               NTLMFLAG_REQUEST_TARGET|
713               NTLMFLAG_NEGOTIATE_NTLM_KEY|
714               NTLM2FLAG|
715               NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
716       print_flags(stderr,
717                   NTLMFLAG_NEGOTIATE_OEM|
718                   NTLMFLAG_REQUEST_TARGET|
719                   NTLMFLAG_NEGOTIATE_NTLM_KEY|
720                   NTLM2FLAG|
721                   NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
722       fprintf(stderr, "\n****\n");
723     });
724
725     /* now size is the size of the base64 encoded package size */
726     size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
727
728     if(size >0 ) {
729       Curl_safefree(*allocuserpwd);
730       *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
731                               proxy?"Proxy-":"",
732                               base64);
733       DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
734       free(base64);
735     }
736     else
737       return CURLE_OUT_OF_MEMORY; /* FIX TODO */
738
739     break;
740
741   case NTLMSTATE_TYPE2:
742     /* We received the type-2 message already, create a type-3 message:
743
744     Index   Description            Content
745     0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
746                                    (0x4e544c4d53535000)
747     8       NTLM Message Type      long (0x03000000)
748     12      LM/LMv2 Response       security buffer(*)
749     20      NTLM/NTLMv2 Response   security buffer(*)
750     28      Domain Name            security buffer(*)
751     36      User Name              security buffer(*)
752     44      Workstation Name       security buffer(*)
753     (52)    Session Key (optional) security buffer(*)
754     (60)    Flags (optional)       long
755     52 (64) start of data block
756
757     */
758
759   {
760 #ifdef USE_WINDOWS_SSPI
761     SecBuffer type_2, type_3;
762     SecBufferDesc type_2_desc, type_3_desc;
763     SECURITY_STATUS status;
764     ULONG attrs;
765     TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
766
767     type_2_desc.ulVersion  = type_3_desc.ulVersion  = SECBUFFER_VERSION;
768     type_2_desc.cBuffers   = type_3_desc.cBuffers   = 1;
769     type_2_desc.pBuffers   = &type_2;
770     type_3_desc.pBuffers   = &type_3;
771
772     type_2.BufferType = SECBUFFER_TOKEN;
773     type_2.pvBuffer   = ntlm->type_2;
774     type_2.cbBuffer   = ntlm->n_type_2;
775     type_3.BufferType = SECBUFFER_TOKEN;
776     type_3.pvBuffer   = ntlmbuf;
777     type_3.cbBuffer   = sizeof(ntlmbuf);
778
779     status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, &ntlm->c_handle,
780                                        (char *) host,
781                                        ISC_REQ_CONFIDENTIALITY |
782                                        ISC_REQ_REPLAY_DETECT |
783                                        ISC_REQ_CONNECTION,
784                                        0, SECURITY_NETWORK_DREP, &type_2_desc,
785                                        0, &ntlm->c_handle, &type_3_desc,
786                                        &attrs, &tsDummy);
787
788     if(status != SEC_E_OK)
789       return CURLE_RECV_ERROR;
790
791     size = type_3.cbBuffer;
792
793     ntlm_sspi_cleanup(ntlm);
794
795 #else
796     int lmrespoff;
797     unsigned char lmresp[24]; /* fixed-size */
798 #if USE_NTRESPONSES
799     int ntrespoff;
800     unsigned char ntresp[24]; /* fixed-size */
801 #endif
802     size_t useroff;
803     const char *user;
804     size_t userlen;
805
806     user = strchr(userp, '\\');
807     if(!user)
808       user = strchr(userp, '/');
809
810     if(user) {
811       domain = userp;
812       domlen = (user - domain);
813       user++;
814     }
815     else
816       user = userp;
817     userlen = strlen(user);
818
819     if(gethostname(host, HOSTNAME_MAX)) {
820       infof(conn->data, "gethostname() failed, continuing without!");
821       hostlen = 0;
822     }
823     else {
824       /* If the workstation if configured with a full DNS name (i.e.
825        * workstation.somewhere.net) gethostname() returns the fully qualified
826        * name, which NTLM doesn't like.
827        */
828       char *dot = strchr(host, '.');
829       if(dot)
830         *dot = '\0';
831       hostlen = strlen(host);
832     }
833
834 #if USE_NTLM2SESSION
835     /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
836     if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
837       unsigned char ntbuffer[0x18];
838       unsigned char tmp[0x18];
839       unsigned char md5sum[MD5_DIGEST_LENGTH];
840       MD5_CTX MD5pw;
841       unsigned char entropy[8];
842
843       /* Need to create 8 bytes random data */
844       Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
845       RAND_bytes(entropy,8);
846
847       /* 8 bytes random data as challenge in lmresp */
848       memcpy(lmresp,entropy,8);
849       /* Pad with zeros */
850       memset(lmresp+8,0,0x10);
851
852       /* Fill tmp with challenge(nonce?) + entropy */
853       memcpy(tmp,&ntlm->nonce[0],8);
854       memcpy(tmp+8,entropy,8);
855
856       MD5_Init(&MD5pw);
857       MD5_Update(&MD5pw, tmp, 16);
858       MD5_Final(md5sum, &MD5pw);
859       /* We shall only use the first 8 bytes of md5sum,
860          but the des code in lm_resp only encrypt the first 8 bytes */
861       if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
862         return CURLE_OUT_OF_MEMORY;
863       lm_resp(ntbuffer, md5sum, ntresp);
864
865       /* End of NTLM2 Session code */
866     }
867     else {
868 #endif
869
870 #if USE_NTRESPONSES
871       unsigned char ntbuffer[0x18];
872 #endif
873       unsigned char lmbuffer[0x18];
874
875 #if USE_NTRESPONSES
876       if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
877         return CURLE_OUT_OF_MEMORY;
878       lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
879 #endif
880
881       mk_lm_hash(conn->data, passwdp, lmbuffer);
882       lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
883       /* A safer but less compatible alternative is:
884        *   lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
885        * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
886 #if USE_NTLM2SESSION
887     }
888 #endif
889
890     lmrespoff = 64; /* size of the message header */
891 #if USE_NTRESPONSES
892     ntrespoff = lmrespoff + 0x18;
893     domoff = ntrespoff + 0x18;
894 #else
895     domoff = lmrespoff + 0x18;
896 #endif
897     useroff = domoff + domlen;
898     hostoff = useroff + userlen;
899
900     /*
901      * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
902      * need to filter it off because libcurl doesn't UNICODE encode the
903      * strings it packs into the NTLM authenticate packet.
904      */
905     ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE;
906
907     /* Create the big type-3 message binary blob */
908     size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
909                     NTLMSSP_SIGNATURE "%c"
910                     "\x03%c%c%c" /* type-3, 32 bits */
911
912                     "%c%c" /* LanManager length */
913                     "%c%c" /* LanManager allocated space */
914                     "%c%c" /* LanManager offset */
915                     "%c%c" /* 2 zeroes */
916
917                     "%c%c" /* NT-response length */
918                     "%c%c" /* NT-response allocated space */
919                     "%c%c" /* NT-response offset */
920                     "%c%c" /* 2 zeroes */
921
922                     "%c%c"  /* domain length */
923                     "%c%c"  /* domain allocated space */
924                     "%c%c"  /* domain name offset */
925                     "%c%c"  /* 2 zeroes */
926
927                     "%c%c"  /* user length */
928                     "%c%c"  /* user allocated space */
929                     "%c%c"  /* user offset */
930                     "%c%c"  /* 2 zeroes */
931
932                     "%c%c"  /* host length */
933                     "%c%c"  /* host allocated space */
934                     "%c%c"  /* host offset */
935                     "%c%c"  /* 2 zeroes */
936
937                     "%c%c"  /* session key length (unknown purpose) */
938                     "%c%c"  /* session key allocated space (unknown purpose) */
939                     "%c%c"  /* session key offset (unknown purpose) */
940                     "%c%c"  /* 2 zeroes */
941
942                     "%c%c%c%c" /* flags */
943
944                     /* domain string */
945                     /* user string */
946                     /* host string */
947                     /* LanManager response */
948                     /* NT response */
949                     ,
950                     0, /* zero termination */
951                     0,0,0, /* type-3 long, the 24 upper bits */
952
953                     SHORTPAIR(0x18),  /* LanManager response length, twice */
954                     SHORTPAIR(0x18),
955                     SHORTPAIR(lmrespoff),
956                     0x0, 0x0,
957
958 #if USE_NTRESPONSES
959                     SHORTPAIR(0x18),  /* NT-response length, twice */
960                     SHORTPAIR(0x18),
961                     SHORTPAIR(ntrespoff),
962                     0x0, 0x0,
963 #else
964                     0x0, 0x0,
965                     0x0, 0x0,
966                     0x0, 0x0,
967                     0x0, 0x0,
968 #endif
969                     SHORTPAIR(domlen),
970                     SHORTPAIR(domlen),
971                     SHORTPAIR(domoff),
972                     0x0, 0x0,
973
974                     SHORTPAIR(userlen),
975                     SHORTPAIR(userlen),
976                     SHORTPAIR(useroff),
977                     0x0, 0x0,
978
979                     SHORTPAIR(hostlen),
980                     SHORTPAIR(hostlen),
981                     SHORTPAIR(hostoff),
982                     0x0, 0x0,
983
984                     0x0, 0x0,
985                     0x0, 0x0,
986                     0x0, 0x0,
987                     0x0, 0x0,
988
989                     LONGQUARTET(ntlm->flags));
990     DEBUGASSERT(size==64);
991
992     DEBUGASSERT(size == (size_t)lmrespoff);
993     /* We append the binary hashes */
994     if(size < (sizeof(ntlmbuf) - 0x18)) {
995       memcpy(&ntlmbuf[size], lmresp, 0x18);
996       size += 0x18;
997     }
998
999     DEBUG_OUT({
1000         fprintf(stderr, "**** TYPE3 header lmresp=");
1001         print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1002     });
1003
1004 #if USE_NTRESPONSES
1005     if(size < (sizeof(ntlmbuf) - 0x18)) {
1006       DEBUGASSERT(size == (size_t)ntrespoff);
1007       memcpy(&ntlmbuf[size], ntresp, 0x18);
1008       size += 0x18;
1009     }
1010
1011     DEBUG_OUT({
1012         fprintf(stderr, "\n                  ntresp=");
1013         print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1014     });
1015
1016 #endif
1017
1018     DEBUG_OUT({
1019         fprintf(stderr, "\n                  flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1020                 LONGQUARTET(ntlm->flags), ntlm->flags);
1021         print_flags(stderr, ntlm->flags);
1022         fprintf(stderr, "\n****\n");
1023     });
1024
1025
1026     /* Make sure that the domain, user and host strings fit in the target
1027        buffer before we copy them there. */
1028     if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
1029       failf(conn->data, "user + domain + host name too big");
1030       return CURLE_OUT_OF_MEMORY;
1031     }
1032
1033     DEBUGASSERT(size == domoff);
1034     memcpy(&ntlmbuf[size], domain, domlen);
1035     size += domlen;
1036
1037     DEBUGASSERT(size == useroff);
1038     memcpy(&ntlmbuf[size], user, userlen);
1039     size += userlen;
1040
1041     DEBUGASSERT(size == hostoff);
1042     memcpy(&ntlmbuf[size], host, hostlen);
1043     size += hostlen;
1044
1045 #ifdef CURL_DOES_CONVERSIONS
1046     /* convert domain, user, and host to ASCII but leave the rest as-is */
1047     if(CURLE_OK != Curl_convert_to_network(conn->data,
1048                                            (char *)&ntlmbuf[domoff],
1049                                            size-domoff)) {
1050       return CURLE_CONV_FAILED;
1051     }
1052 #endif /* CURL_DOES_CONVERSIONS */
1053
1054 #endif
1055
1056     /* convert the binary blob into base64 */
1057     size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1058
1059     if(size >0 ) {
1060       Curl_safefree(*allocuserpwd);
1061       *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1062                               proxy?"Proxy-":"",
1063                               base64);
1064       DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1065       free(base64);
1066     }
1067     else
1068       return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1069
1070     ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1071     authp->done = TRUE;
1072   }
1073   break;
1074
1075   case NTLMSTATE_TYPE3:
1076     /* connection is already authenticated,
1077      * don't send a header in future requests */
1078     if(*allocuserpwd) {
1079       free(*allocuserpwd);
1080       *allocuserpwd=NULL;
1081     }
1082     authp->done = TRUE;
1083     break;
1084   }
1085
1086   return CURLE_OK;
1087 }
1088
1089
1090 void
1091 Curl_ntlm_cleanup(struct connectdata *conn)
1092 {
1093 #ifdef USE_WINDOWS_SSPI
1094   ntlm_sspi_cleanup(&conn->ntlm);
1095   ntlm_sspi_cleanup(&conn->proxyntlm);
1096 #else
1097   (void)conn;
1098 #endif
1099 }
1100
1101 #ifdef USE_WINDOWS_SSPI
1102 CURLcode Curl_ntlm_global_init()
1103 {
1104   /* If security interface is not yet initialized try to do this */
1105   if(s_hSecDll == NULL) {
1106     /* Determine Windows version. Security functions are located in
1107      * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
1108      * contain both these DLLs (security.dll just forwards calls to
1109      * secur32.dll)
1110      */
1111     OSVERSIONINFO osver;
1112     osver.dwOSVersionInfoSize = sizeof(osver);
1113     GetVersionEx(&osver);
1114     if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1115       && osver.dwMajorVersion == 4)
1116       s_hSecDll = LoadLibrary("security.dll");
1117     else
1118       s_hSecDll = LoadLibrary("secur32.dll");
1119     if(s_hSecDll != NULL) {
1120       INIT_SECURITY_INTERFACE pInitSecurityInterface;
1121       pInitSecurityInterface =
1122         (INIT_SECURITY_INTERFACE)GetProcAddress(s_hSecDll,
1123                                                 "InitSecurityInterfaceA");
1124       if(pInitSecurityInterface != NULL)
1125         s_pSecFn = pInitSecurityInterface();
1126     }
1127   }
1128   if(s_pSecFn == NULL)
1129     return CURLE_RECV_ERROR;
1130
1131   return CURLE_OK;
1132 }
1133
1134 void Curl_ntlm_global_cleanup()
1135 {
1136   if(s_hSecDll != NULL) {
1137     FreeLibrary(s_hSecDll);
1138     s_hSecDll = NULL;
1139     s_pSecFn = NULL;
1140   }
1141 }
1142 #endif
1143
1144 #endif /* USE_NTLM */
1145 #endif /* !CURL_DISABLE_HTTP */