]> 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 d56ae28..869befc 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 70db946..b5f088c 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 e866bfa..b8a9245 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 45ac872..226c82e 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 fe13538..1a75f90 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 e3ea413..9e82fa6 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 da7aee2..cbad25f 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 3516f77..75ac2f2 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 80ca86e..9047eb5 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);
+}