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