]> sjero.net Git - wget/commitdiff
[svn] Added NTLM support.
authorhniksic <devnull@localhost>
Wed, 6 Apr 2005 20:42:22 +0000 (13:42 -0700)
committerhniksic <devnull@localhost>
Wed, 6 Apr 2005 20:42:22 +0000 (13:42 -0700)
14 files changed:
AUTHORS
ChangeLog
Makefile.in
configure.in
src/ChangeLog
src/Makefile.in
src/ftp-basic.c
src/ftp.h
src/http-ntlm.c [new file with mode: 0644]
src/http-ntlm.h [new file with mode: 0644]
src/http.c
src/mswindows.c
src/utils.c
src/utils.h

diff --git a/AUTHORS b/AUTHORS
index 5b4be05bd09b6af4a46401571bcf6dbae69e05c4..a916111a800393487b8dbdfc600b3e4ad1d73a37 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -34,3 +34,6 @@ Mauro Tortonesi.  Improved IPv6 support, adding support for dual
 family systems.  Refactored and enhanced FTP IPv6 code.
 
 Nicolas Schodet.  Contributed to cookie code and documentation.
 family systems.  Refactored and enhanced FTP IPv6 code.
 
 Nicolas Schodet.  Contributed to cookie code and documentation.
+
+Daniel Stenberg.  NTLM authentication in http-ntlm.c and http-ntlm.h
+originally written curl donated for use in GNU Wget.
index 5ca6ea74569addcf16d1fc8a59ecdbe5754292af..ebb947539541658141a8f1fecf050c31ee9a5928 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2005-04-06  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * configure.in: Allow the user to disable NTLM authorization.
+       Make sure NTLM is disabled if OpenSSL is unavailable.  If NTLM is
+       *explicitly* requested and OpenSSL is unavailable, abort.
+
+       * configure.in: Renamed USE_* to ENABLE_*.
+
 2005-03-23  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * po/POTFILES.in: Removed headers.c and rbuf.c.
 2005-03-23  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * po/POTFILES.in: Removed headers.c and rbuf.c.
index ef584e5e9ec2eb23a39b0431602e48903aa1ed99..3d1a69fad64b123c4088f7cfeade429003ca96c5 100644 (file)
@@ -182,7 +182,7 @@ $(srcdir)/configure: configure.in aclocal.m4
 # autoheader might not change config.h.in, so touch a stamp file.
 $(srcdir)/src/config.h.in: stamp-h.in
 $(srcdir)/stamp-h.in: configure.in aclocal.m4
 # autoheader might not change config.h.in, so touch a stamp file.
 $(srcdir)/src/config.h.in: stamp-h.in
 $(srcdir)/stamp-h.in: configure.in aclocal.m4
-       cd $(srcdir) && autoheader
+       -cd $(srcdir) && autoheader
        echo timestamp > $(srcdir)/stamp-h.in
 
 src/config.h: stamp-h
        echo timestamp > $(srcdir)/stamp-h.in
 
 src/config.h: stamp-h
index 03dd4342c12614ace4a0e237c0f408119924cbac..11f969eb5a2c3be363f42117d401b0ea3e246bb1 100644 (file)
@@ -58,16 +58,20 @@ AC_ARG_WITH(ssl,
 
 AC_ARG_ENABLE(opie,
 [  --disable-opie          disable support for opie or s/key FTP login],
 
 AC_ARG_ENABLE(opie,
 [  --disable-opie          disable support for opie or s/key FTP login],
-USE_OPIE=$enableval, USE_OPIE=yes)
-test x"${USE_OPIE}" = xyes && AC_DEFINE([USE_OPIE], 1,
+ENABLE_OPIE=$enableval, ENABLE_OPIE=yes)
+test x"${ENABLE_OPIE}" = xyes && AC_DEFINE([ENABLE_OPIE], 1,
    [Define if you want the Opie support for FTP compiled in.])
 
 AC_ARG_ENABLE(digest,
 [  --disable-digest        disable support for HTTP digest authorization],
    [Define if you want the Opie support for FTP compiled in.])
 
 AC_ARG_ENABLE(digest,
 [  --disable-digest        disable support for HTTP digest authorization],
-USE_DIGEST=$enableval, USE_DIGEST=yes)
-test x"${USE_DIGEST}" = xyes && AC_DEFINE([USE_DIGEST], 1,
+ENABLE_DIGEST=$enableval, ENABLE_DIGEST=yes)
+test x"${ENABLE_DIGEST}" = xyes && AC_DEFINE([ENABLE_DIGEST], 1,
    [Define if you want the HTTP Digest Authorization compiled in.])
 
    [Define if you want the HTTP Digest Authorization compiled in.])
 
+AC_ARG_ENABLE(ntlm,
+[  --disable-ntlm          disable support for NTLM authorization],
+[ENABLE_NTLM=$enableval], [ENABLE_NTLM=auto])
+
 AC_ARG_ENABLE(debug,
 [  --disable-debug         disable support for debugging output],
 ENABLE_DEBUG=$enableval, ENABLE_DEBUG=yes)
 AC_ARG_ENABLE(debug,
 [  --disable-debug         disable support for debugging output],
 ENABLE_DEBUG=$enableval, ENABLE_DEBUG=yes)
@@ -76,11 +80,11 @@ test x"${ENABLE_DEBUG}" = xyes && AC_DEFINE([ENABLE_DEBUG], 1,
 
 wget_need_md5=no
 
 
 wget_need_md5=no
 
-case "${USE_OPIE}${USE_DIGEST}" in
+case "${ENABLE_OPIE}${ENABLE_DIGEST}" in
 *yes*)
        wget_need_md5=yes
 esac
 *yes*)
        wget_need_md5=yes
 esac
