Retired the #ifdef DUMP_PACKETS stuff in ssh.c because I'm utterly
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 14 Dec 2001 14:57:50 +0000 (14:57 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 14 Dec 2001 14:57:50 +0000 (14:57 +0000)
sick of recompiling to enable packet dumps. SSH packet dumping is
now provided as a logging option, and dumps to putty.log like all
the other logging options. While I'm at it I cleaned up the format
so that packet types are translated into strings for easy browsing.
POSSIBLE SIDE EFFECT: in the course of this work I had to re-enable
the SSH1 packet length checks which it turns out hadn't actually
been active for some time, so it's possible things might break as a
result. If need be I can always disable those checks for the 0.52
release and think about it more carefully later.

git-svn-id: svn://svn.tartarus.org/sgt/putty@1493 cda61777-01e9-0310-a592-d414129be87e

Makefile
doc/config.but
logging.c [new file with mode: 0644]
plink.c
psftp.c
putty.h
scp.c
ssh.c
terminal.c
windlg.c
window.c

index ea73ed4..38a3c61 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -88,7 +88,7 @@ RES=res
 
 ##-- objects putty puttytel
 GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
-GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ)
+GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ) logging.$(OBJ)
 ##-- objects putty puttytel plink
 LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
 ##-- objects putty plink
@@ -96,13 +96,13 @@ POBJS = be_all.$(OBJ)
 ##-- objects puttytel
 TOBJS = be_nossh.$(OBJ)
 ##-- objects plink
-PLOBJS = plink.$(OBJ)
+PLOBJS = plink.$(OBJ) logging.$(OBJ)
 ##-- objects pscp
 SOBJS = scp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ) wildcard.$(OBJ)
 ##-- objects psftp
 FOBJS = psftp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ)
 ##-- objects pscp psftp
-SFOBJS = sftp.$(OBJ) int64.$(OBJ)
+SFOBJS = sftp.$(OBJ) int64.$(OBJ) logging.$(OBJ)
 ##-- objects putty puttytel pscp psftp plink
 MOBJS = misc.$(OBJ) version.$(OBJ) winstore.$(OBJ) settings.$(OBJ)
 MOBJ2 = tree234.$(OBJ)
@@ -321,6 +321,7 @@ sshzlib.$(OBJ): sshzlib.c network.h int64.h puttymem.h ssh.h
 ssl.$(OBJ): ssl.c network.h asnerror.h misc.h cert.h crypto.h ssl.h int64.h puttymem.h 
 telnet.$(OBJ): telnet.c network.h misc.h puttymem.h putty.h 
 terminal.$(OBJ): terminal.c network.h misc.h puttymem.h putty.h tree234.h 
+logging.$(OBJ): logging.c misc.h puttymem.h putty.h
 test.$(OBJ): test.c network.h int64.h puttymem.h ssh.h 
 tree234.$(OBJ): tree234.c tree234.h 
 unicode.$(OBJ): unicode.c network.h misc.h puttymem.h putty.h 
index 7e08473..2c14f69 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.20 2001/12/14 12:48:24 simon Exp $
+\versionid $Id: config.but,v 1.21 2001/12/14 14:57:50 simon Exp $
 
 \C{config} Configuring PuTTY
 
@@ -136,6 +136,14 @@ can record everything that went to the terminal, so that someone
 else can replay the session later in slow motion and watch to see
 what went wrong.
 
+\b \q{Log SSH packet data}. In this mode (which is only used by SSH
+connections), the SSH message packets sent over the encrypted
+connection are written to the log file. You might need this to debug
+a network-level problem, or more likely to send to the PuTTY authors
+as part of a bug report. \e{BE WARNED} that if you log in using a
+password, the password will appear in the log file, so be sure to
+edit it out before sending the log file to anyone else!
+
 \S{config-logfilename} \q{Log file name}
 
 \cfg{winhelp-topic}{logging.filename}
