]> diplodocus.org Git - nmh/commitdiff
Change "servers" mts.conf entry to only support a single SMTP server.
authorKen Hornstein <kenh@pobox.com>
Sun, 19 Feb 2017 22:05:12 +0000 (17:05 -0500)
committerKen Hornstein <kenh@pobox.com>
Sun, 19 Feb 2017 22:05:12 +0000 (17:05 -0500)
As part of this change, fix SMTP code so the chosen SMTP server is
configured correctly for the netsec code.

INSTALL
Makefile.am
build_nmh
configure.ac
docs/pending-release-notes
etc/mts.conf.in
man/mh-tailor.man
mts/smtp/smtp.c
sbr/client.c

diff --git a/INSTALL b/INSTALL
index ca1c1df..246cf0e 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -260,7 +260,7 @@ Options for configure
      is not given, then the configuration process will search for the
      command `more' and use it as the default.
 
---with-smtpservers='SMTPSERVER1[ SMTPSERVER2...]'    (DEFAULT is localhost)
+--with-smtpserver='SMTPSERVER'    (DEFAULT is localhost)
      If this option is not specified, the mts.conf file will contain
      the line "servers: localhost", which may be manually edited later.
      You may find it convenient to specify a value at configure-time,
index c79adeb..bbda834 100644 (file)
@@ -526,7 +526,7 @@ etc/mts.conf: $(srcdir)/etc/mts.conf.in Makefile
        @rm -f $@
        $(SED) -e 's,%mts%,$(MTS),' \
               -e 's,%mailspool%,$(mailspool),' \
-              -e 's,%smtpservers%,$(smtpservers),' \
+              -e 's,%smtpserver%,$(smtpserver),' \
               -e 's,%default_locking%,$(default_locking),' \
               -e 's,%supported_locks%,$(supported_locks),' \
                                < $(srcdir)/etc/mts.conf.in > $@
index 6e96756..6958faa 100755 (executable)
--- a/build_nmh
+++ b/build_nmh
@@ -222,7 +222,7 @@ fi
 config_prefix=/usr/local/nmh
 config_locking=
 config_mts=smtp
-config_smtpservers=localhost
+config_smtpserver=localhost
 config_sasl='determined by configure'
 config_tls='determined by configure'
 config_debug=n
@@ -252,9 +252,8 @@ if install-mh -check >/dev/null 2>&1; then
 
     mtsconfservers=`grep '^servers:' "$mtsconf"`
     if [ "$mtsconfservers" ]; then
-      servers=`echo "$mtsconfservers" | \
-               sed -e 's/^servers: *//' -e 's/ /\\\ /g'`
-      [ "$servers" ]  &&  config_smtpservers="$servers"
+      servers=`echo "$mtsconfservers" | sed -e 's/^servers: *//'`
+      [ "$servers" ]  &&  config_smtpserver="$servers"
     fi
   fi
 
@@ -294,9 +293,9 @@ if [ $yes -eq 0 ]; then
   [ "$mts" ]  &&  config_mts="$mts"
 
   if [ "$config_mts" = smtp ]; then
-    printf 'SMTP server(s), space separated [%s]: ' $config_smtpservers >&3
-    read response
-    [ "$response" ]  &&  config_smtpservers="$response"
+    printf 'SMTP server [%s]: ' $config_smtpserver >&3
+    read server
+    [ "$server" ]  &&  config_smtpserver="$servers"
   fi
 
   printf 'Cyrus SASL support (y|n) [%s]: ' "$config_sasl" >&3
@@ -314,8 +313,8 @@ config_opts="--prefix=$config_prefix"
   config_opts="$config_opts --with-locking=$config_locking"
 [ "$config_mts"  -a  "$config_mts" != smtp ]  &&
   config_opts="$config_opts --with-mts=$config_mts"
-[ "$config_smtpservers"  -a  "$config_smtpservers" != localhost ]  &&
-  config_opts="$config_opts --with-smtpservers=\"$config_smtpservers\""
+[ "$config_smtpserver"  -a  "$config_smtpserver" != localhost ]  &&
+  config_opts="$config_opts --with-smtpserver=$config_smtpserver"
 [ "$config_sasl" = y ]  &&  config_opts="$config_opts --with-cyrus-sasl"
 [ "$config_tls" = y ]  &&  config_opts="$config_opts --with-tls"
 [ $config_debug = y ]  &&  config_opts="$config_opts --enable-assert"
@@ -374,9 +373,8 @@ if [ -z "$CFLAGS" ]; then
   fi
 fi
 
-printf "\n./configure CFLAGS=\"${CFLAGS}\" $config_opts\n"
-#### Use eval to handle space-separated smtpservers.
-eval ./configure CFLAGS=\""${CFLAGS}"\" $config_opts
+printf '\n./configure %s\n' "$config_opts"
+./configure CFLAGS="${CFLAGS}" $config_opts
 status=$?
 
 if [ $status -eq 0 ]; then
index ae98df8..d1a755c 100644 (file)
@@ -59,13 +59,13 @@ AS_IF([test x"$with_mts" = x"smtp"], [MTS="smtp"],
       [MTS="smtp"])
 AC_SUBST([MTS])dnl
 
-dnl What should be the default mail server(s)?
-AC_ARG_WITH([smtpservers],
-  [AS_HELP_STRING([--with-smtpservers='SMTPSERVER1@<:@ SMTPSERVER2...@:>@'],
-  [specify the default SMTP server(s) @<:@localhost@:>@])])
-AS_IF([test -n "$with_smtpservers"], [smtpservers="$with_smtpservers"],
-      [smtpservers="localhost"])
-AC_SUBST([smtpservers])dnl
+dnl What should be the default mail server?
+AC_ARG_WITH([smtpserver],
+  [AS_HELP_STRING([--with-smtpserver='SMTPSERVER'],
+  [specify the default SMTP server @<:@localhost@:>@])])
+AS_IF([test -n "$with_smtpserver"], [smtpserver="$with_smtpserver"],
+      [smtpserver="localhost"])
+AC_SUBST([smtpserver])dnl
 
 dnl -------------------------------------------------------------------
 dnl Default location is /usr/local/nmh/{bin,etc,libexec,man}, unless we
@@ -645,7 +645,7 @@ RPM build root             : ${nmhrpm}
 backup prefix              : ${backup_prefix}
 transport system           : ${MTS}
 spool default locking type : ${with_locking}
-default smtp servers       : ${smtpservers}
+default smtp server        : ${smtpserver}
 SASL support               : ${sasl_support}
 TLS support                : ${tls_support}
 OAuth support              : ${oauth_support}
index 7de2628..23cc77c 100644 (file)
@@ -68,6 +68,7 @@ NEW FEATURES
 - configure now defaults to enabling each of TLS and Cyrus SASL if the
   necessary headers and libraries are found.
 - Moved build_nmh to top-level directory.
+- Better error reporting for connections to network services
 
 -----------------
 OBSOLETE FEATURES
@@ -80,6 +81,8 @@ OBSOLETE FEATURES
 - msh(1) was deprecated in nmh 1.6, and was removed in this release.
 - Support in alias files for the the "*" address-group (everyone) was
   deprecated in nmh 1.6, and was removed in this release.
+- Support for multiple hostnames in the "servers" entry of mts.conf has
+  been removed.
 
 -------------------
 DEPRECATED FEATURES
index bcf7b2f..0e20f28 100644 (file)
@@ -46,5 +46,5 @@ mmdflfil:
 # Hardcoded POP server name (prevents inc'ing from local mail spool).
 #pophost: localhost
 
-# List of smtp servers to try if using smtp support
-servers: %smtpservers%
+# A SINGLE SMTP server to use when using SMTP support
+servers: %smtpserver%
index 226109f..0a3f524 100644 (file)
@@ -212,12 +212,25 @@ to
 .BR servers :
 localhost
 .RS 5
-A lists of hosts and networks which to look for SMTP servers when
-posting non\-local mail.  It turns out this is a major win for hosts
-which don't run an message transport system.  The value of
+A SINGLE hostname to be used when performing mail submission via SMTP.  Previous
+versions of
+.B nmh
+supported multiple hostnames for
+.BR servers ,
+but the current version of
+.B nmh
+only supports a single entry (the name is kept for backwards compatibility
+reasons).  This can be overridden via the
+.B \-server
+option to
+.IR send (1).
+It is not possible to change the mail submission port number in the
 .B servers
-should be one or more items.  Each item is the name of a host which
-is (hopefully) running a SMTP server.
+entry; see the
+.B \-port
+option to
+.BR send (1)
+for this functionality.
 .SS "SendMail"
 This option is only available if you set
 .B mts
index 0e6e511..77bcb6e 100644 (file)
@@ -81,7 +81,7 @@ static int smtp_init (char *, char *, char *, int, int, int, int, const char *,
 static int sendmail_init (char *, int, int, int, int, const char *,
                          const char *);
 
-static int rclient (char *, char *);
+static int rclient (char *, char *, char **);
 static int sm_ierror (const char *fmt, ...);
 static int sm_nerror (char *);
 static int smtalk (int time, char *fmt, ...);
@@ -111,7 +111,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
            const char *oauth_svc, int tls)
 {
     int result, sd1;
-    char *errstr;
+    char *errstr, *chosen_server;
 
     if (watch)
        verbose = TRUE;
@@ -141,7 +141,14 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
     if (user)
        netsec_set_userid(nsc, user);
 
-    netsec_set_hostname(nsc, server);
+    if ((sd1 = rclient (server, port, &chosen_server)) == NOTOK)
+       return RP_BHST;
+
+    SIGNAL (SIGPIPE, SIG_IGN);
+
+    netsec_set_fd(nsc, sd1, sd1);
+
+    netsec_set_hostname(nsc, chosen_server);
 
     if (sm_debug)
        netsec_set_snoop(nsc, 1);
@@ -157,13 +164,6 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
            return sm_ierror("OAuth2 not supported");
     }
 
-    if ((sd1 = rclient (server, port)) == NOTOK)
-       return RP_BHST;
-
-    SIGNAL (SIGPIPE, SIG_IGN);
-
-    netsec_set_fd(nsc, sd1, sd1);
-
     if (tls & S_TLSENABLEMASK) {
        if (netsec_set_tls(nsc, 1, tls & S_NOVERIFY, &errstr) != OK)
            return sm_nerror(errstr);
@@ -426,11 +426,16 @@ sendmail_init (char *client, int watch, int verbose, int debug, int sasl,
 }
 
 static int
-rclient (char *server, char *service)
+rclient (char *server, char *service, char **chosen_server)
 {
     int sd;
     char response[BUFSIZ];
 
+    if (server == NULL)
+       server = servers;
+
+    *chosen_server = server;
+
     if ((sd = client (server, service, response, sizeof(response),
                      sm_debug)) != NOTOK)
        return sd;
index 9978896..974cf8f 100644 (file)
 #include <netinet/in.h>
 #include <netdb.h>
 #include <arpa/inet.h>
-
-#define        MAXARGS   1000
-
-/*
- * static prototypes
- */
-
-/* client's own static version of several nmh subroutines */
-static char **client_brkstring (char *, char *, char *);
-static int client_brkany (char, char *);
-static char **client_copyip (char **, char **, int);
-static void client_freelist(char **);
+#include <errno.h>
 
 
 int
-client (char *args, char *service, char *response, int len_response, int debug)
+client (char *server, char *service, char *response, int len_response,
+       int debug)
 {
     int sd, rc;
-    char **ap, *arguments[MAXARGS];
     struct addrinfo hints, *res, *ai;
 
-    ap = arguments;
-    if (args != NULL && *args != 0) {
-       ap = client_copyip (client_brkstring (mh_xstrdup(args), " ", "\n"),
-               ap, MAXARGS);
-    } else {
-       if (servers != NULL && *servers != 0)
-           ap = client_copyip (client_brkstring (mh_xstrdup(servers), " ", "\n"),
-               ap, MAXARGS);
-    }
-    if (ap == arguments) {
-       *ap++ = mh_xstrdup("localhost");
-       *ap = NULL;
+    if (!server || *server == '\0') {
+       snprintf(response, len_response, "Internal error: NULL server name "
+                "passed to client()");
+       return NOTOK;
     }
 
     memset(&hints, 0, sizeof(hints));
@@ -56,136 +37,69 @@ client (char *args, char *service, char *response, int len_response, int debug)
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
 
-    for (ap = arguments; *ap; ap++) {
-
-       if (debug) {
-           fprintf(stderr, "Trying to connect to \"%s\" ...\n", *ap);
-       }
-
-       rc = getaddrinfo(*ap, service, &hints, &res);
-
-       if (rc) {
-           if (debug) {
-               fprintf(stderr, "Lookup of \"%s\" failed: %s\n", *ap,
-                       gai_strerror(rc));
-           }
-           continue;
-       }
-
-       for (ai = res; ai != NULL; ai = ai->ai_next) {
-           if (debug) {
-               char address[NI_MAXHOST];
-               char port[NI_MAXSERV];
-
-               rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
-                                sizeof(address), port, sizeof port,
-                                NI_NUMERICHOST | NI_NUMERICSERV);
-
-               fprintf(stderr, "Connecting to %s:%s...\n",
-                       rc ? "unknown" : address,
-                       rc ? "--" : port);
-           }
-
-           sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-
-           if (sd < 0) {
-               if (debug)
-                   fprintf(stderr, "socket() failed: %s\n", strerror(errno));
-               continue;
-           }
-
-           if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
-               freeaddrinfo(res);
-               client_freelist(arguments);
-               return sd;
-           }
-
-           if (debug) {
-               fprintf(stderr, "Connection failed: %s\n", strerror(errno));
-           }
+    if (debug) {
+       fprintf(stderr, "Trying to connect to \"%s\" ...\n", server);
+    }
 
-           close(sd);
-       }
+    rc = getaddrinfo(server, service, &hints, &res);
 
-       freeaddrinfo(res);
+    if (rc) {
+       snprintf(response, len_response, "Lookup of \"%s\" failed: %s",
+                server, gai_strerror(rc));
+       return NOTOK;
     }
 
-    client_freelist(arguments);
-    strncpy (response, "no servers available", len_response);
-    return NOTOK;
-}
+    for (ai = res; ai != NULL; ai = ai->ai_next) {
+       if (debug) {
+           char address[NI_MAXHOST];
+           char port[NI_MAXSERV];
 
+           rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
+                            sizeof(address), port, sizeof port,
+                            NI_NUMERICHOST | NI_NUMERICSERV);
 
-/*
- * Free a list of strings
- */
+           fprintf(stderr, "Connecting to %s:%s...\n",
+                   rc ? "unknown" : address, rc ? "--" : port);
+       }
 
-static void
-client_freelist(char **list)
-{
-    free(*list);
-}
+       sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 
+       if (sd < 0) {
+           if (debug)
+               fprintf(stderr, "socket() failed: %s\n", strerror(errno));
+           rc = errno;
+           continue;
+       }
 
-/*
- * static copies of three nmh subroutines
- */
+       if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
+           freeaddrinfo(res);
+           return sd;
+       }
 
-static char *broken[MAXARGS + 1];
+       rc = errno;
 
-static char **
-client_brkstring (char *strg, char *brksep, char *brkterm)
-{
-    int bi;
-    char c, *sp;
-
-    sp = strg;
-
-    for (bi = 0; bi < MAXARGS; bi++) {
-       while (client_brkany (c = *sp, brksep))
-           *sp++ = 0;
-       if (!c || client_brkany (c, brkterm)) {
-           *sp = 0;
-           broken[bi] = 0;
-           return broken;
+       if (debug) {
+           fprintf(stderr, "Connection failed: %s\n", strerror(errno));
        }
 
-       broken[bi] = sp;
-       while ((c = *++sp) && !client_brkany (c, brksep) && !client_brkany (c, brkterm))
-           continue;
+       close(sd);
     }
-    broken[MAXARGS] = 0;
 
-    return broken;
-}
+    /*
+     * Improve error handling a bit. If we were given multiple IP addresses
+     * then return the old "no servers available" error, but point the user
+     * to -snoop (hopefully that's universal).  Otherwise report a specific
+     * error.
+     */
 
+    if (res->ai_next)
+       snprintf(response, len_response, "no servers available (use -snoop "
+                "for details");
+    else
+       snprintf(response, len_response, "Connection to \"%s\" failed: %s",
+                server, strerror(errno));
 
-/*
- * returns 1 if chr in strg, 0 otherwise
- */
-static int
-client_brkany (char chr, char *strg)
-{
-    char *sp;
-
-    if (strg)
-       for (sp = strg; *sp; sp++)
-           if (chr == *sp)
-               return 1;
-    return 0;
-}
-
+    freeaddrinfo(res);
 
-/*
- * copy a string array and return pointer to end
- */
-static char **
-client_copyip (char **p, char **q, int len_q)
-{
-    while (*p && --len_q > 0)
-       *q++ = *p++;
-
-    *q = NULL;
-
-    return q;
+    return NOTOK;
 }