NTLM has evolved over the years. The last time I looked at the code, wget
only supported NTLM message types 1 and 2. It very well may be that the
server you are connecting to requires type 3 messages.

In 2009, I did a major refactoring of http_ntlm.c (against the wget 1.11.4
sources) to support NTLM type 1, 2, and 3 messages. I did not have any way
to test against servers supporting all three types of messages so the code
was never integrated into wget.

At this point in time, I don't have access to any server supporting any
configuration of NTLM so I cannot do anything with the attached code. If
someone to test all three types of NTML messages and wants to integrate the
attached code into wget, please do so.

Tony
// #define HARDCODE_RANDOM 1
/* NTLM code.
   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   Contributed by Daniel Stenberg.

This file is part of GNU Wget.

GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.

GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Wget.  If not, see <http://www.gnu.org/licenses/>.

Additional permission under GNU GPL version 3 section 7

If you modify this program, or any covered work, by linking or
combining it with the OpenSSL project's OpenSSL library (or a
modified version of that library), containing parts covered by the
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
grants you additional permission to convey the resulting work.
Corresponding Source for a non-source form of such a combination
shall include the source code for the parts of OpenSSL used as well
as that of the covered work.  */

#include <config.h>

/* NTLM details:
   
   http://davenport.sourceforge.net/ntlm.html
   http://www.innovation.ch/java/ntlm.html

*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <openssl/des.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/opensslv.h>

#include "wget.h"
#include "utils.h"
#include "http-ntlm.h"

#if OPENSSL_VERSION_NUMBER < 0x00907001L
#define DES_key_schedule des_key_schedule
#define DES_cblock des_cblock
#define DES_set_odd_parity des_set_odd_parity
#define DES_set_key des_set_key
#define DES_ecb_encrypt des_ecb_encrypt

/* This is how things were done in the old days */
#define DESKEY(x) x
#define DESKEYARG(x) x
#else
/* Modern version */
#define DESKEYARG(x) *x
#define DESKEY(x) &x
#endif

/* Define this to make the type-3 message include the NT response message */
#define USE_NTRESPONSES 1
#define SHORT_TO_LE2(x) ((x) & 0xff), ((x) >> 8)
#define LONG_TO_LE4(x) ((x) & 0xff), (((x) >> 8)&0xff), (((x) >>16)&0xff), 
((x)>>24)
#define LE_TO_SHORT(x) ((x[1] & 0xff) << 8) | (x[0] & 0xff)
#define LE_TO_LONG(x) ((x[3] & 0xff) << 24) | ((x[2] & 0xff) << 16) | ((x[1] & 
0xff) << 8) | (x[0] & 0xff)
#define NTLM_SIGNATURE "NTLMSSP"

/* The following definitions allows the same code to compile in wget 1.11.4 and 
1.12.x;
 * the code references to TOUPPER and ISSPACE can eventually be changed and 
then these
 * definitions can be removed. */
#ifndef TOUPPER
#define TOUPPER(c) c_toupper (c)
#define ISSPACE(c) c_isspace (c)
#endif

struct sb_list {
  size_t size;
  char *buffer;
  char *content;
  bool autofree;
};

struct ntlm_message {
  size_t size;
  int type;
  int data_offset;
  int n_sb;
  int max_sb;
  char *p_signature;
  char *p_optional;
  char sb[0];
};

struct ntlm_initiate {
  char signature[8];         /* "NTLMSSP" */
  char type[4];              /* 32-bit little-endian integer */
  char flags[4];             /* 32-bit little-endian integer */
  struct {
    char sb_domain[8];       /* security buffer */
    char sb_workstation[8];  /* security buffer */
    char os_version[8];      /* vendor-specific version information */
  } optional;
};

struct ntlm_challenge {
  char signature[8];         /* "NTLMSSP" */
  char type[4];              /* 32-bit little-endian integer */
  char sb_target[8];         /* security buffer */
  char flags[4];             /* 32-bit little-endian integer */
  char challenge[8];
  struct {
    char context[8];         /* two 32-bit little-endian integers */
    char sb_target_info[8];  /* security buffer */
    char os_version[8];      /* vendor-specific version information */
  } optional;
};

