diff -uN --strip-trailing-cr putty-0.56-orig/config.c putty-0.56-kls/config.c
--- putty-0.56-orig/config.c	2004-10-24 09:37:32.000000000 -0400
+++ putty-0.56-kls/config.c	2004-12-14 10:03:50.000000000 -0500
@@ -1525,7 +1525,10 @@
 		      'i', HELPCTX(ssh_auth_ki),
 		      dlg_stdcheckbox_handler,
 		      I(offsetof(Config,try_ki_auth)));
-
+	ctrl_checkbox(s, "Attempt \"PKCS#11 smartcard\" auth (SSH2)",
+		      'p', HELPCTX(ssh_auth_pkcs11),
+		      dlg_stdcheckbox_handler,
+		      I(offsetof(Config,try_pkcs11_auth)));
 	s = ctrl_getset(b, "Connection/SSH/Auth", "params",
 			"Authentication parameters");
 	ctrl_checkbox(s, "Allow agent forwarding", 'f',
@@ -1535,10 +1538,19 @@
 		      HELPCTX(ssh_auth_changeuser),
 		      dlg_stdcheckbox_handler,
 		      I(offsetof(Config,change_username)));
-	ctrl_filesel(s, "Private key file for authentication:", 'k',
+/*	ctrl_filesel(s, "Private key file for authentication:", 'k',
 		     FILTER_KEY_FILES, FALSE, "Select private key file",
 		     HELPCTX(ssh_auth_privkey),
 		     dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+*/
+	ctrl_filesel(s, "PKCS#11 library for authentication:", NO_SHORTCUT,
+		     NULL , FALSE, "Select PKCS#11 library file",
+		     HELPCTX(ssh_auth_pkcs11_libfile),
+		     dlg_stdfilesel_handler, I(offsetof(Config, pkcs11_libfile)));
+	ctrl_editbox(s, "Token label:", 't', 50,
+		     HELPCTX(ssh_auth_pkcs11_token_label),
+		     dlg_stdeditbox_handler, I(offsetof(Config,pkcs11_token_label)),
+		     I(sizeof(((Config *)0)->pkcs11_token_label)));
 
 	/*
 	 * The Connection/SSH/Tunnels panel.
@@ -1617,6 +1629,20 @@
 	ctrl_tabdelay(s, pfd->addbutton);
 	ctrl_columns(s, 1, 100);
 
+    ctrl_settitle(b, "Connection/SSH/Commands",
+              "Workarounds for SSH server bugs");
+    s = ctrl_getset(b, "Connection/SSH/Commands", "main",
+            "Local programs to start that use tunnels.");
+
+    ctrl_editbox(s, "Local command", NO_SHORTCUT, 75,
+             HELPCTX(ssh_tunnels_localcmd),
+             dlg_stdeditbox_handler, I(offsetof(Config,local_cmd)),
+             I(sizeof(((Config *)0)->local_cmd)));
+    ctrl_checkbox(s, "Close putty on local command",NO_SHORTCUT,
+              HELPCTX(ssh_tunnels_localcmd),
+              dlg_stdcheckbox_handler,
+              I(offsetof(Config,local_cmd_close)));
+
 	/*
 	 * The Connection/SSH/Bugs panel.
 	 */
diff -uN --strip-trailing-cr putty-0.56-orig/libpkcs11.c putty-0.56-kls/libpkcs11.c
--- putty-0.56-orig/libpkcs11.c	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/libpkcs11.c	2004-12-14 10:03:50.000000000 -0500
@@ -0,0 +1,268 @@
+/*
+ * Convenience pkcs11 library that can be linked into an application,
+ * and will bind to a specific pkcs11 module.
+ *
+ * Copyright (C) 2002  Olaf Kirch <okir@lst.de>
+ */
+
+#include "pkcs11.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
+#ifndef _WIN32
+#ifdef _WINDOWS
+#define _WIN32
+#endif
+#endif
+
+#define MAGIC			0xd00bed00
+
+struct sc_pkcs11_module {
+	unsigned int		_magic;
+#if defined(linux) || defined(_WIN32)
+	void *			_dl_handle;
+#endif
+#ifdef __APPLE__
+	struct mach_header	*_dl_handle;
+	CFBundleRef		bundleRef;  
+#endif
+};
+
+static int	sys_dlopen(sc_pkcs11_module_t *, const char *);
+static int	sys_dlclose(sc_pkcs11_module_t *);
+static void *	sys_dlsym(sc_pkcs11_module_t *, const char *);
+
+/*
+ * Load a module - this will load the shared object, call
+ * C_Initialize, and get the list of function pointers
+ */
+sc_pkcs11_module_t *
+C_LoadModule(const char *mspec, CK_FUNCTION_LIST_PTR_PTR funcs)
+{
+	sc_pkcs11_module_t *mod;
+	CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
+	int rv;
+
+	mod = (sc_pkcs11_module_t *) calloc(1, sizeof(*mod));
+	mod->_magic = MAGIC;
+    rv=sys_dlopen(mod,mspec);
+	if (rv < 0) {
+  //      fprintf(stderr, "failed to sys_dlopen - returned %i", rv)
+		goto failed; 
+    }
+
+	/* Get the list of function pointers */
+	c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))
+				sys_dlsym(mod, "C_GetFunctionList");
+	if (!c_get_function_list) {
+    //    fprintf(stderr, "failed to get function list");
+		goto failed;
+    }
+	rv = c_get_function_list(funcs);
+	if (rv == CKR_OK)
+		return mod;
+
+failed:	C_UnloadModule(mod);
+	return NULL;
+}
+
+/*
+ * Unload a pkcs11 module.
+ * The calling application is responsible for cleaning up
+ * and calling C_Finalize
+ */
+CK_RV
+C_UnloadModule(sc_pkcs11_module_t *mod)
+{
+	if (!mod || mod->_magic != MAGIC)
+		return CKR_ARGUMENTS_BAD;
+
+	if (sys_dlclose(mod) < 0)
+		return CKR_FUNCTION_FAILED;
+
+	memset(mod, 0, sizeof(*mod));
+	free(mod);
+	return CKR_OK;
+}
+
+#ifdef linux
+#include <dlfcn.h>
+
+/*
+ * Module loader for platforms that have dlopen
+ *
+ * This is intentionally primitive; we may want a more
+ * elaborate loader in libopensc one day
+ */
+int
+sys_dlopen(struct sc_pkcs11_module *mod, const char *name)
+{
+	const char	**dir, *ldlist[64];
+	char		pathbuf[4096], *ldenv;
+	unsigned int	n = 0;
+
+	if ((ldenv = getenv("LD_LIBRARY_PATH")) 
+	 && (ldenv = strdup(ldenv))) {
+		ldlist[n] = strtok(ldenv, ":");
+		while (ldlist[n] != NULL && ++n < 63)
+			ldlist[n] = strtok(NULL, ":");
+	}
+	ldlist[n] = NULL;
+
+	if (name == NULL)
+		name = "opensc-pkcs11.so";
+
+	for (dir = ldlist; *dir; dir++) {
+		snprintf(pathbuf, sizeof(pathbuf), "%s/%s", *dir, name);
+		mod->_dl_handle = dlopen(pathbuf, RTLD_NOW);
+		if (mod->_dl_handle != NULL)
+			break;
+	}
+
+	if (mod->_dl_handle == NULL)
+		mod->_dl_handle = dlopen(name, RTLD_NOW);
+
+	if (ldenv)
+		free(ldenv);
+
+	return (mod->_dl_handle? 0 : -1);
+}
+
+int
+sys_dlclose(struct sc_pkcs11_module *mod)
+{
+	if (mod->_dl_handle)
+		dlclose(mod->_dl_handle);
+	mod->_dl_handle = NULL;
+	return 0;
+}
+
+
+void *
+sys_dlsym(sc_pkcs11_module_t *mod, const char *name)
+{
+	if (!mod->_dl_handle)
+		return NULL;
+	return dlsym(mod->_dl_handle, name);
+}
+
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+
+/*
+ * Module loader for the Windows platform.
+ */
+int
+sys_dlopen(struct sc_pkcs11_module *mod, const char *name)
+{
+	if (name == NULL)
+		name = "opensc-pkcs11";
+
+	mod->_dl_handle = LoadLibrary(name);
+
+	return (mod->_dl_handle? 0 : GetLastError());
+}
+
+int
+sys_dlclose(struct sc_pkcs11_module *mod)
+{
+	if (mod->_dl_handle) {
+		if (FreeLibrary(mod->_dl_handle)) {
+			mod->_dl_handle = NULL;
+			return 0;
+		}
+		else
+			return -1;
+	}
+
+	return 0;
+}
+
+void *
+sys_dlsym(sc_pkcs11_module_t *mod, const char *name)
+{
+	if (!mod->_dl_handle)
+		return NULL;
+	return GetProcAddress(mod->_dl_handle, name);
+}
+
+#endif
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+
+/*
+ * Module loader for MacOSX 10
+ */
+int
+sys_dlopen(struct sc_pkcs11_module *mod, const char *name)
+{
+	int name_len;
+
+	if (name == NULL)
+		name = "libopensc-pkcs11.dylib";
+
+	name_len = strlen(name);
+	if (name_len > 7 && strcmp(name +  name_len - 7, ".bundle") != 0) {
+		mod->_dl_handle = NSAddImage(name,
+			NSADDIMAGE_OPTION_WITH_SEARCHING);
+	mod->bundleRef = NULL;
+	}
+	else {
+		CFStringRef text = CFStringCreateWithFormat(
+			NULL, NULL, CFSTR("%s"), name);
+		CFURLRef urlRef = CFURLCreateWithFileSystemPath(
+			kCFAllocatorDefault, text, kCFURLPOSIXPathStyle, 1);
+		mod->bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef);
+		CFRelease(urlRef);
+		CFRelease(text);
+		mod->_dl_handle = NULL;
+	}
+
+	return (mod->_dl_handle == NULL && mod->bundleRef == NULL ? -1 : 0);
+}
+
+int
+sys_dlclose(struct sc_pkcs11_module *mod)
+{
+	if (mod->bundleRef != NULL) {
+		CFBundleUnloadExecutable(mod->bundleRef);
+		CFRelease(mod->bundleRef);
+	}
+
+	return CKR_OK;
+}
+
+void *
+sys_dlsym(sc_pkcs11_module_t *mod, const char *name)
+{
+	NSSymbol symbol = NULL;
+	
+	if (mod->_dl_handle != NULL) {
+		char u_name[4096];
+
+		if (strlen(name) > 4094)
+			return NULL;
+		sprintf(u_name, "_%s", name);
+		symbol = NSLookupSymbolInImage(mod->_dl_handle, u_name,
+			NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW);
+		if (symbol==NULL)
+			return NULL;
+		return NSAddressOfSymbol(symbol);
+	}
+	else {
+		CFStringRef text = CFStringCreateWithFormat(
+			NULL, NULL, CFSTR("%s"), name);
+		symbol = CFBundleGetFunctionPointerForName(
+			mod->bundleRef, text);
+		CFRelease(text);
+		return symbol;
+	}
+}
+#endif
diff -uN --strip-trailing-cr putty-0.56-orig/local_cmd.c putty-0.56-kls/local_cmd.c
--- putty-0.56-orig/local_cmd.c	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/local_cmd.c	2004-12-14 10:03:50.000000000 -0500
@@ -0,0 +1,69 @@
+#include <windows.h>
+
+
+void do_close(void * ssh);
+
+unsigned long __stdcall WaitToClose(void * params);
+
+struct CloseParam {
+    PROCESS_INFORMATION* pi;
+    void * ssh;
+} ;
+
+
+int run_local_cmd(char* cmd, int close, void* ssh) {
+ STARTUPINFO si; PROCESS_INFORMATION *pi;
+ DWORD threadid;
+
+ pi=malloc(sizeof(PROCESS_INFORMATION));
+
+ memset(&si, 0, sizeof(si));
+ si.cb=sizeof(si);
+ memset(pi, 0,sizeof(pi));
+
+
+ if(!CreateProcess( 
+        NULL,
+        cmd,
+        NULL,
+        NULL,
+        FALSE,
+        0,
+        NULL,
+        NULL,
+        &si,
+        pi
+    ) ) {
+            //fprintf(stderr, "failed");
+        }
+
+
+ if(close) {
+    struct CloseParam * params;
+    params=malloc(sizeof( struct CloseParam));
+    params->ssh=ssh;
+    params->pi=pi;
+    CreateThread(NULL, 0, WaitToClose, params, 0, &threadid );
+ } else {
+    free(pi);
+  }
+
+ return close;
+
+}
+
+static unsigned long __stdcall WaitToClose(void * params) {
+    
+    struct CloseParam * toclose= (struct CloseParam *) params;
+    WaitForSingleObject(toclose->pi->hProcess, INFINITE);
+    do_close(toclose->ssh);
+    CloseHandle(toclose->pi->hProcess);
+    CloseHandle(toclose->pi->hThread);
+    free(toclose->pi);
+    free(toclose);
+    exit(0);
+    return 0;
+}
+
+
+
diff -uN --strip-trailing-cr putty-0.56-orig/pkcs11.h putty-0.56-kls/pkcs11.h
--- putty-0.56-orig/pkcs11.h	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/pkcs11.h	2004-12-14 10:03:50.000000000 -0500
@@ -0,0 +1,48 @@
+/*
+ * pkcs11.h: OpenSC project's PKCS#11 library header
+ *
+ * Copyright (C) 2002  Timo Teräs <timo.teras@iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef OPENSC_PKCS11_H
+#define OPENSC_PKCS11_H
+
+#ifndef _WINDOWS
+#include <rsaref/unix.h>
+#include <rsaref/pkcs11.h>
+#else
+#include "rsaref/win32.h"
+#pragma pack(push, cryptoki, 1)
+#include "rsaref/pkcs11.h"
+#pragma pack(pop, cryptoki)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sc_pkcs11_module sc_pkcs11_module_t;
+
+extern sc_pkcs11_module_t *C_LoadModule(const char *name,
+				CK_FUNCTION_LIST_PTR_PTR);
+extern CK_RV C_UnloadModule(sc_pkcs11_module_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -uN --strip-trailing-cr putty-0.56-orig/putty.h putty-0.56-kls/putty.h
--- putty-0.56-orig/putty.h	2004-10-24 09:37:32.000000000 -0400
+++ putty-0.56-kls/putty.h	2004-12-14 10:03:50.000000000 -0500
@@ -369,6 +369,9 @@
     int ssh2_des_cbc;		       /* "des-cbc" nonstandard SSH2 cipher */
     int try_tis_auth;
     int try_ki_auth;
