X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/8e0f9bd3daae9d05dec58026d5a5924367e4e874..fe56a6a89c7a5dbfc2ecedda0d00af9eb1086225:/mts/smtp/smtp.c diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index 39cb713a..75ac2f21 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -88,13 +88,15 @@ static int sm_verbose = 0; static FILE *sm_rfp = NULL; static FILE *sm_wfp = NULL; +static int next_line_encoded = 0; + #ifdef CYRUS_SASL /* * Some globals needed by SASL */ static sasl_conn_t *conn = NULL; /* SASL connection state */ -static int sasl_complete = 0; /* Has authentication succeded? */ +static int sasl_complete = 0; /* Has authentication succeeded? */ static sasl_ssf_t sasl_ssf; /* Our security strength factor */ static int maxoutbuf; /* Maximum crypto output buffer */ static char *sasl_outbuffer; /* SASL output buffer for encryption */ @@ -166,6 +168,7 @@ static int sm_rrecord (char *, int *); 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); @@ -375,7 +378,10 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, saslmech, server_mechs); } - if (sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs, + /* Don't call sm_auth_sasl() for XAUTH2 with -sasl. Instead, call + sm_auth_xoauth2() below. */ + if (xoauth_client_res == NULL && + sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs, server) != RP_OK) { sm_end(NOTOK); return NOTOK; @@ -1213,11 +1219,15 @@ smtalk (int time, char *fmt, ...) } 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) "); - printf ("=> %s\n", buffer); + printf ("=> %s\n", decoded_buffer); + free (decoded_buffer); fflush (stdout); } @@ -1446,7 +1456,7 @@ tls_negotiate(void) #endif /* TLS_SUPPORT */ /* - * Convenience functions to replace occurences of fputs() and fputc() + * Convenience functions to replace occurrences of fputs() and fputc() */ static int @@ -1548,11 +1558,15 @@ again: ; 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) "); - printf ("<= %s\n", buffer); + printf ("<= %s\n", decoded_buffer); + free (decoded_buffer); fflush (stdout); } @@ -1894,3 +1908,75 @@ EHLOset (char *s) 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 + 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); + } +}