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