struct ntlm_response {
  char signature[8];         /* "NTLMSSP" */
  char type[4];              /* 32-bit little-endian integer */
  char sb_lm_response[8];    /* security buffer */
  char sb_ntlm_response[8];  /* security buffer */
  char sb_target[8];         /* security buffer */
  char sb_user[8];           /* security buffer */
  char sb_workstation[8];    /* security buffer */
  struct {
    char sb_session_key[8];  /* security buffer */
    char flags[4];           /* 32-bit little-endian integer */
    char os_version[8];      /* vendor-specific version information */
  } optional;
};

struct ntlm_message_initiate {
  struct ntlm_message msg;
  struct sb_list sb[2];
  struct ntlm_initiate m;
};

struct ntlm_message_challenge {
  struct ntlm_message msg;
  struct sb_list sb[2];
  struct ntlm_challenge m;
};

struct ntlm_message_response {
  struct ntlm_message msg;
  struct sb_list sb[6];
  struct ntlm_response m;
};

/*
  Routines to convert between ASCII (a) and UTF16 (w) strings.

  Assumes that buffers for the destination are allocated of sufficient length.
*/
int
wstrlen(const unsigned char *s)
{
  int x;
  for (x=0; s[x]; x+=2)
    ;
  return x/2;
}

void
atow(unsigned char *d, const unsigned char *s)
{
  int x;
  for (x=0; x <= strlen(s); x++)
    {
      d[x*2] = s[x];
      d[x*2+1] = 0;
    }
}

void
wtoa(unsigned char *d, const unsigned char *s)
{
  int x;
  int w = wstrlen(s);
  for (x=0; x < w; x++)
    {
      d[x] = s[x*2];
      if (!d[x])
        break;
    }
}

void
ntlm_message_init (void *message, const int type)
{
  size_t size = 0;
  switch (type) {
  case 1:
    size = sizeof(struct ntlm_message_initiate);
    break;
  case 2:
    size = sizeof(struct ntlm_message_challenge);
    break;
  case 3:
    size = sizeof(struct ntlm_message_response);
    break;
  }

  memset(message, 0, size);
  struct ntlm_message *msg;
  msg = message;
  msg->size = size;
  msg->type = type;

  switch (type) {
  case 1:
    msg->max_sb = 2;
    msg->p_signature = ((struct ntlm_message_initiate *)msg)->m.signature;
    msg->p_optional = (char *)&((struct ntlm_message_initiate 
*)msg)->m.optional;
    break;
  case 2:
    msg->max_sb = 2;
    msg->p_signature = ((struct ntlm_message_challenge *)msg)->m.signature;
    msg->p_optional = (char *)&((struct ntlm_message_challenge 
*)msg)->m.optional;
    break;
  case 3:
    msg->max_sb = 6;
    msg->p_signature = ((struct ntlm_message_response *)msg)->m.signature;
    msg->p_optional = (char *)&((struct ntlm_message_response 
*)msg)->m.optional;
    break;
  }

  msg->data_offset = msg->p_optional - msg->p_signature;
  strcpy(msg->p_signature, NTLM_SIGNATURE);
  msg->p_signature[8] = type;
}

void
ntlm_message_set_buffer_free (void *message, char *sb, char *content, const 
size_t size, const bool autofree)
{
  struct ntlm_message *msg;
  msg = message;
  assert(msg->n_sb < msg->max_sb);
  assert((sb > (char *)msg) && ((char *)msg + msg->size > sb + 8));

  struct sb_list *sb_list;
  sb_list = (struct sb_list *)&msg->sb;
  sb_list[msg->n_sb].size = size;
  sb_list[msg->n_sb].buffer = sb;
  sb_list[msg->n_sb].content = content;
  sb_list[msg->n_sb].autofree = autofree;
  msg->n_sb++;

  if (sb > msg->p_optional)
    {
      int off = sb - msg->p_signature + 8;
      if (off > msg->data_offset)
        msg->data_offset = off;
    }
}

void
ntlm_message_set_buffer (void *message, char *sb, char *content, const size_t 
size)
{
  ntlm_message_set_buffer_free (message, sb, content, size, false);
}

void
ntlm_message_set_raw (void *message, char *target, const char *content, const 
size_t size)
{
  struct ntlm_message *msg;
  msg = message;
  assert((target > msg->p_signature) && ((char *)msg + msg->size >= target + 
size));

  memcpy(target, content, size);
  if (target > msg->p_optional)
    {
      int off = target - msg->p_signature + size;
      if (off > msg->data_offset)
        msg->data_offset = off;
    }
}

void
ntlm_message_set_string (void *message, char *target, char *s)
{
  ntlm_message_set_buffer (message, target, s, strlen(s));
}

