]> sjero.net Git - wget/blob - src/http-ntlm.c
[svn] Fix setting the NTLM domain.
[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       size = base64_decode (header, buffer);
151       if (size < 0)
152         return 0;               /* malformed base64 from server */
153
154       ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
155
156       if (size >= 48)
157         /* the nonce of interest is index [24 .. 31], 8 bytes */
158         memcpy (ntlm->nonce, &buffer[24], 8);
159
160       /* at index decimal 20, there's a 32bit NTLM flag field */
161     }
162   else
163     {
164       if (ntlm->state >= NTLMSTATE_TYPE1)
165         return 0; /* this is an error */
166
167       ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
168     }
169
170   return 1;
171 }
172
173 /*
174  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
175  * key schedule ks is also set.
176  */
177 static void setup_des_key(unsigned char *key_56,
178                           DES_key_schedule DESKEYARG(ks))
179 {
180   DES_cblock key;
181
182   key[0] = key_56[0];
183   key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
184   key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
185   key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
186   key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
187   key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
188   key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
189   key[7] =  (key_56[6] << 1) & 0xFF;
190
191   DES_set_odd_parity(&key);
192   DES_set_key(&key, ks);
193 }
194
195  /*
196   * takes a 21 byte array and treats it as 3 56-bit DES keys. The
197   * 8 byte plaintext is encrypted with each key and the resulting 24
198   * bytes are stored in the results array.
199   */
200 static void calc_resp(unsigned char *keys,
201                       unsigned char *plaintext,
202                       unsigned char *results)
203 {
204   DES_key_schedule ks;
205
206   setup_des_key(keys, DESKEY(ks));
207   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
208                   DESKEY(ks), DES_ENCRYPT);
209
210   setup_des_key(keys+7, DESKEY(ks));
211   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
212                   DESKEY(ks), DES_ENCRYPT);
213
214   setup_des_key(keys+14, DESKEY(ks));
215   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
216                   DESKEY(ks), DES_ENCRYPT);
217 }
218
219 /*
220  * Set up lanmanager and nt hashed passwords
221  */
222 static void mkhash(const char *password,
223                    unsigned char *nonce,  /* 8 bytes */
224                    unsigned char *lmresp  /* must fit 0x18 bytes */
225 #ifdef USE_NTRESPONSES
226                    , unsigned char *ntresp  /* must fit 0x18 bytes */
227 #endif
228   )
229 {
230   unsigned char lmbuffer[21];
231 #ifdef USE_NTRESPONSES
232   unsigned char ntbuffer[21];
233 #endif
234   unsigned char *pw;
235   static const unsigned char magic[] = {
236     0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
237   };
238   int i;
239   int len = strlen(password);
240
241   /* make it fit at least 14 bytes */
242   pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
243
244   if (len > 14)
245     len = 14;
246   
247   for (i=0; i<len; i++)
248     pw[i] = TOUPPER (password[i]);
249
250   for (; i<14; i++)
251     pw[i] = 0;
252
253   {
254     /* create LanManager hashed password */
255     DES_key_schedule ks;
256
257     setup_des_key(pw, DESKEY(ks));
258     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
259                     DESKEY(ks), DES_ENCRYPT);
260   
261     setup_des_key(pw+7, DESKEY(ks));
262     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
263                     DESKEY(ks), DES_ENCRYPT);
264
265     memset(lmbuffer+16, 0, 5);
266   }
267   /* create LM responses */
268   calc_resp(lmbuffer, nonce, lmresp);
269
270 #ifdef USE_NTRESPONSES
271   {
272     /* create NT hashed password */
273     MD4_CTX MD4;
274
275     len = strlen(password);
276
277     for (i=0; i<len; i++) {
278       pw[2*i]   = password[i];
279       pw[2*i+1] = 0;
280     }
281
282     MD4_Init(&MD4);
283     MD4_Update(&MD4, pw, 2*len);
284     MD4_Final(ntbuffer, &MD4);
285
286     memset(ntbuffer+16, 0, 5);
287   }
288
289   calc_resp(ntbuffer, nonce, ntresp);
290 #endif
291 }
292
293 #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
294 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
295   (((x) >>16)&0xff), ((x)>>24)
296
297 /* this is for creating ntlm header output */
298 char *ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
299                    int *ready)
300 {
301   const char *domain=""; /* empty */
302   const char *host=""; /* empty */
303   int domlen=strlen(domain);
304   int hostlen = strlen(host);
305   int hostoff; /* host name offset */
306   int domoff;  /* domain name offset */
307   int size;
308   char *base64;
309   char ntlmbuf[256]; /* enough, unless the host/domain is very long */
310
311   /* point to the address of the pointer that holds the string to sent to the
312      server, which is for a plain host or for a HTTP proxy */
313   char *output;
314
315   *ready = 0;
316
317   /* not set means empty */
318   if(!user)
319     user="";
320
321   if(!passwd)
322     passwd="";
323   
324   switch(ntlm->state) {
325   case NTLMSTATE_TYPE1:
326   default: /* for the weird cases we (re)start here */
327     hostoff = 32;
328     domoff = hostoff + hostlen;
329     
330     /* Create and send a type-1 message:
331
332     Index Description          Content
333     0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
334                                (0x4e544c4d53535000)
335     8     NTLM Message Type    long (0x01000000)
336     12    Flags                long
337     16    Supplied Domain      security buffer(*)
338     24    Supplied Workstation security buffer(*)
339     32    start of data block
340
341     Format string (merged for pre-ANSI compilers):
342       "NTLMSSP%c"
343       "\x01%c%c%c" 32-bit type = 1
344       "%c%c%c%c"   32-bit NTLM flag field
345       "%c%c"  domain length
346       "%c%c"  domain allocated space
347       "%c%c"  domain name offset
348       "%c%c"  2 zeroes
349       "%c%c"  host length
350       "%c%c"  host allocated space
351       "%c%c"  host name offset
352       "%c%c"  2 zeroes
353       "%s"    host name
354       "%s"   domain string
355     */
356
357     snprintf(ntlmbuf, sizeof(ntlmbuf),
358              "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",
359              0,     /* trailing zero */
360              0,0,0, /* part of type-1 long */
361
362              LONGQUARTET(
363                NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
364                NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
365                /* equals 0x0202 */
366                ),
367              SHORTPAIR(domlen),
368              SHORTPAIR(domlen),
369              SHORTPAIR(domoff),
370              0,0,
371              SHORTPAIR(hostlen),
372              SHORTPAIR(hostlen),
373              SHORTPAIR(hostoff),
374              0,0,
375              host, domain);
376
377     /* initial packet length */
378     size = 32 + hostlen + domlen;
379
380     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
381     base64_encode (ntlmbuf, size, base64);
382
383     output = concat_strings ("NTLM ", base64, (char *) 0);
384     break;
385     
386   case NTLMSTATE_TYPE2:
387     /* We received the type-2 already, create a type-3 message:
388
389     Index   Description            Content
390     0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
391                                    (0x4e544c4d53535000)
392     8       NTLM Message Type      long (0x03000000)
393     12      LM/LMv2 Response       security buffer(*)
394     20      NTLM/NTLMv2 Response   security buffer(*)
395     28      Domain Name            security buffer(*)
396     36      User Name              security buffer(*)
397     44      Workstation Name       security buffer(*)
398     (52)    Session Key (optional) security buffer(*)
399     (60)    Flags (optional)       long
400     52 (64) start of data block
401
402     */
403   
404   {
405     int lmrespoff;
406     int ntrespoff;
407     int useroff;
408     unsigned char lmresp[0x18]; /* fixed-size */
409 #ifdef USE_NTRESPONSES
410     unsigned char ntresp[0x18]; /* fixed-size */
411 #endif
412     const char *usr;
413     int userlen;
414
415     usr = strchr(user, '\\');
416     if(!usr)
417       usr = strchr(user, '/');
418
419     if (usr) {
420       domain = user;
421       domlen = usr - domain;
422       usr++;
423     }
424     else
425       usr = user;
426     userlen = strlen(usr);
427
428     mkhash(passwd, &ntlm->nonce[0], lmresp
429 #ifdef USE_NTRESPONSES
430            , ntresp
431 #endif
432       );
433
434     domoff = 64; /* always */
435     useroff = domoff + domlen;
436     hostoff = useroff + userlen;
437     lmrespoff = hostoff + hostlen;
438     ntrespoff = lmrespoff + 0x18;
439
440     /* Create the big type-3 message binary blob:
441          "NTLMSSP%c"
442          "\x03%c%c%c"  type-3, 32 bits 
443
444          "%c%c%c%c"  LanManager length + allocated space 
445          "%c%c"      LanManager offset 
446          "%c%c"      2 zeroes 
447
448          "%c%c"  NT-response length 
449          "%c%c"  NT-response allocated space 
450          "%c%c"  NT-response offset 
451          "%c%c"  2 zeroes 
452
453          "%c%c"  domain length 
454          "%c%c"  domain allocated space 
455          "%c%c"  domain name offset 
456          "%c%c"  2 zeroes 
457
458          "%c%c"  user length 
459          "%c%c"  user allocated space 
460          "%c%c"  user offset 
461          "%c%c"  2 zeroes 
462
463          "%c%c"  host length 
464          "%c%c"  host allocated space 
465          "%c%c"  host offset 
466          "%c%c%c%c%c%c" 6 zeroes 
467
468          "\xff\xff"   message length 
469          "%c%c"   2 zeroes 
470
471          "\x01\x82"  flags 
472          "%c%c"   2 zeroes */
473
474     size = snprintf(ntlmbuf, sizeof(ntlmbuf),
475                     "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",
476                     0, /* zero termination */
477                     0,0,0, /* type-3 long, the 24 upper bits */
478
479                     SHORTPAIR(0x18),  /* LanManager response length, twice */
480                     SHORTPAIR(0x18),
481                     SHORTPAIR(lmrespoff),
482                     0x0, 0x0,
483                     
484 #ifdef USE_NTRESPONSES
485                     SHORTPAIR(0x18),  /* NT-response length, twice */
486                     SHORTPAIR(0x18),
487 #else
488                     0x0, 0x0,
489                     0x0, 0x0,
490 #endif
491                     SHORTPAIR(ntrespoff),
492                     0x0, 0x0,
493
494                     SHORTPAIR(domlen),
495                     SHORTPAIR(domlen),
496                     SHORTPAIR(domoff),
497                     0x0, 0x0,
498
499                     SHORTPAIR(userlen),
500                     SHORTPAIR(userlen),
501                     SHORTPAIR(useroff),
502                     0x0, 0x0,
503                     
504                     SHORTPAIR(hostlen),
505                     SHORTPAIR(hostlen),
506                     SHORTPAIR(hostoff),
507                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
508              
509                     0x0, 0x0,
510
511                     0x0, 0x0);
512
513     /* size is now 64 */
514     size=64;
515     ntlmbuf[62]=ntlmbuf[63]=0;
516
517     memcpy(&ntlmbuf[size], domain, domlen);
518     size += domlen;
519
520     memcpy(&ntlmbuf[size], usr, userlen);
521     size += userlen;
522
523     /* we append the binary hashes to the end of the blob */
524     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
525       memcpy(&ntlmbuf[size], lmresp, 0x18);
526       size += 0x18;
527     }
528
529 #ifdef USE_NTRESPONSES
530     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
531       memcpy(&ntlmbuf[size], ntresp, 0x18);
532       size += 0x18;
533     }
534 #endif
535
536     ntlmbuf[56] = size & 0xff;
537     ntlmbuf[57] = size >> 8;
538
539     /* convert the binary blob into base64 */
540     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
541     base64_encode (ntlmbuf, size, base64);
542
543     output = concat_strings ("NTLM ", base64, (char *) 0);
544
545     ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
546     *ready = 1;
547   }
548   break;
549
550   case NTLMSTATE_TYPE3:
551     /* connection is already authenticated,
552      * don't send a header in future requests */
553     *ready = 1;
554     output = NULL;
555     break;
556   }
557
558   return output;
559 }