]> diplodocus.org Git - nmh/commitdiff
Attempt to decode base64-encoded strings in -snoop traffic.
authorDavid Levine <levinedl@acm.org>
Sun, 14 Aug 2016 14:57:51 +0000 (10:57 -0400)
committerDavid Levine <levinedl@acm.org>
Sun, 14 Aug 2016 14:57:51 +0000 (10:57 -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 45ee338dadaaa3076bcf6bd964ac8ed284eb07e6..884e0e0ab85d2826363aef9c52b5d6a0f57d3816 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 61f6f8442ae4baa1d075c992f68975bf5e8079e1..46dda0e47be10ab2d7c3c3997bf4abac446407d3 100644 (file)
@@ -1,4 +1,4 @@
-.TH INC %manext1% "April 18, 2014" "%nmhversion%"
+.TH INC %manext1% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -263,7 +263,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.
 .SH FILES
 .PD 0
 .TP 20
 .SH FILES
 .PD 0
 .TP 20
index 0d5d6c9873e608cad37706f815f341548de0c606..b0c7bd48c454907a3d7f3d7ed7643d2195a944ec 100644 (file)
@@ -1,4 +1,4 @@
-.TH MSGCHK %manext1% "April 14, 2013" "%nmhversion%"
+.TH MSGCHK %manext1% "August 14, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -119,7 +119,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.
 .SH FILES
 .fc ^ ~
 .nf
 .SH FILES
 .fc ^ ~
 .nf
@@ -138,6 +142,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..1b1042b9e13e218da6c09d8476a8d81ed334b7ea 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,11 @@ 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
+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 +260,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 f568d991144d2b5dfbaeef92d9f455d3f69f9fb4..87c2cfd2630fa2a47adbd09f41a3f89cdaf04396 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
@@ -418,7 +418,12 @@ 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
@@ -441,7 +446,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 8b89dec3e7fb00bf8845eda7b58f78bce43ab4a2..92b91095f63561e4378841b6b4d420e65ac6cac8 100644 (file)
@@ -90,6 +90,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
@@ -168,6 +170,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);
@@ -1169,11 +1172,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);
     }
 
@@ -1504,11 +1511,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);
        }
 
@@ -1850,3 +1861,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);
+}