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.
+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.
# 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
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],
-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.])
+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)
wget_need_md5=no
-case "${USE_OPIE}${USE_DIGEST}" in
+case "${ENABLE_OPIE}${ENABLE_DIGEST}" in
*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)
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
+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.
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 \
- 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
xfree (respline);
return FTPLOGREFUSED;
}
-#ifdef USE_OPIE
+#ifdef ENABLE_OPIE
{
static const char *skey_head[] = {
"331 s/key ",
pass = skey_response (skey_sequence, seed, pass);
}
}
-#endif /* USE_OPIE */
+#endif /* ENABLE_OPIE */
xfree (respline);
/* Send PASS password. */
request = ftp_request ("PASS", pass);
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+#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
#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"
-#ifdef USE_DIGEST
+#ifdef ENABLE_DIGEST
# include "gen-md5.h"
#endif
#include "convert.h"
/* 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
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. */
++(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
}
return res;
}
-#endif /* USE_DIGEST */
+#endif /* ENABLE_DIGEST */
#define BEGINS_WITH(line, string_constant) \
known_authentication_scheme_p (const char *au)
{
return BEGINS_WITH (au, "Basic")
+#ifdef ENABLE_DIGEST
|| BEGINS_WITH (au, "Digest")
- || BEGINS_WITH (au, "NTLM");
+#endif
+#ifdef ENABLE_NTLM
+ || BEGINS_WITH (au, "NTLM")
+#endif
+ ;
}
#undef BEGINS_WITH
{
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);
-#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
/* 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,
}
#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
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 */