void
ntlm_message_set_string_wide (void *message, char *target, const char *narrow)
{
  int size = strlen(narrow) * 2;
  char *wide = xmalloc(size + 2); // include room for trailing nulls
  atow(wide, narrow);
  ntlm_message_set_buffer_free (message, target, wide, size, true);
}

void
ntlm_message_set_flags (void *message, char *target, const int flags)
{
  char value[4];
  value[0] = 0xff & flags;
  value[1] = 0xff & (flags >> 8);
  value[2] = 0xff & (flags >> 16); 
  value[3] = 0xff & (flags >> 24);
  ntlm_message_set_raw(message, target, value, 4);
}

size_t
ntlm_message_size (const void *message)
{
  const struct ntlm_message *msg;
  msg = message;

  struct sb_list *sb_list;
  sb_list = (struct sb_list *)&msg->sb;

  size_t size = msg->data_offset;
  int x;
  for (x = 0; x < msg->n_sb; x++)
    {
      size += sb_list[x].size;
    }
  return size;
}

void
ntlm_message_emit (const void *message, char *buffer)
{
  const struct ntlm_message *msg;
  msg = message;

  struct sb_list *sb_list;
  sb_list = (struct sb_list *)&msg->sb;

  // Make a pass over the security buffers and assign locations in the emitted 
message
  int x;
  size_t off = msg->data_offset;
  for (x = 0; x < msg->n_sb; x++)
    {
      if (sb_list[x].size > 0)
        {
          char buffer[9];
          sprintf(buffer, "%c%c%c%c%c%c%c%c", SHORT_TO_LE2(sb_list[x].size), 
SHORT_TO_LE2(sb_list[x].size),
                  LONG_TO_LE4(off));
          memcpy(sb_list[x].buffer, buffer, 8);
          off += sb_list[x].size;
        }
    }

  
  // Copy the message
  memcpy(buffer, msg->p_signature, msg->data_offset);
  buffer += msg->data_offset;
  // ...and append the security buffers
  for (x = 0; x < msg->n_sb; x++)
    {
      if (sb_list[x].size > 0)
        {
          memcpy(buffer, sb_list[x].content, sb_list[x].size);
          if (sb_list[x].autofree)
            xfree(sb_list[x].content);
          buffer += sb_list[x].size;
        }
    }
}

#define DEBUGPB(args) do { IF_DEBUG { debug_logprintf_buffer args; } } while (0)
static void
debug_logprintf_buffer (const char *format, const char *buffer, size_t size)
{
  if (opt.debug)
    {
      char *output = alloca(size * 2 + 1);
      int i;
      for (i = 0; i < size; i++)
        sprintf(&output[i*2], "%2.2x", (unsigned char)buffer[i]);
      debug_logprintf (format, output);
    }
}


/*
 * 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(const unsigned char *key_56,
              DES_key_schedule DESKEYARG(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(const unsigned char *keys, const unsigned char *plaintext, unsigned 
char *results)
{
  DES_key_schedule ks;

  setup_des_key(keys, DESKEY(ks));
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
                  DESKEY(ks), DES_ENCRYPT);

  setup_des_key(keys+7, DESKEY(ks));
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
                  DESKEY(ks), DES_ENCRYPT);

  setup_des_key(keys+14, DESKEY(ks));
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
                  DESKEY(ks), DES_ENCRYPT);
}

/*
 * Set up lanmanager and nt hashed passwords
 */
