`ssh-log-pw-blank': known password fields are now omitted from SSH packet logs
authorjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Sat, 2 Oct 2004 00:33:27 +0000 (00:33 +0000)
committerjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Sat, 2 Oct 2004 00:33:27 +0000 (00:33 +0000)
by default (although they can be included). There's also an option to remove
session data, which is good both for privacy and for reducing the size of
logfiles.

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

config.c
doc/config.but
logging.c
putty.h
settings.c
ssh.c
winhelp.h

index 146fb58..cbf3169 100644 (file)
--- a/config.c
+++ b/config.c
@@ -885,6 +885,18 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                      "Always append to the end of it", I(LGXF_APN),
                      "Ask the user every time", I(LGXF_ASK), NULL);
 
                      "Always append to the end of it", I(LGXF_APN),
                      "Ask the user every time", I(LGXF_ASK), NULL);
 
+    if ((midsession && protocol == PROT_SSH) ||
+       (!midsession && backends[3].name != NULL)) {
+       s = ctrl_getset(b, "Session/Logging", "ssh",
+                       "Options specific to SSH packet logging");
+       ctrl_checkbox(s, "Omit known password fields", 'k',
+                     HELPCTX(logging_ssh_omit_password),
+                     dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
+       ctrl_checkbox(s, "Omit session data", 'd',
+                     HELPCTX(logging_ssh_omit_data),
+                     dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
+    }
+
     /*
      * The Terminal panel.
      */
     /*
      * The Terminal panel.
      */
index 2556a38..8a773ef 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.90 2004/09/22 22:15:25 jacob Exp $
+\versionid $Id: config.but,v 1.91 2004/10/02 00:33:27 jacob Exp $
 
 \C{config} Configuring PuTTY
 
 
 \C{config} Configuring PuTTY
 
@@ -148,8 +148,9 @@ 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
 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!
+password, the password can appear in the log file; see
+\k{config-logssh} for options that may help to remove sensitive
+material from the log file before you send it to anyone else.
 
 \S{config-logfilename} \q{Log file name}
 
 
 \S{config-logfilename} \q{Log file name}
 
@@ -198,6 +199,44 @@ Finally (the default option), you might not want to have any
 automatic behaviour, but to ask the user every time the problem
 comes up.
 
 automatic behaviour, but to ask the user every time the problem
 comes up.
 
+\S{config-logssh} Options specific to SSH packet logging
+
+These options only apply if SSH packet data is being logged.
+
+The following options allow particularly sensitive portions of
+unencrypted packets to be automatically left out of the log file.
+They are only intended to deter casual nosiness; an attacker could
+glean a lot of useful information from even these obfuscated logs
+(e.g., length of password).
+
+\S2{config-logssh-omitpw} \q{Omit known password fields}
+
+\cfg{winhelp-topic}{logging.ssh.omitpassword}
+
+When checked, password fields are removed from the log of transmitted
+packets. (This includes any user responses to challenge-response
+authentication methods such as \q{keyboard-interactive}.) This does
+not include X11 authentication data if using X11 forwarding.
+
+Note that this will only omit data that PuTTY \e{knows} to be a
+password. However, if you start another login session within your
+PuTTY session, for instance, any password used will appear in the
+clear in the packet log. The next option may be of use to protect
+against this.
+
+This option is enabled by default.
+
+\S2{config-logssh-omitdata} \q{Omit session data}
+
+\cfg{winhelp-topic}{logging.ssh.omitdata}
+
+When checked, all \q{session data} is omitted; this is defined as data
+in terminal sessions and in forwarded channels (TCP, X11, and
+authentication agent). This will usually substantially reduce the size
+of the resulting log file.
+
+This option is disabled by default.
+
 \H{config-terminal} The Terminal panel
 
 The Terminal configuration panel allows you to control the behaviour
 \H{config-terminal} The Terminal panel
 
 The Terminal configuration panel allows you to control the behaviour
index 5302998..808e429 100644 (file)
--- a/logging.c
+++ b/logging.c
@@ -70,12 +70,14 @@ void log_eventlog(void *handle, const char *event)
 
 /*
  * Log an SSH packet.
 
 /*
  * Log an SSH packet.
+ * If n_blanks != 0, blank or omit some parts.
+ * Set of blanking areas must be in increasing order.
  */
 void log_packet(void *handle, int direction, int type,
  */
 void log_packet(void *handle, int direction, int type,
-               char *texttype, void *data, int len)
+               char *texttype, void *data, int len,
+               int n_blanks, const struct logblank_t *blanks)
 {
     struct LogContext *ctx = (struct LogContext *)handle;
 {
     struct LogContext *ctx = (struct LogContext *)handle;
-    int i, j;
     char dumpdata[80], smalldata[5];
 
     if (ctx->cfg.logtype != LGTYP_PACKETS)
     char dumpdata[80], smalldata[5];
 
     if (ctx->cfg.logtype != LGTYP_PACKETS)
@@ -83,21 +85,81 @@ void log_packet(void *handle, int direction, int type,
     if (!ctx->lgfp)
        logfopen(ctx);
     if (ctx->lgfp) {
     if (!ctx->lgfp)
        logfopen(ctx);
     if (ctx->lgfp) {
+       int p = 0, b = 0, omitted = 0;
+       int output_pos = 0; /* NZ if pending output in dumpdata */
+
+       /* Packet header. */
        fprintf(ctx->lgfp, "%s packet type %d / 0x%02x (%s)\r\n",
                direction == PKT_INCOMING ? "Incoming" : "Outgoing",
                type, type, texttype);
        fprintf(ctx->lgfp, "%s packet type %d / 0x%02x (%s)\r\n",
                direction == PKT_INCOMING ? "Incoming" : "Outgoing",
                type, type, texttype);
-       for (i = 0; i < len; i += 16) {
-           sprintf(dumpdata, "  %08x%*s\r\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 : '.');
+
+       /*
+        * Output a hex/ASCII dump of the packet body, blanking/omitting
+        * parts as specified.
+        */
+       while (p < len) {
+           int blktype;
+
+           /* Move to a current entry in the blanking array. */
+           while ((b < n_blanks) &&
+                  (p >= blanks[b].offset + blanks[b].len))
+               b++;
+           /* Work out what type of blanking to apply to
+            * this byte. */
+           blktype = PKTLOG_EMIT; /* default */
+           if ((b < n_blanks) &&
+               (p >= blanks[b].offset) &&
+               (p < blanks[b].offset + blanks[b].len))
+               blktype = blanks[b].type;
+
+           /* If we're about to stop omitting, it's time to say how
+            * much we omitted. */
+           if ((blktype != PKTLOG_OMIT) && omitted) {
+               fprintf(ctx->lgfp, "  (%d byte%s omitted)\r\n",
+                       omitted, (omitted==1?"":"s"));
+               omitted = 0;
+           }
+
+           /* (Re-)initialise dumpdata as necessary
+            * (start of row, or if we've just stopped omitting) */
+           if (!output_pos && !omitted)
+               sprintf(dumpdata, "  %08x%*s\r\n", p-(p%16), 1+3*16+2+16, "");
+
+           /* Deal with the current byte. */
+           if (blktype == PKTLOG_OMIT) {
+               omitted++;
+           } else {
+               int c;
+               if (blktype == PKTLOG_BLANK) {
+                   c = 'X';
+                   sprintf(smalldata, "XX");
+               } else {  /* PKTLOG_EMIT */
+                   c = ((unsigned char *)data)[p];
+                   sprintf(smalldata, "%02x", c);
+               }
+               dumpdata[10+2+3*(p%16)] = smalldata[0];
+               dumpdata[10+2+3*(p%16)+1] = smalldata[1];
+               dumpdata[10+1+3*16+2+(p%16)] = (isprint(c) ? c : '.');
+               output_pos = (p%16) + 1;
+           }
+
+           p++;
+
+           /* Flush row if necessary */
+           if (((p % 16) == 0) || (p == len) || omitted) {
+               if (output_pos) {
+                   strcpy(dumpdata + 10+1+3*16+2+output_pos, "\r\n");
+                   fputs(dumpdata, ctx->lgfp);
+                   output_pos = 0;
+               }
            }
            }
-           strcpy(dumpdata + 10+1+3*16+2+j, "\r\n");
-           fputs(dumpdata, ctx->lgfp);
+
        }
        }
+
+       /* Tidy up */
+       if (omitted)
+           fprintf(ctx->lgfp, "  (%d byte%s omitted)\r\n",
+                   omitted, (omitted==1?"":"s"));
        fflush(ctx->lgfp);
     }
 }
        fflush(ctx->lgfp);
     }
 }
diff --git a/putty.h b/putty.h
index b12429f..93a39e4 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -425,6 +425,8 @@ struct config_tag {
     Filename logfilename;
     int logtype;
     int logxfovr;
     Filename logfilename;
     int logtype;
     int logxfovr;
+    int logomitpass;
+    int logomitdata;
     int hide_mouseptr;
     int sunken_edge;
     int window_border;
     int hide_mouseptr;
     int sunken_edge;
     int window_border;
@@ -658,8 +660,15 @@ void logtraffic(void *logctx, unsigned char c, int logmode);
 void logflush(void *logctx);
 void log_eventlog(void *logctx, const char *string);
 enum { PKT_INCOMING, PKT_OUTGOING };
 void logflush(void *logctx);
 void log_eventlog(void *logctx, const char *string);
 enum { PKT_INCOMING, PKT_OUTGOING };
+enum { PKTLOG_EMIT, PKTLOG_BLANK, PKTLOG_OMIT };
+struct logblank_t {
+    int offset;
+    int len;
+    int type;
+};
 void log_packet(void *logctx, int direction, int type,
 void log_packet(void *logctx, int direction, int type,
-               char *texttype, void *data, int len);
+               char *texttype, void *data, int len,
+               int n_blanks, const struct logblank_t *blanks);
 
 /*
  * Exports from testback.c
 
 /*
  * Exports from testback.c
index a5f2e44..679fab1 100644 (file)
@@ -167,6 +167,8 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
     write_setting_filename(sesskey, "LogFileName", cfg->logfilename);
     write_setting_i(sesskey, "LogType", cfg->logtype);
     write_setting_i(sesskey, "LogFileClash", cfg->logxfovr);
     write_setting_filename(sesskey, "LogFileName", cfg->logfilename);
     write_setting_i(sesskey, "LogType", cfg->logtype);
     write_setting_i(sesskey, "LogFileClash", cfg->logxfovr);
+    write_setting_i(sesskey, "SSHLogOmitPasswords", cfg->logomitpass);
+    write_setting_i(sesskey, "SSHLogOmitData", cfg->logomitdata);
     p = "raw";
     for (i = 0; backends[i].name != NULL; i++)
        if (backends[i].protocol == cfg->protocol) {
     p = "raw";
     for (i = 0; backends[i].name != NULL; i++)
        if (backends[i].protocol == cfg->protocol) {
@@ -389,6 +391,8 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
     gppfile(sesskey, "LogFileName", &cfg->logfilename);
     gppi(sesskey, "LogType", 0, &cfg->logtype);
     gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr);
     gppfile(sesskey, "LogFileName", &cfg->logfilename);
     gppi(sesskey, "LogType", 0, &cfg->logtype);
     gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr);
+    gppi(sesskey, "SSHLogOmitPasswords", 1, &cfg->logomitpass);
+    gppi(sesskey, "SSHLogOmitData", 0, &cfg->logomitdata);
 
     gpps(sesskey, "Protocol", "default", prot, 10);
     cfg->protocol = default_protocol;
 
     gpps(sesskey, "Protocol", "default", prot, 10);
     cfg->protocol = default_protocol;
diff --git a/ssh.c b/ssh.c
index 5b5a6be..e8d2431 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -267,7 +267,13 @@ static char *ssh2_pkt_type(int pkt_ctx, int type)
     (cp)[2] = (unsigned char)((value) >> 8); \
     (cp)[3] = (unsigned char)(value); }
 
     (cp)[2] = (unsigned char)((value) >> 8); \
     (cp)[3] = (unsigned char)(value); }
 
-enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM };
+/* Enumeration values for fields in SSH-1 packets */
+enum {
+    PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,
+    /* These values are for communicating relevant semantics of
+     * fields to the packet logging code. */
+    PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA
+};
 
 /*
  * Coroutine mechanics for the sillier bits of the code. If these
 
 /*
  * Coroutine mechanics for the sillier bits of the code. If these
@@ -598,6 +604,13 @@ struct ssh_tag {
     int deferred_len, deferred_size;
 
     /*
     int deferred_len, deferred_size;
 
     /*
+     * State associated with packet logging
+     */
+    int pktout_logmode;
+    int pktout_nblanks;
+    struct logblank_t *pktout_blanks;
+
+    /*
      * Gross hack: pscp will try to start SFTP but fall back to
      * scp1 if that fails. This variable is the means by which
      * scp.c can reach into the SSH code and find out which one it
      * Gross hack: pscp will try to start SFTP but fall back to
      * scp1 if that fails. This variable is the means by which
      * scp.c can reach into the SSH code and find out which one it
@@ -684,6 +697,25 @@ static void logeventf(Ssh ssh, const char *fmt, ...)
         sfree(text); \
     } while (0)
 
         sfree(text); \
     } while (0)
 
+/* Functions to leave bits out of the SSH packet log file. */
+
+static void dont_log_password(Ssh ssh, int blanktype)
+{
+    if (ssh->cfg.logomitpass)
+       ssh->pktout_logmode = blanktype;
+}
+
+static void dont_log_data(Ssh ssh, int blanktype)
+{
+    if (ssh->cfg.logomitdata)
+       ssh->pktout_logmode = blanktype;
+}
+
+static void end_log_omission(Ssh ssh)
+{
+    ssh->pktout_logmode = PKTLOG_EMIT;
+}
+
 static int ssh_channelcmp(void *av, void *bv)
 {
     struct ssh_channel *a = (struct ssh_channel *) av;
 static int ssh_channelcmp(void *av, void *bv)
 {
     struct ssh_channel *a = (struct ssh_channel *) av;
@@ -898,11 +930,34 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
 
     ssh->pktin.type = ssh->pktin.body[-1];
 
 
     ssh->pktin.type = ssh->pktin.body[-1];
 
-    if (ssh->logctx)
+    /*
+     * Log incoming packet, possibly omitting sensitive fields.
+     */
+    if (ssh->logctx) {
+       int nblanks = 0;
+       struct logblank_t blank;
+       if (ssh->cfg.logomitdata) {
+           int do_blank = FALSE, blank_prefix = 0;
+           /* "Session data" packets - omit the data field */
+           if ((ssh->pktin.type == SSH1_SMSG_STDOUT_DATA) ||
+               (ssh->pktin.type == SSH1_SMSG_STDERR_DATA)) {
+               do_blank = TRUE; blank_prefix = 0;
+           } else if (ssh->pktin.type == SSH1_MSG_CHANNEL_DATA) {
+               do_blank = TRUE; blank_prefix = 4;
+           }
+           if (do_blank) {
+               blank.offset = blank_prefix;
+               blank.len = ssh->pktin.length;
+               blank.type = PKTLOG_OMIT;
+               nblanks = 1;
+           }
+       }
        log_packet(ssh->logctx,
                   PKT_INCOMING, ssh->pktin.type,
                   ssh1_pkt_type(ssh->pktin.type),
        log_packet(ssh->logctx,
                   PKT_INCOMING, ssh->pktin.type,
                   ssh1_pkt_type(ssh->pktin.type),
-                  ssh->pktin.body, ssh->pktin.length);
+                  ssh->pktin.body, ssh->pktin.length,
+                  nblanks, &blank);
+    }
 
     if (ssh->pktin.type == SSH1_SMSG_STDOUT_DATA ||
        ssh->pktin.type == SSH1_SMSG_STDERR_DATA ||
 
     if (ssh->pktin.type == SSH1_SMSG_STDOUT_DATA ||
        ssh->pktin.type == SSH1_SMSG_STDERR_DATA ||
@@ -1079,10 +1134,32 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
     ssh->pktin.body = ssh->pktin.data;
     ssh->pktin.type = ssh->pktin.data[5];
 
     ssh->pktin.body = ssh->pktin.data;
     ssh->pktin.type = ssh->pktin.data[5];
 
-    if (ssh->logctx)
+    /*
+     * Log incoming packet, possibly omitting sensitive fields.
+     */
+    if (ssh->logctx) {
+       int nblanks = 0;
+       struct logblank_t blank;
+       if (ssh->cfg.logomitdata) {
+           int do_blank = FALSE, blank_prefix = 0;
+           /* "Session data" packets - omit the data field */
+           if (ssh->pktin.type == SSH2_MSG_CHANNEL_DATA) {
+               do_blank = TRUE; blank_prefix = 4;
+           } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
+               do_blank = TRUE; blank_prefix = 8;
+           }
+           if (do_blank) {
+               blank.offset = blank_prefix;
+               blank.len = (ssh->pktin.length-6) - blank_prefix;
+               blank.type = PKTLOG_OMIT;
+               nblanks = 1;
+           }
+       }
        log_packet(ssh->logctx, PKT_INCOMING, ssh->pktin.type,
                   ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type),
        log_packet(ssh->logctx, PKT_INCOMING, ssh->pktin.type,
                   ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type),
-                  ssh->pktin.data+6, ssh->pktin.length-6);
+                  ssh->pktin.data+6, ssh->pktin.length-6,
+                  nblanks, &blank);
+    }
 
     switch (ssh->pktin.type) {
         /*
 
     switch (ssh->pktin.type) {
         /*
@@ -1215,6 +1292,9 @@ static void s_wrpkt_start(Ssh ssh, int type, int len)
 {
     ssh1_pktout_size(ssh, len);
     ssh->pktout.type = type;
 {
     ssh1_pktout_size(ssh, len);
     ssh->pktout.type = type;
+    /* Initialise log omission state */
+    ssh->pktout_nblanks = 0;
+    ssh->pktout_blanks = NULL;
 }
 
 static int s_wrpkt_prepare(Ssh ssh)
 }
 
 static int s_wrpkt_prepare(Ssh ssh)
@@ -1237,7 +1317,10 @@ static int s_wrpkt_prepare(Ssh ssh)
     if (ssh->logctx)
        log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type,
                   ssh1_pkt_type(ssh->pktout.type),
     if (ssh->logctx)
        log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type,
                   ssh1_pkt_type(ssh->pktout.type),
-                  ssh->pktout.body, ssh->pktout.length);
+                  ssh->pktout.body, ssh->pktout.length,
+                  ssh->pktout_nblanks, ssh->pktout_blanks);
+    sfree(ssh->pktout_blanks); ssh->pktout_blanks = NULL;
+    ssh->pktout_nblanks = 0;
 
     if (ssh->v1_compressing) {
        unsigned char *compblk;
 
     if (ssh->v1_compressing) {
        unsigned char *compblk;
@@ -1324,6 +1407,11 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2)
            bn = va_arg(ap1, Bignum);
            pktlen += ssh1_bignum_length(bn);
            break;
            bn = va_arg(ap1, Bignum);
            pktlen += ssh1_bignum_length(bn);
            break;
+         case PKTT_PASSWORD:
+         case PKTT_DATA:
+         case PKTT_OTHER:
+           /* ignore this pass */
+           break;
          default:
            assert(0);
        }
          default:
            assert(0);
        }
@@ -1333,34 +1421,58 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2)
     p = ssh->pktout.body;
 
     while ((argtype = va_arg(ap2, int)) != PKT_END) {
     p = ssh->pktout.body;
 
     while ((argtype = va_arg(ap2, int)) != PKT_END) {
+       int offset = p - ssh->pktout.body, len = 0;
        switch (argtype) {
        switch (argtype) {
+         /* Actual fields in the packet */
          case PKT_INT:
            argint = va_arg(ap2, int);
            PUT_32BIT(p, argint);
          case PKT_INT:
            argint = va_arg(ap2, int);
            PUT_32BIT(p, argint);
-           p += 4;
+           len = 4;
            break;
          case PKT_CHAR:
            argchar = (unsigned char) va_arg(ap2, int);
            *p = argchar;
            break;
          case PKT_CHAR:
            argchar = (unsigned char) va_arg(ap2, int);
            *p = argchar;
-           p++;
+           len = 1;
            break;
          case PKT_DATA:
            argp = va_arg(ap2, unsigned char *);
            arglen = va_arg(ap2, int);
            memcpy(p, argp, arglen);
            break;
          case PKT_DATA:
            argp = va_arg(ap2, unsigned char *);
            arglen = va_arg(ap2, int);
            memcpy(p, argp, arglen);
-           p += arglen;
+           len = arglen;
            break;
          case PKT_STR:
            argp = va_arg(ap2, unsigned char *);
            arglen = strlen((char *)argp);
            PUT_32BIT(p, arglen);
            memcpy(p + 4, argp, arglen);
            break;
          case PKT_STR:
            argp = va_arg(ap2, unsigned char *);
            arglen = strlen((char *)argp);
            PUT_32BIT(p, arglen);
            memcpy(p + 4, argp, arglen);
-           p += 4 + arglen;
+           len = arglen + 4;
            break;
          case PKT_BIGNUM:
            bn = va_arg(ap2, Bignum);
            break;
          case PKT_BIGNUM:
            bn = va_arg(ap2, Bignum);
-           p += ssh1_write_bignum(p, bn);
+           len = ssh1_write_bignum(p, bn);
+           break;
+         /* Tokens for modifications to packet logging */
+         case PKTT_PASSWORD:
+           dont_log_password(ssh, PKTLOG_BLANK);
+           break;
+         case PKTT_DATA:
+           dont_log_data(ssh, PKTLOG_OMIT);
            break;
            break;
+         case PKTT_OTHER:
+           end_log_omission(ssh);
+           break;
+       }
+       p += len;
+       /* Deal with logfile omission, if required. */
+       if (len && (ssh->pktout_logmode != PKTLOG_EMIT)) {
+           ssh->pktout_nblanks++;
+           ssh->pktout_blanks = sresize(ssh->pktout_blanks,
+                                        ssh->pktout_nblanks,
+                                        struct logblank_t);
+           ssh->pktout_blanks[ssh->pktout_nblanks-1].offset = offset;
+           ssh->pktout_blanks[ssh->pktout_nblanks-1].len    = len;
+           ssh->pktout_blanks[ssh->pktout_nblanks-1].type   =
+               ssh->pktout_logmode;
        }
     }
 }
        }
     }
 }
@@ -1439,6 +1551,15 @@ static void ssh2_pkt_ensure(Ssh ssh, int length)
 }
 static void ssh2_pkt_adddata(Ssh ssh, void *data, int len)
 {
 }
 static void ssh2_pkt_adddata(Ssh ssh, void *data, int len)
 {
+    if (ssh->pktout_logmode != PKTLOG_EMIT) {
+       ssh->pktout_nblanks++;
+       ssh->pktout_blanks = sresize(ssh->pktout_blanks, ssh->pktout_nblanks,
+                                    struct logblank_t);
+       ssh->pktout_blanks[ssh->pktout_nblanks-1].offset =
+           ssh->pktout.length - 6;
+       ssh->pktout_blanks[ssh->pktout_nblanks-1].len = len;
+       ssh->pktout_blanks[ssh->pktout_nblanks-1].type = ssh->pktout_logmode;
+    }
     ssh->pktout.length += len;
     ssh2_pkt_ensure(ssh, ssh->pktout.length);
     memcpy(ssh->pktout.data + ssh->pktout.length - len, data, len);
     ssh->pktout.length += len;
     ssh2_pkt_ensure(ssh, ssh->pktout.length);
     memcpy(ssh->pktout.data + ssh->pktout.length - len, data, len);
@@ -1450,6 +1571,7 @@ static void ssh2_pkt_addbyte(Ssh ssh, unsigned char byte)
 static void ssh2_pkt_init(Ssh ssh, int pkt_type)
 {
     ssh->pktout.length = 5;
 static void ssh2_pkt_init(Ssh ssh, int pkt_type)
 {
     ssh->pktout.length = 5;
+    ssh->pktout_nblanks = 0; ssh->pktout_blanks = NULL;
     ssh2_pkt_addbyte(ssh, (unsigned char) pkt_type);
 }
 static void ssh2_pkt_addbool(Ssh ssh, unsigned char value)
     ssh2_pkt_addbyte(ssh, (unsigned char) pkt_type);
 }
 static void ssh2_pkt_addbool(Ssh ssh, unsigned char value)
@@ -1523,7 +1645,10 @@ static int ssh2_pkt_construct(Ssh ssh)
     if (ssh->logctx)
        log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5],
                   ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]),
     if (ssh->logctx)
        log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5],
                   ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]),
-                  ssh->pktout.data + 6, ssh->pktout.length - 6);
+                  ssh->pktout.data + 6, ssh->pktout.length - 6,
+                  ssh->pktout_nblanks, ssh->pktout_blanks);
+    sfree(ssh->pktout_blanks); ssh->pktout_blanks = NULL;
+    ssh->pktout_nblanks = 0;
 
     /*
      * Compress packet payload.
 
     /*
      * Compress packet payload.
@@ -2376,8 +2501,10 @@ static void ssh_agentf_callback(void *cv, void *reply, int replylen)
     } else {
        send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
                    PKT_INT, c->remoteid,
     } else {
        send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
                    PKT_INT, c->remoteid,
+                   PKTT_DATA,
                    PKT_INT, replylen,
                    PKT_DATA, sentreply, replylen,
                    PKT_INT, replylen,
                    PKT_DATA, sentreply, replylen,
+                   PKTT_OTHER,
                    PKT_END);
     }
     if (reply)
                    PKT_END);
     }
     if (reply)
@@ -3154,10 +3281,11 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                    randomstr = snewn(top + 1, char);
 
                    for (i = bottom; i <= top; i++) {
                    randomstr = snewn(top + 1, char);
 
                    for (i = bottom; i <= top; i++) {
-                       if (i == pwlen)
+                       if (i == pwlen) {
                            defer_packet(ssh, s->pwpkt_type,
                            defer_packet(ssh, s->pwpkt_type,
-                                        PKT_STR, s->password, PKT_END);
-                       else {
+                                        PKTT_PASSWORD, PKT_STR, s->password,
+                                        PKTT_OTHER, PKT_END);
+                       } else {
                            for (j = 0; j < i; j++) {
                                do {
                                    randomstr[j] = random_byte();
                            for (j = 0; j < i; j++) {
                                do {
                                    randomstr[j] = random_byte();
@@ -3194,8 +3322,9 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                        ss = s->password;
                    }
                    logevent("Sending length-padded password");
                        ss = s->password;
                    }
                    logevent("Sending length-padded password");
-                   send_packet(ssh, s->pwpkt_type, PKT_INT, len,
-                               PKT_DATA, ss, len, PKT_END);
+                   send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
+                               PKT_INT, len, PKT_DATA, ss, len,
+                               PKTT_OTHER, PKT_END);
                } else {
                    /*
                     * The server has _both_
                } else {
                    /*
                     * The server has _both_
@@ -3206,11 +3335,14 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                    int len;
                    len = strlen(s->password);
                    logevent("Sending unpadded password");
                    int len;
                    len = strlen(s->password);
                    logevent("Sending unpadded password");
-                   send_packet(ssh, s->pwpkt_type, PKT_INT, len,
-                               PKT_DATA, s->password, len, PKT_END);
+                   send_packet(ssh, s->pwpkt_type,
+                               PKTT_PASSWORD, PKT_INT, len,
+                               PKT_DATA, s->password, len,
+                               PKTT_OTHER, PKT_END);
                }
            } else {
                }
            } else {
-               send_packet(ssh, s->pwpkt_type, PKT_STR, s->password, PKT_END);
+               send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
+                           PKT_STR, s->password, PKTT_OTHER, PKT_END);
            }
        }
        logevent("Sent password");
            }
        }
        logevent("Sent password");
@@ -3282,7 +3414,9 @@ int sshfwd_write(struct ssh_channel *c, char *buf, int len)
     if (ssh->version == 1) {
        send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
                    PKT_INT, c->remoteid,
     if (ssh->version == 1) {
        send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
                    PKT_INT, c->remoteid,
-                   PKT_INT, len, PKT_DATA, buf, len, PKT_END);
+                   PKTT_DATA,
+                   PKT_INT, len, PKT_DATA, buf, len,
+                   PKTT_OTHER, PKT_END);
        /*
         * In SSH1 we can return 0 here - implying that forwarded
         * connections are never individually throttled - because
        /*
         * In SSH1 we can return 0 here - implying that forwarded
         * connections are never individually throttled - because
@@ -3928,8 +4062,9 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        } else {
            while (inlen > 0) {
                int len = min(inlen, 512);
        } else {
            while (inlen > 0) {
                int len = min(inlen, 512);
-               send_packet(ssh, SSH1_CMSG_STDIN_DATA,
-                           PKT_INT, len, PKT_DATA, in, len, PKT_END);
+               send_packet(ssh, SSH1_CMSG_STDIN_DATA, PKTT_DATA,
+                           PKT_INT, len, PKT_DATA, in, len,
+                           PKTT_OTHER, PKT_END);
                in += len;
                inlen -= len;
            }
                in += len;
                inlen -= len;
            }
@@ -4573,8 +4708,10 @@ static int ssh2_try_send(struct ssh_channel *c)
            len = c->v.v2.remmaxpkt;
        ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_DATA);
        ssh2_pkt_adduint32(ssh, c->remoteid);
            len = c->v.v2.remmaxpkt;
        ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_DATA);
        ssh2_pkt_adduint32(ssh, c->remoteid);
+       dont_log_data(ssh, PKTLOG_OMIT);
        ssh2_pkt_addstring_start(ssh);
        ssh2_pkt_addstring_data(ssh, data, len);
        ssh2_pkt_addstring_start(ssh);
        ssh2_pkt_addstring_data(ssh, data, len);
+       end_log_omission(ssh);
        ssh2_pkt_send(ssh);
        bufchain_consume(&c->v.v2.outbuffer, len);
        c->v.v2.remwindow -= len;
        ssh2_pkt_send(ssh);
        bufchain_consume(&c->v.v2.outbuffer, len);
        c->v.v2.remwindow -= len;
@@ -5385,8 +5522,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                ssh2_pkt_addstring(ssh, "ssh-connection");      /* service requested */
                ssh2_pkt_addstring(ssh, "password");
                ssh2_pkt_addbool(ssh, FALSE);
                ssh2_pkt_addstring(ssh, "ssh-connection");      /* service requested */
                ssh2_pkt_addstring(ssh, "password");
                ssh2_pkt_addbool(ssh, FALSE);
+               dont_log_password(ssh, PKTLOG_BLANK);
                ssh2_pkt_addstring(ssh, s->password);
                memset(s->password, 0, sizeof(s->password));
                ssh2_pkt_addstring(ssh, s->password);
                memset(s->password, 0, sizeof(s->password));
+               end_log_omission(ssh);
                ssh2_pkt_defer(ssh);
                /*
                 * We'll include a string that's an exact multiple of the
                ssh2_pkt_defer(ssh);
                /*
                 * We'll include a string that's an exact multiple of the
@@ -5430,8 +5569,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                    ssh2_pkt_adduint32(ssh, s->num_prompts);
                }
                if (s->need_pw) {      /* only add pw if we just got one! */
                    ssh2_pkt_adduint32(ssh, s->num_prompts);
                }
                if (s->need_pw) {      /* only add pw if we just got one! */
+                   dont_log_password(ssh, PKTLOG_BLANK);
                    ssh2_pkt_addstring(ssh, s->password);
                    memset(s->password, 0, sizeof(s->password));
                    ssh2_pkt_addstring(ssh, s->password);
                    memset(s->password, 0, sizeof(s->password));
+                   end_log_omission(ssh);
                    s->curr_prompt++;
                }
                if (s->curr_prompt >= s->num_prompts) {
                    s->curr_prompt++;
                }
                if (s->curr_prompt >= s->num_prompts) {
@@ -6412,6 +6553,9 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
     ssh->deferred_send_data = NULL;
     ssh->deferred_len = 0;
     ssh->deferred_size = 0;
     ssh->deferred_send_data = NULL;
     ssh->deferred_len = 0;
     ssh->deferred_size = 0;
+    ssh->pktout_logmode = PKTLOG_EMIT;
+    ssh->pktout_nblanks = 0;
+    ssh->pktout_blanks = NULL;
     ssh->fallback_cmd = 0;
     ssh->pkt_ctx = 0;
     ssh->x11auth = NULL;
     ssh->fallback_cmd = 0;
     ssh->pkt_ctx = 0;
     ssh->x11auth = NULL;
index 5271f92..6b7ca24 100644 (file)
--- a/winhelp.h
+++ b/winhelp.h
@@ -13,6 +13,8 @@
 #define WINHELP_CTX_logging_main "logging.main"
 #define WINHELP_CTX_logging_filename "logging.filename"
 #define WINHELP_CTX_logging_exists "logging.exists"
 #define WINHELP_CTX_logging_main "logging.main"
 #define WINHELP_CTX_logging_filename "logging.filename"
 #define WINHELP_CTX_logging_exists "logging.exists"
+#define WINHELP_CTX_logging_ssh_omit_password "logging.ssh.omitpassword"
+#define WINHELP_CTX_logging_ssh_omit_data "logging.ssh.omitdata"
 #define WINHELP_CTX_keyboard_backspace "keyboard.backspace"
 #define WINHELP_CTX_keyboard_homeend "keyboard.homeend"
 #define WINHELP_CTX_keyboard_funkeys "keyboard.funkeys"
 #define WINHELP_CTX_keyboard_backspace "keyboard.backspace"
 #define WINHELP_CTX_keyboard_homeend "keyboard.homeend"
 #define WINHELP_CTX_keyboard_funkeys "keyboard.funkeys"