diff --git a/logging.c b/logging.c
new file mode 100644 (file)
index 0000000..3caa94a
--- /dev/null
+++ b/logging.c
@@ -0,0 +1,177 @@
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <time.h>
+#include <assert.h>
+
+#include "putty.h"
+
+/* log session to file stuff ... */
+static FILE *lgfp = NULL;
+static char timdatbuf[20];
+static char currlogfilename[FILENAME_MAX];
+
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm);
+
+/*
+ * Log session traffic.
+ */
+void logtraffic(unsigned char c, int logmode)
+{
+    if (cfg.logtype > 0) {
+       if (cfg.logtype == logmode) {
+           /* deferred open file from pgm start? */
+           if (!lgfp)
+               logfopen();
+           if (lgfp)
+               fputc(c, lgfp);
+       }
+    }
+}
+
+/*
+ * Log an SSH packet.
+ */
+void log_packet(int direction, int type, char *texttype, void *data, int len)
+{
+    int i, j, c;
+    char dumpdata[80], smalldata[5];
+
+    if (cfg.logtype != LGTYP_PACKETS)
+       return;
+    if (!lgfp)
+       logfopen();
+    if (lgfp) {
+       fprintf(lgfp, "%s packet type %d / 0x%02x (%s)\n",
+               direction == PKT_INCOMING ? "Incoming" : "Outgoing",
+               type, type, texttype);
+       for (i = 0; i < len; i += 16) {
+           sprintf(dumpdata, "  %08x%*s\n", i, 1+3*16+2+16, "");
+           for (j = 0; j < 16 && i+j < len; j++) {
+               int c = ((unsigned char *)data)[i+j];
+               sprintf(smalldata, "%02x", c);
+               dumpdata[10+2+3*j] = smalldata[0];
+               dumpdata[10+2+3*j+1] = smalldata[1];
+               dumpdata[10+1+3*16+2+j] = (isprint(c) ? c : '.');
+           }
+           strcpy(dumpdata + 10+1+3*16+2+j, "\n");
+           fputs(dumpdata, lgfp);
+       }
+    }
+}
+
+/* open log file append/overwrite mode */
+void logfopen(void)
+{
+    char buf[256];
+    time_t t;
+    struct tm tm;
+    char writemod[4];
+
+    if (!cfg.logtype)
+       return;
+    sprintf(writemod, "wb");          /* default to rewrite */
+
+    time(&t);
+    tm = *localtime(&t);
+
+    /* substitute special codes in file name */
+    xlatlognam(currlogfilename,cfg.logfilename,cfg.host, &tm);
+
+    lgfp = fopen(currlogfilename, "r");        /* file already present? */
+    if (lgfp) {
+       int i;
+       fclose(lgfp);
+       i = askappend(currlogfilename);
+       if (i == 1)
+           writemod[0] = 'a';         /* set append mode */
+       else if (i == 0) {             /* cancelled */
+           lgfp = NULL;
+           cfg.logtype = 0;           /* disable logging */
+           return;
+       }
+    }
+
+    lgfp = fopen(currlogfilename, writemod);
+    if (lgfp) {                               /* enter into event log */
+       sprintf(buf, "%s session log (%s mode) to file : ",
+               (writemod[0] == 'a') ? "Appending" : "Writing new",
+               (cfg.logtype == LGTYP_ASCII ? "ASCII" :
+                cfg.logtype == LGTYP_DEBUG ? "raw" : "<ukwn>"));
+       /* Make sure we do not exceed the output buffer size */
+       strncat(buf, currlogfilename, 128);
+       buf[strlen(buf)] = '\0';
+       logevent(buf);
+
+       /* --- write header line into log file */
+       fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
+       strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
+       fputs(buf, lgfp);
+       fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
+    }
+}
+
+void logfclose(void)
+{
+    if (lgfp) {
+       fclose(lgfp);
+       lgfp = NULL;
+    }
+}
+
+/*
+ * translate format codes into time/date strings
+ * and insert them into log file name
+ *
+ * "&Y":YYYY   "&m":MM   "&d":DD   "&T":hhmm   "&h":<hostname>   "&&":&
+ */
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm) {
+    char buf[10], *bufp;
+    int size;
+    char *ds = d; /* save start pos. */
+    int len = FILENAME_MAX-1;
+
+    while (*s) {
+       /* Let (bufp, len) be the string to append. */
+       bufp = buf;                    /* don't usually override this */
+       if (*s == '&') {
+           char c;
+           s++;
+           if (*s) switch (c = *s++, tolower(c)) {
+             case 'y':
+               size = strftime(buf, sizeof(buf), "%Y", tm);
+               break;
+             case 'm':
+               size = strftime(buf, sizeof(buf), "%m", tm);
+               break;
+             case 'd':
+               size = strftime(buf, sizeof(buf), "%d", tm);
+               break;
+             case 't':
+               size = strftime(buf, sizeof(buf), "%H%M%S", tm);
+               break;
+             case 'h':
+               bufp = hostname;
+               size = strlen(bufp);
+               break;
+             default:
+               buf[0] = '&';
+               size = 1;
+               if (c != '&')
+                   buf[size++] = c;
+           }
+       } else {
+           buf[0] = *s++;
+           size = 1;
+       }
+       if (size > len)
+           size = len;
+       memcpy(d, bufp, size);
+       d += size;
+       len -= size;
+    }
+    *d = '\0';
+}
diff --git a/plink.c b/plink.c
index 7023f9d..6c21150 100644 (file)
--- a/plink.c
+++ b/plink.c
@@ -163,6 +163,44 @@ void askcipher(char *ciphername, int cs)
 }
 
 /*
+ * Ask whether to wipe a session log file before writing to it.
+ * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
+ */
+int askappend(char *filename)
+{
+    HANDLE hin;
+    DWORD savemode, i;
+
+    static const char msgtemplate[] =
+       "The session log file \"%.*s\" already exists.\n"
+       "You can overwrite it with a new session log,\n"
+       "append your session log to the end of it,\n"
+       "or disable session logging for this session.\n"
+       "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
+       "or just press Return to disable logging.\n"
+       "Wipe the log file? (y/n, Return cancels logging) ";
+
+    char line[32];
+
+    fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
+    fflush(stderr);
+
+    hin = GetStdHandle(STD_INPUT_HANDLE);
+    GetConsoleMode(hin, &savemode);
+    SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
+                        ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
+    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
+    SetConsoleMode(hin, savemode);
+
+    if (line[0] == 'y' || line[0] == 'Y')
+       return 2;
+    else if (line[0] == 'n' || line[0] == 'N')
+       return 1;
+    else
+       return 0;
+}
+
+/*
  * Warn about the obsolescent key file format.
  */
 void old_keyfile_warning(void)