+    int try_pkcs11_auth;
+    Filename pkcs11_libfile;
+    char pkcs11_token_label[50];
     int ssh_subsys;		       /* run a subsystem rather than a command */
     int ssh_subsys2;		       /* fallback to go with remote_cmd2 */
     int ssh_no_shell;		       /* avoid running a shell */
@@ -464,6 +467,9 @@
     int x11_forward;
     char x11_display[128];
     int x11_auth;
+    /* local command */
+    char local_cmd[512];
+    int local_cmd_close; /* close connection after local command terminates */
     /* port forwarding */
     int lport_acceptall; /* accept conns from hosts other than localhost */
     int rport_acceptall; /* same for remote forwarded ports (SSH2 only) */
diff -uN --strip-trailing-cr putty-0.56-orig/settings.c putty-0.56-kls/settings.c
--- putty-0.56-orig/settings.c	2004-10-24 09:37:32.000000000 -0400
+++ putty-0.56-kls/settings.c	2004-12-14 10:07:06.000000000 -0500
@@ -228,11 +228,16 @@
 	   cfg->ssh_cipherlist);
     write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
     write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
+    write_setting_i(sesskey, "AuthPKCS11", cfg->try_pkcs11_auth);
     write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
     write_setting_i(sesskey, "SshProt", cfg->sshprot);
     write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
     write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile);
