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