diff --git a/psftp.c b/psftp.c
index feefbbc..2923e73 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -1456,6 +1456,44 @@ void askcipher(char *ciphername, int cs)
 }
 
 /*
+ * Ask whether to wipe a session log file before writing to it.
+ * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
+ */
+int askappend(char *filename)
+{
+    HANDLE hin;
+    DWORD savemode, i;
+
+    static const char msgtemplate[] =
+       "The session log file \"%.*s\" already exists.\n"
+       "You can overwrite it with a new session log,\n"
+       "append your session log to the end of it,\n"
+       "or disable session logging for this session.\n"
+       "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
+       "or just press Return to disable logging.\n"
+       "Wipe the log file? (y/n, Return cancels logging) ";
+
+    char line[32];
+
+    fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
+    fflush(stderr);
+
+    hin = GetStdHandle(STD_INPUT_HANDLE);
+    GetConsoleMode(hin, &savemode);
+    SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
+                        ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
+    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
+    SetConsoleMode(hin, savemode);
+
+    if (line[0] == 'y' || line[0] == 'Y')
+       return 2;
+    else if (line[0] == 'n' || line[0] == 'N')
+       return 1;
+    else
+       return 0;
+}
+
+/*
  * Warn about the obsolescent key file format.
  */
 void old_keyfile_warning(void)
diff --git a/putty.h b/putty.h
index 4302b84..27a6564 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -130,7 +130,8 @@ GLOBAL unsigned char unitab_ctrl[256];
 #define LGXF_ASK -1                   /* existing logfile ask */
 #define LGTYP_NONE  0                 /* logmode: no logging */
 #define LGTYP_ASCII 1                 /* logmode: pure ascii */
-#define LGTYP_DEBUG 2                 /* logmode: all chars of taffic */
+#define LGTYP_DEBUG 2                 /* logmode: all chars of traffic */
+#define LGTYP_PACKETS 3                       /* logmode: SSH data packets */
 GLOBAL char *logfile;
 
 /*
@@ -486,6 +487,13 @@ void logfclose(void);
 void term_copyall(void);
 
 /*
+ * Exports from logging.c.
+ */
+void logtraffic(unsigned char c, int logmode);
+enum { PKT_INCOMING, PKT_OUTGOING };
+void log_packet(int direction, int type, char *texttype, void *data, int len);
+
+/*
  * Exports from raw.c.
  */
 
diff --git a/scp.c b/scp.c
index c40d7cc..45930c0 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -227,6 +227,44 @@ void askcipher(char *ciphername, int cs)
 }
 
 /*
+ * Ask whether to wipe a session log file before writing to it.
+ * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
+ */
+int askappend(char *filename)
+{
+    HANDLE hin;
+    DWORD savemode, i;
+
+    static const char msgtemplate[] =
+       "The session log file \"%.*s\" already exists.\n"
+       "You can overwrite it with a new session log,\n"
+       "append your session log to the end of it,\n"
+       "or disable session logging for this session.\n"
+       "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
+       "or just press Return to disable logging.\n"
+       "Wipe the log file? (y/n, Return cancels logging) ";
+
+    char line[32];
+
+    fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
+    fflush(stderr);
+
+    hin = GetStdHandle(STD_INPUT_HANDLE);
+    GetConsoleMode(hin, &savemode);
+    SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
+                        ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
+    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
+    SetConsoleMode(hin, savemode);
+
+    if (line[0] == 'y' || line[0] == 'Y')
+       return 2;
+    else if (line[0] == 'n' || line[0] == 'N')
+       return 1;
+    else
+       return 0;
+}
+
+/*
  * Warn about the obsolescent key file format.
  */
 void old_keyfile_warning(void)
