diff --git a/CHANGES b/CHANGES index a545097..aa9edb8 100755 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Changes to proxytunnel version 1.5.0 -- Mon Aug 15 12:18:41 CEST 2005 + +- Allow overriding of NTLM 'DOMAIN', using -t + +Changes to proxytunnel version 1.4.0 -- Mon Aug 15 11:40:18 CEST 2005 + +- Included version-2 of the NTLM patch by Paul Solomon + Changes to proxytunnel version 1.2.3 -- Tue Nov 2 17:03:00 CET 2004 - Patched a possible buffer overflow as reported by Dan Margolis diff --git a/CREDITS b/CREDITS index 837638f..5714d06 100644 --- a/CREDITS +++ b/CREDITS @@ -12,6 +12,7 @@ people. Andrew Griffiths - String format fixes Dieter Heiliger - User-agent header idea Fred Donck - User/Pass Env Vars + Paul Solomon - NTLM support Furthermore we would like to thank the wonderful people at SourceForge diff --git a/Makefile b/Makefile index ff090f9..c1678f3 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CC = gcc CFLAGS = -Wall -DHAVE_GETOPT_LONG LDFLAGS = INSTALLPATH = $(DESTDIR)/usr/local/bin -MANPATH = $(DESTDIR)/usr/local/man/man1 +MANPATH = $(DESTDIR)/usr/man/man1 PROGNAME = proxytunnel OBJ = proxytunnel.o \ @@ -15,7 +15,10 @@ OBJ = proxytunnel.o \ http.o \ basicauth.o \ messages.o \ - cmdline.o + cmdline.o \ + ntlm.o \ + md4.o \ + md5.o proxytunnel: $(OBJ) $(CC) -o $(PROGNAME) $(LDFLAGS) $(OBJ) diff --git a/README b/README index 78bf893..c8ab302 100755 --- a/README +++ b/README @@ -3,8 +3,8 @@ proxytunnel ----------- Author: Jos Visser , Mark Janssen -Date: Thu Sep 30 11:22:03 CEST 2004 -Version: 1.2.0 +Date: Mon Aug 15 12:15:00 CEST 2005 +Version: 1.5.0 Hi all, @@ -22,7 +22,7 @@ Proxytunnel is very easy to use, when running proxytunnel with the help option it specifies it's command-line options. $ ./proxytunnel --help -Proxytunnel 1.2.0 +Proxytunnel 1.5.0 Jos Visser (Muppet) , Mark Janssen (Maniac) Purpose: @@ -35,6 +35,7 @@ Usage: Proxytunnel [OPTIONS]... -a INT --standalone=INT Run as standalone daemon on specified port -u STRING --user=STRING Username to send to HTTPS proxy for auth -s STRING --pass=STRING Password to send to HTTPS proxy for auth + -t STRING --domain=STRING NTLM Domain (default: autodetect) -U STRING --uservar=STRING Env var with Username for HTTPS proxy auth -S STRING --passvar=STRING Env var with Password for HTTPS proxy auth -g STRING --proxyhost=STRING HTTPS Proxy host to connect to @@ -42,6 +43,7 @@ Usage: Proxytunnel [OPTIONS]... -d STRING --desthost=STRING Destination host to built the tunnel to -D INT --destport=INT Destination portnumber to built the tunnel to -H STRING --header=STRING Add STRING to HTTP headers sent to proxy + -N --ntlm Use NTLM Based Authentication -n --dottedquad Convert destination hostname to dotted quad -v --verbose Turn on verbosity (default=off) -q --quiet Suppress messages (default=off) @@ -52,7 +54,6 @@ Proxytunnel -i [ -u user -s pass ] -g host -G port -d host -D port [ -n ] [ -v | Proxytunnel -i [ -U envvar -S envvar ] -g host -G port -d host -D port [ -n ] [ -v | -q ] Proxytunnel -a port [ -u user -s pass ] -g host -G port -d host -D port [ -n ] [ -v | -q ] - To use this program with OpenSSH to connect to a host somewhere, create a $HOME/.ssh/config file with the following content: @@ -88,6 +89,13 @@ and 563 (SNEWS), so some hacking is necessary to start the SSH daemon on the required port. (On the server side add an extra Port statement in the sshd_config file) +When your proxy uses NTLM authentication (like Microsoft IIS proxy) +you need to specify -N to enable NTLM, and then specify your username +and password (and optionally domain, if autodetection fails). Usename +and password can be specified on the commandline, or, more securely, +using environment variables. The domain can only be specified on the +commandline. + When all this is in place, execute an "ssh foobar" and you're in business! Share and Enjoy! diff --git a/base64.c b/base64.c index 5432f52..34ebf74 100644 --- a/base64.c +++ b/base64.c @@ -21,11 +21,26 @@ #include "config.h" #include "cmdline.h" #include "base64.h" +#include /* Needed for base64 encoding... */ static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#define BAD -1 +static const char base64val[] = { + BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, + BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, + BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, + BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD, + BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD +}; +#define DECODE64(c) (isascii(c) ? base64val[c] : BAD) + + /* * Small MAX macro */ @@ -72,3 +87,53 @@ void base64(unsigned char *out, const unsigned char *in, int len) } *out = '\0'; } + +int unbase64(char *out, const char *in, int maxlen) +/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */ +/* maxlen limits output buffer size, set to zero to ignore */ +{ + int len = 0; + register unsigned char digit1, digit2, digit3, digit4; + + if (in[0] == '+' && in[1] == ' ') + in += 2; + if (*in == '\r') + return(0); + + do { + digit1 = in[0]; + if (DECODE64(digit1) == BAD) + return(-1); + digit2 = in[1]; + if (DECODE64(digit2) == BAD) + return(-1); + digit3 = in[2]; + if (digit3 != '=' && DECODE64(digit3) == BAD) + return(-1); + digit4 = in[3]; + if (digit4 != '=' && DECODE64(digit4) == BAD) + return(-1); + in += 4; + ++len; + if (maxlen && len > maxlen) + return(-1); + *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); + if (digit3 != '=') + { + ++len; + if (maxlen && len > maxlen) + return(-1); + *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); + if (digit4 != '=') + { + ++len; + if (maxlen && len > maxlen) + return(-1); + *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); + } + } + } while + (*in && *in != '\r' && digit4 != '='); + + return (len); +} diff --git a/base64.h b/base64.h index 6115750..b265f49 100644 --- a/base64.h +++ b/base64.h @@ -20,3 +20,4 @@ /* base64.h */ void base64(unsigned char *out, const unsigned char *in, int len); +int unbase64(char *out, const char *in, int maxlen); diff --git a/cmdline.c b/cmdline.c index 1224fde..a2f645b 100755 --- a/cmdline.c +++ b/cmdline.c @@ -59,6 +59,7 @@ cmdline_parser_print_help (void) #endif " -u STRING --user=STRING Username to send to HTTPS proxy for auth\n" " -s STRING --pass=STRING Password to send to HTTPS proxy for auth\n" +" -t STRING --domain=STRING NTLM Domain (default: autodetect)\n" " -U STRING --uservar=STRING Env var with Username for HTTPS proxy auth\n" " -S STRING --passvar=STRING Env var with Password for HTTPS proxy auth\n" " -g STRING --proxyhost=STRING HTTPS Proxy host to connect to\n" @@ -66,6 +67,7 @@ cmdline_parser_print_help (void) " -d STRING --desthost=STRING Destination host to built the tunnel to\n" " -D INT --destport=INT Destination portnumber to built the tunnel to\n" " -H STRING --header=STRING Add STRING to HTTP headers sent to proxy\n" +" -N --ntlm Use NTLM Based Authentication\n" " -n --dottedquad Convert destination hostname to dotted quad\n" " -v --verbose Turn on verbosity (default=off)\n" " -q --quiet Suppress messages (default=off)\n", PACKAGE); @@ -116,20 +118,24 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->destport_given = 0; args_info->dottedquad_given = 0; args_info->verbose_given = 0; + args_info->ntlm_given = 0; args_info->inetd_given = 0; args_info->quiet_given = 0; args_info->header_given = 0; + args_info->domain_given = 0; /* No... we can't make this a function... -- Maniac */ #define clear_args() \ { \ args_info->user_arg = NULL; \ args_info->pass_arg = NULL; \ + args_info->domain_arg = NULL; \ args_info->proxyhost_arg = NULL; \ args_info->desthost_arg = NULL; \ args_info->header_arg = NULL; \ args_info->dottedquad_flag = 0; \ args_info->verbose_flag = 0; \ + args_info->ntlm_flag = 0; \ args_info->inetd_flag = 0; \ args_info->quiet_flag = 0; \ args_info->standalone_arg = 0; \ @@ -156,6 +162,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { "version", 0, NULL, 'V' }, { "user", 1, NULL, 'u' }, { "pass", 1, NULL, 's' }, + { "domain", 1, NULL, 't' }, { "uservar", 1, NULL, 'U' }, { "passvar", 1, NULL, 'S' }, { "proxyhost", 1, NULL, 'g' }, @@ -165,15 +172,16 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { "header", 1, NULL, 'H' }, { "dottedquad", 0, NULL, 'n' }, { "verbose", 0, NULL, 'v' }, + { "ntlm", 0, NULL, 'N' }, { "inetd", 0, NULL, 'i' }, { "standalone", 1, NULL, 'a' }, { "quiet", 0, NULL, 'q' }, { NULL, 0, NULL, 0 } }; - c = getopt_long (argc, argv, "hVia:u:s:U:S:g:G:d:D:H:nvq", long_options, &option_index); + c = getopt_long (argc, argv, "hVia:u:s:t:U:S:g:G:d:D:H:nvNq", long_options, &option_index); #else - c = getopt( argc, argv, "hVia:u:s:U:S:g:G:d:D:H:nvq" ); + c = getopt( argc, argv, "hVia:u:s:t:U:S:g:G:d:D:H:nvNq" ); #endif if (c == -1) break; /* Exit from `while (1)' loop. */ @@ -251,6 +259,17 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->pass_arg = gengetopt_strdup (optarg); break; + case 't': /* Env Var with NTLM DOMAIN (when overriding). */ + if (args_info->domain_given) + { + fprintf (stderr, "%s: `--domain' (`-t') option given more than once\n", PACKAGE); + clear_args (); + exit (1); + } + args_info->domain_given = 1; + args_info->domain_arg = gengetopt_strdup (optarg); + break; + case 'S': /* Env Var with Password to send to HTTPS proxy for authentication. */ if (args_info->pass_given) { @@ -324,6 +343,10 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar case 'v': /* Turn on verbosity. */ args_info->verbose_flag = !(args_info->verbose_flag); + break; + + case 'N': /* Turn on NTLM. */ + args_info->ntlm_flag = !(args_info->ntlm_flag); break; case 'q': /* Suppress messages -- Quiet mode */ @@ -342,6 +365,14 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar } /* switch */ } /* while */ + if (! args_info->proxyhost_given && ! args_info->proxyport_given + && ! args_info->desthost_given + && ! args_info->destport_given ) + { + clear_args (); + cmdline_parser_print_help (); + exit (0); + } if (! args_info->proxyhost_given) { fprintf (stderr, "%s: `--proxyhost' (`-g') option required!\n", PACKAGE); diff --git a/cmdline.h b/cmdline.h index d353d1b..2a512b5 100755 --- a/cmdline.h +++ b/cmdline.h @@ -26,6 +26,7 @@ struct gengetopt_args_info { char * user_arg; /* Username to send to HTTPS proxy for auth. */ char * pass_arg; /* Password to send to HTTPS proxy for auth. */ + char * domain_arg; /* NTLM Domain override */ char * proxyhost_arg; /* HTTPS Proxy host to connect to. */ int proxyport_arg; /* HTTPS Proxy host portnumber to connect to. */ char * desthost_arg; /* Destination host to built the tunnel to. */ @@ -33,6 +34,7 @@ struct gengetopt_args_info { int destport_arg; /* Dest host portnumber to built the tunnel to. */ int dottedquad_flag; /* Resolve hostname to dottedquad notation. */ int verbose_flag; /* Turn on verbosity (default=off). */ + int ntlm_flag; /* Turn on ntlm (default=off). */ int inetd_flag; /* Turn on inetd (default=off). */ int quiet_flag; /* Turn on quiet mode (default=off). */ int standalone_arg; /* Turn on stdalone (-a) on port */ @@ -41,12 +43,14 @@ struct gengetopt_args_info { int version_given; /* Whether version was given. */ int user_given; /* Whether user was given. */ int pass_given; /* Whether pass was given. */ + int domain_given; /* Whether domain was given. */ int proxyhost_given; /* Whether proxyhost was given. */ int proxyport_given; /* Whether proxyport was given. */ int desthost_given; /* Whether desthost was given. */ int destport_given; /* Whether destport was given. */ int dottedquad_given; /* Whether dottedquad was given. */ int verbose_given; /* Whether verbose was given. */ + int ntlm_given; /* Whether ntlm was given. */ int inetd_given; /* Whether inetd was given. */ int quiet_given; /* Whether quiet mode was given. */ int header_given; /* Whenther extra headers are given */ diff --git a/config.h b/config.h index 8475f87..493029e 100755 --- a/config.h +++ b/config.h @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VERSION "1.2.3" +#define VERSION "1.5.0" #define PACKAGE "Proxytunnel" #define PURPOSE "Build generic tunnels through HTTPS proxies" #define AUTHORS "Jos Visser (Muppet) , Mark Janssen (Maniac) " diff --git a/debian/changelog b/debian/changelog index bfdb18a..6ec8d33 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,15 @@ +proxytunnel (1.5.0-1) unstable; urgency=high + + * New version + * NTLM support + + -- Mark Janssen Mon, 15 Aug 2005 12:24:00 +0200 + proxytunnel (1.2.3-1) unstable; urgency=high * Added security-patch from gentoo security team, fix buffer overflow - -- Mark Janssen Tue Nov 2 17:08:35 CET 2004 + -- Mark Janssen Wed, 20 Nov 2002 15:12:10 +0200 proxytunnel (1.2.0-1) unstable; urgency=low diff --git a/debian/copyright b/debian/copyright index 358a05d..74ce56e 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,5 +1,5 @@ This package was debianized by Mark Janssen on -Tue Nov 2 17:08:57 CET 2004 +Mon Aug 15 12:20:26 CEST 2005 It was downloaded from http://proxytunnel.sourceforge.net diff --git a/debian/dirs b/debian/dirs index a65408f..4ab2d2c 100644 --- a/debian/dirs +++ b/debian/dirs @@ -1,2 +1,3 @@ usr/bin usr/share/man +usr/man/man1 diff --git a/debian/docs b/debian/docs index 94a0111..1d4dae9 100644 --- a/debian/docs +++ b/debian/docs @@ -1,2 +1,3 @@ CREDITS README +CHANGES diff --git a/http.c b/http.c index 213a1b8..d7dfdfb 100644 --- a/http.c +++ b/http.c @@ -29,6 +29,7 @@ #include "io.h" #include "proxytunnel.h" #include "basicauth.h" +#include "ntlm.h" /* * Analyze the proxy's HTTP response. This must be a HTTP/1.? 200 OK type @@ -51,6 +52,19 @@ void analyze_HTTP() message( "HTTP return code: '%s'\n", p ); p += strlen( p ) + 1; message( "%s\n", p ); + + if (!ntlm_challenge && strcmp( p, "407") != 0) { + do { + readline(); + if (strncmp( buf, "Proxy-Authenticate: NTLM ", 25) == 0) { + if (parse_type2(&buf[25]) < 0) + exit(1); + } + } while ( strcmp( buf, "\r\n" ) != 0 ); + } + if (ntlm_challenge == 1) { + return proxy_protocol(); + } exit( 1 ); } } @@ -105,8 +119,19 @@ void proxy_protocol() /* * Create connect string including the authorization part */ - sprintf( buf, "%sProxy-authorization: Basic %s\r\n", - buf, basicauth ); + if (args_info.ntlm_flag) { + if (ntlm_challenge == 1) { + build_type3_response(); + sprintf( buf, "%sProxy-Authorization: NTLM %s\r\n", + buf, ntlm_type3_buf ); + } else if (ntlm_challenge == 0){ + sprintf( buf, "%sProxy-Authorization: NTLM %s\r\n", + buf, ntlm_type1_buf ); + } + } else { + sprintf( buf, "%sProxy-authorization: Basic %s\r\n", + buf, basicauth ); + } } if ( args_info.header_given ) @@ -130,7 +155,6 @@ void proxy_protocol() my_perror( "Socket write error" ); exit( 1 ); } - /* * Read the first line of the response and analyze it */ @@ -141,7 +165,11 @@ void proxy_protocol() * Then, repeat reading lines of the responses until a blank line * (which signifies the end of the response) is encountered. */ - do { - readline(); - } while ( strcmp( buf, "\r\n" ) != 0 ); + if (ntlm_challenge == 1) { + ntlm_challenge = 2; + } else { + do { + readline(); + } while ( strcmp( buf, "\r\n" ) != 0 ); + } } diff --git a/proxytunnel.c b/proxytunnel.c index 35b4799..d336067 100755 --- a/proxytunnel.c +++ b/proxytunnel.c @@ -37,6 +37,7 @@ #include "cmdline.h" #include "basicauth.h" #include "proxytunnel.h" +#include "ntlm.h" /* Define DARWIN if compiling on MacOS-X (Darwin), to work around some * inconsistencies. (Darwin doesn't know socklen_t) */ @@ -231,6 +232,10 @@ void do_daemon() read_fd = write_fd = sd_client; tunnel_connect(); proxy_protocol(); + if (args_info.ntlm_flag) { + proxy_protocol(); + proxy_protocol(); + } cpio(); exit( 0 ); } @@ -278,7 +283,11 @@ int main( int argc, char *argv[] ) if( args_info.user_given && args_info.pass_given ) { - make_basicauth(); + if (args_info.ntlm_flag) { + build_type1(); + message("Build Type 1 NTLM Message : %s\n", ntlm_type1_buf); + } else + make_basicauth(); } /* Do we need to run as a standalone daemon? */