+    write_setting_filename(sesskey, "PKCS11LibFile", cfg->pkcs11_libfile);
+    write_setting_s(sesskey, "PKCS11TokenLabel", cfg->pkcs11_token_label);
     write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd);
+    write_setting_s(sesskey, "LocalCommand", cfg->local_cmd);
+    write_setting_i(sesskey, "LocalCommandClose", cfg->local_cmd_close);
     write_setting_i(sesskey, "RFCEnviron", cfg->rfc_environ);
     write_setting_i(sesskey, "PassiveTelnet", cfg->passive_telnet);
     write_setting_i(sesskey, "BackspaceIsDelete", cfg->bksp_is_delete);
@@ -489,10 +494,17 @@
     gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
     gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
     gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
+    gppi(sesskey, "AuthPKCS11", 0, &cfg->try_pkcs11_auth);
     gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell);
     gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
+    gppfile(sesskey, "PKCS11LibFile", &cfg->pkcs11_libfile);
+    gpps(sesskey, "PKCS11TokenLabel", "", cfg->pkcs11_token_label,
+ 	 sizeof(cfg->pkcs11_token_label));
     gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
 	 sizeof(cfg->remote_cmd));
+    gpps(sesskey, "LocalCommand", "", cfg->local_cmd,
+         sizeof(cfg->local_cmd));
+    gppi(sesskey, "LocalCommandClose", 0, &cfg->local_cmd_close);
     gppi(sesskey, "RFCEnviron", 0, &cfg->rfc_environ);
     gppi(sesskey, "PassiveTelnet", 0, &cfg->passive_telnet);
     gppi(sesskey, "BackspaceIsDelete", 1, &cfg->bksp_is_delete);