-if test x"$USE_OPIE" = xyes; then
+if test x"$ENABLE_OPIE" = xyes; then
   OPIE_OBJ='ftp-opie$o'
 fi
 AC_SUBST(OPIE_OBJ)
   OPIE_OBJ='ftp-opie$o'
 fi
 AC_SUBST(OPIE_OBJ)
@@ -413,6 +417,26 @@ main(){return 0;}
   CPPFLAGS=$wget_save_CPPFLAGS
 fi
 
   CPPFLAGS=$wget_save_CPPFLAGS
 fi
 
+dnl Enable NTLM if requested and if SSL is available.
+NTLM_OBJ=''
+if test x"$ssl_success" = xyes
+then
+  if test x"$ENABLE_NTLM" != xno
+  then
+    AC_DEFINE([ENABLE_NTLM], 1,
+     [Define if you want the NTLM authorization support compiled in.])
+    NTLM_OBJ='http-ntlm$o'
+  fi
+else
+  dnl If SSL is unavailable and the user explicitly requested NTLM,
+  dnl abort.
+  if test x"$ENABLE_NTLM" = xyes
+  then
+    AC_MSG_ERROR([NTLM authorization requested and OpenSSL not found; aborting])
+  fi
+fi
+AC_SUBST(NTLM_OBJ)
+
 dnl
 dnl Find an md5 implementation.
 dnl
 dnl
 dnl Find an md5 implementation.
 dnl
index 36b8928cd87b9abd328c4c46685be8e5a4a8aa18..67694db14aa9520ba2c54a539398e4361832413f 100644 (file)
@@ -1,3 +1,24 @@
+2005-04-06  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * http.c (pconn): Include NTLM data, which is per-connection.
+       (known_authentication_scheme_p): Recognize NTLM authorization.
+       (create_authorization_line): Call ntlm_input and ntlm_output.
+
+       * http-ntlm.c: New file, donated by Daniel Stenberg and originally
+       written for curl, heavily modified for Wget.
+
+       * utils.c (base64_encode): Relocated from http.c, since it is now
+       used by http-ntlm.c, and will possibly be used elsewhere.
+       (base64_decode): New function, originally based on code from GNU
+       recode.
+
+2005-04-02  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * ftp.c (ftp_loop): Ditto.
+
+       * ftp-basic.c (ftp_pasv): Use the xzero shorthand for memset(0).
+       (ftp_lpsv): Ditto.
+
 2005-04-05  Mauro Tortonesi  <mauro@ferrara.linux.it>
 
        * Makefile.in: removed string_t.c from list of source files.
 2005-04-05  Mauro Tortonesi  <mauro@ferrara.linux.it>
 
        * Makefile.in: removed string_t.c from list of source files.
index da7bab417cc51df347ebffd78a4d2eebf81ba26e..e0acdc809703c69d5a683256e874cf1a12ad58bc 100644 (file)
@@ -69,13 +69,14 @@ ETAGS = etags
 ALLOCA     = @ALLOCA@
 MD5_OBJ    = @MD5_OBJ@
 OPIE_OBJ   = @OPIE_OBJ@
 ALLOCA     = @ALLOCA@
 MD5_OBJ    = @MD5_OBJ@
 OPIE_OBJ   = @OPIE_OBJ@
