]> sjero.net Git - wget/blob - src/http-ntlm.c
[svn] *** empty log message ***
[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
52 #include "wget.h"
53 #include "utils.h"
54 #include "http-ntlm.h"
55
56 #if OPENSSL_VERSION_NUMBER < 0x00907001L
57 #define DES_key_schedule des_key_schedule
58 #define DES_cblock des_cblock
59 #define DES_set_odd_parity des_set_odd_parity
60 #define DES_set_key des_set_key
61 #define DES_ecb_encrypt des_ecb_encrypt
62
63 /* This is how things were done in the old days */
64 #define DESKEY(x) x
65 #define DESKEYARG(x) x
66 #else
67 /* Modern version */
68 #define DESKEYARG(x) *x
69 #define DESKEY(x) &x
70 #endif
71
72 /* Define this to make the type-3 message include the NT response message */
73 #define USE_NTRESPONSES 1
74 \f
75 /* Flag bits definitions available at on
76    http://davenport.sourceforge.net/ntlm.html */
77
78 #define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
79 #define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
80 #define NTLMFLAG_REQUEST_TARGET                  (1<<2)
81 /* unknown (1<<3) */
82 #define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
83 #define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
84 #define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
85 #define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
86 #define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
87 #define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
88 /* unknown (1<<10) */
89 /* unknown (1<<11) */
90 #define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
91 #define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
92 #define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
93 #define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
94 #define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
95 #define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
96 #define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
97 #define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
98 #define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
99 #define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
100 #define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
101 #define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
102 /* unknown (1<24) */
103 /* unknown (1<25) */
104 /* unknown (1<26) */
105 /* unknown (1<27) */
106 /* unknown (1<28) */
107 #define NTLMFLAG_NEGOTIATE_128                   (1<<29)
108 #define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
109 #define NTLMFLAG_NEGOTIATE_56                    (1<<31)
110 \f
111 /*
112   (*) = A "security buffer" is a triplet consisting of two shorts and one
113   long:
114
115   1. a 'short' containing the length of the buffer in bytes
116   2. a 'short' containing the allocated space for the buffer in bytes
117   3. a 'long' containing the offset to the start of the buffer from the
118      beginning of the NTLM message, in bytes.
119 */
120
121 /* return 1 on success, 0 otherwise */
122 int
123 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
184 setup_des_key(unsigned char *key_56,
185               DES_key_schedule DESKEYARG(ks))
186 {
187   DES_cblock key;
188
189   key[0] = key_56[0];
190   key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
191   key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
192   key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
193   key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
194   key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
195   key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
196   key[7] =  (key_56[6] << 1) & 0xFF;
197
198   DES_set_odd_parity(&key);
199   DES_set_key(&key, ks);
200 }
201
202  /*
203   * takes a 21 byte array and treats it as 3 56-bit DES keys. The
204   * 8 byte plaintext is encrypted with each key and the resulting 24
205   * bytes are stored in the results array.
206   */
207 static void
208 calc_resp(unsigned char *keys, unsigned char *plaintext, 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
229 mkhash(const char *password,
230        unsigned char *nonce,    /* 8 bytes */
231        unsigned char *lmresp    /* must fit 0x18 bytes */
232 #ifdef USE_NTRESPONSES
233        , unsigned char *ntresp  /* must fit 0x18 bytes */
234 #endif
235   )
236 {
237   unsigned char lmbuffer[21];
238 #ifdef USE_NTRESPONSES
239   unsigned char ntbuffer[21];
240 #endif
241   unsigned char *pw;
242   static const unsigned char magic[] = {
243     0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
244   };
245   int i;
246   int len = strlen(password);
247
248   /* make it fit at least 14 bytes */
249   pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
250
251   if (len > 14)
252     len = 14;
253   
254   for (i=0; i<len; i++)
255     pw[i] = TOUPPER (password[i]);
256
257   for (; i<14; i++)
258     pw[i] = 0;
259
260   {
261     /* create LanManager hashed password */
262     DES_key_schedule ks;
263
264     setup_des_key(pw, DESKEY(ks));
265     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
266                     DESKEY(ks), DES_ENCRYPT);
267   
268     setup_des_key(pw+7, DESKEY(ks));
269     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
270                     DESKEY(ks), DES_ENCRYPT);
271
272     memset(lmbuffer+16, 0, 5);
273   }
274   /* create LM responses */
275   calc_resp(lmbuffer, nonce, lmresp);
276
277 #ifdef USE_NTRESPONSES
278   {
279     /* create NT hashed password */
280     MD4_CTX MD4;
281
282     len = strlen(password);
283
284     for (i=0; i<len; i++) {
285       pw[2*i]   = password[i];
286       pw[2*i+1] = 0;
287     }
288
289     MD4_Init(&MD4);
290     MD4_Update(&MD4, pw, 2*len);
291     MD4_Final(ntbuffer, &MD4);
292
293     memset(ntbuffer+16, 0, 5);
294   }
295
296   calc_resp(ntbuffer, nonce, ntresp);
297 #endif
298 }
299
300 #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
301 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
302   (((x) >>16)&0xff), ((x)>>24)
303
304 /* this is for creating ntlm header output */
305 char *
306 ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
307              int *ready)
308 {
309   const char *domain=""; /* empty */
310   const char *host=""; /* empty */
311   int domlen=strlen(domain);
312   int hostlen = strlen(host);
313   int hostoff; /* host name offset */
314   int domoff;  /* domain name offset */
315   int size;
316   char *base64;
317   char ntlmbuf[256]; /* enough, unless the host/domain is very long */
318
319   /* point to the address of the pointer that holds the string to sent to the
320      server, which is for a plain host or for a HTTP proxy */
321   char *output;
322
323   *ready = 0;
324
325   /* not set means empty */
326   if(!user)
327     user="";
328
329   if(!passwd)
330     passwd="";
331   
332   switch(ntlm->state) {
333   case NTLMSTATE_TYPE1:
334   default: /* for the weird cases we (re)start here */
335     hostoff = 32;
336     domoff = hostoff + hostlen;
337
338     DEBUGP (("Creating a type-1 NTLM message.\n"));
339     
340     /* Create and send a type-1 message:
341
342     Index Description          Content
343     0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
344                                (0x4e544c4d53535000)
345     8     NTLM Message Type    long (0x01000000)
346     12    Flags                long
347     16    Supplied Domain      security buffer(*)
348     24    Supplied Workstation security buffer(*)
349     32    start of data block
350
351     Format string (merged for pre-ANSI compilers):
352       "NTLMSSP%c"
353       "\x01%c%c%c" 32-bit type = 1
354       "%c%c%c%c"   32-bit NTLM flag field
355       "%c%c"  domain length
356       "%c%c"  domain allocated space
357       "%c%c"  domain name offset
358       "%c%c"  2 zeroes
359       "%c%c"  host length
360       "%c%c"  host allocated space
361       "%c%c"  host name offset
362       "%c%c"  2 zeroes
363       "%s"    host name
364       "%s"   domain string
365     */
366
367     snprintf(ntlmbuf, sizeof(ntlmbuf),
368              "NTLMSSP%c\001%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",
369              0,     /* trailing zero */
370              0,0,0, /* part of type-1 long */
371
372              LONGQUARTET(
373                NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
374                NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
375                /* equals 0x0202 */
376                ),
377              SHORTPAIR(domlen),
378              SHORTPAIR(domlen),
379              SHORTPAIR(domoff),
380              0,0,
381              SHORTPAIR(hostlen),
382              SHORTPAIR(hostlen),
383              SHORTPAIR(hostoff),
384              0,0,
385              host, domain);
386
387     /* initial packet length */
388     size = 32 + hostlen + domlen;
389
390     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
391     base64_encode (ntlmbuf, size, base64);
392
393     output = concat_strings ("NTLM ", base64, (char *) 0);
394     break;
395     
396   case NTLMSTATE_TYPE2:
397     /* We received the type-2 already, create a type-3 message:
398
399     Index   Description            Content
400     0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
401                                    (0x4e544c4d53535000)
402     8       NTLM Message Type      long (0x03000000)
403     12      LM/LMv2 Response       security buffer(*)
404     20      NTLM/NTLMv2 Response   security buffer(*)
405     28      Domain Name            security buffer(*)
406     36      User Name              security buffer(*)
407     44      Workstation Name       security buffer(*)
408     (52)    Session Key (optional) security buffer(*)
409     (60)    Flags (optional)       long
410     52 (64) start of data block
411
412     */
413   
414   {
415     int lmrespoff;
416     int ntrespoff;
417     int useroff;
418     unsigned char lmresp[0x18]; /* fixed-size */
419 #ifdef USE_NTRESPONSES
420     unsigned char ntresp[0x18]; /* fixed-size */
421 #endif
422     const char *usr;
423     int userlen;
424
425     DEBUGP (("Creating a type-3 NTLM message.\n"));
426
427     usr = strchr(user, '\\');
428     if(!usr)
429       usr = strchr(user, '/');
430
431     if (usr) {
432       domain = user;
433       domlen = usr - domain;
434       usr++;
435     }
436     else
437       usr = user;
438     userlen = strlen(usr);
439
440     mkhash(passwd, &ntlm->nonce[0], lmresp
441 #ifdef USE_NTRESPONSES
442            , ntresp
443 #endif
444       );
445
446     domoff = 64; /* always */
447     useroff = domoff + domlen;
448     hostoff = useroff + userlen;
449     lmrespoff = hostoff + hostlen;
450     ntrespoff = lmrespoff + 0x18;
451
452     /* Create the big type-3 message binary blob:
453          "NTLMSSP%c"
454          "\x03%c%c%c"  type-3, 32 bits 
455
456          "%c%c%c%c"  LanManager length + allocated space 
457          "%c%c"      LanManager offset 
458          "%c%c"      2 zeroes 
459
460          "%c%c"  NT-response length 
461          "%c%c"  NT-response allocated space 
462          "%c%c"  NT-response offset 
463          "%c%c"  2 zeroes 
464
465          "%c%c"  domain length 
466          "%c%c"  domain allocated space 
467          "%c%c"  domain name offset 
468          "%c%c"  2 zeroes 
469
470          "%c%c"  user length 
471          "%c%c"  user allocated space 
472          "%c%c"  user offset 
473          "%c%c"  2 zeroes 
474
475          "%c%c"  host length 
476          "%c%c"  host allocated space 
477          "%c%c"  host offset 
478          "%c%c%c%c%c%c" 6 zeroes 
479
480          "\xff\xff"   message length 
481          "%c%c"   2 zeroes 
482
483          "\x01\x82"  flags 
484          "%c%c"   2 zeroes */
485
486     size = snprintf(ntlmbuf, sizeof(ntlmbuf),
487                     "NTLMSSP%c\003%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\377\377%c%c\001\202%c%c",
488                     0, /* zero termination */
489                     0,0,0, /* type-3 long, the 24 upper bits */
490
491                     SHORTPAIR(0x18),  /* LanManager response length, twice */
492                     SHORTPAIR(0x18),
493                     SHORTPAIR(lmrespoff),
494                     0x0, 0x0,
495                     
496 #ifdef USE_NTRESPONSES
497                     SHORTPAIR(0x18),  /* NT-response length, twice */
498                     SHORTPAIR(0x18),
499 #else
500                     0x0, 0x0,
501                     0x0, 0x0,
502 #endif
503                     SHORTPAIR(ntrespoff),
504                     0x0, 0x0,
505
506                     SHORTPAIR(domlen),
507                     SHORTPAIR(domlen),
508                     SHORTPAIR(domoff),
509                     0x0, 0x0,
510
511                     SHORTPAIR(userlen),
512                     SHORTPAIR(userlen),
513                     SHORTPAIR(useroff),
514                     0x0, 0x0,
515                     
516                     SHORTPAIR(hostlen),
517                     SHORTPAIR(hostlen),
518                     SHORTPAIR(hostoff),
519                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
520              
521                     0x0, 0x0,
522
523                     0x0, 0x0);
524
525     /* size is now 64 */
526     size=64;
527     ntlmbuf[62]=ntlmbuf[63]=0;
528
529     memcpy(&ntlmbuf[size], domain, domlen);
530     size += domlen;
531
532     memcpy(&ntlmbuf[size], usr, userlen);
533     size += userlen;
534
535     /* we append the binary hashes to the end of the blob */
536     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
537       memcpy(&ntlmbuf[size], lmresp, 0x18);
538       size += 0x18;
539     }
540
541 #ifdef USE_NTRESPONSES
542     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
543       memcpy(&ntlmbuf[size], ntresp, 0x18);
544       size += 0x18;
545     }
546 #endif
547
548     ntlmbuf[56] = size & 0xff;
549     ntlmbuf[57] = size >> 8;
550
551     /* convert the binary blob into base64 */
552     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
553     base64_encode (ntlmbuf, size, base64);
554
555     output = concat_strings ("NTLM ", base64, (char *) 0);
556
557     ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
558     *ready = 1;
559   }
560   break;
561
562   case NTLMSTATE_TYPE3:
563     /* connection is already authenticated,
564      * don't send a header in future requests */
565     *ready = 1;
566     output = NULL;
567     break;
568   }
569
570   return output;
571 }