diff -uN --strip-trailing-cr putty-0.56-orig/ssh.c putty-0.56-kls/ssh.c
--- putty-0.56-orig/ssh.c	2004-10-24 09:31:55.000000000 -0400
+++ putty-0.56-kls/ssh.c	2005-02-11 09:35:26.000000000 -0500
@@ -6,6 +6,11 @@
 #include "putty.h"
 #include "tree234.h"
 #include "ssh.h"
+#include "pkcs11.h"
+#include "sshscard.h"
+
+
+
 
 #ifndef FALSE
 #define FALSE 0
@@ -675,7 +680,20 @@
     int agent_response_len;
 };
 
+/*  need these?
+CK_MECHANISM_TYPE opt_mechanism = NO_MECHANISM;
+*/
+
+
+int loaded_pkcs11=FALSE;
+int run_local_cmd(char* cmd, int close, Ssh ssh) ;
+
+#ifdef linux
+#define logevent(s) fprintf(stderr, s);
+#else
 #define logevent(s) logevent(ssh->frontend, s)
+#endif
+
 
 /* logevent, only printf-formatted. */
 static void logeventf(Ssh ssh, const char *fmt, ...)
@@ -2217,6 +2235,11 @@
     crFinishV;
 }
 
+void do_close(void * ssh) {
+//    logevent("closing");
+    ssh_do_close( (Ssh) ssh);
+}
+
 static void ssh_do_close(Ssh ssh)
 {
     int i;
@@ -4749,7 +4772,7 @@
 {
     struct do_ssh2_authconn_state {
 	enum {
-	    AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,
+	    AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE, AUTH_PUBLICKEY_PKCS11,
 		AUTH_PASSWORD,
 		AUTH_KEYBOARD_INTERACTIVE
 	} method;
@@ -4762,8 +4785,9 @@
 		AUTH_TYPE_KEYBOARD_INTERACTIVE,
 		AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
 	} type;
-	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
-	int tried_pubkey_config, tried_agent, tried_keyb_inter;
+	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter, can_pkcs11;
+	int tried_pubkey_config, tried_pkcs11, tried_agent, tried_keyb_inter;
+    int trying_keyfile;
 	int kbd_inter_running;
 	int we_are_in;
 	int num_prompts, curr_prompt, echo;
@@ -4893,7 +4917,9 @@
 	s->tried_pubkey_config = FALSE;
 	s->tried_agent = FALSE;
 	s->tried_keyb_inter = FALSE;
+	s->tried_pkcs11 = FALSE;
 	s->kbd_inter_running = FALSE;
+
 	/* Load the pub half of ssh->cfg.keyfile so we notice if it's in Pageant */
 	if (!filename_is_null(ssh->cfg.keyfile)) {
 	    int keytype;
@@ -4917,7 +4943,15 @@
 		s->publickey_blob = NULL;
 	    }
 	} else
-	    s->publickey_blob = NULL;
+	    s->publickey_blob=NULL;
+
+    if (!loaded_pkcs11 && ssh->cfg.try_pkcs11_auth && !filename_is_null(ssh->cfg.pkcs11_libfile))  {
+        if( (s->can_pkcs11=init_pkcs11_library((void *) ssh->frontend, (char *) &ssh->cfg.pkcs11_libfile)) ) {
+		 loaded_pkcs11=1;
+	    } else {
+		 logevent("failed to load pkcs11 library");
+	    }
+    }
 
 	while (1) {
 	    /*
@@ -5024,6 +5058,7 @@
 
 		s->can_pubkey =
 		    in_commasep_string("publickey", methods, methlen);
+		s->can_pkcs11= ssh->cfg.try_pkcs11_auth && s->can_pubkey;
 		s->can_passwd =
 		    in_commasep_string("password", methods, methlen);
 		s->can_keyb_inter = ssh->cfg.try_ki_auth &&
@@ -5215,13 +5250,13 @@
 		sfree(s->response);
 	    }
 
-	    if (!s->method && s->can_pubkey && s->publickey_blob
-		&& !s->tried_pubkey_config) {
+	    if (!s->method && (
+             (s->can_pubkey && s->publickey_blob && !s->tried_pubkey_config) 
+             || (loaded_pkcs11 && s->can_pkcs11 && !s->tried_pkcs11))) {
 		unsigned char *pub_blob;
 		char *algorithm, *comment;
 		int pub_blob_len;
 
-		s->tried_pubkey_config = TRUE;
 
 		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
 		ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
@@ -5232,12 +5267,27 @@
 		 * First, offer the public blob to see if the server is
 		 * willing to accept it.
 		 */
+        if(s->can_pubkey && s->publickey_blob && !s->tried_pubkey_config) {
+            s->tried_pubkey_config = TRUE;
+            s->trying_keyfile=TRUE;
 		pub_blob =
 		    (unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile,
 							  &algorithm,
-							  &pub_blob_len,
-							  NULL);
+							  &pub_blob_len, NULL);
+    
+        } else {
+            s->tried_pkcs11 =TRUE;
+            s->trying_keyfile=FALSE;
+            pub_blob =
+                (unsigned char *)ssh2_userkey_loadpkcs11pub(&ssh->cfg.pkcs11_token_label,
+                              &algorithm,
+                              &pub_blob_len);
+            comment=&ssh->cfg.pkcs11_token_label;
+
+        }
+
 		if (pub_blob) {
+            logevent("got pub blob");
 		    ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);
 		    ssh2_pkt_addstring(ssh, s->username);
 		    ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */
@@ -5262,6 +5312,15 @@
 		     * Actually attempt a serious authentication using
 		     * the key.
 		     */
+             logeventf(ssh, "keyfile? %i" , s->trying_keyfile);
+ 
+             s->method = AUTH_PUBLICKEY_FILE;
+ 	     if (s->trying_keyfile==FALSE) {
+                 sprintf(s->pwprompt,
+                      "Passphrase for smartcard:");
+                 s->need_pw = TRUE;
+                 s->method = AUTH_PUBLICKEY_PKCS11;
+             } else {
 		    if (ssh2_userkey_encrypted(&ssh->cfg.keyfile, &comment)) {
 			sprintf(s->pwprompt,
 				"Passphrase for key \"%.100s\": ",
@@ -5270,15 +5329,19 @@
 		    } else {
 			s->need_pw = FALSE;
 		    }
+             }
+             logeventf(ssh, "keyfile? %i need pw? %i", s->trying_keyfile, s->need_pw);
 		    if (flags & FLAG_VERBOSE) {
 			c_write_str(ssh, "Authenticating with public key \"");
-			c_write_str(ssh, comment);
+	                if(s->trying_keyfile==TRUE && comment) c_write_str(ssh, comment);
 			c_write_str(ssh, "\"\r\n");
 		    }
-		    s->method = AUTH_PUBLICKEY_FILE;
+
 		}
 	    }
 