+NTLM_OBJ   = @NTLM_OBJ@
 SSL_OBJ    = @SSL_OBJ@
 GETOPT_OBJ = @GETOPT_OBJ@
 
 OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o              \
       ftp$o ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \
 SSL_OBJ    = @SSL_OBJ@
 GETOPT_OBJ = @GETOPT_OBJ@
 
 OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o              \
       ftp$o ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \
-      host$o html-parse$o html-url$o http$o init$o      \
-      log$o main$o $(MD5_OBJ) netrc$o progress$o recur$o   \
+      host$o html-parse$o html-url$o http$o $(NTLM_OBJ) init$o    \
+      log$o main$o $(MD5_OBJ) netrc$o progress$o recur$o          \
       res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o       \
       utils$o version$o xmalloc$o 
 
       res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o       \
       utils$o version$o xmalloc$o 
 
index d3714a03891c4ea6fcba8128717791c29ed4eb84..592dd59adac304cee0993ba35f66c8fbac90f51c 100644 (file)
@@ -158,7 +158,7 @@ ftp_login (int csock, const char *acc, const char *pass)
       xfree (respline);
       return FTPLOGREFUSED;
     }
       xfree (respline);
       return FTPLOGREFUSED;
     }
-#ifdef USE_OPIE
+#ifdef ENABLE_OPIE
   {
     static const char *skey_head[] = {
       "331 s/key ",
   {
     static const char *skey_head[] = {
       "331 s/key ",
@@ -195,7 +195,7 @@ ftp_login (int csock, const char *acc, const char *pass)
         pass = skey_response (skey_sequence, seed, pass);
       }
   }
         pass = skey_response (skey_sequence, seed, pass);
       }
   }
-#endif /* USE_OPIE */
+#endif /* ENABLE_OPIE */
   xfree (respline);
   /* Send PASS password.  */
   request = ftp_request ("PASS", pass);
   xfree (respline);
   /* Send PASS password.  */
   request = ftp_request ("PASS", pass);
index 85ed5730cf8a3f7fb7eb06a911dd0b77d52231d4..0c8116fe4474970718aacfc95c5d225d7c7abdcc 100644 (file)
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -62,7 +62,7 @@ uerr_t ftp_syst PARAMS ((int, enum stype *));
 uerr_t ftp_pwd PARAMS ((int, char **));
 uerr_t ftp_size PARAMS ((int, const char *, wgint *));
 
 uerr_t ftp_pwd PARAMS ((int, char **));
 uerr_t ftp_size PARAMS ((int, const char *, wgint *));
 
-#ifdef USE_OPIE
+#ifdef ENABLE_OPIE
 const char *skey_response PARAMS ((int, const char *, const char *));
 #endif
 
 const char *skey_response PARAMS ((int, const char *, const char *));
 #endif
 
