source: trunk/essentials/net-misc/wget/src/http-ntlm.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

File size: 16.2 KB
Line 
1/* NTLM code.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 Donated by Daniel Stenberg.
4
5This file is part of GNU Wget.
6
7GNU Wget is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12GNU Wget is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with Wget; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21In addition, as a special exception, the Free Software Foundation
22gives permission to link the code of its release of Wget with the
23OpenSSL project's "OpenSSL" library (or with modified versions of it
24that use the same license as the "OpenSSL" library), and distribute
25the linked executables. You must obey the GNU General Public License
26in all respects for all of the code used other than "OpenSSL". If you
27modify this file, you may extend this exception to your version of the
28file, but you are not obligated to do so. If you do not wish to do
29so, 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
52#include "wget.h"
53#include "utils.h"
54#include "http-ntlm.h"
55
56#if OPENSSL_VERSION_NUMBER < 0x00907001L
57#define DES_key_schedule des_key_schedule
58#define DES_cblock des_cblock
59#define DES_set_odd_parity des_set_odd_parity
60#define DES_set_key des_set_key
61#define DES_ecb_encrypt des_ecb_encrypt
62
63/* This is how things were done in the old days */
64#define DESKEY(x) x
65#define DESKEYARG(x) x
66#else
67/* Modern version */
68#define DESKEYARG(x) *x
69#define DESKEY(x) &x
70#endif
71
72/* Define this to make the type-3 message include the NT response message */
73#define USE_NTRESPONSES 1
74
75
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
112
113/*
114 (*) = A "security buffer" is a triplet consisting of two shorts and one
115 long:
116
117 1. a 'short' containing the length of the buffer in bytes
118 2. a 'short' containing the allocated space for the buffer in bytes
119 3. a 'long' containing the offset to the start of the buffer from the
120 beginning of the NTLM message, in bytes.
121*/
122
123/* return 1 on success, 0 otherwise */
124int
125ntlm_input (struct ntlmdata *ntlm, const char *header)
126{
127 if (0 != strncmp (header, "NTLM", 4))
128 return 0;
129
130 header += 4;
131 while (*header && ISSPACE(*header))
132 header++;
133
134 if (*header)
135 {
136 /* We got a type-2 message here:
137
138 Index Description Content
139 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
140 (0x4e544c4d53535000)
141 8 NTLM Message Type long (0x02000000)
142 12 Target Name security buffer(*)
143 20 Flags long
144 24 Challenge 8 bytes
145 (32) Context (optional) 8 bytes (two consecutive longs)
146 (40) Target Information (optional) security buffer(*)
147 32 (48) start of data block
148 */
149 int size;
150 char *buffer = (char *) alloca (strlen (header));
151
152 DEBUGP (("Received a type-2 NTLM message.\n"));
153
154 size = base64_decode (header, buffer);
155 if (size < 0)
156 return 0; /* malformed base64 from server */
157
158 ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
159
160 if (size >= 48)
161 /* the nonce of interest is index [24 .. 31], 8 bytes */
162 memcpy (ntlm->nonce, &buffer[24], 8);
163
164 /* at index decimal 20, there's a 32bit NTLM flag field */
165 }
166 else
167 {
168 if (ntlm->state >= NTLMSTATE_TYPE1)
169 {
170 DEBUGP (("Unexpected empty NTLM message.\n"));
171 return 0; /* this is an error */
172 }
173
174 DEBUGP (("Empty NTLM message, starting transaction.\n"));
175 ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
176 }
177
178 return 1;
179}
180
181/*
182 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
183 * key schedule ks is also set.
184 */
185static void
186setup_des_key(unsigned char *key_56,
187 DES_key_schedule DESKEYARG(ks))
188{
189 DES_cblock key;
190
191 key[0] = key_56[0];
192 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
193 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
194 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
195 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
196 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
197 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
198 key[7] = (key_56[6] << 1) & 0xFF;
199
200 DES_set_odd_parity(&key);
201 DES_set_key(&key, ks);
202}
203
204 /*
205 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
206 * 8 byte plaintext is encrypted with each key and the resulting 24
207 * bytes are stored in the results array.
208 */
209static void
210calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
211{
212 DES_key_schedule ks;
213
214 setup_des_key(keys, DESKEY(ks));
215 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
216 DESKEY(ks), DES_ENCRYPT);
217
218 setup_des_key(keys+7, DESKEY(ks));
219 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
220 DESKEY(ks), DES_ENCRYPT);
221
222 setup_des_key(keys+14, DESKEY(ks));
223 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
224 DESKEY(ks), DES_ENCRYPT);
225}
226
227/*
228 * Set up lanmanager and nt hashed passwords
229 */
230static void
231mkhash(const char *password,
232 unsigned char *nonce, /* 8 bytes */
233 unsigned char *lmresp /* must fit 0x18 bytes */
234#ifdef USE_NTRESPONSES
235 , unsigned char *ntresp /* must fit 0x18 bytes */
236#endif
237 )
238{
239 unsigned char lmbuffer[21];
240#ifdef USE_NTRESPONSES
241 unsigned char ntbuffer[21];
242#endif
243 unsigned char *pw;
244 static const unsigned char magic[] = {
245 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
246 };
247 int i;
248 int len = strlen(password);
249
250 /* make it fit at least 14 bytes */
251 pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
252
253 if (len > 14)
254 len = 14;
255
256 for (i=0; i<len; i++)
257 pw[i] = TOUPPER (password[i]);
258
259 for (; i<14; i++)
260 pw[i] = 0;
261
262 {
263 /* create LanManager hashed password */
264 DES_key_schedule ks;
265
266 setup_des_key(pw, DESKEY(ks));
267 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
268 DESKEY(ks), DES_ENCRYPT);
269
270 setup_des_key(pw+7, DESKEY(ks));
271 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
272 DESKEY(ks), DES_ENCRYPT);
273
274 memset(lmbuffer+16, 0, 5);
275 }
276 /* create LM responses */
277 calc_resp(lmbuffer, nonce, lmresp);
278
279#ifdef USE_NTRESPONSES
280 {
281 /* create NT hashed password */
282 MD4_CTX MD4;
283
284 len = strlen(password);
285
286 for (i=0; i<len; i++) {
287 pw[2*i] = password[i];
288 pw[2*i+1] = 0;
289 }
290
291 MD4_Init(&MD4);
292 MD4_Update(&MD4, pw, 2*len);
293 MD4_Final(ntbuffer, &MD4);
294
295 memset(ntbuffer+16, 0, 5);
296 }
297
298 calc_resp(ntbuffer, nonce, ntresp);
299#endif
300}
301
302#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
303#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
304 (((x) >>16)&0xff), ((x)>>24)
305
306/* this is for creating ntlm header output */
307char *
308ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
309 int *ready)
310{
311 const char *domain=""; /* empty */
312 const char *host=""; /* empty */
313 int domlen=strlen(domain);
314 int hostlen = strlen(host);
315 int hostoff; /* host name offset */
316 int domoff; /* domain name offset */
317 int size;
318 char *base64;
319 char ntlmbuf[256]; /* enough, unless the host/domain is very long */
320
321 /* point to the address of the pointer that holds the string to sent to the
322 server, which is for a plain host or for a HTTP proxy */
323 char *output;
324
325 *ready = 0;
326
327 /* not set means empty */
328 if(!user)
329 user="";
330
331 if(!passwd)
332 passwd="";
333
334 switch(ntlm->state) {
335 case NTLMSTATE_TYPE1:
336 default: /* for the weird cases we (re)start here */
337 hostoff = 32;
338 domoff = hostoff + hostlen;
339
340 DEBUGP (("Creating a type-1 NTLM message.\n"));
341
342 /* Create and send a type-1 message:
343
344 Index Description Content
345 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
346 (0x4e544c4d53535000)
347 8 NTLM Message Type long (0x01000000)
348 12 Flags long
349 16 Supplied Domain security buffer(*)
350 24 Supplied Workstation security buffer(*)
351 32 start of data block
352
353 Format string (merged for pre-ANSI compilers):
354 "NTLMSSP%c"
355 "\x01%c%c%c" 32-bit type = 1
356 "%c%c%c%c" 32-bit NTLM flag field
357 "%c%c" domain length
358 "%c%c" domain allocated space
359 "%c%c" domain name offset
360 "%c%c" 2 zeroes
361 "%c%c" host length
362 "%c%c" host allocated space
363 "%c%c" host name offset
364 "%c%c" 2 zeroes
365 "%s" host name
366 "%s" domain string
367 */
368
369 snprintf(ntlmbuf, sizeof(ntlmbuf),
370 "NTLMSSP%c\001%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",
371 0, /* trailing zero */
372 0,0,0, /* part of type-1 long */
373
374 LONGQUARTET(
375 NTLMFLAG_NEGOTIATE_OEM| /* 2 */
376 NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
377 /* equals 0x0202 */
378 ),
379 SHORTPAIR(domlen),
380 SHORTPAIR(domlen),
381 SHORTPAIR(domoff),
382 0,0,
383 SHORTPAIR(hostlen),
384 SHORTPAIR(hostlen),
385 SHORTPAIR(hostoff),
386 0,0,
387 host, domain);
388
389 /* initial packet length */
390 size = 32 + hostlen + domlen;
391
392 base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
393 base64_encode (ntlmbuf, size, base64);
394
395 output = concat_strings ("NTLM ", base64, (char *) 0);
396 break;
397
398 case NTLMSTATE_TYPE2:
399 /* We received the type-2 already, create a type-3 message:
400
401 Index Description Content
402 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
403 (0x4e544c4d53535000)
404 8 NTLM Message Type long (0x03000000)
405 12 LM/LMv2 Response security buffer(*)
406 20 NTLM/NTLMv2 Response security buffer(*)
407 28 Domain Name security buffer(*)
408 36 User Name security buffer(*)
409 44 Workstation Name security buffer(*)
410 (52) Session Key (optional) security buffer(*)
411 (60) Flags (optional) long
412 52 (64) start of data block
413
414 */
415
416 {
417 int lmrespoff;
418 int ntrespoff;
419 int useroff;
420 unsigned char lmresp[0x18]; /* fixed-size */
421#ifdef USE_NTRESPONSES
422 unsigned char ntresp[0x18]; /* fixed-size */
423#endif
424 const char *usr;
425 int userlen;
426
427 DEBUGP (("Creating a type-3 NTLM message.\n"));
428
429 usr = strchr(user, '\\');
430 if(!usr)
431 usr = strchr(user, '/');
432
433 if (usr) {
434 domain = user;
435 domlen = usr - domain;
436 usr++;
437 }
438 else
439 usr = user;
440 userlen = strlen(usr);
441
442 mkhash(passwd, &ntlm->nonce[0], lmresp
443#ifdef USE_NTRESPONSES
444 , ntresp
445#endif
446 );
447
448 domoff = 64; /* always */
449 useroff = domoff + domlen;
450 hostoff = useroff + userlen;
451 lmrespoff = hostoff + hostlen;
452 ntrespoff = lmrespoff + 0x18;
453
454 /* Create the big type-3 message binary blob:
455 "NTLMSSP%c"
456 "\x03%c%c%c" type-3, 32 bits
457
458 "%c%c%c%c" LanManager length + allocated space
459 "%c%c" LanManager offset
460 "%c%c" 2 zeroes
461
462 "%c%c" NT-response length
463 "%c%c" NT-response allocated space
464 "%c%c" NT-response offset
465 "%c%c" 2 zeroes
466
467 "%c%c" domain length
468 "%c%c" domain allocated space
469 "%c%c" domain name offset
470 "%c%c" 2 zeroes
471
472 "%c%c" user length
473 "%c%c" user allocated space
474 "%c%c" user offset
475 "%c%c" 2 zeroes
476
477 "%c%c" host length
478 "%c%c" host allocated space
479 "%c%c" host offset
480 "%c%c%c%c%c%c" 6 zeroes
481
482 "\xff\xff" message length
483 "%c%c" 2 zeroes
484
485 "\x01\x82" flags
486 "%c%c" 2 zeroes */
487
488 size = snprintf(ntlmbuf, sizeof(ntlmbuf),
489 "NTLMSSP%c\003%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\377\377%c%c\001\202%c%c",
490 0, /* zero termination */
491 0,0,0, /* type-3 long, the 24 upper bits */
492
493 SHORTPAIR(0x18), /* LanManager response length, twice */
494 SHORTPAIR(0x18),
495 SHORTPAIR(lmrespoff),
496 0x0, 0x0,
497
498#ifdef USE_NTRESPONSES
499 SHORTPAIR(0x18), /* NT-response length, twice */
500 SHORTPAIR(0x18),
501#else
502 0x0, 0x0,
503 0x0, 0x0,
504#endif
505 SHORTPAIR(ntrespoff),
506 0x0, 0x0,
507
508 SHORTPAIR(domlen),
509 SHORTPAIR(domlen),
510 SHORTPAIR(domoff),
511 0x0, 0x0,
512
513 SHORTPAIR(userlen),
514 SHORTPAIR(userlen),
515 SHORTPAIR(useroff),
516 0x0, 0x0,
517
518 SHORTPAIR(hostlen),
519 SHORTPAIR(hostlen),
520 SHORTPAIR(hostoff),
521 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
522
523 0x0, 0x0,
524
525 0x0, 0x0);
526
527 /* size is now 64 */
528 size=64;
529 ntlmbuf[62]=ntlmbuf[63]=0;
530
531 /* Make sure that the user and domain strings fit in the target buffer
532 before we copy them there. */
533 if(size + userlen + domlen >= sizeof(ntlmbuf))
534 return NULL;
535
536 memcpy(&ntlmbuf[size], domain, domlen);
537 size += domlen;
538
539 memcpy(&ntlmbuf[size], usr, userlen);
540 size += userlen;
541
542 /* we append the binary hashes to the end of the blob */
543 if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
544 memcpy(&ntlmbuf[size], lmresp, 0x18);
545 size += 0x18;
546 }
547
548#ifdef USE_NTRESPONSES
549 if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
550 memcpy(&ntlmbuf[size], ntresp, 0x18);
551 size += 0x18;
552 }
553#endif
554
555 ntlmbuf[56] = size & 0xff;
556 ntlmbuf[57] = size >> 8;
557
558 /* convert the binary blob into base64 */
559 base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
560 base64_encode (ntlmbuf, size, base64);
561
562 output = concat_strings ("NTLM ", base64, (char *) 0);
563
564 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
565 *ready = 1;
566 }
567 break;
568
569 case NTLMSTATE_TYPE3:
570 /* connection is already authenticated,
571 * don't send a header in future requests */
572 *ready = 1;
573 output = NULL;
574 break;
575 }
576
577 return output;
578}
Note: See TracBrowser for help on using the repository browser.