static void
mkhash(const char *password,
       int flags,
       const unsigned char *nonce,    /* 8 bytes */
       unsigned char *lmresp,    /* must fit 0x18 bytes */
       unsigned char *ntresp  /* must fit 0x18 bytes */
  )
{
  static const unsigned char magic[] = {
    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
  };

  memset(lmresp, 0, 24);
  memset(ntresp, 0, 24);

  /* The flags received in the type 2 response control the contents generated:
       if NTLMFLAG_NEGOTIATE_NTLM2_KEY:     NTLM 2 session response
       else if NTLMFLAG_NEGOTIATE_NTLM_KEY: NTLM response
       else:                                LM response */
  int type = 0;
  if (flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
    type = 2;
  else if (flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
    type = 1;
  DEBUGP(("NTLM: calculate hash: %s\n", (type == 0 ? "LM response" : (type == 1 
? "NTLM response" : "NTLM 2 session response"))));

  if (type < 2)
    {
      // Both LM and NTLM response messages include the LM response
      unsigned char lmhash[21];

      if (strlen(password) <= 14)
        {
          /* make the password fit at least 14 bytes */
          int len = strlen(password);
          char *pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);

          int i;
          for (i=0; i<len; i++)
            pw[i] = TOUPPER (password[i]);

          for (; i<14; i++)
            pw[i] = 0;

          /* create LanManager hashed password */
          DES_key_schedule ks;

          setup_des_key(pw, DESKEY(ks));
          DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmhash,
                    DESKEY(ks), DES_ENCRYPT);
  
          setup_des_key(pw+7, DESKEY(ks));
          DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmhash+8),
                    DESKEY(ks), DES_ENCRYPT);

          memset(lmhash+16, 0, 5);
          DEBUGPB(("NTLM - LM key: %s\n", lmhash, sizeof(lmhash)));
          DEBUGPB(("NTLM - Nonce: %s\n", nonce, 8));
          calc_resp(lmhash, nonce, lmresp);
          DEBUGPB(("NTLM - LM response: %s\n", lmresp, 24));
        }
      else
        {
          // Cannot calculate LM response if password is greater than 14 
character
          // return zero-filled buffer
          DEBUGP(("NTLM: Password too long (%i) to calculate LM Response; 
sending zeroes.\n", strlen(password)));
        }
    }

  if (type == 1)
  {
    // NTLM response messages include the NTLM version 1 response
    unsigned char nthash[21];
    MD4_CTX MD4;

    int size = strlen(password) * 2;
    char *pw = xmalloc(size + 2);
    atow(pw, password);

    MD4_Init(&MD4);
    MD4_Update(&MD4, pw, size);
    MD4_Final(nthash, &MD4);

    memset(nthash+16, 0, 5);
    DEBUGPB(("NTLM - NT key: %s\n", nthash, sizeof(nthash)));
    DEBUGPB(("NTLM - Nonce: %s\n", nonce, 8));
    calc_resp(nthash, nonce, ntresp);
    DEBUGPB(("NTLM - NT response: %s\n", ntresp, 24));
  }
  else if (type == 2)
  {
    /* create NTLM2 session response */ 
    unsigned char nthash[21];
    unsigned char session_nonce[16];
    unsigned char session_hash[16];
    MD4_CTX MD4;
    MD5_CTX MD5;
   
    unsigned char salt[8];
    int i;
    for (i = 0; i < 8; i++)
      salt[i] = random_number(256);

#ifdef HARDCODE_RANDOM
    if (opt.debug)
      {
        extern char fake_random[8];
        memcpy(salt, fake_random, 8);
      }
#endif

    memcpy(lmresp, salt, 8);

    memcpy(session_nonce, nonce, 8);
    memcpy(session_nonce + 8, salt, 8);

    DEBUGPB(("NTLM - Session nonce: %s\n", session_nonce, 
sizeof(session_nonce)));
    MD5_Init(&MD5);
    MD5_Update(&MD5, session_nonce, 16);
    MD5_Final(session_hash, &MD5);

    int size = strlen(password) * 2;
    char *pw = xmalloc(size + 2);
    atow(pw, password);

    MD4_Init(&MD4);
    MD4_Update(&MD4, pw, size);
    MD4_Final(nthash, &MD4);

    memset(nthash+16, 0, 5);
    DEBUGPB(("NTLM - NT hash: %s\n", nthash, sizeof(nthash)));
    DEBUGPB(("NTLM - Session hash: %s\n", session_hash, sizeof(session_hash)));
    calc_resp(nthash, session_hash, ntresp);
    DEBUGPB(("NTLM - NT Response: %s\n", ntresp, 24));
  }
}

