From da304a48a24d7cc7fafae13c994d94ad3d6483f2 Mon Sep 17 00:00:00 2001 From: Ken Hornstein Date: Fri, 19 Nov 2010 20:13:39 +0000 Subject: [PATCH] (Minor) cleanup of some of the autoconf code with respect to the handling of compiler flags for SASL, and also rototill (and simplify) the autoconf handling for the same. Add TLS support for the SMTP MTA. --- aclocal.m4 | 28 ++---- config/Makefile.in | 2 +- configure.in | 118 +++++++----------------- man/mh-chart.man | 2 + man/post.man | 12 ++- man/send.man | 10 ++ mts/smtp/Makefile.in | 3 +- mts/smtp/smtp.c | 248 ++++++++++++++++++++++++++++++++++++++++---------- mts/smtp/smtp.h | 2 +- sbr/Makefile.in | 5 +- uip/Makefile.in | 7 +- uip/post.c | 17 +++- uip/send.c | 9 ++ uip/whatnowsbr.c | 11 ++- uip/whom.c | 8 ++ 15 files changed, 311 insertions(+), 171 deletions(-) diff --git a/aclocal.m4 b/aclocal.m4 index 7941c07..20d123f 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,24 +1,14 @@ -# Originally by John Hawkinson -# Under Solaris, those -# applications need to link with "-lsocket -lnsl". Under IRIX, they -# need to link with "-lnsl" but should *not* link with "-lsocket" -# because libsocket.a breaks a number of things (for instance, -# gethostbyname() under IRIX 5.2, and snoop sockets under most versions -# of IRIX). # -# The check for libresolv is in case you are attempting to link -# statically and happen to have a libresolv.a lying around (and no -# libnsl.a). An example of such a case would be Solaris with -# BIND 4.9.5 installed. - -AC_DEFUN(AC_CHECK_NETLIBS, -[AC_CHECK_FUNC(getaddrinfo, , - AC_CHECK_LIB(nsl, getaddrinfo, , - AC_CHECK_LIB(resolv, getaddrinfo))) -AC_CHECK_FUNC(socket, , - AC_CHECK_LIB(socket, socket)) -]) +# Updated for more modern systems. Check to see if we need to link against +# optional libraries for networking functions. +# + +AC_DEFUN([AC_CHECK_NETLIBS], +[AC_SEARCH_LIBS([gethostbyname], [nsl], , + [AC_MSG_ERROR([gethostbyname not found])]) + AC_SEARCH_LIBS([connect], [socket], , [AC_MSG_ERROR([connect not found])]) +])dnl dnl -------------- dnl CHECK FOR NDBM diff --git a/config/Makefile.in b/config/Makefile.in index aba161b..6c4613d 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -25,7 +25,7 @@ default_pager = @pagerpath@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -INCLUDES = -I.. -I$(top_srcdir) +INCLUDES = -I.. -I$(top_srcdir) @CPPFLAGS@ CONFIGDEFS = -DNMHBINDIR='"$(bindir)"' -DNMHETCDIR='"$(etcdir)"' -DNMHLIBDIR='"$(libdir)"' \ -DDEFAULT_EDITOR='"$(default_editor)"' -DDEFAULT_PAGER='"$(default_pager)"' diff --git a/configure.in b/configure.in index e43fca1..7730717 100644 --- a/configure.in +++ b/configure.in @@ -4,12 +4,8 @@ dnl dnl $Id$ dnl -dnl 2.13 definitely chokes; 2.53 is the earliest version I've tested. -dnl 2.58 needed for help string macro but that only affects help output -dnl 2.50 is the major breakpoint between the old autoconf and the new, -dnl so require that. If there are bug reports about 2.50-2.52 not working -dnl we can always move this up a little. -AC_PREREQ(2.50) +dnl Move this up a bit +AC_PREREQ(2.61) AC_INIT(nmh, m4_normalize(m4_include([VERSION]))) AC_CONFIG_SRCDIR(h/nmh.h) @@ -106,8 +102,8 @@ AC_DEFINE(LOCALE) dnl Do you want client-side support for using SASL for authentication? dnl Note that this code will be enabled for both POP and SMTP -AC_ARG_WITH(cyrus-sasl, AS_HELP_STRING([--with-cyrus-sasl=DIR], - [specify location of Cyrus SASL library])) +AC_ARG_WITH(cyrus-sasl, AS_HELP_STRING([--with-cyrus-sasl], + [Enable SASL support via the Cyrus SASL library])) if test x"$with_cyrus_sasl" != x -a x"$with_cyrus_sasl" != x"no"; then AC_DEFINE(CYRUS_SASL, 1, [Define to use the Cyrus SASL library for authentication of POP and SMTP.])dnl @@ -116,6 +112,15 @@ else sasl_support=no fi +dnl Do you want client-side support for encryption with TLS? +AC_ARG_WITH(tls, AS_HELP_STRING([--with-tls], [Enable TLS support])) +if test x"$with_tls" != x -a x"$with_tls" != x"no"; then + AC_DEFINE(TLS_SUPPORT, 1, [Support TLS for session encryption.])dnl + tls_support=yes +else + tls_support=no +fi + dnl What should be the default editor? AC_ARG_WITH(editor, AS_HELP_STRING([--with-editor=EDITOR],[specify the default editor])) @@ -142,16 +147,6 @@ if test x"$with_hesiod" != x -a x"$with_hesiod" != x"no"; then AC_DEFINE(HESIOD,1,[Define this to compile support for using Hesiod.])dnl fi -dnl Do you want client-side support for kpop -AC_ARG_WITH(krb4, AS_HELP_STRING([--with-krb4=DIR], - [specify location of Kerberos V4 for KPOP support])) -if test x"$with_krb4" != x -a x"$with_krb4" != x"no"; then - enable_pop=yes - AC_DEFINE(KPOP, 1, - [Define to compile client-side support for kpop (kerberized pop) into inc and msgchk.])dnl - AC_DEFINE(KPOP_PRINCIPAL, "pop", [Define this to "pop" when using Kerberos V4])dnl -fi - dnl After we know if we're including apop and kpop support, do pop stuff if test x"$enable_pop" = x"yes"; then AC_DEFINE(POP, 1, @@ -520,11 +515,6 @@ AC_CHECK_FUNCS(waitpid wait3 sigaction sigprocmask sigblock sigsetmask \ sighold sigrelse writev lstat uname tzset killpg mkstemp \ getutent nl_langinfo mbtowc wcwidth) -dnl solaris has these in the nsl library -AC_SEARCH_LIBS(getaddrinfo, nsl, - [AC_DEFINE(HAVE_GETADDRINFO,1, - [Define to 1 if you have the `getaddrinfo' function.])]) - dnl sigsetjmp may be a macro AC_MSG_CHECKING(for sigsetjmp) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], @@ -709,66 +699,25 @@ fi AC_SUBST(HESIOD_INCLUDES)dnl AC_SUBST(HESIOD_LIBS)dnl -dnl ---------------------------------- -dnl CHECK FOR KRB4 (Kerberos4 support) -dnl ---------------------------------- -if test x"$with_krb4" != x -a x"$with_krb4" != x"no"; then - if test x"$with_krb4" != x"yes"; then - KRB4_INCLUDES="-I$with_krb4/include" - if test -d "$with_krb4/include/kerberosIV"; then - KRB4_INCLUDES="$KRB4_INCLUDES -I$with_krb4/include/kerberosIV" - fi - KRB4_LIBS="-L$with_krb4/lib" - elif test -d /usr/include/kerberosIV; then - KRB4_INCLUDES="-I/usr/include/kerberosIV" - fi -dnl First, check if we have -lk5crypto, since that means we have a recent krb5 - - AC_CHECK_LIB(k5crypto, krb5_encrypt, - [AC_CHECK_LIB(krb4, krb_rd_req, - [KRB4_LIBS="$KRB4_LIBS -lkrb4 -ldes425 -lkrb5 -lk5crypto -lcom_err"], - [AC_MSG_ERROR(Kerberos 4 compatibility libraries not found)], - $KRB4_LIBS -ldes425 -lkrb5 -lk5crypto -lcom_err)], - - [AC_CHECK_LIB(krb4, krb_rd_req, - [KRB4_LIBS="$KRB4_LIBS -lkrb4 -ldes425 -lkrb5 -lcrypto -lcom_err"], - [AC_CHECK_LIB(krb, krb_rd_req, - [KRB4_LIBS="$KRB4_LIBS -lkrb -ldes"], - [AC_MSG_ERROR(Kerberos 4 libraries not found)], - $KRB4_LIBS -ldes)], - $KRB4_LIBS -ldes425 -lkrb5 -lcrypto -lcom_err)], - $KRB4_LIBS) - -fi -AC_SUBST(KRB4_INCLUDES)dnl -AC_SUBST(KRB4_LIBS)dnl - dnl -------------------- -dnl CHECK FOR CYRUS SASL +dnl CHECK FOR CYRUS-SASL dnl -------------------- -if test x"$with_cyrus_sasl" != x -a x"$with_cyrus_sasl" != x"no"; then - if test x"$with_cyrus_sasl" != x"yes"; then - SASL_INCLUDES="-I$with_cyrus_sasl/include" - SASL_LIBS="-L$with_cyrus_sasl/lib" - - dnl Do OS-specific hardcoding of SASL shared library path into executables, - dnl so user isn't forced to set environment variables like Solaris' - dnl LD_LIBRARY_PATH. - case "$target_os" in - solaris*) - SASL_LIBS="$SASL_LIBS -R$with_cyrus_sasl/lib" - ;; - esac - fi - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $SASL_LIBS" - AC_CHECK_LIB(sasl2, sasl_client_new, - [SASL_LIBS="$SASL_LIBS -lsasl2"], - [AC_MSG_ERROR(Cyrus SASL library not found)]) - LDFLAGS="$save_LDFLAGS" -fi -AC_SUBST(SASL_INCLUDES)dnl -AC_SUBST(SASL_LIBS)dnl + +AS_IF([test x"$sasl_support" = x"yes"],[ + AC_CHECK_HEADER([sasl.h], , [AC_MSG_ERROR([sasl.h not found])]) + AC_CHECK_LIB([sasl2], [sasl_client_new], , + [AC_MSG_ERROR([Cyrus SASL library not found])])]) + +dnl ----------------- +dnl CHECK FOR OPENSSL +dnl ----------------- + +AS_IF([test x"$tls_support" = x"yes"],[ + AC_CHECK_HEADER([openssl/ssl.h], , [AC_MSG_ERROR([openssl/ssl.h not found])]) + AC_CHECK_LIB([crypto], [BIO_write], , + [AC_MSG_ERROR([OpenSSL crypto library not found])]) + AC_CHECK_LIB([ssl], [SSL_library_init], , + [AC_MSG_ERROR([OpenSSL library not found])])]) dnl --------------------- dnl CHECK TERMCAP LIBRARY @@ -1077,10 +1026,6 @@ if test x"$enable_pop" = x"yes"; then pop_kinds="${pop_kinds}APOP " fi - if test x"$with_krb4" != x -a x"$with_krb4" != x"no"; then - pop_kinds="${pop_kinds}KPOP " - fi - pop_kinds="${pop_kinds}POP3)" fi @@ -1106,5 +1051,6 @@ default editor : ${editorpath} default pager : ${pagerpath} email address masquerading : ${masquerade} pop is enabled : ${pop_kinds} -SASL support : ${sasl_support}" +SASL support : ${sasl_support} +TLS support : ${tls_support}" echo "" diff --git a/man/mh-chart.man b/man/mh-chart.man index 5e097e4..b31cb0b 100644 --- a/man/mh-chart.man +++ b/man/mh-chart.man @@ -553,6 +553,7 @@ or .RB [ \-user .IR username ] .I file +.RB [ \-tls ] .RB [ \-version ] .RB [ \-help ] @@ -737,6 +738,7 @@ all/to/cc/me] .IR mechanism ] .RB [ \-user .IR username ] +.RB [ \-tls ] .RB [ \-width .IR columns ] .RB [ file diff --git a/man/post.man b/man/post.man index 892215a..772bbfb 100644 --- a/man/post.man +++ b/man/post.man @@ -211,10 +211,20 @@ to provide to SASL other than the default. If SASL authentication is successful, .BR nmh will attempt to negotiate a security layer for session encryption. -Encrypted data is labelled with `(encrypted)' and `(decrypted)' when +Encrypted data is labelled with `(sasl-encrypted)' and `(sasl-decrypted)' when viewing the SMTP transaction with the .B \-snoop switch. +.PP +If +.B nmh +has been compiled with TLS support, the +.B \-tls +switch will require the negotiation of TLS support when connecting to the +SMTP MTA. Encrypted data is labelled with `(tls-encrypted)' and +`(tls-decrypted)' when viewing the SMTP transction with the +.B \-snoop +switch. .SH FILES .fc ^ ~ diff --git a/man/send.man b/man/send.man index 25fa357..a20296e 100644 --- a/man/send.man +++ b/man/send.man @@ -354,6 +354,16 @@ viewing the SMTP transaction with the .B \-snoop switch. .PP +If +.B nmh +has been compiled with TLS support, the +.B \-tls +switch will require the negotiation of TLS support when connecting to the +SMTP MTA. Encrypted data is labelled with `(tls-encrypted)' and +`(tls-decrypted)' when viewing the SMTP transction with the +.B \-snoop +switch. +.PP The files specified by the profile entry \*(lqAliasfile:\*(rq and any additional alias files given by the .B \-alias diff --git a/mts/smtp/Makefile.in b/mts/smtp/Makefile.in index f8b0ed3..e837ddc 100644 --- a/mts/smtp/Makefile.in +++ b/mts/smtp/Makefile.in @@ -19,8 +19,7 @@ etcdir = @sysconfdir@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -SASL_INCLUDES = @SASL_INCLUDES@ -INCLUDES = -I../.. -I$(srcdir) -I$(top_srcdir) $(SASL_INCLUDES) +INCLUDES = -I../.. -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@ LINT = @LINT@ LINTFLAGS = @LINTFLAGS@ diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index 7413639..e6bca9a 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -24,6 +24,11 @@ #include #endif /* CYRUS_SASL */ +#ifdef TLS_SUPPORT +#include +#include +#endif /* TLS_SUPPORT */ + /* * This module implements an interface to SendMail very similar * to the MMDF mm_(3) routines. The sm_() routines herein talk @@ -91,12 +96,8 @@ static char *sasl_pw_context[2]; /* Context to pass into sm_get_pass */ static int maxoutbuf; /* Maximum crypto output buffer */ static char *sasl_outbuffer; /* SASL output buffer for encryption */ static int sasl_outbuflen; /* Current length of data in outbuf */ -static char *sasl_inbuffer; /* SASL input buffer for encryption */ -static char *sasl_inptr; /* Pointer to current inbuf position */ -static int sasl_inbuflen; /* Current length of data in inbuf */ static int sm_get_user(void *, int, const char **, unsigned *); static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **); -static int sm_fgetc(FILE *); static sasl_callback_t callbacks[] = { { SASL_CB_USER, sm_get_user, NULL }, @@ -108,11 +109,29 @@ static sasl_callback_t callbacks[] = { { SASL_CB_LIST_END, NULL, NULL }, }; -#define SASL_MAXRECVBUF 65536 #else /* CYRUS_SASL */ -#define sm_fgetc fgetc +int sasl_ssf = 0; #endif /* CYRUS_SASL */ +#ifdef TLS_SUPPORT +static SSL_CTX *sslctx = NULL; +static SSL *ssl = NULL; +static BIO *sbior = NULL; +static BIO *sbiow = NULL; +#endif /* TLS_SUPPORT */ + +#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) +#define SASL_MAXRECVBUF 65536 +static int sm_fgetc(FILE *); +static char *sasl_inbuffer; /* SASL input buffer for encryption */ +static char *sasl_inptr; /* Pointer to current inbuf position */ +static int sasl_inbuflen; /* Current length of data in inbuf */ +#else +#define sm_fgetc fgetc +#endif + +static int tls_active = 0; + static char *sm_noreply = "No reply text given"; static char *sm_moreply = "; "; @@ -127,7 +146,7 @@ char *EHLOkeys[MAXEHLO + 1]; * static prototypes */ static int smtp_init (char *, char *, char *, int, int, int, int, int, int, - char *, char *); + char *, char *, int); static int sendmail_init (char *, char *, int, int, int, int, int, int, char *, char *); @@ -159,11 +178,11 @@ static int sm_auth_sasl(char *, char *, char *); int sm_init (char *client, char *server, char *port, int watch, int verbose, int debug, int onex, int queued, int sasl, char *saslmech, - char *user) + char *user, int tls) { if (sm_mts == MTS_SMTP) return smtp_init (client, server, port, watch, verbose, - debug, onex, queued, sasl, saslmech, user); + debug, onex, queued, sasl, saslmech, user, tls); else return sendmail_init (client, server, watch, verbose, debug, onex, queued, sasl, saslmech, user); @@ -172,7 +191,7 @@ sm_init (char *client, char *server, char *port, int watch, int verbose, static int smtp_init (char *client, char *server, char *port, int watch, int verbose, int debug, int onex, int queued, - int sasl, char *saslmech, char *user) + int sasl, char *saslmech, char *user, int tls) { #ifdef CYRUS_SASL char *server_mechs; @@ -196,17 +215,19 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, } } -#ifdef ZMAILER + /* + * Last-ditch check just in case client still isn't set to anything + */ + if (client == NULL || *client == '\0') client = "localhost"; -#endif -#ifdef CYRUS_SASL +#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) sasl_inbuffer = malloc(SASL_MAXRECVBUF); if (!sasl_inbuffer) return sm_ierror("Unable to allocate %d bytes for read buffer", SASL_MAXRECVBUF); -#endif /* CYRUS_SASL */ +#endif /* CYRUS_SASL || TLS_SUPPORT */ if ((sd1 = rclient (server, port)) == NOTOK) return RP_BHST; @@ -227,6 +248,8 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, return sm_ierror ("unable to fdopen"); } + tls_active = 0; + sm_alarmed = 0; alarm (SM_OPEN); result = smhear (); @@ -244,19 +267,107 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, /* * Give EHLO or HELO command */ - if (client && *client) { + + doingEHLO = 1; + result = smtalk (SM_HELO, "EHLO %s", client); + doingEHLO = 0; + + if (result >= 500 && result <= 599) + result = smtalk (SM_HELO, "HELO %s", client); + + if (result != 250) { + sm_end (NOTOK); + return RP_RPLY; + } + +#ifdef TLS_SUPPORT + /* + * If the user requested TLS support, then try to do the STARTTLS command + * as part of the initial dialog. Assuming this works, we then need to + * restart the EHLO dialog after TLS negotiation is complete. + */ + + if (tls) { + if (! EHLOset("STARTTLS")) { + sm_end(NOTOK); + return sm_ierror("SMTP server does not support TLS"); + } + + result = smtalk(SM_HELO, "STARTTLS"); + + if (result != 220) { + sm_end(NOTOK); + return RP_RPLY; + } + + /* + * Okay, the other side should be waiting for us to start TLS + * negotiation. Oblige them. + */ + + if (! sslctx) { + SSL_METHOD *method; + + SSL_library_init(); + SSL_load_error_strings(); + + method = TLSv1_client_method(); /* Not sure about this */ + + sslctx = SSL_CTX_new(method); + + if (! sslctx) { + sm_end(NOTOK); + return sm_ierror("Unable to initialize OpenSSL context: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + } + + ssl = SSL_new(sslctx); + + if (! ssl) { + sm_end(NOTOK); + return sm_ierror("Unable to create SSL connection: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + sbior = BIO_new_socket(fileno(sm_rfp), BIO_NOCLOSE); + sbiow = BIO_new_socket(fileno(sm_wfp), BIO_NOCLOSE); + + if (sbior == NULL || sbiow == NULL) { + sm_end(NOTOK); + return sm_ierror("Unable to create BIO endpoints: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + SSL_set_bio(ssl, sbior, sbiow); + + if (SSL_connect(ssl) < 1) { + sm_end(NOTOK); + return sm_ierror("Unable to negotiate SSL connection: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + if (sm_debug) { + SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + printf("SSL negotiation successful: %s(%d) %s\n", + SSL_CIPHER_get_name(cipher), + SSL_CIPHER_get_bits(cipher, NULL), + SSL_CIPHER_get_version(cipher)); + + } + + tls_active = 1; + doingEHLO = 1; result = smtalk (SM_HELO, "EHLO %s", client); doingEHLO = 0; - if (result >= 500 && result <= 599) - result = smtalk (SM_HELO, "HELO %s", client); - if (result != 250) { sm_end (NOTOK); return RP_RPLY; } } +#endif /* TLS_SUPPORT */ #ifdef CYRUS_SASL /* @@ -325,10 +436,12 @@ sendmail_init (char *client, char *server, int watch, int verbose, client = LocalName(); /* no clientname -> LocalName */ } -#ifdef ZMAILER + /* + * Last-ditch check just in case client still isn't set to anything + */ + if (client == NULL || *client == '\0') client = "localhost"; -#endif #ifdef CYRUS_SASL sasl_inbuffer = malloc(SASL_MAXRECVBUF); @@ -369,7 +482,6 @@ sendmail_init (char *client, char *server, int watch, int verbose, vecp = 0; vec[vecp++] = r1bindex (sendmail, '/'); vec[vecp++] = "-bs"; -#ifndef ZMAILER vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb"; vec[vecp++] = "-oem"; vec[vecp++] = "-om"; @@ -377,7 +489,6 @@ sendmail_init (char *client, char *server, int watch, int verbose, if (verbose) vec[vecp++] = "-ov"; # endif /* not RAND */ -#endif /* not ZMAILER */ vec[vecp++] = NULL; setgid (getegid ()); @@ -413,22 +524,20 @@ sendmail_init (char *client, char *server, int watch, int verbose, return RP_RPLY; } - if (client && *client) { - doingEHLO = 1; - result = smtalk (SM_HELO, "EHLO %s", client); - doingEHLO = 0; + doingEHLO = 1; + result = smtalk (SM_HELO, "EHLO %s", client); + doingEHLO = 0; - if (500 <= result && result <= 599) - result = smtalk (SM_HELO, "HELO %s", client); + if (500 <= result && result <= 599) + result = smtalk (SM_HELO, "HELO %s", client); - switch (result) { - case 250: - break; + switch (result) { + case 250: + break; - default: - sm_end (NOTOK); - return RP_RPLY; - } + default: + sm_end (NOTOK); + return RP_RPLY; } #ifdef CYRUS_SASL @@ -460,10 +569,8 @@ sendmail_init (char *client, char *server, int watch, int verbose, } #endif /* CYRUS_SASL */ -#ifndef ZMAILER if (onex) smtalk (SM_HELO, "ONEX"); -#endif if (watch) smtalk (SM_HELO, "VERB on"); @@ -680,6 +787,11 @@ sm_end (int type) break; } + if (tls_active) { + SSL_shutdown(ssl); + SSL_free(ssl); + } + if (sm_rfp != NULL) { alarm (SM_CLOS); fclose (sm_rfp); @@ -791,12 +903,13 @@ sm_auth_sasl(char *user, char *mechlist, char *inhost) } /* - * Initialize the security properties + * Initialize the security properties. But if TLS is active, then + * don't negotiate encryption here. */ memset(&secprops, 0, sizeof(secprops)); secprops.maxbufsize = SASL_MAXRECVBUF; - secprops.max_ssf = UINT_MAX; + secprops.max_ssf = tls_active ? 0 : UINT_MAX; result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); @@ -1030,10 +1143,10 @@ smtalk (int time, char *fmt, ...) va_end(ap); if (sm_debug) { -#ifdef CYRUS_SASL if (sasl_ssf) - printf("(encrypted) "); -#endif /* CYRUS_SASL */ + printf("(sasl-encrypted) "); + if (tls_active) + printf("(tls-encrypted) "); printf ("=> %s\n", buffer); fflush (stdout); } @@ -1116,11 +1229,24 @@ sm_fwrite(char *buffer, int len) const char *output; unsigned int outputlen; - if (sasl_complete == 0 || sasl_ssf == 0) + if (sasl_complete == 0 || sasl_ssf == 0) { #endif /* CYRUS_SASL */ +#ifdef TLS_SUPPORT + if (tls_active) { + int ret; + + ret = SSL_write(ssl, buffer, len); + + if (SSL_get_error(ssl, ret) != SSL_ERROR_NONE) { + sm_ierror("TLS error during write: %s", + ERR_error_string(ERR_get_error(), NULL)); + return NOTOK; + } + } else +#endif /* TLS_SUPPORT */ fwrite(buffer, sizeof(*buffer), len, sm_wfp); #ifdef CYRUS_SASL - else { + } else { while (len >= maxoutbuf - sasl_outbuflen) { memcpy(sasl_outbuffer + sasl_outbuflen, buffer, maxoutbuf - sasl_outbuflen); @@ -1241,10 +1367,10 @@ again: ; for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer), &bc) != NOTOK ; ) { if (sm_debug) { -#ifdef CYRUS_SASL if (sasl_ssf > 0) - printf("(decrypted) "); -#endif /* CYRUS_SASL */ + printf("(sasl-decrypted) "); + if (tls_active) + printf("(tls-decrypted) "); printf ("<= %s\n", buffer); fflush (stdout); } @@ -1382,9 +1508,9 @@ sm_fgets(char *buffer, int size, FILE *f) } -#ifdef CYRUS_SASL +#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) /* - * Read from the network, but do SASL encryption + * Read from the network, but do SASL or TLS encryption */ static int @@ -1409,6 +1535,28 @@ sm_fgetc(FILE *f) while (retbufsize == 0) { +#ifdef TLS_SUPPORT + if (tls_active) { + cc = SSL_read(ssl, tmpbuf, sizeof(tmpbuf)); + + if (cc == 0) { + result = SSL_get_error(ssl, cc); + + if (result != SSL_ERROR_ZERO_RETURN) { + sm_ierror("TLS peer aborted connection"); + } + + return EOF; + } + + if (cc < 0) { + sm_ierror("SSL_read failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return -2; + } + } else +#endif /* TLS_SUPPORT */ + cc = read(fileno(f), tmpbuf, sizeof(tmpbuf)); if (cc == 0) @@ -1451,7 +1599,7 @@ sm_fgetc(FILE *f) return (int) sasl_inbuffer[0]; } -#endif /* CYRUS_SASL */ +#endif /* CYRUS_SASL || TLS_SUPPORT */ static int sm_rerror (int rc) diff --git a/mts/smtp/smtp.h b/mts/smtp/smtp.h index 4fdcdfe..12fdedb 100644 --- a/mts/smtp/smtp.h +++ b/mts/smtp/smtp.h @@ -24,7 +24,7 @@ struct smtp { * prototypes */ /* int client (); */ -int sm_init (char *, char *, char *, int, int, int, int, int, int, char *, char *); +int sm_init (char *, char *, char *, int, int, int, int, int, int, char *, char *, int); int sm_winit (int, char *); int sm_wadr (char *, char *, char *); int sm_waend (void); diff --git a/sbr/Makefile.in b/sbr/Makefile.in index 69a280c..0f84568 100644 --- a/sbr/Makefile.in +++ b/sbr/Makefile.in @@ -19,10 +19,9 @@ etcdir = @sysconfdir@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ -KRB4_INCLUDES = @KRB4_INCLUDES@ # for mts HESIOD_INCLUDES = @HESIOD_INCLUDES@ # for mts CONFIGDEFS = -DNMHETCDIR='"$(etcdir)"' -DMAILSPOOL='"$(mailspool)"' -DSENDMAILPATH='"$(sendmailpath)"' -INCLUDES = -I.. -I. -I$(top_srcdir) +INCLUDES = -I.. -I. -I$(top_srcdir) @CPPFLAGS@ LEX = @LEX@ AWK = @AWK@ @@ -40,7 +39,7 @@ mailspool = @mailspool@ sendmailpath = @sendmailpath@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) -COMPILE2 = $(CC) -c $(DEFS) $(CONFIGDEFS) $(INCLUDES) $(KRB4_INCLUDES) $(HESIOD_INCLUDES) $(CFLAGS) +COMPILE2 = $(CC) -c $(DEFS) $(CONFIGDEFS) $(INCLUDES) $(HESIOD_INCLUDES) $(CFLAGS) diff --git a/uip/Makefile.in b/uip/Makefile.in index 1e1ae9b..6f27177 100644 --- a/uip/Makefile.in +++ b/uip/Makefile.in @@ -20,18 +20,15 @@ CC = @CC@ CFLAGS = @CFLAGS@ DEFS = @DEFS@ HESIOD_INCLUDES = @HESIOD_INCLUDES@ -SASL_INCLUDES = @SASL_INCLUDES@ -INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir) $(HESIOD_INCLUDES) $(SASL_INCLUDES) +INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir) $(HESIOD_INCLUDES) @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ MTSLIB = ../mts/libmts.a -KRB4_LIBS = @KRB4_LIBS@ -SASL_LIBS = @SASL_LIBS@ HESIOD_LIBS = @HESIOD_LIBS@ NDBM_LIBS = @NDBM_LIBS@ LOCALLIBS = ../config/version.o ../config/config.o $(MTSLIB) ../sbr/libmh.a -LINKLIBS = $(LOCALLIBS) $(KRB4_LIBS) $(SASL_LIBS) $(HESIOD_LIBS) $(LIBS) +LINKLIBS = $(LOCALLIBS) $(HESIOD_LIBS) $(LIBS) LINT = @LINT@ LINTFLAGS = @LINTFLAGS@ diff --git a/uip/post.c b/uip/post.c index ba898a4..87e31e8 100644 --- a/uip/post.c +++ b/uip/post.c @@ -46,6 +46,12 @@ # define SASLminc(a) 0 #endif /* CYRUS_SASL */ +#ifndef TLS_SUPPORT +# define TLSminc(a) (a) +#else /* TLS_SUPPORT */ +# define TLSminc(a) 0 +#endif /* TLS_SUPPORT */ + #define FCCS 10 /* max number of fccs allowed */ #define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : c) @@ -140,6 +146,8 @@ static struct swit switches[] = { { "user", SASLminc(-4) }, #define PORTSW 40 { "port server port name/number", 4 }, +#define TLSSW 41 + { "tls", TLSminc(-3) }, { NULL, 0 } }; @@ -239,6 +247,7 @@ static int sasl=0; /* Use SASL auth for SMTP */ static char *saslmech=NULL; /* Force use of particular SASL mech */ static char *user=NULL; /* Authenticate as this user */ static char *port="smtp"; /* Name of server port for SMTP */ +static int tls=0; /* Use TLS for encryption */ static unsigned msgflags = 0; /* what we've seen */ @@ -526,6 +535,10 @@ main (int argc, char **argv) if (!(port = *argp++) || *port == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; + + case TLSSW: + tls++; + continue; } } if (msg) @@ -1415,7 +1428,7 @@ post (char *file, int bccque, int talk) if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose, snoop, onex, queued, sasl, saslmech, - user)) + user, tls)) || rp_isbad (retval = sm_winit (smtpmode, from))) die (NULL, "problem initializing server; %s", rp_string (retval)); @@ -1454,7 +1467,7 @@ verify_all_addresses (int talk) if (!whomsw || checksw) if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose, snoop, 0, queued, sasl, - saslmech, user)) + saslmech, user, tls)) || rp_isbad (retval = sm_winit (smtpmode, from))) die (NULL, "problem initializing server; %s", rp_string (retval)); diff --git a/uip/send.c b/uip/send.c index 8409654..7eb75bd 100644 --- a/uip/send.c +++ b/uip/send.c @@ -21,6 +21,12 @@ # define SASLminc(a) 0 #endif /* CYRUS_SASL */ +#ifndef TLS_SUPPORT +# define TLSminc(a) (a) +#else /* TLS_SUPPORT */ +# define TLSminc(a) 0 +#endif /* TLS_SUPPORT */ + static struct swit switches[] = { #define ALIASW 0 { "alias aliasfile", 0 }, @@ -108,6 +114,8 @@ static struct swit switches[] = { { "attachformat", 7 }, #define PORTSW 42 { "port server-port-name/number" , 4 }, +#define TLSSW 43 + { "tls", TLSminc(-3) }, { NULL, 0 } }; @@ -265,6 +273,7 @@ main (int argc, char **argv) case SOMLSW: case SNOOPSW: case SASLSW: + case TLSSW: vec[vecp++] = --cp; continue; diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index da2debd..58ac8bd 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -980,6 +980,12 @@ check_draft (char *msgnam) # define SASLminc(a) 0 #endif /* CYRUS_SASL */ +#ifndef TLS_SUPPORT +# define TLSminc(a) (a) +#else /* TLS_SUPPORT */ +# define TLSminc(a) 0 +#endif /* TLS_SUPPORT */ + static struct swit sendswitches[] = { #define ALIASW 0 { "alias aliasfile", 0 }, @@ -1058,13 +1064,15 @@ static struct swit sendswitches[] = { #define SASLMECHSW 37 { "saslmech", SASLminc(-5) }, #define USERSW 38 - { "user", SASLminc(4) }, + { "user", SASLminc(-4) }, #define SNDATTACHSW 39 { "attach file", 6 }, #define SNDATTACHFORMAT 40 { "attachformat", 7 }, #define PORTSW 41 { "port server-port-name/number", 4 }, +#define TLSSW 42 + { "tls", TLSminc(-3) }, { NULL, 0 } }; @@ -1219,6 +1227,7 @@ sendit (char *sp, char **arg, char *file, int pushed) case SOMLSW: case SNOOPSW: case SASLSW: + case TLSSW: vec[vecp++] = --cp; continue; diff --git a/uip/whom.c b/uip/whom.c index 51ce5fe..fe01326 100644 --- a/uip/whom.c +++ b/uip/whom.c @@ -19,6 +19,12 @@ # define SASLminc(a) 0 #endif /* CYRUS_SASL */ +#ifndef TLS_SUPPORT +# define TLSminc(a) (a) +#else /* TLS_SUPPORT */ +# define TLSminc(a) 0 +#endif /* TLS_SUPPORT */ + static struct swit switches[] = { #define ALIASW 0 { "alias aliasfile", 0 }, @@ -52,6 +58,8 @@ static struct swit switches[] = { { "user username", SASLminc(-4) }, #define PORTSW 15 { "port server port name/number", 4 }, +#define TLSSW 16 + { "tls", TLSminc(-3) }, { NULL, 0 } }; -- 1.7.10.4