diff options
| author | Daniel Stenberg <daniel@haxx.se> | 2003-06-11 13:38:55 +0000 | 
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2003-06-11 13:38:55 +0000 | 
| commit | 73c5f24fa40460f41d6cd9114827383edc57e287 (patch) | |
| tree | b006a03480c0aa21c51ae5f0682c7c538b9631c5 /lib | |
| parent | 4c80e103a055b719de04818615349be2b28b7858 (diff) | |
Initial take at NTLM authentication. It doesn't really work at this point
but the infrastructure is there.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.am | 3 | ||||
| -rw-r--r-- | lib/base64.c | 6 | ||||
| -rw-r--r-- | lib/http.c | 8 | ||||
| -rw-r--r-- | lib/http_ntlm.c | 501 | ||||
| -rw-r--r-- | lib/http_ntlm.h | 67 | ||||
| -rw-r--r-- | lib/transfer.c | 12 | ||||
| -rw-r--r-- | lib/url.c | 15 | ||||
| -rw-r--r-- | lib/urldata.h | 18 | 
8 files changed, 626 insertions, 4 deletions
| diff --git a/lib/Makefile.am b/lib/Makefile.am index 64cfaa74f..ebec015d8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -68,7 +68,8 @@ strequal.h easy.c security.h security.c krb4.c krb4.h memdebug.c	\  memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c strtok.h	\  connect.c connect.h llist.c llist.h hash.c hash.h multi.c		\  content_encoding.c content_encoding.h share.c share.h http_digest.c \ -md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h +md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h \ +http_ntlm.c http_ntlm.h  noinst_HEADERS = setup.h transfer.h diff --git a/lib/base64.c b/lib/base64.c index 0f461eabd..ee533189f 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -232,13 +232,17 @@ int main(int argc, char **argv, char **envp)    int base64Len;    unsigned char *data;    int dataLen; +  int i;    base64 = (char *)suck(&base64Len);    data = (unsigned char *)malloc(base64Len * 3/4 + 8);    dataLen = Curl_base64_decode(base64, data);    fprintf(stderr, "%d\n", dataLen); -  fwrite(data,1,dataLen,stdout); + +  for(i=0; i < dataLen; i++)  +    printf("%02x ", data[i]); +  puts("");    free(base64); free(data);    return 0; diff --git a/lib/http.c b/lib/http.c index e5d2b49d3..b06de06a8 100644 --- a/lib/http.c +++ b/lib/http.c @@ -90,6 +90,7 @@  #include "strequal.h"  #include "ssluse.h"  #include "http_digest.h" +#include "http_ntlm.h"  #define _MPRINTF_REPLACE /* use our functions only */  #include <curl/mprintf.h> @@ -696,7 +697,12 @@ CURLcode Curl_http(struct connectdata *conn)  	return result;    } else  #endif -  if(data->state.digest.nonce) { +  if(data->state.ntlm.state) { +    result = Curl_output_ntlm(conn); +    if(result) +      return result; +  } +  else if(data->state.digest.nonce) {      result = Curl_output_digest(conn,                                  (unsigned char *)request,                                  (unsigned char *)ppath); diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c new file mode 100644 index 000000000..841342526 --- /dev/null +++ b/lib/http_ntlm.c @@ -0,0 +1,501 @@ +/*************************************************************************** + *                                  _   _ ____  _      + *  Project                     ___| | | |  _ \| |     + *                             / __| | | | |_) | |     + *                            | (__| |_| |  _ <| |___  + *                             \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + *  + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +/* All NTLM details here: http://www.innovation.ch/java/ntlm.html */ + +#ifndef CURL_DISABLE_HTTP +#ifdef USE_SSLEAY +/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" +#include "base64.h" +#include "http_ntlm.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#include <openssl/des.h> +#include <openssl/md4.h> + +/* The last #include file should be: */ +#ifdef MALLOCDEBUG +#include "memdebug.h" +#endif + +/* +  The one and only master resource for NTLM "hacking": + +  ====> http://www.innovation.ch/java/ntlm.html <==== + +  Brought to the world by Ronald Tschalär. +*/ + +/* Test example header: + +WWW-Authenticate: NTLM + +*/ + +CURLntlm Curl_input_ntlm(struct connectdata *conn, +                         char *header) /* rest of the www-authenticate: +                                          header */ +{ +  struct SessionHandle *data=conn->data; + +  /* skip initial whitespaces */ +  while(*header && isspace((int)*header)) +    header++; + +  if(checkprefix("NTLM", header)) { +    char buffer[256]; +    header += strlen("NTLM"); + +    while(*header && isspace((int)*header)) +      header++; + +    if(*header) { +      /* we got a type-2 message here */ + +      /* My test-IE session reveived this type-2: + +      TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgA\ +      yAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4\ +      AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwB\ +      jAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== + +      which translates to this: + +      4e 54 4c 4d 53 53 50 00 02 00 00 00 02 00 02 00 30 00 00 00 06 82 81 00 +      73 9d 40 61 50 e0 c8 d7 00 00 00 00 00 00 00 00 6e 00 6e 00 32 00 00 00 +      43 43 02 00 04 00 43 00 43 00 01 00 12 00 45 00 4c 00 49 00 53 00 41 00 +      42 00 45 00 54 00 48 00 04 00 18 00 63 00 63 00 2e 00 69 00 63 00 65 00 +      64 00 65 00 76 00 2e 00 6e 00 75 00 03 00 2c 00 65 00 6c 00 69 00 73 00 +      61 00 62 00 65 00 74 00 68 00 2e 00 63 00 63 00 2e 00 69 00 63 00 65 00 +      64 00 65 00 76 00 2e 00 6e 00 75 00 00 00 00 00 + +      */ + +      int size = Curl_base64_decode(header, buffer); + +      data->state.ntlm.state = NTLMSTATE_TYPE2; /* we got a type-2 */ + +      if(size == 48) +        /* the nonce of interest is index [24 .. 31], 8 bytes */ +        memcpy(data->state.ntlm.nonce, &buffer[24], 8); +    } +    else { +      data->state.ntlm.state = NTLMSTATE_TYPE1; /* we should sent away a +                                                  type-1 */ +    } +  } +  return CURLNTLM_FINE; +} + +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The + * key schedule ks is also set. + */ +static void setup_des_key(unsigned char *key_56, +                          DES_key_schedule *ks) +{ +  DES_cblock key; + +  key[0] = key_56[0]; +  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1); +  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2); +  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3); +  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4); +  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5); +  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6); +  key[7] =  (key_56[6] << 1) & 0xFF; + +  DES_set_odd_parity(&key); +  DES_set_key(&key, ks); +} + + /* +  * takes a 21 byte array and treats it as 3 56-bit DES keys. The +  * 8 byte plaintext is encrypted with each key and the resulting 24 +  * bytes are stored in the results array. +  */ +static void calc_resp(unsigned char *keys, +                      unsigned char *plaintext, +                      unsigned char *results) +{ +  des_key_schedule ks; + +  setup_des_key(keys, &ks); +  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, &ks, +                  DES_ENCRYPT); + +  setup_des_key(keys+7, &ks); +  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), &ks, +                  DES_ENCRYPT); + +  setup_des_key(keys+14, &ks); +  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), &ks, +                  DES_ENCRYPT); +} + +static void mkhash(char *password, +                   unsigned char *nonce,  /* 8 bytes */ +                   unsigned char *lmresp, /* must fit 0x18 bytes */ +                   unsigned char *ntresp) /* must fit 0x18 bytes */ +{ +  /* setup LanManager password */ +  unsigned char lmbuffer[0x18]; +  unsigned char ntbuffer[0x18]; +   +  unsigned char lm_pw[14]; +  int len = strlen(password); +  unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; +  int i; + +  if (len > 14) +    len = 14; +   +  for (i=0; i<len; i++) +    lm_pw[i] = toupper(password[i]); + +  for (; i<14; i++) +    lm_pw[i] = 0; + +  /* create LanManager hashed password */ +  { +    DES_key_schedule ks; + +    setup_des_key(lm_pw, &ks); +    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, &ks, +                    DES_ENCRYPT); +   +    setup_des_key(lm_pw+7, &ks); +    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer+8, &ks, +                    DES_ENCRYPT); + +    memset(lmbuffer+16, 0, 5); + +  } + +  { +    /* create NT hashed password */ +    int len = strlen(password); +    unsigned char nt_pw[256]; +    MD4_CTX MD4; + +    for (i=0; i<len; i++) { +      nt_pw[2*i]   = password[i]; +      nt_pw[2*i+1] = 0; +    } + +    MD4_Init(&MD4); +    MD4_Update(&MD4, nt_pw, 2*len); +    MD4_Final(nt_pw, &MD4); + +    memset(ntbuffer+16, 0, 5); + +  } +  /* create responses */ + +  calc_resp(lmbuffer, nonce, lmresp); +  calc_resp(ntbuffer, nonce, ntresp); +} + +/* convert an ascii string to upper case unicode, the destination buffer +   must fit twice the source size */ +static void ascii_to_unicode(unsigned char *destunicode, +                             unsigned char *sourceascii, +                             bool conv) +{ +  while (*sourceascii) { +    destunicode[0] = conv?toupper(*sourceascii):*sourceascii; +    destunicode[1] = '\0'; +    destunicode += 2; +    sourceascii++; +  } +} + +#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8) + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn) +{ +  struct SessionHandle *data=conn->data; +  const char *domain="HEMMA"; +  const char *host="LILLASYSTER"; +  int domlen=strlen(domain); +  int hostlen = strlen(host); +  int hostoff; /* host name offset */ +  int domoff;  /* domain name offset */ +  int size; +  char *base64=NULL; + +  unsigned char ntlm[256]; /* enough, unless the host/domain is very long */ +  if(NTLMSTATE_TYPE1 == data->state.ntlm.state) { +    hostoff = 32; +    domoff = hostoff + hostlen; +     +    /* IE used this in the initial dump: + +    Authorization: NTLM \ +    TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA\r\n + +    This translates into: + +    4e 54 4c 4d 53 53 50 00 01 00 00 00 06 82 00 00 00 00 00 00 00 00 00 00 00 +    00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 30 00 00 00 + +    Which isn't following the web spec. This uses 0x8206 instead of 0xb203 +    and sends a longer chunk of data than we do! Interestingly, there's no +    host or domain either. + +    */ + +    snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" +             "\x01" /* type 1 */ +             "%c%c%c" +             "\x03\xb2" +             "%c%c" +             "%c%c"  /* domain length */ +             "%c%c"  /* domain length */ +             "%c%c"  /* domain name offset */ +             "%c%c"  /* host length */ +             "%c%c"  /* host length */ +             "%c%c"  /* host name offset */ +             "%c%c" +             "%s" /* host name */ +             "%s", /* domain string */ +             0,0,0,0,0,0, +             SHORTPAIR(domlen), +             SHORTPAIR(domlen), +             SHORTPAIR(domoff), +             SHORTPAIR(hostlen), +             SHORTPAIR(hostlen), +             SHORTPAIR(hostoff), +             0,0, +             host, domain); + +    /* initial packet length */ +    size = 8 + 1 + 3 + 18 + hostlen + domlen; +#if 0 +    #define CHUNK "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x06\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00" +    memcpy(ntlm, CHUNK, sizeof(CHUNK)-1); +    size = sizeof(CHUNK)-1; +#endif     +    /* now keeper of the base64 encoded package size */ +    size = Curl_base64_encode(ntlm, size, &base64); + +    if(size >0 ) { +      conn->allocptr.userpwd = aprintf("Authorization: NTLM %s\r\n", +                                       base64); +      free(base64); +    } +    else +      return CURLE_OUT_OF_MEMORY; /* FIX TODO */ +  } +  else { +    /* We are not in the first state, create a type-3 message */ + +    /* +      My test-IE session sent this type-3: + +      TlRMTVNTUAADAAAAGAAYAEoAAAAAAAAAYgAAAAUABQA0AAAABgAGADk\ +      AAAALAAsAPwAAAEhFTU1BZGFuaWVsTElMTEFTWVNURVJPVPJELoebUg\ +      4SvW0ed2QmKu0SjX4qNrI= + +      Which translates to: + +      4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 4a 00 00 00 00 00 00 00 +      62 00 00 00 05 00 05 00 34 00 00 00 06 00 06 00 39 00 00 00 0b 00 0b 00 +      3f 00 00 00 48 45 4d 4d 41 64 61 6e 69 65 6c 4c 49 4c 4c 41 53 59 53 54 +      45 52 4f 54 f2 44 2e 87 9b 52 0e 12 bd 6d 1e 77 64 26 2a ed 12 8d 7e 2a +      36 b2 + +      Note how the domain + username + hostname ARE NOT unicoded in any way. +      Domain and hostname are uppercase, while username are case sensitive. + +      We sent (badly): + +      4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 56 00 00 00 00 00 00 00 +      6e 00 00 00 05 00 05 00 40 00 00 00 06 00 06 00 45 00 00 00 0b 00 0b 00 +      4b 00 00 00 00 00 00 00 6c 00 00 00 01 82 48 45 4d 4d 41 64 61 6e 69 65 +      6c 4c 49 4c 4c 41 53 59 53 54 45 52 86 99 4a 4f 1a 54 93 85 f9 a4 85 d7 +      ed 14 17 31 8c a6 4d e9 c1 b1 23 a7 +    */ + +    int lmrespoff; +    int ntrespoff; +    int useroff; +    unsigned char lmresp[0x18+1]; +    unsigned char ntresp[0x18+1]; + +    int userlen = strlen(data->state.user); +     +    mkhash(data->state.passwd, &data->state.ntlm.nonce[0], lmresp, ntresp); + +    /* these are going unicode */ +    domlen *= 2; +    userlen *= 2; +    hostlen *= 2; + +    domoff = 64; /* always */ +    useroff = domoff + domlen; +    hostoff = useroff + userlen; +    lmrespoff = hostoff + hostlen; +    ntrespoff = lmrespoff + 0x18; + +    /* Create the big type-3 message binary blob */ +    size = snprintf((char *)ntlm, sizeof(ntlm), +                    "NTLMSSP%c" +                    "\x03" /* type 3 */ +                    "%c%c%c" /* 3 zeroes */ + +                    "%c%c%c%c" /* LanManager length twice */ +                    "%c%c" /* LanManager offset */ +                    "%c%c" /* 2 zeroes */ + +                    "%c%c%c%c" /* NT-response length twice */ +                    "%c%c" /* NT-response offset */ +                    "%c%c" /* 2 zeroes */ +                     +                    "%c%c"  /* domain length */ +                    "%c%c"  /* domain length */ +                    "%c%c"  /* domain name offset */ +                    "%c%c"  /* 2 zeroes */ +                     +                    "%c%c"  /* user length */ +                    "%c%c"  /* user length */ +                    "%c%c"  /* user offset */ +                    "%c%c"  /* 2 zeroes */ +                     +                    "%c%c"  /* host length */ +                    "%c%c"  /* host length */ +                    "%c%c"  /* host offset */ +                    "%c%c%c%c%c%c"  /* 6 zeroes */ +                     +                    "\xff\xff"  /* message length */ +                    "%c%c"  /* 2 zeroes */ +                     +                    "\x01\x82" /* flags */ +                    "%c%c"  /* 2 zeroes */ + +                    /* domain string */ +                    /* user string */ +                    /* host string */ +                    /* LanManager response */ +                    /* NT response */ +                    , +                    0, +                    0,0,0, + +                    SHORTPAIR(0x18),  /* LanManager response length, twice */ +                    SHORTPAIR(0x18), +                    SHORTPAIR(lmrespoff), +                    0x0, 0x0, +                     +                    SHORTPAIR(0x18),  /* NT-response length, twice */ +                    SHORTPAIR(0x18), +                    SHORTPAIR(ntrespoff), +                    0x0, 0x0, + +                    SHORTPAIR(domlen), +                    SHORTPAIR(domlen), +                    SHORTPAIR(domoff), +                    0x0, 0x0, + +                    SHORTPAIR(userlen), +                    SHORTPAIR(userlen), +                    SHORTPAIR(useroff), +                    0x0, 0x0, +                     +                    SHORTPAIR(hostlen), +                    SHORTPAIR(hostlen), +                    SHORTPAIR(hostoff), +                    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +              +                    0x0, 0x0, + +                    0x0, 0x0); + +    /* size is now 64 */ +#if 1 +    ascii_to_unicode(&ntlm[size], (unsigned char *)domain, TRUE); +    size += domlen; +     +    ascii_to_unicode(&ntlm[size], (unsigned char *)data->state.user, FALSE); +    size += userlen; + +    ascii_to_unicode(&ntlm[size], (unsigned char *)host, TRUE); +    size += hostlen; +#else +    strcpy(&ntlm[size], (unsigned char *)domain); +    size += domlen; + +    strcpy(&ntlm[size], (unsigned char *)data->state.user); +    size += userlen; + +    strcpy(&ntlm[size], (unsigned char *)host); +    size += hostlen; +#endif + +    /* we append the binary hashes to the end of the blob */ +    if(size < ((int)sizeof(ntlm) - 0x18)) { +      memcpy(&ntlm[size], lmresp, 0x18); +      size += 0x18; +    } +#ifdef USE_NT +    if(size < ((int)sizeof(ntlm) - 0x18)) {       +      memcpy(&ntlm[size+0x18], ntresp, 0x18); +      size += 0x18*2; +    } +#endif + +    ntlm[56] = size & 0xff; +    ntlm[57] = size >> 8; +     +    /* convert the binary blob into base64 */ +    size = Curl_base64_encode(ntlm, size, &base64); + +    if(size >0 ) { +      conn->allocptr.userpwd = aprintf("Authorization: NTLM %s\r\n", +                                       base64); +      free(base64); +    } +    else +      return CURLE_OUT_OF_MEMORY; /* FIX TODO */ + +  } + +  return CURLE_OK; +} +#endif /* USE_SSLEAY */ +#endif /* !CURL_DISABLE_HTTP */ diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h new file mode 100644 index 000000000..30e0b67a1 --- /dev/null +++ b/lib/http_ntlm.h @@ -0,0 +1,67 @@ +#ifndef __HTTP_NTLM_H +#define __HTTP_NTLM_H +/*************************************************************************** + *                                  _   _ ____  _      + *  Project                     ___| | | |  _ \| |     + *                             / __| | | | |_) | |     + *                            | (__| |_| |  _ <| |___  + *                             \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + *  + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + +typedef enum { +  CURLNTLM_NONE, /* not a ntlm */ +  CURLNTLM_BAD,  /* an ntlm, but one we don't like */ +  CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ +  CURLNTLM_FINE, /* an ntlm we act on */ + +  CURLNTLM_LAST  /* last entry in this enum, don't use */ +} CURLntlm; + +/* this is for ntlm header input */ +CURLntlm Curl_input_ntlm(struct connectdata *conn, char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn); + +void Curl_ntlm_cleanup(struct SessionHandle *data); + + +/* type-1 octet-stream, sent in the first NTLM-authenticated request + +byte    protocol[8];     'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' +byte    type;            0x01 +byte    zero[3]; +short   flags;           0xb203 +byte    zero[2]; + +short   dom_len;         domain string length +short   dom_len;         domain string length +short   dom_off;         domain string offset +byte    zero[2]; + +short   host_len;        host string length +short   host_len;        host string length +short   host_off;        host string offset (always 0x20) +byte    zero[2]; + +byte    host[*];         host string (ASCII) +byte    dom[*];          domain string (ASCII) + +*/ + +#endif diff --git a/lib/transfer.c b/lib/transfer.c index 2eda08889..7d060c689 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -96,6 +96,7 @@  #include "getinfo.h"  #include "ssluse.h"  #include "http_digest.h" +#include "http_ntlm.h"  #ifdef GSSAPI  #include "http_negotiate.h"  #endif @@ -736,6 +737,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,                  conn->newurl = strdup(data->change.url);  	    }  #endif +            else if(Curl_compareheader(k->p, +                                       "WWW-Authenticate:", "NTLM") && +                    (401 == k->httpcode) && +                    data->set.httpntlm /* NTLM authentication is  +                                          activated */) { +              CURLntlm ntlm; +              ntlm = Curl_input_ntlm(conn, +                                     k->p+strlen("WWW-Authenticate:")); + +              conn->newurl = strdup(data->change.url); /* clone string */ +            }              else if(checkprefix("WWW-Authenticate:", k->p) &&                      (401 == k->httpcode) &&                      data->set.httpdigest /* Digest authentication is  @@ -855,17 +855,32 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)        /* default */        data->set.httpdigest = FALSE;        data->set.httpnegotiate = FALSE; +      data->set.httpntlm = FALSE;              break;      case CURLHTTP_DIGEST:        /* Enable HTTP Digest authentication */        data->set.httpdigest = TRUE;        data->set.httpnegotiate = FALSE; +      data->set.httpntlm = FALSE;              break; +    case CURLHTTP_NTLM: +      /* Enable HTTP NTLM authentication */ +#ifdef USE_SSLEAY +      /* We can only support NTLM if OpenSSL is present, as we need their +         crypto package for it */ +      data->set.httpdigest = FALSE; +      data->set.httpnegotiate = FALSE; +      data->set.httpntlm = TRUE;       +      break; +#else +      /* fall-through */ +#endif      case CURLHTTP_NEGOTIATE:  #ifdef GSSAPI        /* Enable HTTP Negotaiate authentication */        data->set.httpdigest = FALSE;        data->set.httpnegotiate = TRUE; +      data->set.httpntlm = FALSE;              break;  #else        /* fall-through */ diff --git a/lib/urldata.h b/lib/urldata.h index 459c5c468..4a2e97f06 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -164,6 +164,20 @@ struct digestdata {    int algo;  }; +typedef enum { +  NTLMSTATE_NONE, +  NTLMSTATE_TYPE1, +  NTLMSTATE_TYPE2, +  NTLMSTATE_TYPE3, +  NTLMSTATE_LAST +} curlntlm; + +/* Struct used for Digest challenge-response authentication */ +struct ntlmdata { +  curlntlm state; +  unsigned char nonce[8]; +}; +  #ifdef GSSAPI  struct negotiatedata {    OM_uint32 status; @@ -640,6 +654,7 @@ struct UrlState {                        is always set TRUE when curl_easy_perform() is called. */    struct digestdata digest; +  struct ntlmdata ntlm;  #ifdef GSSAPI    struct negotiatedata negotiate; @@ -688,8 +703,9 @@ struct UserDefined {    char *set_proxy;   /* proxy to use */    long use_port;     /* which port to use (when not using default) */    char *userpwd;     /* <user:password>, if used */ -  bool httpdigest;   /* if HTTP Digest is enabled */ +  bool httpdigest;    /* if HTTP Digest authentication is enabled */    bool httpnegotiate; /* if HTTP Negotiate authentication is enabled */ +  bool httpntlm;      /* if HTTP NTLM authentication is enabled */    char *set_range;   /* range, if used. See README for detailed specification                          on this syntax. */    long followlocation; /* as in HTTP Location: */ | 