diff --git a/src/http-ntlm.c b/src/http-ntlm.c
new file mode 100644 (file)
index 0000000..ce7dd98
--- /dev/null
@@ -0,0 +1,561 @@
+/* NTLM code.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   Donated 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 2 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, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
+
+#include <config.h>
+
+/* NTLM details:
+   
+   http://davenport.sourceforge.net/ntlm.html
+   http://www.innovation.ch/java/ntlm.html
+
+*/
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#include <stdlib.h>
+
+#include <openssl/des.h>
+#include <openssl/md4.h>
+#include <openssl/ssl.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 */
+#undef USE_NTRESPONSES
+\f
+/* Flag bits definitions available at on
+   http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
+#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
+#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
+#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
+#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
+#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
+/* unknown (1<<10) */
+/* unknown (1<<11) */
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
+#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
+#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
+#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
+#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+\f
+/*
+  (*) = A "security buffer" is a triplet consisting of two shorts and one
+  long:
+
+  1. a 'short' containing the length of the buffer in bytes
+  2. a 'short' containing the allocated space for the buffer in bytes
+  3. a 'long' containing the offset to the start of the buffer from the
+     beginning of the NTLM message, in bytes.
+*/
+
+/* return 1 on success, 0 otherwise */
+int ntlm_input (struct ntlmdata *ntlm, const char *header)
+{
+  if (0 != strncmp (header, "NTLM", 4))
+    return 0;
+
+  header += 4;
+  while (*header && ISSPACE(*header))
+    header++;
+
+  if (*header)
+    {
+      /* We got a type-2 message here:
+
+         Index   Description         Content
+         0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
+                                     (0x4e544c4d53535000)
+         8       NTLM Message Type   long (0x02000000)
+         12      Target Name         security buffer(*)
+         20      Flags               long
+         24      Challenge           8 bytes
+         (32)    Context (optional)  8 bytes (two consecutive longs)
+         (40)    Target Information  (optional) security buffer(*)
+         32 (48) start of data block
+      */
+      int size;
+      unsigned char *buffer = (unsigned char *) alloca (strlen (header));
+
+      size = base64_decode (header, buffer);
+      if (size < 0)
+       return 0;               /* malformed base64 from server */
+
+      ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+      if (size >= 48)
+        /* the nonce of interest is index [24 .. 31], 8 bytes */
+        memcpy (ntlm->nonce, &buffer[24], 8);
+
+      /* at index decimal 20, there's a 32bit NTLM flag field */
+    }
+  else
+    {
+      if (ntlm->state >= NTLMSTATE_TYPE1)
+        return 0; /* this is an error */
+
+      ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
+    }
+
+  return 1;
+}
+
+/*
+ * 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 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(unsigned char *keys,
+                      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,
+                   unsigned char *nonce,  /* 8 bytes */
+                   unsigned char *lmresp  /* must fit 0x18 bytes */
+#ifdef USE_NTRESPONSES
+                   , unsigned char *ntresp  /* must fit 0x18 bytes */
+#endif
+  )
+{
+  unsigned char lmbuffer[21];
+#ifdef USE_NTRESPONSES
+  unsigned char ntbuffer[21];
+#endif
+  unsigned char *pw;
+  static const unsigned char magic[] = {
+    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
+  };
+  int i;
+  int len = strlen(password);
+
+  /* make it fit at least 14 bytes */
+  pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
+
+  if (len > 14)
+    len = 14;
+  
+  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 *)lmbuffer,
+                    DESKEY(ks), DES_ENCRYPT);
+  
+    setup_des_key(pw+7, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
+                    DESKEY(ks), DES_ENCRYPT);
+
+    memset(lmbuffer+16, 0, 5);
+  }
+  /* create LM responses */
+  calc_resp(lmbuffer, nonce, lmresp);
+
+#ifdef USE_NTRESPONSES
+  {
+    /* create NT hashed password */
+    MD4_CTX MD4;
+
+    len = strlen(password);
+
+    for (i=0; i<len; i++) {
+      pw[2*i]   = password[i];
+      pw[2*i+1] = 0;
+    }
+
+    MD4_Init(&MD4);
+    MD4_Update(&MD4, pw, 2*len);
+    MD4_Final(ntbuffer, &MD4);
+
+    memset(ntbuffer+16, 0, 5);
+  }
+
+  calc_resp(ntbuffer, nonce, ntresp);
+#endif
+}
+
+#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
+  (((x) >>16)&0xff), ((x)>>24)
+
+/* this is for creating ntlm header output */
+char *ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
+                  int *ready)
+{
+  const char *domain=""; /* empty */
+  const char *host=""; /* empty */
+  int domlen=strlen(domain);
+  int hostlen = strlen(host);
+  int hostoff; /* host name offset */
+  int domoff;  /* domain name offset */
+  int size;
+  char *base64;
+  unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
+
+  /* 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 = 0;
+
+  /* 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 */
+    hostoff = 32;
+    domoff = hostoff + hostlen;
+    
+    /* Create and send a type-1 message:
+
+    Index Description          Content
+    0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
+                               (0x4e544c4d53535000)
+    8     NTLM Message Type    long (0x01000000)
+    12    Flags                long
+    16    Supplied Domain      security buffer(*)
+    24    Supplied Workstation security buffer(*)
+    32    start of data block
+
+    */
+
+    snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
+             "\x01%c%c%c" /* 32-bit type = 1 */
+             "%c%c%c%c"   /* 32-bit NTLM flag field */
+             "%c%c"  /* domain length */
+             "%c%c"  /* domain allocated space */
+             "%c%c"  /* domain name offset */
+             "%c%c"  /* 2 zeroes */
+             "%c%c"  /* host length */
+             "%c%c"  /* host allocated space */
+             "%c%c"  /* host name offset */
+             "%c%c"  /* 2 zeroes */
+             "%s"   /* host name */
+             "%s",  /* domain string */
+             0,     /* trailing zero */
+             0,0,0, /* part of type-1 long */
+
+             LONGQUARTET(
+               NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
+               NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
+               /* equals 0x0202 */
+               ),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domoff),
+             0,0,
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostoff),
+             0,0,
+             host, domain);
+
+    /* initial packet length */
+    size = 32 + hostlen + domlen;
+
+    base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
+    base64_encode (ntlmbuf, base64, size);
+
+    output = concat_strings ("NTLM ", base64, (char *) 0);
+    break;
+    
+  case NTLMSTATE_TYPE2:
+    /* We received the type-2 already, create a type-3 message:
+
+    Index   Description            Content
+    0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                   (0x4e544c4d53535000)
+    8       NTLM Message Type      long (0x03000000)
+    12      LM/LMv2 Response       security buffer(*)
+    20      NTLM/NTLMv2 Response   security buffer(*)
+    28      Domain Name            security buffer(*)
+    36      User Name              security buffer(*)
+    44      Workstation Name       security buffer(*)
+    (52)    Session Key (optional) security buffer(*)
+    (60)    Flags (optional)       long
+    52 (64) start of data block
+
+    */
+  
+  {
+    int lmrespoff;
+    int ntrespoff;
+    int useroff;
+    unsigned char lmresp[0x18]; /* fixed-size */
+#ifdef USE_NTRESPONSES
+    unsigned char ntresp[0x18]; /* fixed-size */
+#endif
+    const char *usr;
+    int userlen;
+
+    usr = strchr(user, '\\');
+    if(!usr)
+      usr = strchr(user, '/');
+
+    if (usr) {
+      domain = usr;
+      domlen = usr - domain;
+      usr++;
+    }
+    else
+      usr = user;
+    userlen = strlen(usr);
+
+    mkhash(passwd, &ntlm->nonce[0], lmresp
+#ifdef USE_NTRESPONSES
+           , ntresp
+#endif
+      );
+
+    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 *)ntlmbuf, sizeof(ntlmbuf),
+                    "NTLMSSP%c"
+                    "\x03%c%c%c" /* type-3, 32 bits */
+
+                    "%c%c%c%c" /* LanManager length + allocated space */
+                    "%c%c" /* LanManager offset */
+                    "%c%c" /* 2 zeroes */
+
+                    "%c%c" /* NT-response length */
+                    "%c%c" /* NT-response allocated space */
+                    "%c%c" /* NT-response offset */
+                    "%c%c" /* 2 zeroes */
+                    
+                    "%c%c"  /* domain length */
+                    "%c%c"  /* domain allocated space */
+                    "%c%c"  /* domain name offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* user length */
+                    "%c%c"  /* user allocated space */
+                    "%c%c"  /* user offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* host length */
+                    "%c%c"  /* host allocated space */
+                    "%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, /* zero termination */
+                    0,0,0, /* type-3 long, the 24 upper bits */
+
+                    SHORTPAIR(0x18),  /* LanManager response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(lmrespoff),
+                    0x0, 0x0,
+                    
+#ifdef USE_NTRESPONSES
+                    SHORTPAIR(0x18),  /* NT-response length, twice */
+                    SHORTPAIR(0x18),
+#else
+                    0x0, 0x0,
+                    0x0, 0x0,
+#endif
+                    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 */
+    size=64;
+    ntlmbuf[62]=ntlmbuf[63]=0;
+
+    memcpy(&ntlmbuf[size], domain, domlen);
+    size += domlen;
+
+    memcpy(&ntlmbuf[size], usr, userlen);
+    size += userlen;
+
+    /* we append the binary hashes to the end of the blob */
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+      memcpy(&ntlmbuf[size], lmresp, 0x18);
+      size += 0x18;
+    }
+
+#ifdef USE_NTRESPONSES
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
+      memcpy(&ntlmbuf[size], ntresp, 0x18);
+      size += 0x18;
+    }
+#endif
+
+    ntlmbuf[56] = size & 0xff;
+    ntlmbuf[57] = size >> 8;
+
+    /* convert the binary blob into base64 */
+    base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
+    base64_encode (ntlmbuf, base64, size);
+
+    output = concat_strings ("NTLM ", base64, (char *) 0);
+
+    ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+    *ready = 1;
+  }
+  break;
+
+  case NTLMSTATE_TYPE3:
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    *ready = 1;
+    output = NULL;
+    break;
+  }
+
+  return output;
+}
diff --git a/src/http-ntlm.h b/src/http-ntlm.h
new file mode 100644 (file)
index 0000000..ec6ddc3
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __HTTP_NTLM_H
+#define __HTTP_NTLM_H
+/* Declarations for http_ntlm.c
+   Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
+
+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 2 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, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
+
+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];
+};
+
+/* this is for ntlm header input */
+int ntlm_input PARAMS ((struct ntlmdata *, const char *));
+
+/* this is for creating ntlm header output */
+char *ntlm_output PARAMS ((struct ntlmdata *,
+                          const char *, const char *, int *));
+#endif
index 47355c91299ed381a04581b5cc1a9b05491c2d6b..c509b4aea1fcace5e612339dc917d6f870ddf993 100644 (file)
@@ -65,9 +65,12 @@ extern int errno;
 #include "netrc.h"
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"
 #include "netrc.h"
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"
-#endif /* HAVE_SSL */
+#endif
+#ifdef ENABLE_NTLM
+# include "http-ntlm.h"
+#endif
 #include "cookies.h"
 #include "cookies.h"
