]> sjero.net Git - wget/blob - src/http-ntlm.c
Merging to reinstate autoreconf.
[wget] / src / http-ntlm.c
1 /* NTLM code.
2    Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
3    Contributed by Daniel Stenberg.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 /* NTLM details:
33    
34    http://davenport.sourceforge.net/ntlm.html
35    http://www.innovation.ch/java/ntlm.html
36
37 */
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42
43 #include <openssl/des.h>
44 #include <openssl/md4.h>
45 #include <openssl/opensslv.h>
46
47 #include "wget.h"
48 #include "utils.h"
49 #include "http-ntlm.h"
50
51 #if OPENSSL_VERSION_NUMBER < 0x00907001L
52 #define DES_key_schedule des_key_schedule
53 #define DES_cblock des_cblock
54 #define DES_set_odd_parity des_set_odd_parity
55 #define DES_set_key des_set_key
56 #define DES_ecb_encrypt des_ecb_encrypt
57
58 /* This is how things were done in the old days */
59 #define DESKEY(x) x
60 #define DESKEYARG(x) x
61 #else
62 /* Modern version */
63 #define DESKEYARG(x) *x
64 #define DESKEY(x) &x
65 #endif
66
67 /* Define this to make the type-3 message include the NT response message */
68 #define USE_NTRESPONSES 1
69 \f
70 /* Flag bits definitions available at on
71    http://davenport.sourceforge.net/ntlm.html */
72
73 #define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
74 #define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
75 #define NTLMFLAG_REQUEST_TARGET                  (1<<2)
76 /* unknown (1<<3) */
77 #define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
78 #define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
79 #define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
80 #define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
81 #define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
82 #define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
83 /* unknown (1<<10) */
84 /* unknown (1<<11) */
85 #define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
86 #define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
87 #define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
88 #define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
89 #define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
90 #define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
91 #define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
92 #define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
93 #define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
94 #define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
95 #define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
96 #define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
97 /* unknown (1<24) */
98 /* unknown (1<25) */
99 /* unknown (1<26) */
100 /* unknown (1<27) */
101 /* unknown (1<28) */
102 #define NTLMFLAG_NEGOTIATE_128                   (1<<29)
103 #define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
104 #define NTLMFLAG_NEGOTIATE_56                    (1<<31)
105 \f
106 /*
107   (*) = A "security buffer" is a triplet consisting of two shorts and one
108   long:
109
110   1. a 'short' containing the length of the buffer in bytes
111   2. a 'short' containing the allocated space for the buffer in bytes
112   3. a 'long' containing the offset to the start of the buffer from the
113      beginning of the NTLM message, in bytes.
114 */
115
116 /* return true on success, false otherwise */
117 bool
118 ntlm_input (struct ntlmdata *ntlm, const char *header)
119 {
120   if (0 != strncmp (header, "NTLM", 4))
121     return false;
122
123   header += 4;
124   while (*header && c_isspace(*header))
125     header++;
126
127   if (*header)
128     {
129       /* We got a type-2 message here:
130
131          Index   Description         Content
132          0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
133                                      (0x4e544c4d53535000)
134          8       NTLM Message Type   long (0x02000000)
135          12      Target Name         security buffer(*)
136          20      Flags               long
137          24      Challenge           8 bytes
138          (32)    Context (optional)  8 bytes (two consecutive longs)
139          (40)    Target Information  (optional) security buffer(*)
140          32 (48) start of data block
141       */
142       int size;
143       char *buffer = (char *) alloca (strlen (header));
144
145       DEBUGP (("Received a type-2 NTLM message.\n"));
146
147       size = base64_decode (header, buffer);
148       if (size < 0)
149         return false;           /* malformed base64 from server */
150
151       ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
152
153       if (size >= 48)
154         /* the nonce of interest is index [24 .. 31], 8 bytes */
155         memcpy (ntlm->nonce, &buffer[24], 8);
156
157       /* at index decimal 20, there's a 32bit NTLM flag field */
158     }
159   else
160     {
161       if (ntlm->state >= NTLMSTATE_TYPE1)
162         {
163           DEBUGP (("Unexpected empty NTLM message.\n"));
164           return false; /* this is an error */
165         }
166
167       DEBUGP (("Empty NTLM message, starting transaction.\n"));
168       ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
169     }
170
171   return true;
172 }
173
174 /*
175  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
176  * key schedule ks is also set.
177  */
178 static void
179 setup_des_key(unsigned char *key_56,
180               DES_key_schedule DESKEYARG(ks))
181 {
182   DES_cblock key;
183
184   key[0] = key_56[0];
185   key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
186   key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
187   key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
188   key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
189   key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
190   key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
191   key[7] =  (key_56[6] << 1) & 0xFF;
192
193   DES_set_odd_parity(&key);
194   DES_set_key(&key, ks);
195 }
196
197  /*
198   * takes a 21 byte array and treats it as 3 56-bit DES keys. The
199   * 8 byte plaintext is encrypted with each key and the resulting 24
200   * bytes are stored in the results array.
201   */
202 static void
203 calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
204 {
205   DES_key_schedule ks;
206
207   setup_des_key(keys, DESKEY(ks));
208   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
209                   DESKEY(ks), DES_ENCRYPT);
210
211   setup_des_key(keys+7, DESKEY(ks));
212   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
213                   DESKEY(ks), DES_ENCRYPT);
214
215   setup_des_key(keys+14, DESKEY(ks));
216   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
217                   DESKEY(ks), DES_ENCRYPT);
218 }
219
220 /*
221  * Set up lanmanager and nt hashed passwords
222  */
223 static void
224 mkhash(const char *password,
225        unsigned char *nonce,    /* 8 bytes */
226        unsigned char *lmresp    /* must fit 0x18 bytes */
227 #ifdef USE_NTRESPONSES
228        , unsigned char *ntresp  /* must fit 0x18 bytes */
229 #endif
230   )
231 {
232   unsigned char lmbuffer[21];
233 #ifdef USE_NTRESPONSES
234   unsigned char ntbuffer[21];
235 #endif
236   unsigned char *pw;
237   static const unsigned char magic[] = {
238     0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
239   };
240   int i;
241   int len = strlen(password);
242
243   /* make it fit at least 14 bytes */
244   pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
245
246   if (len > 14)
247     len = 14;
248   
249   for (i=0; i<len; i++)
250     pw[i] = c_toupper (password[i]);
251
252   for (; i<14; i++)
253     pw[i] = 0;
254
255   {
256     /* create LanManager hashed password */
257     DES_key_schedule ks;
258
259     setup_des_key(pw, DESKEY(ks));
260     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
261                     DESKEY(ks), DES_ENCRYPT);
262   
263     setup_des_key(pw+7, DESKEY(ks));
264     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
265                     DESKEY(ks), DES_ENCRYPT);
266
267     memset(lmbuffer+16, 0, 5);
268   }
269   /* create LM responses */
270   calc_resp(lmbuffer, nonce, lmresp);
271
272 #ifdef USE_NTRESPONSES
273   {
274     /* create NT hashed password */
275     MD4_CTX MD4;
276
277     len = strlen(password);
278
279     for (i=0; i<len; i++) {
280       pw[2*i]   = password[i];
281       pw[2*i+1] = 0;
282     }
283
284     MD4_Init(&MD4);
285     MD4_Update(&MD4, pw, 2*len);
286     MD4_Final(ntbuffer, &MD4);
287
288     memset(ntbuffer+16, 0, 5);
289   }
290
291   calc_resp(ntbuffer, nonce, ntresp);
292 #endif
293 }
294
295 #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
296 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
297   (((x) >>16)&0xff), ((x)>>24)
298
299 /* this is for creating ntlm header output */
300 char *
301 ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
302              bool *ready)
303 {
304   const char *domain=""; /* empty */
305   const char *host=""; /* empty */
306   int domlen=strlen(domain);
307   int hostlen = strlen(host);
308   int hostoff; /* host name offset */
309   int domoff;  /* domain name offset */
310   int size;
311   char *base64;
312   char ntlmbuf[256]; /* enough, unless the host/domain is very long */
313
314   /* point to the address of the pointer that holds the string to sent to the
315      server, which is for a plain host or for a HTTP proxy */
316   char *output;
317
318   *ready = false;
319
320   /* not set means empty */
321   if(!user)
322     user="";
323
324   if(!passwd)
325     passwd="";
326   
327   switch(ntlm->state) {
328   case NTLMSTATE_TYPE1:
329   default: /* for the weird cases we (re)start here */
330     hostoff = 32;
331     domoff = hostoff + hostlen;
332
333     DEBUGP (("Creating a type-1 NTLM message.\n"));
334     
335     /* Create and send a type-1 message:
336
337     Index Description          Content
338     0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
339                                (0x4e544c4d53535000)
340     8     NTLM Message Type    long (0x01000000)
341     12    Flags                long
342     16    Supplied Domain      security buffer(*)
343     24    Supplied Workstation security buffer(*)
344     32    start of data block
345
346     */
347
348     snprintf (ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
349               "\x01%c%c%c" /* 32-bit type = 1 */
350               "%c%c%c%c"   /* 32-bit NTLM flag field */
351               "%c%c"  /* domain length */
352               "%c%c"  /* domain allocated space */
353               "%c%c"  /* domain name offset */
354               "%c%c"  /* 2 zeroes */
355               "%c%c"  /* host length */
356               "%c%c"  /* host allocated space */
357               "%c%c"  /* host name offset */
358               "%c%c"  /* 2 zeroes */
359               "%s"   /* host name */
360               "%s",  /* domain string */
361               0,     /* trailing zero */
362               0,0,0, /* part of type-1 long */
363
364               LONGQUARTET(
365                 NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
366                 NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
367                 /* equals 0x0202 */
368                 ),
369               SHORTPAIR(domlen),
370               SHORTPAIR(domlen),
371               SHORTPAIR(domoff),
372               0,0,
373               SHORTPAIR(hostlen),
374               SHORTPAIR(hostlen),
375               SHORTPAIR(hostoff),
376               0,0,
377               host, domain);
378
379     /* initial packet length */
380     size = 32 + hostlen + domlen;
381
382     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
383     base64_encode (ntlmbuf, size, base64);
384
385     output = concat_strings ("NTLM ", base64, (char *) 0);
386     break;
387     
388   case NTLMSTATE_TYPE2:
389     /* We received the type-2 already, create a type-3 message:
390
391     Index   Description            Content
392     0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
393                                    (0x4e544c4d53535000)
394     8       NTLM Message Type      long (0x03000000)
395     12      LM/LMv2 Response       security buffer(*)
396     20      NTLM/NTLMv2 Response   security buffer(*)
397     28      Domain Name            security buffer(*)
398     36      User Name              security buffer(*)
399     44      Workstation Name       security buffer(*)
400     (52)    Session Key (optional) security buffer(*)
401     (60)    Flags (optional)       long
402     52 (64) start of data block
403
404     */
405   
406   {
407     int lmrespoff;
408     int ntrespoff;
409     int useroff;
410     unsigned char lmresp[0x18]; /* fixed-size */
411 #ifdef USE_NTRESPONSES
412     unsigned char ntresp[0x18]; /* fixed-size */
413 #endif
414     const char *usr;
415     int userlen;
416
417     DEBUGP (("Creating a type-3 NTLM message.\n"));
418
419     usr = strchr(user, '\\');
420     if(!usr)
421       usr = strchr(user, '/');
422
423     if (usr) {
424       domain = user;
425       domlen = usr - domain;
426       usr++;
427     }
428     else
429       usr = user;
430     userlen = strlen(usr);
431
432     mkhash(passwd, &ntlm->nonce[0], lmresp
433 #ifdef USE_NTRESPONSES
434            , ntresp
435 #endif
436       );
437
438     domoff = 64; /* always */
439     useroff = domoff + domlen;
440     hostoff = useroff + userlen;
441     lmrespoff = hostoff + hostlen;
442     ntrespoff = lmrespoff + 0x18;
443
444     /* Create the big type-3 message binary blob */
445
446     size = snprintf (ntlmbuf, sizeof(ntlmbuf),
447                      "NTLMSSP%c"
448                      "\x03%c%c%c" /* type-3, 32 bits */
449
450                      "%c%c%c%c" /* LanManager length + allocated space */
451                      "%c%c" /* LanManager offset */
452                      "%c%c" /* 2 zeroes */
453
454                      "%c%c" /* NT-response length */
455                      "%c%c" /* NT-response allocated space */
456                      "%c%c" /* NT-response offset */
457                      "%c%c" /* 2 zeroes */
458
459                      "%c%c"  /* domain length */
460                      "%c%c"  /* domain allocated space */
461                      "%c%c"  /* domain name offset */
462                      "%c%c"  /* 2 zeroes */
463                     
464                      "%c%c"  /* user length */
465                      "%c%c"  /* user allocated space */
466                      "%c%c"  /* user offset */
467                      "%c%c"  /* 2 zeroes */
468                     
469                      "%c%c"  /* host length */
470                      "%c%c"  /* host allocated space */
471                      "%c%c"  /* host offset */
472                      "%c%c%c%c%c%c"  /* 6 zeroes */
473                     
474                      "\xff\xff"  /* message length */
475                      "%c%c"  /* 2 zeroes */
476                     
477                      "\x01\x82" /* flags */
478                      "%c%c"  /* 2 zeroes */
479
480                      /* domain string */
481                      /* user string */
482                      /* host string */
483                      /* LanManager response */
484                      /* NT response */
485                      ,
486                      0, /* zero termination */
487                      0,0,0, /* type-3 long, the 24 upper bits */
488
489                      SHORTPAIR(0x18),  /* LanManager response length, twice */
490                      SHORTPAIR(0x18),
491                      SHORTPAIR(lmrespoff),
492                      0x0, 0x0,
493
494 #ifdef USE_NTRESPONSES
495                      SHORTPAIR(0x18),  /* NT-response length, twice */
496                      SHORTPAIR(0x18),
497 #else
498                      0x0, 0x0,
499                      0x0, 0x0,
500 #endif
501                      SHORTPAIR(ntrespoff),
502                      0x0, 0x0,
503
504                      SHORTPAIR(domlen),
505                      SHORTPAIR(domlen),
506                      SHORTPAIR(domoff),
507                      0x0, 0x0,
508
509                      SHORTPAIR(userlen),
510                      SHORTPAIR(userlen),
511                      SHORTPAIR(useroff),
512                      0x0, 0x0,
513
514                      SHORTPAIR(hostlen),
515                      SHORTPAIR(hostlen),
516                      SHORTPAIR(hostoff),
517                      0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
518
519                      0x0, 0x0,
520
521                      0x0, 0x0);
522
523     /* size is now 64 */
524     size=64;
525     ntlmbuf[62]=ntlmbuf[63]=0;
526
527     /* Make sure that the user and domain strings fit in the target buffer
528        before we copy them there. */
529     if(size + userlen + domlen >= sizeof(ntlmbuf))
530       return NULL;
531     
532     memcpy(&ntlmbuf[size], domain, domlen);
533     size += domlen;
534
535     memcpy(&ntlmbuf[size], usr, userlen);
536     size += userlen;
537
538     /* we append the binary hashes to the end of the blob */
539     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
540       memcpy(&ntlmbuf[size], lmresp, 0x18);
541       size += 0x18;
542     }
543
544 #ifdef USE_NTRESPONSES
545     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
546       memcpy(&ntlmbuf[size], ntresp, 0x18);
547       size += 0x18;
548     }
549 #endif
550
551     ntlmbuf[56] = size & 0xff;
552     ntlmbuf[57] = size >> 8;
553
554     /* convert the binary blob into base64 */
555     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
556     base64_encode (ntlmbuf, size, base64);
557
558     output = concat_strings ("NTLM ", base64, (char *) 0);
559
560     ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
561     *ready = true;
562   }
563   break;
564
565   case NTLMSTATE_TYPE3:
566     /* connection is already authenticated,
567      * don't send a header in future requests */
568     *ready = true;
569     output = NULL;
570     break;
571   }
572
573   return output;
574 }