diff --git a/ssh.c b/ssh.c
index 9f27e3a..bc7f5bf 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -15,9 +15,6 @@
 #define TRUE 1
 #endif
 
-/* uncomment this for packet level debugging */
-/* #define DUMP_PACKETS */
-
 #define logevent(s) { logevent(s); \
                       if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
                       { fprintf(stderr, "%s\n", s); fflush(stderr); } }
 #define SSH2_MSG_CHANNEL_SUCCESS                  99   /* 0x63 */
 #define SSH2_MSG_CHANNEL_FAILURE                  100  /* 0x64 */
 
+/*
+ * Packet type contexts, so that ssh2_pkt_type can correctly decode
+ * the ambiguous type numbers back into the correct type strings.
+ */
+#define SSH2_PKTCTX_DHGROUP1         0x0001
+#define SSH2_PKTCTX_DHGEX            0x0002
+#define SSH2_PKTCTX_PUBLICKEY        0x0010
+#define SSH2_PKTCTX_PASSWORD         0x0020
+#define SSH2_PKTCTX_KBDINTER         0x0040
+#define SSH2_PKTCTX_AUTH_MASK        0x00F0
+
 #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1  /* 0x1 */
 #define SSH2_DISCONNECT_PROTOCOL_ERROR            2    /* 0x2 */
 #define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED       3    /* 0x3 */
@@ -161,6 +169,97 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_SSH2_HMAC                             2
 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD            4
 
+static int ssh_pkt_ctx = 0;
+
+#define translate(x) if (type == x) return #x
+#define translatec(x,ctx) if (type == x && (ssh_pkt_ctx & ctx)) return #x
+char *ssh1_pkt_type(int type)
+{
+    translate(SSH1_MSG_DISCONNECT);
+    translate(SSH1_SMSG_PUBLIC_KEY);
+    translate(SSH1_CMSG_SESSION_KEY);
+    translate(SSH1_CMSG_USER);
+    translate(SSH1_CMSG_AUTH_RSA);
+    translate(SSH1_SMSG_AUTH_RSA_CHALLENGE);
+    translate(SSH1_CMSG_AUTH_RSA_RESPONSE);
+    translate(SSH1_CMSG_AUTH_PASSWORD);
+    translate(SSH1_CMSG_REQUEST_PTY);
+    translate(SSH1_CMSG_WINDOW_SIZE);
+    translate(SSH1_CMSG_EXEC_SHELL);
+    translate(SSH1_CMSG_EXEC_CMD);
+    translate(SSH1_SMSG_SUCCESS);
+    translate(SSH1_SMSG_FAILURE);
+    translate(SSH1_CMSG_STDIN_DATA);
+    translate(SSH1_SMSG_STDOUT_DATA);
+    translate(SSH1_SMSG_STDERR_DATA);
+    translate(SSH1_CMSG_EOF);
+    translate(SSH1_SMSG_EXIT_STATUS);
+    translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
+    translate(SSH1_MSG_CHANNEL_OPEN_FAILURE);
+    translate(SSH1_MSG_CHANNEL_DATA);
+    translate(SSH1_MSG_CHANNEL_CLOSE);
+    translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);
+    translate(SSH1_SMSG_X11_OPEN);
+    translate(SSH1_CMSG_PORT_FORWARD_REQUEST);
+    translate(SSH1_MSG_PORT_OPEN);
+    translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING);
+    translate(SSH1_SMSG_AGENT_OPEN);
+    translate(SSH1_MSG_IGNORE);
+    translate(SSH1_CMSG_EXIT_CONFIRMATION);
+    translate(SSH1_CMSG_X11_REQUEST_FORWARDING);
+    translate(SSH1_CMSG_AUTH_RHOSTS_RSA);
+    translate(SSH1_MSG_DEBUG);
+    translate(SSH1_CMSG_REQUEST_COMPRESSION);
+    translate(SSH1_CMSG_AUTH_TIS);
+    translate(SSH1_SMSG_AUTH_TIS_CHALLENGE);
+    translate(SSH1_CMSG_AUTH_TIS_RESPONSE);
+    translate(SSH1_CMSG_AUTH_CCARD);
+    translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE);
+    translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);
+    return "unknown";
+}
+char *ssh2_pkt_type(int type)
+{
+    translate(SSH2_MSG_DISCONNECT);
+    translate(SSH2_MSG_IGNORE);
+    translate(SSH2_MSG_UNIMPLEMENTED);
+    translate(SSH2_MSG_DEBUG);
+    translate(SSH2_MSG_SERVICE_REQUEST);
+    translate(SSH2_MSG_SERVICE_ACCEPT);
+    translate(SSH2_MSG_KEXINIT);
+    translate(SSH2_MSG_NEWKEYS);
+    translatec(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP1);
+    translatec(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP1);
+    translatec(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
+    translatec(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
+    translatec(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
+    translatec(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);
+    translate(SSH2_MSG_USERAUTH_REQUEST);
+    translate(SSH2_MSG_USERAUTH_FAILURE);
+    translate(SSH2_MSG_USERAUTH_SUCCESS);
+    translate(SSH2_MSG_USERAUTH_BANNER);
+    translatec(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);
+    translatec(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);
+    translatec(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);
+    translatec(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);
+    translate(SSH2_MSG_GLOBAL_REQUEST);
+    translate(SSH2_MSG_REQUEST_SUCCESS);
+    translate(SSH2_MSG_REQUEST_FAILURE);
+    translate(SSH2_MSG_CHANNEL_OPEN);
+    translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+    translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+    translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+    translate(SSH2_MSG_CHANNEL_DATA);
+    translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);
+    translate(SSH2_MSG_CHANNEL_EOF);
+    translate(SSH2_MSG_CHANNEL_CLOSE);
+    translate(SSH2_MSG_CHANNEL_REQUEST);
+    translate(SSH2_MSG_CHANNEL_SUCCESS);
+    translate(SSH2_MSG_CHANNEL_FAILURE);
+    return "unknown";
+}
+#undef translate
+#undef translatec
 
 #define GET_32BIT(cp) \
     (((unsigned long)(unsigned char)(cp)[0] << 24) | \
@@ -626,10 +725,6 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen)
 
     if (cipher)
        cipher->decrypt(pktin.data, st->biglen);
-#ifdef DUMP_PACKETS
-    debug(("Got packet len=%d pad=%d\n", st->len, st->pad));
-    dmemdump(pktin.data, st->biglen);
-#endif
 
     st->realcrc = crc32(pktin.data, st->biglen - 4);
     st->gotcrc = GET_32BIT(pktin.data + st->biglen - 4);
@@ -643,10 +738,6 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen)
     if (ssh1_compressing) {
        unsigned char *decompblk;
        int decomplen;
-#ifdef DUMP_PACKETS
-       debug(("Packet payload pre-decompression:\n"));
-       dmemdump(pktin.body - 1, pktin.length + 1);
-#endif
        zlib_decompress_block(pktin.body - 1, pktin.length + 1,
                              &decompblk, &decomplen);
 
@@ -661,12 +752,13 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen)
        memcpy(pktin.body - 1, decompblk, decomplen);
        sfree(decompblk);
        pktin.length = decomplen - 1;
-#ifdef DUMP_PACKETS
-       debug(("Packet payload post-decompression:\n"));
-       dmemdump(pktin.body - 1, pktin.length + 1);
-#endif
     }
 