-#ifdef USE_DIGEST
+#ifdef ENABLE_DIGEST
 # include "gen-md5.h"
 #endif
 #include "convert.h"
 # include "gen-md5.h"
 #endif
 #include "convert.h"
@@ -824,6 +827,11 @@ static struct {
 
   /* Whether a ssl handshake has occoured on this connection.  */
   int ssl;
 
   /* Whether a ssl handshake has occoured on this connection.  */
   int ssl;
+
+#ifdef ENABLE_NTLM
+  /* NTLM data of the current connection.  */
+  struct ntlmdata ntlm;
+#endif
 } pconn;
 
 /* Mark the persistent connection as invalid and free the resources it
 } pconn;
 
 /* Mark the persistent connection as invalid and free the resources it
@@ -2574,47 +2582,6 @@ http_atotm (const char *time_string)
    consisting of answering to the server's challenge with the proper
    MD5 digests.  */
 
    consisting of answering to the server's challenge with the proper
    MD5 digests.  */
 
-/* How many bytes it will take to store LEN bytes in base64.  */
-#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
-
-/* Encode the string S of length LENGTH to base64 format and place it
-   to STORE.  STORE will be 0-terminated, and must point to a writable
-   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
-static void
-base64_encode (const char *s, char *store, int length)
-{
-  /* Conversion table.  */
-  static char tbl[64] = {
-    'A','B','C','D','E','F','G','H',
-    'I','J','K','L','M','N','O','P',
-    'Q','R','S','T','U','V','W','X',
-    'Y','Z','a','b','c','d','e','f',
-    'g','h','i','j','k','l','m','n',
-    'o','p','q','r','s','t','u','v',
-    'w','x','y','z','0','1','2','3',
-    '4','5','6','7','8','9','+','/'
-  };
-  int i;
-  unsigned char *p = (unsigned char *)store;
-
-  /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
-  for (i = 0; i < length; i += 3)
-    {
-      *p++ = tbl[s[0] >> 2];
-      *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
-      *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
-      *p++ = tbl[s[2] & 0x3f];
-      s += 3;
-    }
-  /* Pad the result if necessary...  */
-  if (i == length + 1)
-    *(p - 1) = '=';
-  else if (i == length + 2)
-    *(p - 1) = *(p - 2) = '=';
-  /* ...and zero-terminate it.  */
-  *p = '\0';
-}
-
 /* Create the authentication header contents for the `Basic' scheme.
    This is done by encoding the string `USER:PASS' in base64 and
    prepending `HEADER: Basic ' to it.  */
 /* Create the authentication header contents for the `Basic' scheme.
    This is done by encoding the string `USER:PASS' in base64 and
    prepending `HEADER: Basic ' to it.  */