+ 
+
 	    if (!s->method && s->can_keyb_inter && !s->tried_keyb_inter) {
 		s->method = AUTH_KEYBOARD_INTERACTIVE;
 		s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
@@ -5417,24 +5480,38 @@
 		}
 	    }
 
-	    if (s->method == AUTH_PUBLICKEY_FILE) {
+	    if (s->method == AUTH_PUBLICKEY_FILE || s->method == AUTH_PUBLICKEY_PKCS11) {
 		/*
 		 * We have our passphrase. Now try the actual authentication.
 		 */
 		struct ssh2_userkey *key;
 		const char *error = NULL;
-
-		key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password,
-					&error);
+	logevent("loading key");
+		if (s->method == AUTH_PUBLICKEY_FILE) { 
+			key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password,&error);
+        	} else {
+		 /* need key identifier - label) */
+       		   	key = ssh2_load_pkcs11key(&ssh->cfg.pkcs11_token_label, s->password);
+				logevent("loaded pkcs11 key");
+        	}
 		if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
 		    if (key == SSH2_WRONG_PASSPHRASE) {
 			c_write_str(ssh, "Wrong passphrase\r\n");
+			 if(s->method == AUTH_PUBLICKEY_FILE) {
 			s->tried_pubkey_config = FALSE;
 		    } else {
+				/* never gets here */
+		             s->tried_pkcs11=FALSE;
+             		 } 
+		    } else {
 			c_write_str(ssh, "Unable to load private key (");
-			c_write_str(ssh, error);
+			if(error) c_write_str(ssh, error);
 			c_write_str(ssh, ")\r\n");
+			if(s->method ==AUTH_PUBLICKEY_FILE ) {
 			s->tried_pubkey_config = TRUE;
+             		} else {
+                		s->tried_pkcs11 = TRUE;
+             		}
 		    }
 		    /* Send a spurious AUTH_NONE to return to the top. */
 		    ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);
@@ -5485,14 +5562,20 @@
 			   ssh->pktout.length - 5);
                     p += ssh->pktout.length - 5;
                     assert(p == sigdata_len);
+	if((!key) || (!key->alg) || (!key->alg->sign) || (!key->data) )	{logevent("Bad key");exit(-1);}
+	else {logevent("Signing"); }
 		    sigblob = key->alg->sign(key->data, (char *)sigdata,
 					     sigdata_len, &sigblob_len);
+		    /* check return of sigblob */
+	if(!sigblob) {
+		logevent("Signing failed"); exit(1);
+	}
 		    ssh2_add_sigblob(ssh, pkblob, pkblob_len,
 				     sigblob, sigblob_len);
 		    sfree(pkblob);
 		    sfree(sigblob);
 		    sfree(sigdata);
-
+ 	logevent("Sending signature");
 		    ssh2_pkt_send(ssh);
 		    s->type = AUTH_TYPE_PUBLICKEY;
 		    key->alg->freekey(key->data);
