(Minor) cleanup of some of the autoconf code with respect to the handling
authorKen Hornstein <kenh@pobox.com>
Fri, 19 Nov 2010 20:13:39 +0000 (20:13 +0000)
committerKen Hornstein <kenh@pobox.com>
Fri, 19 Nov 2010 20:13:39 +0000 (20:13 +0000)
of compiler flags for SASL, and also rototill (and simplify) the autoconf
handling for the same.

Add TLS support for the SMTP MTA.

15 files changed:
aclocal.m4
config/Makefile.in
configure.in
man/mh-chart.man
man/post.man
man/send.man
mts/smtp/Makefile.in
mts/smtp/smtp.c
mts/smtp/smtp.h
sbr/Makefile.in
uip/Makefile.in
uip/post.c
uip/send.c
uip/whatnowsbr.c
uip/whom.c

index 7941c07..20d123f 100644 (file)
@@ -1,24 +1,14 @@
 
-# Originally by John Hawkinson <jhawk@mit.edu>
-# 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
index aba161b..6c4613d 100644 (file)
@@ -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)"'
 
index e43fca1..7730717 100644 (file)
@@ -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 <setjmp.h>]],
@@ -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 ""
index 5e097e4..b31cb0b 100644 (file)
@@ -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
index 892215a..772bbfb 100644 (file)
@@ -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 ^ ~
index 25fa357..a20296e 100644 (file)
@@ -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
index f8b0ed3..e837ddc 100644 (file)
@@ -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@
 
index 7413639..e6bca9a 100644 (file)
 #include <errno.h>
 #endif /* CYRUS_SASL */
 
+#ifdef TLS_SUPPORT
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#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)
index 4fdcdfe..12fdedb 100644 (file)
@@ -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);
index 69a280c..0f84568 100644 (file)
@@ -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)
 
 
 
index 1e1ae9b..6f27177 100644 (file)
@@ -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@
index ba898a4..87e31e8 100644 (file)
 # 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));
 
index 8409654..7eb75bd 100644 (file)
 # 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;
 
index da2debd..58ac8bd 100644 (file)
@@ -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;
 
index 51ce5fe..fe01326 100644 (file)
 # 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 }
 };