@@ -2639,7 +2606,7 @@ basic_authentication_encode (const char *user, const char *passwd)
     ++(x);                                     \
 } while (0)
 
     ++(x);                                     \
 } while (0)
 
-#ifdef USE_DIGEST
+#ifdef ENABLE_DIGEST
 /* Parse HTTP `WWW-Authenticate:' header.  AU points to the beginning
    of a field in such a header.  If the field is the one specified by
    ATTR_NAME ("realm", "opaque", and "nonce" are used by the current
 /* Parse HTTP `WWW-Authenticate:' header.  AU points to the beginning
    of a field in such a header.  If the field is the one specified by
    ATTR_NAME ("realm", "opaque", and "nonce" are used by the current
@@ -2825,7 +2792,7 @@ username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
   }
   return res;
 }
   }
   return res;
 }
-#endif /* USE_DIGEST */
+#endif /* ENABLE_DIGEST */
 
 
 #define BEGINS_WITH(line, string_constant)                             \
 
 
 #define BEGINS_WITH(line, string_constant)                             \
@@ -2837,8 +2804,13 @@ static int
 known_authentication_scheme_p (const char *au)
 {
   return BEGINS_WITH (au, "Basic")
 known_authentication_scheme_p (const char *au)
 {
   return BEGINS_WITH (au, "Basic")
+#ifdef ENABLE_DIGEST
     || BEGINS_WITH (au, "Digest")
     || BEGINS_WITH (au, "Digest")
-    || BEGINS_WITH (au, "NTLM");
+#endif
+#ifdef ENABLE_NTLM
+    || BEGINS_WITH (au, "NTLM")
+#endif
+    ;
 }
 
 #undef BEGINS_WITH
 }
 
 #undef BEGINS_WITH