/* return true on success, false otherwise */
bool
ntlm_input (struct ntlmdata *ntlm, const char *header)
{
  if (0 != strncmp (header, "NTLM", 4))
    {
      DEBUGP(("NTLM: Not an NTLM authenticate header\n"));
      return false;
    }

  header += 4;
  while (*header && ISSPACE(*header))
    header++;

  /* Normal exchange consists of four NTLM headers:
     1. Receive null header
     2. Send type-1 message
     3. Receive type-2 message
     4. Send type-3 message
  */
  if (!*header)
    {
      // Received a null header
      if (ntlm->state <= NTLMSTATE_TYPE1)
        {
          // ... and expecting it.
          DEBUGP (("NTLM: Empty message, starting transaction.\n"));
          ntlm->state = NTLMSTATE_TYPE1; /* we should respond by sending a 
type-1 message */
        }
      else
        {
          // ... but not expecting it.
          DEBUGP (("NTLM: Unexpected empty message.\n"));
          return false; /* this is an error */
        }
    }
  else
    {
      /* Received a non-null NTLM header; it should be a type-2 message */
      int size;
      char *buffer = (char *) alloca (strlen (header));

      size = base64_decode (header, buffer);
      if (size < 0)
        {
          DEBUGP (("NTLM: Received malformed base64 in header from server.\n"));
          return false;           /* malformed base64 from server */
        }

      if (strcmp (buffer, NTLM_SIGNATURE))
        {
          DEBUGP (("NTLM: header does not have a valid signature.\n"));
          return false;
        }

      struct ntlm_challenge *ntlm_challenge = (struct ntlm_challenge *)buffer;
      int type = LE_TO_LONG(ntlm_challenge->type);
      if (type != 2)
        {
          DEBUGP (("NTLM Expecting type 2 message, but received %i\n", type));
          return false;
        }

      if (size < (void *)(&ntlm_challenge->optional) - (void *)ntlm_challenge)
        {
          DEBUGP (("NTLM: message is too short (%i bytes, expecting %i at least 
bytes)\n", size,
              (void *)&ntlm_challenge->optional - (void *)ntlm_challenge));
          return false;
        }

      memset(ntlm, 0, sizeof(struct ntlmdata));
      ntlm->state = NTLMSTATE_TYPE2; /* we should respond by sending a type-3 
message */
      assert(sizeof(ntlm_challenge->challenge) <= sizeof(ntlm->nonce));
      memcpy (ntlm->nonce, ntlm_challenge->challenge, 
sizeof(ntlm_challenge->challenge));
      ntlm->flags = LE_TO_LONG(ntlm_challenge->flags);
    }

  return true;
}

