doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
http_ntlm.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: http_ntlm.c,v 1.28 2004/03/08 16:20:51 bagder Exp $
22  ***************************************************************************/
23 #include "setup.h"
24 
25 /* NTLM details:
26 
27  http://davenport.sourceforge.net/ntlm.html
28  http://www.innovation.ch/java/ntlm.html
29 
30 */
31 
32 #ifndef CURL_DISABLE_HTTP
33 #ifdef USE_SSLEAY
34 /* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
35 
36 /* -- WIN32 approved -- */
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 
43 #include "urldata.h"
44 #include "sendf.h"
45 #include "strequal.h"
46 #include "base64.h"
47 #include "http_ntlm.h"
48 #include "url.h"
49 #include "http.h" /* for Curl_http_auth_stage() */
50 
51 #define _MPRINTF_REPLACE /* use our functions only */
52 #include <curl/mprintf.h>
53 
54 #include <openssl/des.h>
55 #include <openssl/md4.h>
56 #include <openssl/ssl.h>
57 
58 #if OPENSSL_VERSION_NUMBER < 0x00907001L
59 #define DES_key_schedule des_key_schedule
60 #define DES_cblock des_cblock
61 #define DES_set_odd_parity des_set_odd_parity
62 #define DES_set_key des_set_key
63 #define DES_ecb_encrypt des_ecb_encrypt
64 
65 /* This is how things were done in the old days */
66 #define DESKEY(x) x
67 #define DESKEYARG(x) x
68 #else
69 /* Modern version */
70 #define DESKEYARG(x) *x
71 #define DESKEY(x) &x
72 #endif
73 
74 /* The last #include file should be: */
75 #ifdef CURLDEBUG
76 #include "memdebug.h"
77 #endif
78 
79 /* Define this to make the type-3 message include the NT response message */
80 #undef USE_NTRESPONSES
81 
82 /*
83  (*) = A "security buffer" is a triplet consisting of two shorts and one
84  long:
85 
86  1. a 'short' containing the length of the buffer in bytes
87  2. a 'short' containing the allocated space for the buffer in bytes
88  3. a 'long' containing the offset to the start of the buffer from the
89  beginning of the NTLM message, in bytes.
90 */
91 
92 
94  bool proxy, /* if proxy or not */
95  char *header) /* rest of the www-authenticate:
96  header */
97 {
98  /* point to the correct struct with this */
99  struct ntlmdata *ntlm;
100 
101  ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
102 
103  /* skip initial whitespaces */
104  while(*header && isspace((int)*header))
105  header++;
106 
107  if(checkprefix("NTLM", header)) {
108  unsigned char buffer[256];
109  header += strlen("NTLM");
110 
111  while(*header && isspace((int)*header))
112  header++;
113 
114  if(*header) {
115  /* We got a type-2 message here:
116 
117  Index Description Content
118  0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
119  (0x4e544c4d53535000)
120  8 NTLM Message Type long (0x02000000)
121  12 Target Name security buffer(*)
122  20 Flags long
123  24 Challenge 8 bytes
124  (32) Context (optional) 8 bytes (two consecutive longs)
125  (40) Target Information (optional) security buffer(*)
126  32 (48) start of data block
127  */
128 
129  size_t size = Curl_base64_decode(header, (char *)buffer);
130 
131  ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
132 
133  if(size >= 48)
134  /* the nonce of interest is index [24 .. 31], 8 bytes */
135  memcpy(ntlm->nonce, &buffer[24], 8);
136 
137  /* at index decimal 20, there's a 32bit NTLM flag field */
138 
139  }
140  else {
141  if(ntlm->state >= NTLMSTATE_TYPE1)
142  return CURLNTLM_BAD;
143 
144  ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
145  }
146  }
147  return CURLNTLM_FINE;
148 }
149 
150 /*
151  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
152  * key schedule ks is also set.
153  */
154 static void setup_des_key(unsigned char *key_56,
155  DES_key_schedule DESKEYARG(ks))
156 {
157  DES_cblock key;
158 
159  key[0] = key_56[0];
160  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
161  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
162  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
163  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
164  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
165  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
166  key[7] = (key_56[6] << 1) & 0xFF;
167 
168  DES_set_odd_parity(&key);
169  DES_set_key(&key, ks);
170 }
171 
172  /*
173  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
174  * 8 byte plaintext is encrypted with each key and the resulting 24
175  * bytes are stored in the results array.
176  */
177 static void calc_resp(unsigned char *keys,
178  unsigned char *plaintext,
179  unsigned char *results)
180 {
181  DES_key_schedule ks;
182 
183  setup_des_key(keys, DESKEY(ks));
184  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
185  DESKEY(ks), DES_ENCRYPT);
186 
187  setup_des_key(keys+7, DESKEY(ks));
188  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
189  DESKEY(ks), DES_ENCRYPT);
190 
191  setup_des_key(keys+14, DESKEY(ks));
192  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
193  DESKEY(ks), DES_ENCRYPT);
194 }
195 
196 /*
197  * Set up lanmanager and nt hashed passwords
198  */
199 static void mkhash(char *password,
200  unsigned char *nonce, /* 8 bytes */
201  unsigned char *lmresp /* must fit 0x18 bytes */
202 #ifdef USE_NTRESPONSES
203  , unsigned char *ntresp /* must fit 0x18 bytes */
204 #endif
205  )
206 {
207  unsigned char lmbuffer[21];
208 #ifdef USE_NTRESPONSES
209  unsigned char ntbuffer[21];
210 #endif
211  unsigned char *pw;
212  static const unsigned char magic[] = {
213  0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
214  };
215  unsigned int i;
216  size_t len = strlen(password);
217 
218  /* make it fit at least 14 bytes */
219  pw = malloc(len<7?14:len*2);
220  if(!pw)
221  return; /* this will lead to a badly generated package */
222 
223  if (len > 14)
224  len = 14;
225 
226  for (i=0; i<len; i++)
227  pw[i] = toupper(password[i]);
228 
229  for (; i<14; i++)
230  pw[i] = 0;
231 
232  {
233  /* create LanManager hashed password */
234  DES_key_schedule ks;
235 
236  setup_des_key(pw, DESKEY(ks));
237  DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
238  DESKEY(ks), DES_ENCRYPT);
239 
240  setup_des_key(pw+7, DESKEY(ks));
241  DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
242  DESKEY(ks), DES_ENCRYPT);
243 
244  memset(lmbuffer+16, 0, 5);
245  }
246  /* create LM responses */
247  calc_resp(lmbuffer, nonce, lmresp);
248 
249 #ifdef USE_NTRESPONSES
250  {
251  /* create NT hashed password */
252  MD4_CTX MD4;
253 
254  len = strlen(password);
255 
256  for (i=0; i<len; i++) {
257  pw[2*i] = password[i];
258  pw[2*i+1] = 0;
259  }
260 
261  MD4_Init(&MD4);
262  MD4_Update(&MD4, pw, 2*len);
263  MD4_Final(ntbuffer, &MD4);
264 
265  memset(ntbuffer+16, 0, 8);
266  }
267 
268  calc_resp(ntbuffer, nonce, ntresp);
269 #endif
270 
271  free(pw);
272 }
273 
274 #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
275 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
276  (((x) >>16)&0xff), ((x)>>24)
277 
278 /* this is for creating ntlm header output */
280  bool proxy,
281  bool *ready)
282 {
283  const char *domain=""; /* empty */
284  const char *host=""; /* empty */
285  int domlen=(int)strlen(domain);
286  int hostlen = (int)strlen(host);
287  int hostoff; /* host name offset */
288  int domoff; /* domain name offset */
289  size_t size;
290  char *base64=NULL;
291  unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
292 
293  /* point to the address of the pointer that holds the string to sent to the
294  server, which is for a plain host or for a HTTP proxy */
295  char **allocuserpwd;
296 
297  /* point to the name and password for this */
298  char *userp;
299  char *passwdp;
300  /* point to the correct struct with this */
301  struct ntlmdata *ntlm;
302 
303  *ready = FALSE;
304 
305  if(proxy) {
306  allocuserpwd = &conn->allocptr.proxyuserpwd;
307  userp = conn->proxyuser;
308  passwdp = conn->proxypasswd;
309  ntlm = &conn->proxyntlm;
310  }
311  else {
312  allocuserpwd = &conn->allocptr.userpwd;
313  userp = conn->user;
314  passwdp = conn->passwd;
315  ntlm = &conn->ntlm;
316  }
317 
318  /* not set means empty */
319  if(!userp)
320  userp=(char *)"";
321 
322  if(!passwdp)
323  passwdp=(char *)"";
324 
325  switch(ntlm->state) {
326  case NTLMSTATE_TYPE1:
327  default: /* for the weird cases we (re)start here */
328  hostoff = 32;
329  domoff = hostoff + hostlen;
330 
331  /* Create and send a type-1 message:
332 
333  Index Description Content
334  0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
335  (0x4e544c4d53535000)
336  8 NTLM Message Type long (0x01000000)
337  12 Flags long
338  16 Supplied Domain security buffer(*)
339  24 Supplied Workstation security buffer(*)
340  32 start of data block
341 
342  */
343 
344  snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
345  "\x01%c%c%c" /* 32-bit type = 1 */
346  "%c%c%c%c" /* 32-bit NTLM flag field */
347  "%c%c" /* domain length */
348  "%c%c" /* domain allocated space */
349  "%c%c" /* domain name offset */
350  "%c%c" /* 2 zeroes */
351  "%c%c" /* host length */
352  "%c%c" /* host allocated space */
353  "%c%c" /* host name offset */
354  "%c%c" /* 2 zeroes */
355  "%s" /* host name */
356  "%s", /* domain string */
357  0, /* trailing zero */
358  0,0,0, /* part of type-1 long */
359 
360  LONGQUARTET(
361  NTLMFLAG_NEGOTIATE_OEM| /* 2 */
363  /* equals 0x0202 */
364  ),
365  SHORTPAIR(domlen),
366  SHORTPAIR(domlen),
367  SHORTPAIR(domoff),
368  0,0,
369  SHORTPAIR(hostlen),
370  SHORTPAIR(hostlen),
371  SHORTPAIR(hostoff),
372  0,0,
373  host, domain);
374 
375  /* initial packet length */
376  size = 32 + hostlen + domlen;
377 
378  /* now keeper of the base64 encoded package size */
379  size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
380 
381  if(size >0 ) {
382  Curl_safefree(*allocuserpwd);
383  *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
384  proxy?"Proxy-":"",
385  base64);
386  free(base64);
387  }
388  else
389  return CURLE_OUT_OF_MEMORY; /* FIX TODO */
390 
391  break;
392 
393  case NTLMSTATE_TYPE2:
394  /* We received the type-2 already, create a type-3 message:
395 
396  Index Description Content
397  0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
398  (0x4e544c4d53535000)
399  8 NTLM Message Type long (0x03000000)
400  12 LM/LMv2 Response security buffer(*)
401  20 NTLM/NTLMv2 Response security buffer(*)
402  28 Domain Name security buffer(*)
403  36 User Name security buffer(*)
404  44 Workstation Name security buffer(*)
405  (52) Session Key (optional) security buffer(*)
406  (60) Flags (optional) long
407  52 (64) start of data block
408 
409  */
410 
411  {
412  int lmrespoff;
413  int ntrespoff;
414  int useroff;
415  unsigned char lmresp[0x18]; /* fixed-size */
416 #ifdef USE_NTRESPONSES
417  unsigned char ntresp[0x18]; /* fixed-size */
418 #endif
419  const char *user;
420  int userlen;
421 
422  user = strchr(userp, '\\');
423  if(!user)
424  user = strchr(userp, '/');
425 
426  if (user) {
427  domain = userp;
428  domlen = user - domain;
429  user++;
430  }
431  else
432  user = userp;
433  userlen = strlen(user);
434 
435  mkhash(passwdp, &ntlm->nonce[0], lmresp
436 #ifdef USE_NTRESPONSES
437  , ntresp
438 #endif
439  );
440 
441  domoff = 64; /* always */
442  useroff = domoff + domlen;
443  hostoff = useroff + userlen;
444  lmrespoff = hostoff + hostlen;
445  ntrespoff = lmrespoff + 0x18;
446 
447  /* Create the big type-3 message binary blob */
448  size = snprintf((char *)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  memcpy(&ntlmbuf[size], domain, domlen);
530  size += domlen;
531 
532  memcpy(&ntlmbuf[size], user, userlen);
533  size += userlen;
534 
535  /* we append the binary hashes to the end of the blob */
536  if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
537  memcpy(&ntlmbuf[size], lmresp, 0x18);
538  size += 0x18;
539  }
540 
541 #ifdef USE_NTRESPONSES
542  if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
543  memcpy(&ntlmbuf[size], ntresp, 0x18);
544  size += 0x18;
545  }
546 #endif
547 
548  ntlmbuf[56] = size & 0xff;
549  ntlmbuf[57] = size >> 8;
550 
551  /* convert the binary blob into base64 */
552  size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
553 
554  if(size >0 ) {
555  Curl_safefree(*allocuserpwd);
556  *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
557  proxy?"Proxy-":"",
558  base64);
559  free(base64);
560  }
561  else
562  return CURLE_OUT_OF_MEMORY; /* FIX TODO */
563 
564  ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
565  *ready = TRUE;
566 
567  /* Switch to web authentication after proxy authentication is done */
568  if (proxy)
569  Curl_http_auth_stage(conn->data, 401);
570  }
571  break;
572 
573  case NTLMSTATE_TYPE3:
574  /* connection is already authenticated,
575  * don't send a header in future requests */
576  if(*allocuserpwd) {
577  free(*allocuserpwd);
578  *allocuserpwd=NULL;
579  }
580  *ready = TRUE;
581  break;
582  }
583 
584  return CURLE_OK;
585 }
586 #endif /* USE_SSLEAY */
587 #endif /* !CURL_DISABLE_HTTP */
CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header)
case const int
Definition: Callbacks.cpp:52
void MD4_Update(MD4_CTX *context, const unsigned char *input, unsigned int inputLen)
Definition: MD4.cpp:186
size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
Definition: base64.c:123
CURLcode
Definition: curl.h:209
size_t Curl_base64_decode(const char *src, char *dest)
Definition: base64.c:81
CURLntlm
Definition: http_ntlm.h:26
void MD4_Final(MD4_CTX *context, unsigned char digest[16])
Definition: MD4.cpp:220
GLenum GLsizei len
Definition: glext.h:3472
char * proxyuser
Definition: urldata.h:449
int i
Definition: process.py:33
Definition: MD4.cpp:44
void Curl_http_auth_stage(struct SessionHandle *data, int stage)
Definition: http.c:1043
char * passwd
Definition: urldata.h:447
struct ntlmdata proxyntlm
Definition: urldata.h:571
#define NULL
Definition: Lib.h:88
GLuint buffer
Definition: glext.h:3108
#define NTLMFLAG_NEGOTIATE_OEM
Definition: http_ntlm.h:50
struct ntlmdata ntlm
Definition: urldata.h:568
Definition: curl.h:210
struct SessionHandle * data
Definition: urldata.h:403
#define checkprefix(a, b)
Definition: strequal.h:37
char * proxypasswd
Definition: urldata.h:450
CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy, bool *ready)
unsigned char nonce[8]
Definition: urldata.h:189
#define snprintf
Definition: Str.h:70
GLsizeiptr size
Definition: glext.h:3112
idKey * keys
Definition: KeyInput.cpp:196
void Curl_safefree(void *ptr)
Definition: url.c:172
#define FALSE
Definition: mprintf.c:70
#define TRUE
Definition: mprintf.c:69
curlntlm state
Definition: urldata.h:188
#define NTLMFLAG_NEGOTIATE_NTLM_KEY
Definition: http_ntlm.h:76
struct connectdata::dynamically_allocated_data allocptr
void MD4_Init(MD4_CTX *context)
Definition: MD4.cpp:175
idCVar password("password","", CVAR_GAME|CVAR_NOCHEAT,"client password used when connecting")
char * user
Definition: urldata.h:446