+    pktin.type = pktin.body[-1];
+
+    log_packet(PKT_INCOMING, pktin.type, ssh1_pkt_type(pktin.type),
+              pktin.body, pktin.length);
+
     if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
        pktin.type == SSH1_SMSG_STDERR_DATA ||
        pktin.type == SSH1_MSG_DEBUG ||
@@ -679,8 +771,6 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen)
        }
     }
 
-    pktin.type = pktin.body[-1];
-
     if (pktin.type == SSH1_MSG_DEBUG) {
        /* log debug message */
        char buf[80];
@@ -807,11 +897,6 @@ static int ssh2_rdpkt(unsigned char **data, int *datalen)
        sccipher->decrypt(pktin.data + st->cipherblk,
                          st->packetlen - st->cipherblk);
 
-#ifdef DUMP_PACKETS
-    debug(("Got packet len=%d pad=%d\n", st->len, st->pad));
-    dmemdump(pktin.data, st->packetlen);
-#endif
-
     /*
      * Check the MAC.
      */
@@ -844,11 +929,6 @@ static int ssh2_rdpkt(unsigned char **data, int *datalen)
            }
            pktin.length = 5 + newlen;
            memcpy(pktin.data + 5, newpayload, newlen);
-#ifdef DUMP_PACKETS
-           debug(("Post-decompression payload:\n"));
-           dmemdump(pktin.data + 5, newlen);
-#endif
-
            sfree(newpayload);
        }
     }
@@ -856,6 +936,9 @@ static int ssh2_rdpkt(unsigned char **data, int *datalen)
     pktin.savedpos = 6;
     pktin.type = pktin.data[5];
 