@@ -2855,10 +2827,20 @@ create_authorization_line (const char *au, const char *user,
 {
   if (0 == strncasecmp (au, "Basic", 5))
     return basic_authentication_encode (user, passwd);
 {
   if (0 == strncasecmp (au, "Basic", 5))
     return basic_authentication_encode (user, passwd);
-#ifdef USE_DIGEST
+#ifdef ENABLE_DIGEST
   if (0 == strncasecmp (au, "Digest", 6))
     return digest_authentication_encode (au, user, passwd, method, path);
   if (0 == strncasecmp (au, "Digest", 6))
     return digest_authentication_encode (au, user, passwd, method, path);
-#endif /* USE_DIGEST */
+#endif
+#ifdef ENABLE_NTLM
+  if (0 == strncasecmp (au, "NTLM", 4))
+    {
+      int ok = ntlm_input (&pconn.ntlm, au);
+      if (!ok)
+       return NULL;
+      /* #### we shouldn't ignore the OK that ntlm_output returns. */
+      return ntlm_output (&pconn.ntlm, user, passwd, &ok);
+    }
+#endif
   return NULL;
 }
 \f
   return NULL;
 }
 \f
index a16b4b81fbc217cf05b13142316694b312e9eb8a..0d083e2982b8bf1c2033dc73850f00fb236edca3 100644 (file)
@@ -357,7 +357,7 @@ fake_fork (void)
 
   /* Create the child process detached form the current console and in a
      suspended state.  */
 
   /* Create the child process detached form the current console and in a
      suspended state.  */
-  memset (&si, 0, sizeof (si));
+  xzero (si);
   si.cb = sizeof (si);
   rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
                       CREATE_SUSPENDED | DETACHED_PROCESS,
   si.cb = sizeof (si);
   rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
                       CREATE_SUSPENDED | DETACHED_PROCESS,
index 2894d8f30a69b62253b3a5a83358e3f3d6322070..2e45c4d5812edb4966cd83aa9ae98e0c88d6a53c 100644 (file)
@@ -2170,3 +2170,143 @@ xsleep (double seconds)
 }
 
 #endif /* not WINDOWS */
 }
 
 #endif /* not WINDOWS */
