]> sjero.net Git - wget/blob - src/http-ntlm.c
[svn] Added NTLM support.
[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       unsigned char *buffer = (unsigned 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   unsigned 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     */
342
343     snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
344              "\x01%c%c%c" /* 32-bit type = 1 */
345              "%c%c%c%c"   /* 32-bit NTLM flag field */
346              "%c%c"  /* domain length */
347              "%c%c"  /* domain allocated space */
348              "%c%c"  /* domain name offset */
349              "%c%c"  /* 2 zeroes */
350              "%c%c"  /* host length */
351              "%c%c"  /* host allocated space */
352              "%c%c"  /* host name offset */
353              "%c%c"  /* 2 zeroes */
354              "%s"   /* host name */
355              "%s",  /* domain string */
356              0,     /* trailing zero */
357              0,0,0, /* part of type-1 long */
358
359              LONGQUARTET(
360                NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
361                NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
362                /* equals 0x0202 */
363                ),
364              SHORTPAIR(domlen),
365              SHORTPAIR(domlen),
366              SHORTPAIR(domoff),
367              0,0,
368              SHORTPAIR(hostlen),
369              SHORTPAIR(hostlen),
370              SHORTPAIR(hostoff),
371              0,0,
372              host, domain);
373
374     /* initial packet length */
375     size = 32 + hostlen + domlen;
376
377     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
378     base64_encode (ntlmbuf, base64, size);
379
380     output = concat_strings ("NTLM ", base64, (char *) 0);
381     break;
382     
383   case NTLMSTATE_TYPE2:
384     /* We received the type-2 already, create a type-3 message:
385
386     Index   Description            Content
387     0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
388                                    (0x4e544c4d53535000)
389     8       NTLM Message Type      long (0x03000000)
390     12      LM/LMv2 Response       security buffer(*)
391     20      NTLM/NTLMv2 Response   security buffer(*)
392     28      Domain Name            security buffer(*)
393     36      User Name              security buffer(*)
394     44      Workstation Name       security buffer(*)
395     (52)    Session Key (optional) security buffer(*)
396     (60)    Flags (optional)       long
397     52 (64) start of data block
398
399     */
400   
401   {
402     int lmrespoff;
403     int ntrespoff;
404     int useroff;
405     unsigned char lmresp[0x18]; /* fixed-size */
406 #ifdef USE_NTRESPONSES
407     unsigned char ntresp[0x18]; /* fixed-size */
408 #endif
409     const char *usr;
410     int userlen;
411
412     usr = strchr(user, '\\');
413     if(!usr)
414       usr = strchr(user, '/');
415
416     if (usr) {
417       domain = usr;
418       domlen = usr - domain;
419       usr++;
420     }
421     else
422       usr = user;
423     userlen = strlen(usr);
424
425     mkhash(passwd, &ntlm->nonce[0], lmresp
426 #ifdef USE_NTRESPONSES
427            , ntresp
428 #endif
429       );
430
431     domoff = 64; /* always */
432     useroff = domoff + domlen;
433     hostoff = useroff + userlen;
434     lmrespoff = hostoff + hostlen;
435     ntrespoff = lmrespoff + 0x18;
436
437     /* Create the big type-3 message binary blob */
438     size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
439                     "NTLMSSP%c"
440                     "\x03%c%c%c" /* type-3, 32 bits */
441
442                     "%c%c%c%c" /* LanManager length + allocated space */
443                     "%c%c" /* LanManager offset */
444                     "%c%c" /* 2 zeroes */
445
446                     "%c%c" /* NT-response length */
447                     "%c%c" /* NT-response allocated space */
448                     "%c%c" /* NT-response offset */
449                     "%c%c" /* 2 zeroes */
450                     
451                     "%c%c"  /* domain length */
452                     "%c%c"  /* domain allocated space */
453                     "%c%c"  /* domain name offset */
454                     "%c%c"  /* 2 zeroes */
455                     
456                     "%c%c"  /* user length */
457                     "%c%c"  /* user allocated space */
458                     "%c%c"  /* user offset */
459                     "%c%c"  /* 2 zeroes */
460                     
461                     "%c%c"  /* host length */
462                     "%c%c"  /* host allocated space */
463                     "%c%c"  /* host offset */
464                     "%c%c%c%c%c%c"  /* 6 zeroes */
465                     
466                     "\xff\xff"  /* message length */
467                     "%c%c"  /* 2 zeroes */
468                     
469                     "\x01\x82" /* flags */
470                     "%c%c"  /* 2 zeroes */
471
472                     /* domain string */
473                     /* user string */
474                     /* host string */
475                     /* LanManager response */
476                     /* NT response */
477                     ,
478                     0, /* zero termination */
479                     0,0,0, /* type-3 long, the 24 upper bits */
480
481                     SHORTPAIR(0x18),  /* LanManager response length, twice */
482                     SHORTPAIR(0x18),
483                     SHORTPAIR(lmrespoff),
484                     0x0, 0x0,
485                     
486 #ifdef USE_NTRESPONSES
487                     SHORTPAIR(0x18),  /* NT-response length, twice */
488                     SHORTPAIR(0x18),
489 #else
490                     0x0, 0x0,
491                     0x0, 0x0,
492 #endif
493                     SHORTPAIR(ntrespoff),
494                     0x0, 0x0,
495
496                     SHORTPAIR(domlen),
497                     SHORTPAIR(domlen),
498                     SHORTPAIR(domoff),
499                     0x0, 0x0,
500
501                     SHORTPAIR(userlen),
502                     SHORTPAIR(userlen),
503                     SHORTPAIR(useroff),
504                     0x0, 0x0,
505                     
506                     SHORTPAIR(hostlen),
507                     SHORTPAIR(hostlen),
508                     SHORTPAIR(hostoff),
509                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
510              
511                     0x0, 0x0,
512
513                     0x0, 0x0);
514
515     /* size is now 64 */
516     size=64;
517     ntlmbuf[62]=ntlmbuf[63]=0;
518
519     memcpy(&ntlmbuf[size], domain, domlen);
520     size += domlen;
521
522     memcpy(&ntlmbuf[size], usr, userlen);
523     size += userlen;
524
525     /* we append the binary hashes to the end of the blob */
526     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
527       memcpy(&ntlmbuf[size], lmresp, 0x18);
528       size += 0x18;
529     }
530
531 #ifdef USE_NTRESPONSES
532     if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
533       memcpy(&ntlmbuf[size], ntresp, 0x18);
534       size += 0x18;
535     }
536 #endif
537
538     ntlmbuf[56] = size & 0xff;
539     ntlmbuf[57] = size >> 8;
540
541     /* convert the binary blob into base64 */
542     base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
543     base64_encode (ntlmbuf, base64, size);
544
545     output = concat_strings ("NTLM ", base64, (char *) 0);
546
547     ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
548     *ready = 1;
549   }
550   break;
551
552   case NTLMSTATE_TYPE3:
553     /* connection is already authenticated,
554      * don't send a header in future requests */
555     *ready = 1;
556     output = NULL;
557     break;
558   }
559
560   return output;
561 }