+    log_packet(PKT_INCOMING, pktin.type, ssh2_pkt_type(pktin.type),
+              pktin.data+6, pktin.length-6);
+
     if (pktin.type == SSH2_MSG_IGNORE || pktin.type == SSH2_MSG_DEBUG)
        goto next_packet;              /* FIXME: print DEBUG message */
 
@@ -930,13 +1013,12 @@ static int s_wrpkt_prepare(void)
 
     pktout.body[-1] = pktout.type;
 
+    log_packet(PKT_OUTGOING, pktout.type, ssh1_pkt_type(pktout.type),
+              pktout.body, pktout.length);
+
     if (ssh1_compressing) {
        unsigned char *compblk;
        int complen;
-#ifdef DUMP_PACKETS
-       debug(("Packet payload pre-compression:\n"));
-       dmemdump(pktout.body - 1, pktout.length + 1);
-#endif
        zlib_compress_block(pktout.body - 1, pktout.length + 1,
                            &compblk, &complen);
        ssh1_pktout_size(complen - 1);
@@ -954,10 +1036,6 @@ static int s_wrpkt_prepare(void)
     PUT_32BIT(pktout.data + biglen, crc);
     PUT_32BIT(pktout.data, len);
 
-#ifdef DUMP_PACKETS
-    debug(("Sending packet len=%d\n", biglen + 4));
-    dmemdump(pktout.data, biglen + 4);
-#endif
     if (cipher)
        cipher->encrypt(pktout.data + 4, biglen);
 
@@ -1221,18 +1299,15 @@ static int ssh2_pkt_construct(void)
     int cipherblk, maclen, padding, i;
     static unsigned long outgoing_sequence = 0;
 
+    log_packet(PKT_OUTGOING, pktout.data[5], ssh2_pkt_type(pktout.data[5]),
+              pktout.data + 6, pktout.length - 6);
+
     /*
      * Compress packet payload.
      */
     {
        unsigned char *newpayload;
        int newlen;
-#ifdef DUMP_PACKETS
-       if (cscomp && cscomp != &ssh_comp_none) {
-           debug(("Pre-compression payload:\n"));
-           dmemdump(pktout.data + 5, pktout.length - 5);
-       }
-#endif
        if (cscomp && cscomp->compress(pktout.data + 5, pktout.length - 5,
                                       &newpayload, &newlen)) {
            pktout.length = 5;
@@ -1261,11 +1336,6 @@ static int ssh2_pkt_construct(void)
                        outgoing_sequence);
     outgoing_sequence++;              /* whether or not we MACed */
 
-#ifdef DUMP_PACKETS
-    debug(("Sending packet len=%d\n", pktout.length + padding));
-    dmemdump(pktout.data, pktout.length + padding);
-#endif
-
     if (cscipher)
        cscipher->encrypt(pktout.data, pktout.length + padding);
 
@@ -3435,6 +3505,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
      */
     if (kex == &ssh_diffiehellman_gex) {
        logevent("Doing Diffie-Hellman group exchange");
+       ssh_pkt_ctx |= SSH2_PKTCTX_DHGEX;
        /*
         * Work out how big a DH group we will need to allow that
         * much data.
@@ -3455,6 +3526,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
        kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
        kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;
     } else {
+       ssh_pkt_ctx |= SSH2_PKTCTX_DHGROUP1;
        dh_setup_group1();
        kex_init_value = SSH2_MSG_KEXDH_INIT;
        kex_reply_value = SSH2_MSG_KEXDH_REPLY;
@@ -3798,6 +3870,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
         * just in case it succeeds, and (b) so that we know what
         * authentication methods we can usefully try next.
         */
+       ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
+
        ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
        ssh2_pkt_addstring(username);
        ssh2_pkt_addstring("ssh-connection");   /* service requested */
@@ -3919,6 +3993,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            }
 
            method = 0;
+           ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
 
            if (!method && can_pubkey && agent_exists() && !tried_agent) {
                /*
@@ -3930,6 +4005,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                static int authed = FALSE;
                void *r;
 
+               ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
+
                tried_agent = TRUE;
 
                logevent("Pageant is running. Requesting keys.");
@@ -4066,6 +4143,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
 
                tried_pubkey_config = TRUE;
 
+               ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
+
                /*
                 * Try the public key supplied in the configuration.
                 *
@@ -4118,6 +4197,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
                tried_keyb_inter = TRUE;
 
+               ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
+
                ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
                ssh2_pkt_addstring(username);
                ssh2_pkt_addstring("ssh-connection");   /* service requested */
@@ -4143,6 +4224,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
                tried_keyb_inter = TRUE;
 
+               ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
+
                /* We've got packet with that "interactive" info
                   dump banners, and set its prompt as ours */
                {
@@ -4169,6 +4252,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
 
            if (!method && can_passwd) {
                method = AUTH_PASSWORD;
+               ssh_pkt_ctx |= SSH2_PKTCTX_PASSWORD;
                sprintf(pwprompt, "%.90s@%.90s's password: ", username,
                        savedhost);
                need_pw = TRUE;
index 77bb390..2962b0a 100644 (file)
@@ -206,10 +206,6 @@ static void erase_lots(int, int, int);
 static void swap_screen(int);
 static void update_sbar(void);
 static void deselect(void);
-/* log session to file stuff ... */
-static FILE *lgfp = NULL;
-static void logtraffic(unsigned char c, int logmode);
-static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm);
 
 /*
  * Resize a line to make it `cols' columns wide.
@@ -3630,138 +3626,3 @@ int from_backend(int is_stderr, char *data, int len)
      */
     return 0;
 }
-
-/*
- * Log session traffic.
- */
-void logtraffic(unsigned char c, int logmode)
-{
-    if (cfg.logtype > 0) {
-       if (cfg.logtype == logmode) {
-           /* deferred open file from pgm start? */
-           if (!lgfp)
-               logfopen();
-           if (lgfp)
-               fputc(c, lgfp);
-       }
-    }
-}
-
-void settimstr(char *ta, int no_sec);
-char *subslfcode(char *dest, char *src, char *dstrt);
-char *stpncpy(char *dst, const char *src, size_t maxlen);
-char timdatbuf[20];
-char currlogfilename[FILENAME_MAX];
-
-/* open log file append/overwrite mode */
-void logfopen(void)
-{
-    char buf[256];
-    time_t t;
-    struct tm tm;
-    char writemod[4];
-
-    if (!cfg.logtype)
-       return;
-    sprintf(writemod, "wb");          /* default to rewrite */
-
-    time(&t);
-    tm = *localtime(&t);
-
-    /* substitute special codes in file name */
-    xlatlognam(currlogfilename,cfg.logfilename,cfg.host, &tm);
-
-    lgfp = fopen(currlogfilename, "r");        /* file already present? */
-    if (lgfp) {
-       int i;
-       fclose(lgfp);
-       i = askappend(currlogfilename);
-       if (i == 1)
-           writemod[0] = 'a';         /* set append mode */
-       else if (i == 0) {             /* cancelled */
-           lgfp = NULL;
-           cfg.logtype = 0;           /* disable logging */
-           return;
-       }
-    }
-
-    lgfp = fopen(currlogfilename, writemod);
-    if (lgfp) {                               /* enter into event log */
-       sprintf(buf, "%s session log (%s mode) to file : ",
-               (writemod[0] == 'a') ? "Appending" : "Writing new",
-               (cfg.logtype == LGTYP_ASCII ? "ASCII" :
-                cfg.logtype == LGTYP_DEBUG ? "raw" : "<ukwn>"));
-       /* Make sure we do not exceed the output buffer size */
-       strncat(buf, currlogfilename, 128);
-       buf[strlen(buf)] = '\0';
-       logevent(buf);
-
-       /* --- write header line into log file */
-       fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
-       strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
-       fputs(buf, lgfp);
-       fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
-    }
-}
-
-void logfclose(void)
-{
-    if (lgfp) {
-       fclose(lgfp);
-       lgfp = NULL;
-    }
-}
-
-/*
- * translate format codes into time/date strings
- * and insert them into log file name
- *
- * "&Y":YYYY   "&m":MM   "&d":DD   "&T":hhmm   "&h":<hostname>   "&&":&
- */
-static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm) {
-    char buf[10], *bufp;
-    int size;
-    char *ds = d; /* save start pos. */
-    int len = FILENAME_MAX-1;
-
-    while (*s) {
-       /* Let (bufp, len) be the string to append. */
-       bufp = buf;                    /* don't usually override this */
-       if (*s == '&') {
-           char c;
-           s++;
-           if (*s) switch (c = *s++, tolower(c)) {
-             case 'y':
-               size = strftime(buf, sizeof(buf), "%Y", tm);
-               break;
-             case 'm':
-               size = strftime(buf, sizeof(buf), "%m", tm);
-               break;
-             case 'd':
-               size = strftime(buf, sizeof(buf), "%d", tm);
-               break;
-             case 't':
-               size = strftime(buf, sizeof(buf), "%H%M%S", tm);
-               break;
-             case 'h':
-               bufp = hostname;
-               size = strlen(bufp);
-               break;
-             default:
-               buf[0] = '&';
-               size = 1;
-               if (c != '&')
-                   buf[size++] = c;
-           }
-       } else {
-           buf[0] = *s++;
-           size = 1;
-       }
-       if (size > len)
-           size = len;
-       memcpy(d, bufp, size);
-       d += size;
-       len -= size;
-    }
-    *d = '\0';
-}
index 9da0225..c3f13b7 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -257,6 +257,7 @@ enum { IDCX_ABOUT =
     IDC_LSTATOFF,
     IDC_LSTATASCII,
     IDC_LSTATRAW,
+    IDC_LSTATPACKET,
     IDC_LGFSTATIC,
     IDC_LGFEDIT,
     IDC_LGFBUTTON,
@@ -621,6 +622,7 @@ char *help_context_cmd(int id)
       case IDC_LSTATOFF:
       case IDC_LSTATASCII:
       case IDC_LSTATRAW:
+      case IDC_LSTATPACKET:
         return "JI(`',`logging.main')";
       case IDC_LGFSTATIC:
       case IDC_LGFEDIT:
@@ -1032,9 +1034,11 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
     SetDlgItemText(hwnd, IDC_RLLUSEREDIT, cfg.localusername);
     SetDlgItemText(hwnd, IDC_LOGEDIT, cfg.username);
     SetDlgItemText(hwnd, IDC_LGFEDIT, cfg.logfilename);
-    CheckRadioButton(hwnd, IDC_LSTATOFF, IDC_LSTATRAW,
-                    cfg.logtype == 0 ? IDC_LSTATOFF :
-                    cfg.logtype == 1 ? IDC_LSTATASCII : IDC_LSTATRAW);
+    CheckRadioButton(hwnd, IDC_LSTATOFF, IDC_LSTATPACKET,
+                    cfg.logtype == LGTYP_NONE ? IDC_LSTATOFF :
+                    cfg.logtype == LGTYP_ASCII ? IDC_LSTATASCII :
+                    cfg.logtype == LGTYP_DEBUG ? IDC_LSTATRAW :
+                    IDC_LSTATPACKET);
     CheckRadioButton(hwnd, IDC_LSTATXOVR, IDC_LSTATXASK,
                     cfg.logxfovr == LGXF_OVR ? IDC_LSTATXOVR :
                     cfg.logxfovr == LGXF_ASK ? IDC_LSTATXASK :
@@ -1254,7 +1258,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
     }
 
     if (panel == loggingpanelstart) {
-       /* The Logging panel. Accelerators used: [acgo] tplfwe */
+       /* The Logging panel. Accelerators used: [acgo] tplsfwe */
        struct ctlpos cp;
        ctlposinit(&cp, hwnd, 80, 3, 13);
        bartitle(&cp, "Options controlling session logging",
@@ -1264,7 +1268,9 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
                 "Session logging:", IDC_LSTATSTATIC,
                 "Logging &turned off completely", IDC_LSTATOFF,
                 "Log &printable output only", IDC_LSTATASCII,
-                "&Log all session output", IDC_LSTATRAW, NULL);
+                "&Log all session output", IDC_LSTATRAW,
+                "Log &SSH packet data", IDC_LSTATPACKET,
+                NULL);
        editbutton(&cp, "Log &file name:",
                   IDC_LGFSTATIC, IDC_LGFEDIT, "Bro&wse...",
                   IDC_LGFBUTTON);
@@ -2608,14 +2614,17 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
              case IDC_LSTATOFF:
              case IDC_LSTATASCII:
              case IDC_LSTATRAW:
+             case IDC_LSTATPACKET:
                if (HIWORD(wParam) == BN_CLICKED ||
                    HIWORD(wParam) == BN_DOUBLECLICKED) {
                    if (IsDlgButtonChecked(hwnd, IDC_LSTATOFF))
-                       cfg.logtype = 0;
+                       cfg.logtype = LGTYP_NONE;
                    if (IsDlgButtonChecked(hwnd, IDC_LSTATASCII))
-                       cfg.logtype = 1;
+                       cfg.logtype = LGTYP_ASCII;
                    if (IsDlgButtonChecked(hwnd, IDC_LSTATRAW))
-                       cfg.logtype = 2;
+                       cfg.logtype = LGTYP_DEBUG;
+                   if (IsDlgButtonChecked(hwnd, IDC_LSTATPACKET))
+                       cfg.logtype = LGTYP_PACKETS;
                }
                break;
              case IDC_LSTATXASK:
index 52af23e..54665c9 100644 (file)
--- a/window.c
+++ b/window.c
@@ -633,15 +633,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     set_input_locale(GetKeyboardLayout(0));
 
     /*
-     * Finally show the window!
+     * Open the initial log file if there is one.
      */
-    ShowWindow(hwnd, show);
-    SetForegroundWindow(hwnd);
+    logfopen();
 
     /*
-     * Open the initial log file if there is one.
+     * Finally show the window!
      */
-    logfopen();
+    ShowWindow(hwnd, show);
+    SetForegroundWindow(hwnd);
 
     /*
      * Set the palette up.