+
+/* Encode the string S of length LENGTH to base64 format and place it
+   to STORE.  STORE will be 0-terminated, and must point to a writable
+   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
+
+void
+base64_encode (const char *s, char *store, int length)
+{
+  /* Conversion table.  */
+  static char tbl[64] = {
+    'A','B','C','D','E','F','G','H',
+    'I','J','K','L','M','N','O','P',
+    'Q','R','S','T','U','V','W','X',
+    'Y','Z','a','b','c','d','e','f',
+    'g','h','i','j','k','l','m','n',
+    'o','p','q','r','s','t','u','v',
+    'w','x','y','z','0','1','2','3',
+    '4','5','6','7','8','9','+','/'
+  };
+  int i;
+  unsigned char *p = (unsigned char *)store;
+
+  /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
+  for (i = 0; i < length; i += 3)
+    {
+      *p++ = tbl[s[0] >> 2];
+      *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+      *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+      *p++ = tbl[s[2] & 0x3f];
+      s += 3;
+    }
+  /* Pad the result if necessary...  */
+  if (i == length + 1)
+    *(p - 1) = '=';
+  else if (i == length + 2)
+    *(p - 1) = *(p - 2) = '=';
+  /* ...and zero-terminate it.  */
+  *p = '\0';
+}
+
+#define IS_ASCII(c) (((c) & 0x80) == 0)
+#define IS_BASE64(c) ((IS_ASCII (c) && base64_char_to_value[c] >= 0) || c == '=')
+
+/* Get next character from the string, except that non-base64
+   characters are ignored, as mandated by rfc2045.  */
+#define NEXT_BASE64_CHAR(c, p) do {                    \
+  c = *p++;                                            \
+} while (c != '\0' && !IS_BASE64 (c))
+
+/* Decode data from BASE64 (assumed to be encoded as base64) into
+   memory pointed to by TO.  TO should be large enough to accomodate
+   the decoded data, which is guaranteed to be less than
+   strlen(base64).
+
+   Since TO is assumed to contain binary data, it is not
+   NUL-terminated.  The function returns the length of the data
+   written to TO.  -1 is returned in case of error caused by malformed
+   base64 input.  */
+
+int
+base64_decode (const char *base64, char *to)
+{
+  /* Table of base64 values for first 128 characters.  */
+  static short base64_char_to_value[128] =
+    {
+      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, /*   0-  9 */
+      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, /*  10- 19 */
+      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, /*  20- 29 */
+      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, /*  30- 39 */
+      -1,  -1,  -1,  62,  -1,  -1,  -1,  63,  52,  53, /*  40- 49 */
+      54,  55,  56,  57,  58,  59,  60,  61,  -1,  -1, /*  50- 59 */
+      -1,  -1,  -1,  -1,  -1,  0,   1,   2,   3,   4,  /*  60- 69 */
+      5,   6,   7,   8,   9,   10,  11,  12,  13,  14, /*  70- 79 */
+      15,  16,  17,  18,  19,  20,  21,  22,  23,  24, /*  80- 89 */
+      25,  -1,  -1,  -1,  -1,  -1,  -1,  26,  27,  28, /*  90- 99 */
+      29,  30,  31,  32,  33,  34,  35,  36,  37,  38, /* 100-109 */
+      39,  40,  41,  42,  43,  44,  45,  46,  47,  48, /* 110-119 */
+      49,  50,  51,  -1,  -1,  -1,  -1,  -1            /* 120-127 */
+    };
+
+  const char *p = base64;
+  char *q = to;
+
+  while (1)
+    {
+      unsigned char c;
+      unsigned long value;
+
+      /* Process first byte of a quadruplet.  */
+      NEXT_BASE64_CHAR (c, p);
+      if (!c)
+       break;
+      if (c == '=')
+       return -1;              /* illegal '=' while decoding base64 */
+      value = base64_char_to_value[c] << 18;
+
+      /* Process scond byte of a quadruplet.  */
+      NEXT_BASE64_CHAR (c, p);
+      if (!c)
+       return -1;              /* premature EOF while decoding base64 */
+      if (c == '=')
+       return -1;              /* illegal `=' while decoding base64 */
+      value |= base64_char_to_value[c] << 12;
+      *q++ = value >> 16;
+
+      /* Process third byte of a quadruplet.  */
+      NEXT_BASE64_CHAR (c, p);
+      if (!c)
+       return -1;              /* premature EOF while decoding base64 */
+
+      if (c == '=')
+       {
+         NEXT_BASE64_CHAR (c, p);
+         if (!c)
+           return -1;          /* premature EOF while dcoding base64 */
+         if (c != '=')
+           return -1;          /* padding `=' expected but not found */
+         continue;
+       }
+
+      value |= base64_char_to_value[c] << 6;
+      *q++ = 0xff & value >> 8;
+
+      /* Process fourth byte of a quadruplet.  */
+      NEXT_BASE64_CHAR (c, p);
+      if (!c)
+       return -1;              /* premature EOF while dcoding base64 */
+      if (c == '=')
+       continue;
+
+      value |= base64_char_to_value[c];
+      *q++ = 0xff & value;
+    }
+
+  return q - to;
+}
+
+#undef IS_ASCII
+#undef IS_BASE64
+#undef NEXT_BASE64_CHAR
index f93d2ae95b04a11f1e075f02b5fa5805c1a06008..119cd281e104b8101dad5671dbd8b1da722c2062 100644 (file)
@@ -125,4 +125,10 @@ double random_float PARAMS ((void));
 int run_with_timeout PARAMS ((double, void (*) (void *), void *));
 void xsleep PARAMS ((double));
 
 int run_with_timeout PARAMS ((double, void (*) (void *), void *));
 void xsleep PARAMS ((double));
 
+/* How many bytes it will take to store LEN bytes in base64.  */
+#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
+
+void base64_encode PARAMS ((const char *, char *, int));
+int base64_decode PARAMS ((const char *, char *));
+
 #endif /* UTILS_H */
 #endif /* UTILS_H */