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