]> diplodocus.org Git - nmh/commitdiff
Attempt to decode base64-encoded strings in -snoop traffic.
authorDavid Levine <david.levine@gonift.com>
Sun, 14 Aug 2016 14:59:13 +0000 (10:59 -0400)
committerDavid Levine <david.levine@gonift.com>
Sun, 14 Aug 2016 14:59:13 +0000 (10:59 -0400)
docs/pending-release-notes
h/prototypes.h
man/inc.man
man/msgchk.man
man/post.man
man/send.man
man/whom.man
mts/smtp/smtp.c
sbr/base64.c

index d56ae28d8913207b6700637cb94348b128910088..869befccef9878209ca05386ddcc070840ad492c 100644 (file)
@@ -45,6 +45,7 @@ NEW FEATURES
   binary when using the sendmail/pipe MTS.
 - Added support to send(1) to specify switches to post(1) based on address or
   domain name in From: header line in message draft.
   binary when using the sendmail/pipe MTS.
 - Added support to send(1) to specify switches to post(1) based on address or
   domain name in From: header line in message draft.
+- post(8) -snoop now attempts to decode base64-encoded SMTP traffic.
 
 -----------------
 OBSOLETE FEATURES
 
 -----------------
 OBSOLETE FEATURES
index 70db9463241123508c77b244b3e8d830026af3b2..b5f088c999c26c40c63158a602b3e179e102db89 100644 (file)
@@ -482,6 +482,8 @@ int writeBase64raw (unsigned char *, size_t, unsigned char *);
  */
 int decodeBase64 (const char *, const char **, size_t *, int, unsigned char *);
 
  */
 int decodeBase64 (const char *, const char **, size_t *, int, unsigned char *);
 
+void hexify (const unsigned char *, size_t, char **);
+
 /*
  * credentials management
  */
 /*
  * credentials management
  */
index e866bfab5c441ba6a3a620188bd6e66650c706ac..b8a924546d9baac84c5bbc7939824d7273f3d49c 100644 (file)
@@ -1,4 +1,4 @@
-.TH INC %manext1% "March 23, 2016" "%nmhversion%"
+.TH INC %manext1% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -267,7 +267,11 @@ will attempt to negotiate a security layer for session encryption.
 Encrypted traffic is labelled with `(encrypted)' and `(decrypted)'
 when viewing the POP transaction with the
 .B \-snoop
 Encrypted traffic is labelled with `(encrypted)' and `(decrypted)'
 when viewing the POP transaction with the
 .B \-snoop
-switch.
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.
 .PP
 If
 .B nmh
 .PP
 If
 .B nmh
index 45ac8724eb5624f1702b4fc677c540470295ce94..226c82e459d59f254114c6f98c2bf48c73e86649 100644 (file)
@@ -1,4 +1,4 @@
-.TH MSGCHK %manext1% "March 23, 2016" "%nmhversion%"
+.TH MSGCHK %manext1% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -123,7 +123,11 @@ a security layer for session encryption.  Encrypted traffic is labelled
 with `(encrypted)' and `(decrypted)' when viewing the POP transaction
 with the
 .B \-snoop
 with `(encrypted)' and `(decrypted)' when viewing the POP transaction
 with the
 .B \-snoop
-switch.
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.
 .PP
 If
 .B nmh
 .PP
 If
 .B nmh
@@ -165,6 +169,7 @@ None
 .SH "SEE ALSO"
 .IR inc (1),
 .IR mh\-mail (5)
 .SH "SEE ALSO"
 .IR inc (1),
 .IR mh\-mail (5)
+.IR post (8)
 .SH DEFAULTS
 .nf
 .RB ` user "' defaults to the current user"
 .SH DEFAULTS
 .nf
 .RB ` user "' defaults to the current user"