/* this is for creating ntlm header output */
char *
ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd, bool 
*ready)
{
  struct ntlm_message_initiate ntlm_initiate;
  struct ntlm_message_response ntlm_response;

  size_t size;
  char *base64;

  /* point to the address of the pointer that holds the string to sent to the
     server, which is for a plain host or for a HTTP proxy */
  char *output;

  *ready = false;

  /* not set means empty */
  if(!user)
    user="";

  if(!passwd)
    passwd="";
  
  switch(ntlm->state) {
  case NTLMSTATE_TYPE1:
  default: /* for the weird cases we (re)start here */
  {
    DEBUGP (("NTLM: Creating a type 1 message.\n"));
    
    ntlm_message_init (&ntlm_initiate, 1);
    ntlm_message_set_flags(&ntlm_initiate, ntlm_initiate.m.flags,
          NTLMFLAG_NEGOTIATE_OEM |
          NTLMFLAG_NEGOTIATE_UNICODE |
          NTLMFLAG_NEGOTIATE_NTLM_KEY |
          NTLMFLAG_NEGOTIATE_NTLM2_KEY);

    size = ntlm_message_size(&ntlm_initiate);
    char *initiate = alloca(size);
    ntlm_message_emit(&ntlm_initiate, initiate);

    base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
    base64_encode (initiate, size, base64);

    output = concat_strings ("NTLM ", base64, (char *) 0);
    break;
  }
    
  case NTLMSTATE_TYPE2:
  {
    unsigned char lmresp[0x18]; /* fixed-size */
    unsigned char ntresp[0x18]; /* fixed-size */

    ntlm_message_init (&ntlm_response, 3);
    mkhash(passwd, ntlm->flags, ntlm->nonce, lmresp, ntresp);
    ntlm_message_set_buffer (&ntlm_response, ntlm_response.m.sb_lm_response, 
lmresp, 24);
    ntlm_message_set_buffer (&ntlm_response, ntlm_response.m.sb_ntlm_response, 
ntresp, 24);

    // Add the user, domain, and workstation (that is, the current 'host' 
computer)
    // Look for DOMAIN\user, DOMAIN/user, or simply user

    char *domain = "";
    char *u = alloca(strlen(user) + 1);
    strcpy(u, user);
    char *usr = strchr(u, '\\');
    if(!usr)
      usr = strchr(u, '/');

    if (usr)
      {
        int domlen = usr - u;
        domain = alloca(domlen + 1);
        strncpy(domain, u, domlen);
        domain[domlen] = '\x0';
        usr++;
      }
    else
      usr = u;

#define HOSTNAME_MAX 1024
    char host[HOSTNAME_MAX];

    if (gethostname(host, HOSTNAME_MAX))
        host[0] = '\0';
    else
      {
        /* If the workstation if configured with a full DNS name (i.e.
         * workstation.somewhere.net) gethostname() returns the fully qualified
         * name, which NTLM doesn't like.
         */
        char *dot = strchr(host, '.');
        if (dot)
          *dot = '\0';
      }

    if (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE)
      {
        ntlm_message_set_string_wide (&ntlm_response, ntlm_response.m.sb_user, 
usr);
        ntlm_message_set_string_wide (&ntlm_response, 
ntlm_response.m.sb_target, domain);

        if (*host)
          ntlm_message_set_string_wide (&ntlm_response, 
ntlm_response.m.sb_workstation, host);
      }
    else
      {
        ntlm_message_set_string (&ntlm_response, ntlm_response.m.sb_user, usr);
        ntlm_message_set_string (&ntlm_response, ntlm_response.m.sb_target, 
domain);

        if (*host)
          ntlm_message_set_string (&ntlm_response, 
ntlm_response.m.sb_workstation, host);
      }

    size = ntlm_message_size(&ntlm_response);
    char *response = alloca(size);
    ntlm_message_emit(&ntlm_response, response);

    base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
    base64_encode (response, size, base64);
    output = concat_strings ("NTLM ", base64, (char *) 0);

    ntlm->state = NTLMSTATE_TYPE3;
    *ready = true;
  }
  break;

  case NTLMSTATE_TYPE3:
    /* connection is already authenticated,
     * don't send a header in future requests */
    *ready = true;
    output = NULL;
    break;
  }

  return output;
}
#ifndef __HTTP_NTLM_H
#define __HTTP_NTLM_H
/* Declarations for http_ntlm.c
   Copyright (C) 1995, 1996, 1997, 2000, 2007, 2008 Free Software Foundation, 
Inc.
   Contributed by Daniel Stenberg.

This file is part of GNU Wget.

GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.

GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Wget.  If not, see <http://www.gnu.org/licenses/>.

Additional permission under GNU GPL version 3 section 7

If you modify this program, or any covered work, by linking or
combining it with the OpenSSL project's OpenSSL library (or a
modified version of that library), containing parts covered by the
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
grants you additional permission to convey the resulting work.
Corresponding Source for a non-source form of such a combination
shall include the source code for the parts of OpenSSL used as well
as that of the covered work.  */

/* Flag bits definitions available at on
   http://davenport.sourceforge.net/ntlm.html

   Additional bits identified from:
     curl sources
     python sources
 */

#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)   /* source: davenport 
*/
#define NTLMFLAG_REQUEST_TARGET                  (1<<2)   /* source: davenport 
*/
/* unknown (1<<3) */
#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)   /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_NT_ONLY               (1<<10)  /* source: python */
#define NTLMFLAG_NEGOTIATE_ANONYMOUS             (1<<11)  /* source: curl */
#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)  /* source: davenport 
*/
#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)  /* source: davenport 
*/
#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)  /* source: davenport 
*/
#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)  /* source: davenport 
*/
#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)  /* source: davenport 
*/
#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)  /* source: davenport 
*/
#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)  /* source: davenport 
*/
/* unknown (1<24) */
#define NTLMFLAG_NEGOTIATE_VERSION               (1<<25)  /* source: python */
/* unknown (1<26) */
/* unknown (1<27) */
/* unknown (1<28) */
#define NTLMFLAG_NEGOTIATE_128                   (1<<29)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)  /* source: davenport 
*/
#define NTLMFLAG_NEGOTIATE_56                    (1<<31)  /* source: davenport 
*/

typedef enum {
  NTLMSTATE_NONE,
  NTLMSTATE_TYPE1,
  NTLMSTATE_TYPE2,
  NTLMSTATE_TYPE3,
  NTLMSTATE_LAST
} wgetntlm;

/* Struct used for NTLM challenge-response authentication */
struct ntlmdata {
  wgetntlm state;
  unsigned char nonce[8];
  int flags;
};

/* this is for ntlm header input */
bool ntlm_input (struct ntlmdata *, const char *);

/* this is for creating ntlm header output */
char *ntlm_output (struct ntlmdata *, const char *, const char *, bool *);
#endif

Reply via email to