@@ -5895,6 +5978,14 @@
     }
 
     /*
+     * Run local command and, if requested wait for it to end and close
+     */
+    if( strlen(ssh->cfg.local_cmd)>0) {
+        run_local_cmd(ssh->cfg.local_cmd, ssh->cfg.local_cmd_close, ssh);
+    };
+    
+
+    /*
      * Now allocate a pty for the session.
      */
     if (ssh->mainchan && !ssh->cfg.nopty) {
diff -uN --strip-trailing-cr putty-0.56-orig/ssh.h putty-0.56-kls/ssh.h
--- putty-0.56-orig/ssh.h	2004-10-06 18:31:01.000000000 -0400
+++ putty-0.56-kls/ssh.h	2004-12-14 10:03:50.000000000 -0500
@@ -11,6 +11,10 @@
 extern void sshfwd_close(struct ssh_channel *c);
 extern int sshfwd_write(struct ssh_channel *c, char *, int);
 extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
+typedef struct ssh_tag *Ssh;
+extern void ssh_do_close(Ssh ssh);
+
+
 
 /*
  * Useful thing.
diff -uN --strip-trailing-cr putty-0.56-orig/sshrsa.h putty-0.56-kls/sshrsa.h
--- putty-0.56-orig/sshrsa.h	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/sshrsa.h	2004-12-14 10:03:50.000000000 -0500
@@ -0,0 +1,14 @@
+
+#define GET_32BIT(cp) \
+    (((unsigned long)(unsigned char)(cp)[0] << 24) | \
+    ((unsigned long)(unsigned char)(cp)[1] << 16) | \
+    ((unsigned long)(unsigned char)(cp)[2] << 8) | \
+    ((unsigned long)(unsigned char)(cp)[3]))
+
+#define PUT_32BIT(cp, value) { \
+    (cp)[0] = (unsigned char)((value) >> 24); \
+    (cp)[1] = (unsigned char)((value) >> 16); \
+    (cp)[2] = (unsigned char)((value) >> 8); \
+    (cp)[3] = (unsigned char)(value); }
+
+
diff -uN --strip-trailing-cr putty-0.56-orig/sshscard.c putty-0.56-kls/sshscard.c
--- putty-0.56-orig/sshscard.c	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/sshscard.c	2005-02-11 10:10:03.000000000 -0500
@@ -0,0 +1,366 @@
+#include "ssh.h"
+#include "sshrsa.h"
+#include "pkcs11.h"
+#include "sshscard.h"
+#include "putty.h"
+
+const struct ssh_signkey ssh_pkcs11_rsa;
+
+typedef struct {
+    CK_SESSION_HANDLE session ;   
+    CK_FUNCTION_LIST_PTR funcs ;
+    CK_SLOT_ID slot;
+    CK_OBJECT_HANDLE pubkey ; 
+    CK_OBJECT_HANDLE privkey  ;
+} ssh2_pkcs11_key_t;
+
+struct sc_pkcs11_module * pkcs11_module =NULL;
+CK_SESSION_HANDLE pkcs11_session = CK_INVALID_HANDLE;
+CK_FUNCTION_LIST_PTR pkcs11_funcs=NULL;
+CK_SLOT_ID pkcs11_slot;
+
+void * frontend;
+
+/* logevent, only printf-formatted. */
+
+#define logevent(s) logevent(frontend,s);
+static void logeventf(const char *fmt, ...)
+{
+    va_list ap;
+    char *buf;
+
+    va_start(ap, fmt);
+    buf = dupvprintf(fmt, ap);
+    va_end(ap);
+    logevent(buf);
+    sfree(buf);
+}
+
+#define CHECK_CKR_BREAK(msg) \
+	if(r!=CKR_OK) {\
+                logeventf(msg,r);\
+		break ; }
+
+		//logeventf(ssh, msg, r);
+
+#define CHECK_CKR_NULL(msg) \
+	if(r!=CKR_OK) {\
+                logeventf(msg,r);\
+		return NULL ; }
+
+#define CHECK_CKR_ZERO(msg)\
+	if(r!=CKR_OK) {\
+                logeventf(msg,r);\
+		return 0 ; }
+
+int find_pkcs11_key(ssh2_pkcs11_key_t * keydata, int private) {
+	CK_RV r;
+        CK_ATTRIBUTE keyattr;
+        CK_ULONG count;
+
+        CK_OBJECT_HANDLE key = CK_INVALID_HANDLE;
+        CK_OBJECT_CLASS class=CKO_PUBLIC_KEY;
+        if(private) class=CKO_PRIVATE_KEY;
+
+        keyattr.type=CKA_CLASS;
+        keyattr.pValue=&class;
+        keyattr.ulValueLen = sizeof (class);
+        if(keydata->funcs->C_FindObjectsInit(keydata->session, &keyattr, 1)!=CKR_OK) {
+                fprintf(stderr,"Failed to initialize pkcs11 key finder.");
+                return 0;
+        }
+        if( (r=keydata->funcs->C_FindObjects(keydata->session, &key, 1, &count)) !=CKR_OK || count==0 ) {
+                fprintf(stderr, "no pkcs11 key found r: %ld , count: %ld", r, count);
+                keydata->funcs->C_FindObjectsFinal(keydata->session);
+                return 0;
+        }
+        keydata->funcs->C_FindObjectsFinal(keydata->session);
+        if(private) {keydata->privkey=key;} else {keydata->pubkey=key;}
+	fprintf(stderr,"Found %s key", private ? "private" : "public" );
+        return 1;
+
+}
+
+static unsigned long getmodulusbits(ssh2_pkcs11_key_t * key) {
+
+    CK_RV r;
+    CK_ATTRIBUTE template;
+    CK_ULONG ulCount=1;
+    CK_ULONG bits;
+
+    template.type=CKA_MODULUS_BITS;
+    template.pValue=NULL;
+    template.ulValueLen=0;
+
+    r=key->funcs->C_GetAttributeValue(key->session,key->privkey, &template, ulCount);
+
+    template.type=CKA_MODULUS_BITS;
+    template.pValue=&bits;
+
+    r=key->funcs->C_GetAttributeValue(key->session,key->privkey, &template, ulCount);
+
+
+    if(r !=CKR_OK) {
+        return 0;
+    }
+    return bits;
+}
+
+struct ssh2_userkey *ssh2_load_pkcs11key(char* label, char *passphrase)
+{
+    CK_RV r;
+    ssh2_pkcs11_key_t * keydata;
+    struct ssh2_userkey *ret;
+    int passlen= passphrase ? strlen(passphrase) : 0;
+
+    ret = NULL;                /* return NULL for most errors */
+
+    if (!passphrase) 
+	    goto error; 
+
+    if ((r=pkcs11_funcs->C_Login(pkcs11_session, CKU_USER, 
+            (CK_UTF8CHAR *) passphrase, passlen)) != CKR_OK) {
+            fprintf(stderr, "Failed to login to pkcs11 card - %ld", r);
+            return NULL;
+    }
+
+    keydata=snew(ssh2_pkcs11_key_t);
+    if(keydata==NULL) {
+	    return NULL;
+    }
+    keydata->funcs=pkcs11_funcs;
+    keydata->session=pkcs11_session;
+    keydata->slot=pkcs11_slot;
+    keydata->pubkey=CK_INVALID_HANDLE;
+    keydata->privkey=CK_INVALID_HANDLE;
+
+    if (find_pkcs11_key(keydata,1)==0) {
+            return NULL;
+    }
+
+
+    ret = snew(struct ssh2_userkey);
+    ret->alg=&ssh_pkcs11_rsa;
+    ret->data=(void *) keydata;
+    ret->comment="PKCS11 library";
+
+    /*
+     * Create and return the key.
+     */
+
+
+    if (!ret->data) {
+    sfree(ret->comment);
+    sfree(ret);
+    ret = NULL;
+    }
+    return ret;
+
+    /*
+     * Error processing.
+     */
+  error:
+    if (keydata)
+    sfree(keydata);
+    return ret;
+}
+
+static unsigned char *rsa2_pkcs11_public_blob(void * keydata, int *len)
+{
+    CK_RV r;
+    CK_ATTRIBUTE template[]= {
+	    	{CKA_PUBLIC_EXPONENT, NULL, 0},
+		{CKA_MODULUS, NULL, 0}
+    };
+    CK_BYTE* modulus;
+    CK_BYTE* exponent;
+    Bignum bn_mod, bn_exp;
+    CK_ULONG ulCount=2;
+
+    struct RSAKey rsakey; 
+
+    ssh2_pkcs11_key_t* key=(ssh2_pkcs11_key_t *) keydata;
+
+   /* need to get exponent and modulus */
+
+    if(key->pubkey==CK_INVALID_HANDLE && ((r=find_pkcs11_key(key, 0))!=1 )) {
+            fprintf(stderr,"Failed to find public key - %ld ",r );
+            return NULL;
+    }
+
+    r=key->funcs->C_GetAttributeValue(key->session, key->pubkey, template, ulCount);
+    if(r!=CKR_OK) {
+	    	fprintf(stderr, "failed to get attribute size - %ld", r);
+		return 0;
+    }
+    exponent=snewn(template[0].ulValueLen, CK_BYTE);
+    template[0].pValue=exponent;
+    modulus=snewn(template[1].ulValueLen, CK_BYTE);
+    template[1].pValue=modulus;
+
+    r=key->funcs->C_GetAttributeValue(key->session,key->pubkey, template, ulCount);
+    if(r !=CKR_OK) {
+	fprintf(stderr, "failed to get public key values - %ld ", r );
+        return NULL;
+    }
+
+    fprintf(stderr, "got exponent %i and modulus %i", *exponent, *modulus);
+
+    rsakey.exponent=bignum_from_bytes(template[0].pValue, template[0].ulValueLen);
+    rsakey.modulus=bignum_from_bytes(template[1].pValue, template[1].ulValueLen);
+ 	
+    sfree(exponent); sfree(modulus);
+    return ssh_rsa.public_blob(&rsakey, len);
+}
+
+
+unsigned char * ssh2_userkey_loadpkcs11pub(char* keylabel, 
+			      char** algorithm,
+                              int *pub_blob_len)
+{
+ 
+  ssh2_pkcs11_key_t key;
+  key.session=pkcs11_session;
+  key.funcs=pkcs11_funcs;
+  key.slot=0;
+  key.pubkey=CK_INVALID_HANDLE;
+  key.privkey= CK_INVALID_HANDLE;
+  *algorithm="ssh-rsa";
+  /* will need to get key first, to use label */
+
+  return rsa2_pkcs11_public_blob(&key, pub_blob_len);
+
+}
+
+
+
+static unsigned char *rsa2_pkcs11_sign(void *keydata, char *data, int datalen,
+                int *psiglen)
+{
+    ssh2_pkcs11_key_t *key=(ssh2_pkcs11_key_t *) keydata;
+    CK_RV r;
+    CK_MECHANISM mech = {CKM_SHA1_RSA_PKCS, NULL, 0} ;
+    CK_ULONG mech_count;
+    CK_ULONG siglen;
+    unsigned char *sig, *bytes;
+    int i, j, nbytes;
+
+    if( (!key) || (!key->funcs) || (!key->session) || (!key->privkey) ) { exit(-1);}
+    r=key->funcs->C_SignInit(key->session, &mech, key->privkey); 
+    if (r!=CKR_OK) {
+	    	fprintf(stderr, "failed to init signing mechanism - %ld", r);
+		return NULL;
+    } 
+
+    r=key->funcs->C_Sign(key->session, data, datalen, NULL, &siglen);
+    if (r!=CKR_OK) {
+	    	fprintf(stderr, "failed to get signature length");
+		return NULL;
+    } 
+    sig=snewn(siglen, unsigned char);
+
+    r=key->funcs->C_Sign(key->session, data, datalen, sig, &siglen);
+    if (r!=CKR_OK) {
+	    	fprintf(stderr, "failed to get signature  - %ld ", r);
+		return NULL;
+    }
+    fprintf(stderr, "signed! returning %ld bytes", siglen);
+
+    nbytes = siglen;
+    bytes = snewn(4 + 7 + 4 + nbytes, unsigned char);
+    PUT_32BIT(bytes, 7);
+    memcpy(bytes + 4, "ssh-rsa", 7);
+    PUT_32BIT(bytes + 4 + 7, nbytes);
+    for (i = 0; i < nbytes; i++)
+    bytes[4 + 7 + 4 + i] = sig[i]; // bignum_byte(out, nbytes - 1 - i);
+
+    *psiglen = 4 + 7 + 4 + nbytes;
+    return bytes;
+}
+
+static void rsa2_pkcs11_freekey(void * keydata) {
+  ssh2_pkcs11_key_t * key=(ssh2_pkcs11_key_t *) keydata;
+  sfree(key);
+}
+
+const struct ssh_signkey ssh_pkcs11_rsa = {
+    NULL,
+    rsa2_pkcs11_freekey,
+    NULL,
+    rsa2_pkcs11_public_blob,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    rsa2_pkcs11_sign,
+    "ssh-rsa",
+    "rsa2"
+};
+
+
+/*
+const struct ssh_signkey ssh_scard_rsa = {
+    rsa2_newkey,
+    rsa2_freekey,
+    rsa2_fmtkey,
+    rsa2_public_blob,
+    rsa2_private_blob,
+    rsa2_createkey,
+    rsa2_openssh_createkey,
+    rsa2_openssh_fmtkey,
+    rsa2_fingerprint,
+    rsa2_verifysig,
+    rsa2_sign,
+    "ssh-rsa",
+    "rsa2"
+};
+*/
+
+int
+init_pkcs11_library(void * ssh_frontend, char* pkcs11_library_name) {
+        CK_RV r;
+        CK_ULONG slot_cnt = 0;
+        CK_SLOT_ID_PTR slot_list=NULL;
+
+
+        frontend=ssh_frontend;
+
+	if (pkcs11_library_name==NULL) {
+#ifdef linux
+        pkcs11_library_name="/tmp/opensc/src/pkcs11/.libs/opensc-pkcs11.so";
+#endif
+#ifdef _WIN
+        pkcs11_library_name="opensc-pkcs11";
+#endif
+	}
+        logevent("attempting pkcs11...");
+        /* load module */
+        pkcs11_module=C_LoadModule(pkcs11_library_name,&pkcs11_funcs);
+//      pkcs11_module=malloc(sizeof(struct sc_pkcs11_module));
+//      load_pkcs11_module(pkcs11_library_name, ssh);
+        if(pkcs11_module==NULL) {
+            logevent("Failed to load pkcs11 module");
+            return 0;
+        } 
+
+        r=pkcs11_funcs->C_Initialize(NULL); 
+        CHECK_CKR_ZERO("Failed to initialize pkcs11 library - %ld")
+
+	r=pkcs11_funcs->C_GetSlotList(FALSE, slot_list, &slot_cnt);
+	CHECK_CKR_ZERO("Failed to get slot count - returned - %ld")
+
+        slot_list=snewn(slot_cnt, CK_SLOT_ID);
+        r=pkcs11_funcs->C_GetSlotList(FALSE, slot_list, &slot_cnt);
+        CHECK_CKR_ZERO("Failed to get pkcs11 slot list - %ld")
+
+        pkcs11_slot=slot_list[0];
+        r=pkcs11_funcs->C_OpenSession(pkcs11_slot, CKF_SERIAL_SESSION,
+                NULL, NULL, &pkcs11_session);
+        CHECK_CKR_ZERO("Failed to get pkcs11 session - %ld")
+
+	return TRUE;
+}
+
diff -uN --strip-trailing-cr putty-0.56-orig/sshscard.h putty-0.56-kls/sshscard.h
--- putty-0.56-orig/sshscard.h	1969-12-31 19:00:00.000000000 -0500
+++ putty-0.56-kls/sshscard.h	2005-02-11 09:44:03.000000000 -0500
@@ -0,0 +1,15 @@
+
+#ifndef SSHSCARD_H
+#define SSHSCARD_H
+
+
+int init_pkcs11_library(void * frontend, char* pkcs11_library_name);
+
+struct ssh2_userkey *ssh2_load_pkcs11key(char* keylabel, char *passphrase);
+        
+unsigned char * ssh2_userkey_loadpkcs11pub( char* keylabel, char** algorithm,
+                              int *pub_blob_len);
+
+
+#endif
+
Common subdirectories: putty-0.56-orig/unix and putty-0.56-kls/unix
diff -uN --strip-trailing-cr putty-0.56-orig/winhelp.h putty-0.56-kls/winhelp.h
--- putty-0.56-orig/winhelp.h	2004-10-24 09:37:32.000000000 -0400
+++ putty-0.56-kls/winhelp.h	2004-12-14 10:03:50.000000000 -0500
@@ -88,6 +88,9 @@
 #define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
 #define WINHELP_CTX_ssh_auth_tis "ssh.auth.tis"
 #define WINHELP_CTX_ssh_auth_ki "ssh.auth.ki"
+#define WINHELP_CTX_ssh_auth_pkcs11 "ssh.auth.pkcs11"
+#define WINHELP_CTX_ssh_auth_pkcs11_libfile "ssh.auth.pkcs11libfile"
+#define WINHELP_CTX_ssh_auth_pkcs11_token_label "ssh.auth.pkcs11tokenlabel"
 #define WINHELP_CTX_selection_buttons "selection.buttons"
 #define WINHELP_CTX_selection_shiftdrag "selection.shiftdrag"
 #define WINHELP_CTX_selection_rect "selection.rect"
@@ -102,6 +105,7 @@
 #define WINHELP_CTX_translation_cyrillic "translation.cyrillic"
 #define WINHELP_CTX_translation_linedraw "translation.linedraw"
 #define WINHELP_CTX_ssh_tunnels_x11 "ssh.tunnels.x11"
+#define WINHELP_CTX_ssh_tunnels_localcmd "ssh.tunnels.localcommand"
 #define WINHELP_CTX_ssh_tunnels_x11auth "ssh.tunnels.x11auth"
 #define WINHELP_CTX_ssh_tunnels_portfwd "ssh.tunnels.portfwd"
 #define WINHELP_CTX_ssh_tunnels_portfwd_localhost "ssh.tunnels.portfwd.localhost"