index fe13538178a4707f9f293fd1ab03a8c9d60e4ff9..1a75f9043e586c6a479ee83bea9848280a166625 100644 (file)
@@ -1,4 +1,4 @@
-.TH POST %manext8% "July 8, 2014" "%nmhversion%"
+.TH POST %manext8% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -232,7 +232,12 @@ will attempt to negotiate a security layer for session encryption.
 Encrypted data is labelled with `(sasl-encrypted)' and `(sasl-decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
 Encrypted data is labelled with `(sasl-encrypted)' and `(sasl-decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
-switch.  The
+qswitch.
+switch.
+Base64-encoded data is wrapped with `b64<>'.
+(Beware that the SMTP transaction may contain authentication information either
+in plaintext or easily decoded base64.)
+The
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
@@ -256,6 +261,9 @@ is labelled with `(tls-encrypted)' and
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
 switch.
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
 switch.
+Base64-encoded data is wrapped with `b64<>'.
+(Beware that the SMTP transaction may contain authentication information either
+in plaintext or easily decoded base64.)
 The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
 The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
index e3ea413c560238674fa1027ad099594147067d3a..9e82fa636ce4947c38c983333f6017887da12e4b 100644 (file)
@@ -1,7 +1,7 @@
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
-.TH SEND %manext1% "July 8, 2016" "%nmhversion%"
+.TH SEND %manext1% "August 14, 2016" "%nmhversion%"
 .SH NAME
 send \- send a message
 .SH SYNOPSIS
 .SH NAME
 send \- send a message
 .SH SYNOPSIS
@@ -422,7 +422,11 @@ will attempt to negotiate a security layer for session encryption.
 Encrypted data is labelled with `(encrypted)' and `(decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
 Encrypted data is labelled with `(encrypted)' and `(decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
-switch.  The
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.  The
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
@@ -463,7 +467,11 @@ taken place, before any SMTP commands are sent or received.  Encrypted data
 is labelled with `(tls-encrypted)' and
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
 is labelled with `(tls-encrypted)' and
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
-switch.
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.
 The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
 The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
index da7aee2e2dd4ad95d068c603041dba764c905719..cbad25f5718608530c983fb42c2bdc62bc72a671 100644 (file)
@@ -1,4 +1,4 @@
-.TH WHOM %manext1% "April 14, 2013" "%nmhversion%"
+.TH WHOM %manext1% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -102,7 +102,11 @@ will attempt to negotiate a security layer for session encryption.
 Encrypted data is labelled with `(encrypted)' and `(decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
 Encrypted data is labelled with `(encrypted)' and `(decrypted)' when
 viewing the SMTP transaction with the
 .B \-snoop
-switch.  The
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.  The
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
 .B \-saslmaxssf
 switch can be used to select the maximum value of the Security Strength Factor.
 This is an integer value and the exact meaning of this value depends on the
@@ -118,7 +122,11 @@ switches will require and disable the negotiation of TLS support when connecting
 SMTP MTA.  Encrypted data is labelled with `(tls-encrypted)' and
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
 SMTP MTA.  Encrypted data is labelled with `(tls-encrypted)' and
 `(tls-decrypted)' when viewing the SMTP transction with the
 .B \-snoop
-switch.
+switch; see the
+.B post
+man page description of
+.B \-snoop
+for its other features.
 .PP
 The files specified by the profile entry \*(lqAliasfile:\*(rq and any
 additional alias files given by the
 .PP
 The files specified by the profile entry \*(lqAliasfile:\*(rq and any
 additional alias files given by the
index 3516f7760f790025d5146c296da611f923954411..75ac2f2102b06d9873a3cad053ed08037da1efe0 100644 (file)
@@ -88,6 +88,8 @@ static int sm_verbose = 0;
 static FILE *sm_rfp = NULL;
 static FILE *sm_wfp = NULL;
 
 static FILE *sm_rfp = NULL;
 static FILE *sm_wfp = NULL;
 
+static int next_line_encoded = 0;
+
 #ifdef CYRUS_SASL
 /*
  * Some globals needed by SASL
 #ifdef CYRUS_SASL
 /*
  * Some globals needed by SASL
@@ -166,6 +168,7 @@ static int sm_rrecord (char *, int *);
 static int sm_rerror (int);
 static void alrmser (int);
 static char *EHLOset (char *);
 static int sm_rerror (int);
 static void alrmser (int);
 static char *EHLOset (char *);
+static char *prepare_for_display (const char *, int *);
 static int sm_fwrite(char *, int);
 static int sm_fputs(char *);
 static int sm_fputc(int);
 static int sm_fwrite(char *, int);
 static int sm_fputs(char *);
 static int sm_fputc(int);
@@ -1216,11 +1219,15 @@ smtalk (int time, char *fmt, ...)
     }
 
     if (sm_debug) {
     }
 
     if (sm_debug) {
+       char *decoded_buffer =
+            prepare_for_display (buffer, &next_line_encoded);
+
        if (sasl_ssf)
                printf("(sasl-encrypted) ");
        if (tls_active)
                printf("(tls-encrypted) ");
        if (sasl_ssf)
                printf("(sasl-encrypted) ");
        if (tls_active)
                printf("(tls-encrypted) ");
-       printf ("=> %s\n", buffer);
+       printf ("=> %s\n", decoded_buffer);
+       free (decoded_buffer);
        fflush (stdout);
     }
 
        fflush (stdout);
     }
 
@@ -1551,11 +1558,15 @@ again: ;
     for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer),
                                   &bc) != NOTOK ; ) {
        if (sm_debug) {
     for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer),
                                   &bc) != NOTOK ; ) {
        if (sm_debug) {
+           char *decoded_buffer =
+                prepare_for_display (buffer, &next_line_encoded);
+
            if (sasl_ssf > 0)
                printf("(sasl-decrypted) ");
            if (tls_active)
                printf("(tls-decrypted) ");
            if (sasl_ssf > 0)
                printf("(sasl-decrypted) ");
            if (tls_active)
                printf("(tls-decrypted) ");
-           printf ("<= %s\n", buffer);
+           printf ("<= %s\n", decoded_buffer);
+           free (decoded_buffer);
            fflush (stdout);
        }
 
            fflush (stdout);
        }
 
@@ -1897,3 +1908,75 @@ EHLOset (char *s)
 
     return 0;
 }
 
     return 0;
 }
+
+
+/*
+ * Detects, using heuristics, if an SMTP server or client response string
+ * contains a base64-encoded portion.  If it does, decodes it and replaces
+ * any non-printable characters with a hex representation.  Caller is
+ * responsible for free'ing return value.  If the decode fails, a copy of
+ * the input string is returned.
+ */
+static
+char *
+prepare_for_display (const char *string, int *next_line_encoded) {
+    const char *start = NULL;
+    const char *decoded;
+    size_t decoded_len;
+    int prefix_len = -1;
+
+    if (strncmp (string, "AUTH XOAUTH2 ", 13) == 0) {
+        /* Entire XOAUTH2 line. */
+        prefix_len = 13;
+        *next_line_encoded = 0;
+    } else if (strncmp (string, "AUTH LOGIN ", 11) == 0) {
+        /* AUTH LOGIN followed by login name.
+           For AUTH LOGIN not followed by the name, the response to the 334
+           server request will be handled by the code below. */
+        prefix_len = 11;
+        *next_line_encoded = 0;
+    } else if (strncmp (string, "AUTH PLAIN ", 11) == 0) {
+        /* AUTH PLAIN followed by authorization/authentication string, e.g.,
+           the display output will be:
+           AUTH PLAIN b64<test@example.com[0x00]test@example.com[0x00]my_password>
+           For AUTH PLAIN not followed by the string, the response to the 334
+           will be handled by the code below. */
+        prefix_len = 11;
+        *next_line_encoded = 0;
+    } else if (strncmp (string, "334 ", 4) == 0) {
+        /* 334 is the server's request for user or password. */
+        prefix_len = 4;
+        /* The next (client response) line must be base64 encoded. */
+        *next_line_encoded = 1;
+    } else if (*next_line_encoded) {
+        /* "next" line now refers to this line, which is a base64-encoded
+           client response. */
+        prefix_len = 0;
+        *next_line_encoded = 0;
+    } else {
+        *next_line_encoded = 0;
+    }
+
+    if (prefix_len > -1) {
+        start = string + prefix_len;
+    }
+
+    if (start  &&  decodeBase64 (start, &decoded, &decoded_len, 1, NULL) == OK) {
+        char *hexified;
+        char *prefix = mh_xmalloc(prefix_len + 1);
+        char *display_string;
+
+        /* prefix is the beginning portion, which isn't base64 encoded. */
+        snprintf (prefix, prefix_len + 1, "%*s", prefix_len, string);
+        hexify ((const unsigned char *) decoded, decoded_len, &hexified);
+        /* Wrap the decoded portion in "b64<>". */
+        display_string = concat (prefix, "b64<", hexified, ">", NULL);
+        free (hexified);
+        free (prefix);
+        free ((char *) decoded);
+
+        return display_string;
+    } else {
+        return getcpy (string);
+    }
+}
index 80ca86e08726bb4f8774e7929fb80524bf3ab73a..9047eb5f0a855fbaa26234998c7fe5b38ad82568 100644 (file)
@@ -324,3 +324,35 @@ test_end:
 
     return OK;
 }
 
     return OK;
 }
+
+
+/*
+ * Prepare an unsigned char array for display by replacing non-printable
+ * ASCII bytes with their hex representation.  Assumes ASCII input.  output
+ * is allocated by the function and must be freed by the caller.
+ */
+void
+hexify (const unsigned char *input, size_t len, char **output) {
+    /* Start with a charstring capacity that's arbitrarily larger than len. */
+    const charstring_t tmp = charstring_create (2 * len);
+    const unsigned char *cp = input;
+    size_t i;
+
+    for (i = 0; i < len; ++i, ++cp) {
+        if (isprint(*cp)) {
+            charstring_push_back (tmp, (const char) *cp);
+        } else {
+            char s[16];
+            const int num = snprintf(s, sizeof s, "[0x%02x]", *cp);
+
+            if (num <= 0  ||  (unsigned int) num >= sizeof s) {
+                advise (NULL, "hexify failed to write nonprintable character, needed %d bytes", num + 1);
+            } else {
+                charstring_append_cstring (tmp, s);
+            }
+        }
+    }
+
+    *output = charstring_buffer_copy (tmp);
+    charstring_free (tmp);
+}