Massive overhaul of networking code. Changes:
authorKen Hornstein <kenh@pobox.com>
Fri, 16 Jan 2009 02:28:54 +0000 (02:28 +0000)
committerKen Hornstein <kenh@pobox.com>
Fri, 16 Jan 2009 02:28:54 +0000 (02:28 +0000)
- All networking interfaces now converted to new APIs (getaddrinfo() and
  the like).  All networking now supports IPv6 (with the exception of
  the built-in FTP client).
- SASL security layers are now supported for SMTP.
- Command-line and profile-based selection of the SMTP server and port.

20 files changed:
aclocal.m4
configure.in
docs/README.SASL
docs/pending-release-notes [new file with mode: 0644]
h/netdb.h [deleted file]
h/prototypes.h
man/mh-tailor.man
man/post.man
man/send.man
mts/smtp/hosts.c
mts/smtp/smtp.c
mts/smtp/smtp.h
sbr/client.c
sbr/mts.c
uip/ftpsbr.c
uip/mhlsbr.c
uip/popsbr.c
uip/post.c
uip/send.c
uip/whatnowsbr.c

index 6091daa..7941c07 100644 (file)
@@ -13,9 +13,9 @@
 # BIND 4.9.5 installed.
 
 AC_DEFUN(AC_CHECK_NETLIBS,
-[AC_CHECK_FUNC(gethostbyname, ,
-  AC_CHECK_LIB(nsl, gethostbyname, ,
-    AC_CHECK_LIB(resolv, gethostbyname)))
+[AC_CHECK_FUNC(getaddrinfo, ,
+  AC_CHECK_LIB(nsl, getaddrinfo, ,
+    AC_CHECK_LIB(resolv, getaddrinfo)))
 AC_CHECK_FUNC(socket, ,
   AC_CHECK_LIB(socket, socket))
 ])
index ce9c4ba..6d4a9d4 100644 (file)
@@ -521,12 +521,9 @@ AC_CHECK_FUNCS(waitpid wait3 sigaction sigprocmask sigblock sigsetmask \
                getutent nl_langinfo mbtowc wcwidth)
 
 dnl solaris has these in the nsl library
-AC_SEARCH_LIBS(gethostbyname, nsl,
-  [AC_DEFINE(HAVE_GETHOSTBYNAME,1,
-    [Define to 1 if you have the `gethostbyname' function.])])
-AC_SEARCH_LIBS(sethostent, nsl,
-  [AC_DEFINE(HAVE_SETHOSTENT,1,
-    [Define to 1 if you have the `sethostent' function.])])
+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)
index 3dd7623..224600d 100644 (file)
@@ -15,18 +15,22 @@ works if you use --enable-pop and the SMTP mail transport.
 
 This release of NMH only supports "Version 2" of the Cyrus SASL library.
 It should work with any newer Cyrus SASL release, but it was tested with
-Cyrus SASL 2.1.12.  In particular, the CRAM-MD5 and GSSAPI (Kerberos 5)
-mechanisms were tested.
+Cyrus SASL 2.1.22.  In particular, the CRAM-MD5 and GSSAPI (Kerberos 5)
+mechanisms were tested.  Older versions of Cyrus-SASL had a bug which
+could manifest when negotiating encrypting depending on the encryption
+type you used, so a newer version of Cyrus-SASL is recommended.
 
-Currently, security layers ("encryption" in SASL-speak) are only supported
-for POP.  This means that if your POP server _and_ the selected GSSAPI
-mechanism supports it, POP communications will be encrypted.  Currently
-SMTP does NOT support security layers; this may be added in a future
-release.
+Currently, security layers ("encryption" in SASL-speak) are supported
+for both POP and SMTP.  This means that if your POP or SMTP server
+_and_ the selected SASL mechanism supports it, client-server
+communications will be encrypted.  In theory this should work with
+any SASL mechanism that supports security layers; it has only been
+tested with the GSSAPI mechanism.
 
 If you are curious as to whether or not your communications are actually
-encrypted or not, you can use the -snoop flag to the POP utilities.
-Communication that is encrypted is preceeded by an (*).
+encrypted or not, you can use the -snoop flag to the POP or SMTP utilities.
+Communication that is encrypted is preceeded by an (encrypted) or
+(decrypted), depending on the direction of communication.
 
 If you would like to use the GSSAPI SASL mechanism (Kerberos V), you
 should read very carefully the documentation that comes with
diff --git a/docs/pending-release-notes b/docs/pending-release-notes
new file mode 100644 (file)
index 0000000..7c05abe
--- /dev/null
@@ -0,0 +1,11 @@
+Things to add to the release notes for the next full release:
+
+- SASL security layers (encryption) are now supported for the SMTP MTA.
+- You can now select the SMTP server and port from either "send" or a
+  user's mh_profile (you could always select the server; that option is
+  now documented).  These are available via the -server and -port switches.
+- All networking code has been modified to use the new networking APIs
+  (getaddrinfo and friends).  All networking code (with the exception of
+  the ftp client) now supports IPv6.
+- Support for prefixing a \01 in the "servers" entry in mts.conf to
+  connect to all servers on a particular named net has been removed.
diff --git a/h/netdb.h b/h/netdb.h
deleted file mode 100644 (file)
index 41b0226..0000000
--- a/h/netdb.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * netdb.h
- *
- * Copyright (c) 1980,1983,1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to the University of California at Berkeley. The name of the University
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
- *
- * $Id$
- */
-
-/*
- * Structures returned by network
- * data base library.  All addresses
- * are supplied in host order, and
- * returned in network order (suitable
- * for use in system calls).
- */
-struct hostent {
-       char    *h_name;        /* official name of host */
-       char    **h_aliases;    /* alias list */
-       int     h_addrtype;     /* host address type */
-       int     h_length;       /* length of address */
-       char    **h_addr_list;  /* list of addresses from name server */
-#define        h_addr  h_addr_list[0]  /* address, for backward compatiblity */
-};
-
-/*
- * Assumption here is that a network number
- * fits in 32 bits -- probably a poor one.
- */
-struct netent {
-       char            *n_name;        /* official name of net */
-       char            **n_aliases;    /* alias list */
-       int             n_addrtype;     /* net address type */
-       unsigned long   n_net;          /* network # */
-};
-
-struct servent {
-       char    *s_name;        /* official service name */
-       char    **s_aliases;    /* alias list */
-       int     s_port;         /* port # */
-       char    *s_proto;       /* protocol to use */
-};
-
-struct protoent {
-       char    *p_name;        /* official protocol name */
-       char    **p_aliases;    /* alias list */
-       int     p_proto;        /* protocol # */
-};
-
-struct hostent *gethostbyname(), *gethostbyaddr(), *gethostent();
-struct netent  *getnetbyname(), *getnetbyaddr(), *getnetent();
-struct servent *getservbyname(), *getservbyport(), *getservent();
-struct protoent        *getprotobyname(), *getprotobynumber(), *getprotoent();
-
-/*
- * Error return codes from gethostbyname() and gethostbyaddr()
- * (left in extern int h_errno).
- */
-
-#define        HOST_NOT_FOUND  1 /* Authoritative Answer Host not found */
-#define        TRY_AGAIN       2 /* Non-Authoritive Host not found, or SERVERFAIL */
-#define        NO_RECOVERY     3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
-#define        NO_DATA         4 /* Valid name, no data record of requested type */
-#define        NO_ADDRESS      NO_DATA         /* no address, look for MX record */
index 1de4067..32f6a3d 100644 (file)
@@ -33,6 +33,7 @@ void ambigsw (char *, struct swit *);
 int atooi(char *);
 char **brkstring (char *, char *, char *);
 int check_charset (char *, int);
+int client(char *, char *, char *, int, int);
 void closefds(int);
 char *concat (char *, ...);
 int context_del (char *);
index 4fc80b1..6a3fda5 100644 (file)
@@ -288,19 +288,14 @@ All words following the official names are aliases for that host.
 .RE
 .PP
 .BR servers :
-localhost \\01localnet
+localhost
 .RS 5
 A lists of hosts and networks which to look for SMTP servers when
 posting local mail.  It turns out this is a major win for hosts which
 don't run an message transport system.  The value of
 .B servers
-should be one or more items.  Each item is the name of either a host
-or a net (in the latter case, precede the name of the net by a \\01).
-This list is searched when looking for a smtp server to post mail.
-If a host is present, the SMTP port on that host is tried.  If a net
-is present, the SMTP port on each host in that net is tried.  Note that
-if you are running with the BIND code, then any networks specified are
-ignored (sorry, the interface went away under BIND).
+should be one or more items.  Each item is the name of a host which
+is (hopefully) running a SMTP server.
 .SS "SendMail"
 This option is only available if you set
 .B mts
index f437f62..892215a 100644 (file)
@@ -181,6 +181,16 @@ account, or when remote email robots give improper precedence to the envelope
 .BR sendmail 's
 \*(lqX\-Authentication\-Warning:\*(rq header). 
 .PP
+If nmh is using the SMTP MTA, the
+.B \-server
+and the
+.B \-port
+switches can be used to override the default mail server (defined by the
+.RI servers
+entry in
+.I %etcdir%/mts.conf
+).
+.PP
 If
 .B nmh
 has been compiled with SASL support, the
@@ -198,15 +208,13 @@ and the the
 switch can be used to select a authorization userid
 to provide to SASL other than the default.
 .PP
-Currently SASL security layers are not supported for SMTP.
-.BR nmh 's
-SMTP SASL code
-will always negotiate an unencrypted connection.  This means that while the SMTP
-authentication can be encrypted, the subsequent data stream can not.  This is in
-contrast to
-.BR nmh 's
-POP3 SASL support, where encryption is supported for both the
-authentication and the data stream.
+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
+viewing the SMTP transaction with the
+.B \-snoop
+switch.
 
 .SH FILES
 .fc ^ ~
index 0c65f5a..25fa357 100644 (file)
@@ -29,6 +29,10 @@ send \- send a message
 .IR seconds ]
 .RB [ \-verbose " | " \-noverbose ]
 .RB [ \-watch " | " \-nowatch ]
+.RB [ \-server
+.IR servername ]
+.RB [ \-port
+.IR port-name/number ]
 .RB [ \-sasl ]
 .RB [ \-saslmech
 .IR mechanism ]
@@ -315,6 +319,16 @@ switch, the user can direct
 .B send
 as to how long it should make header lines containing addresses.
 .PP
+If nmh is using the SMTP MTA, the
+.B \-server
+and the
+.B \-port
+switches can be used to override the default mail server (defined by the
+.RI servers
+entry in
+.I %etcdir%/mts.conf
+).
+.PP
 If
 .B nmh
 has been compiled with SASL support, the
@@ -332,15 +346,13 @@ and the the
 switch can be used to select a authorization userid
 to provide to SASL other than the default.
 .PP
-Currently SASL security layers are not supported for SMTP.
-.BR nmh 's
-SMTP SASL code
-will always negotiate an unencrypted connection.  This means that while the SMTP
-authentication can be encrypted, the subsequent data stream can not.  This is in
-contrast to
-.BR nmh 's
-POP3 SASL support, where encryption is supported for both the
-authentication and the data stream.
+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
+viewing the SMTP transaction with the
+.B \-snoop
+switch.
 .PP
 The files specified by the profile entry \*(lqAliasfile:\*(rq and any
 additional alias files given by the
index 33eb9e6..908e619 100644 (file)
@@ -38,7 +38,7 @@ OfficialName (char *name)
 {
     unsigned char *p;
     char *q, site[BUFSIZ];
-    struct hostent *hp;
+    struct addrinfo hints, *res;
 
     static char buffer[BUFSIZ];
     char **r;
@@ -52,12 +52,14 @@ OfficialName (char *name)
     if (!mh_strcasecmp (LocalName(), site))
        return LocalName();
 
-#ifdef HAVE_SETHOSTENT
-    sethostent (1);
-#endif
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_CANONNAME;
+    hints.ai_family = PF_UNSPEC;
 
-    if ((hp = gethostbyname (q))) {
-       strncpy (buffer, hp->h_name, sizeof(buffer));
+    if (getaddrinfo(q, NULL, &hints, &res) == 0) {
+       strncpy (buffer, res->ai_canonname, sizeof(buffer));
+       buffer[sizeof(buffer) - 1] = '\0';
+       freeaddrinfo(res);
        return buffer;
     }
     if (hosts.h_name || init_hs ()) {
index 35eefb4..37a7b07 100644 (file)
@@ -13,9 +13,6 @@
 #include <h/mts.h>
 #include <signal.h>
 #include <h/signals.h>
-#ifdef MPOP
-#include <errno.h>
-#endif
 
 #ifdef CYRUS_SASL
 #include <sasl/sasl.h>
@@ -82,11 +79,6 @@ static int sm_verbose = 0;
 static FILE *sm_rfp = NULL;
 static FILE *sm_wfp = NULL;
 
-#ifdef MPOP
-static int sm_ispool = 0;
-static char sm_tmpfil[BUFSIZ];
-#endif /* MPOP */
-
 #ifdef CYRUS_SASL
 /*
  * Some globals needed by SASL
@@ -97,8 +89,14 @@ static int sasl_complete = 0;                /* Has authentication succeded? */
 static sasl_ssf_t sasl_ssf;            /* Our security strength factor */
 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 },
@@ -109,6 +107,10 @@ static sasl_callback_t callbacks[] = {
 #define SM_SASL_N_CB_AUTHNAME 2
     { SASL_CB_LIST_END, NULL, NULL },
 };
+
+#define SASL_MAXRECVBUF 65536
+#else /* CYRUS_SASL */
+#define sm_fgetc fgetc
 #endif /* CYRUS_SASL */
 
 static char *sm_noreply = "No reply text given";
@@ -124,11 +126,11 @@ char *EHLOkeys[MAXEHLO + 1];
 /*
  * static prototypes
  */
-static int smtp_init (char *, char *, int, int, int, int, int, int,
+static int smtp_init (char *, char *, char *, int, int, int, int, int, int,
                      char *, char *);
 static int sendmail_init (char *, char *, int, int, int, int, int);
 
-static int rclient (char *, char *, char *);
+static int rclient (char *, char *);
 static int sm_ierror (char *fmt, ...);
 static int smtalk (int time, char *fmt, ...);
 static int sm_wrecord (char *, int);
@@ -136,19 +138,15 @@ static int sm_wstream (char *, int);
 static int sm_werror (void);
 static int smhear (void);
 static int sm_rrecord (char *, int *);
-static int sm_rerror (void);
+static int sm_rerror (int);
 static RETSIGTYPE alrmser (int);
 static char *EHLOset (char *);
-
-#ifdef MPOP
-static int sm_perror (char *fmt, ...);
-/*
- * smtp.c's own static copy of several nmh library subroutines
- */
-static char **smail_brkstring (char *, char *, char *);
-static int smail_brkany (char, char *);
-char **smail_copyip (char **, char **, int);
-#endif
+static int sm_fwrite(char *, int);
+static int sm_fputs(char *);
+static int sm_fputc(int);
+static int sm_getc(void);
+static void sm_fflush(void);
+static int sm_fgets(char *, int, FILE *);
 
 #ifdef CYRUS_SASL
 /*
@@ -158,16 +156,13 @@ char **smail_copyip (char **, char **, int);
 static int sm_auth_sasl(char *, char *, char *);
 #endif /* CYRUS_SASL */
 
-/* from mts/generic/client.c */
-int client (char *, char *, char *, int, char *, int);
-
 int
-sm_init (char *client, char *server, int watch, int verbose,
+sm_init (char *client, char *server, char *port, int watch, int verbose,
          int debug, int onex, int queued, int sasl, char *saslmech,
          char *user)
 {
     if (sm_mts == MTS_SMTP)
-       return smtp_init (client, server, watch, verbose,
+       return smtp_init (client, server, port, watch, verbose,
                          debug, onex, queued, sasl, saslmech, user);
     else
        return sendmail_init (client, server, watch, verbose,
@@ -175,7 +170,7 @@ sm_init (char *client, char *server, int watch, int verbose,
 }
 
 static int
-smtp_init (char *client, char *server, int watch, int verbose,
+smtp_init (char *client, char *server, char *port, int watch, int verbose,
           int debug, int onex, int queued, int sasl, char *saslmech,
           char *user)
 {
@@ -190,11 +185,6 @@ smtp_init (char *client, char *server, int watch, int verbose,
     sm_verbose = verbose;
     sm_debug = debug;
 
-#ifdef MPOP
-    if (sm_ispool)
-       goto all_done;
-#endif
-
     if (sm_rfp != NULL && sm_wfp != NULL)
        goto send_options;
 
@@ -211,27 +201,15 @@ smtp_init (char *client, char *server, int watch, int verbose,
        client = "localhost";
 #endif
 
-    if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK)
-       return RP_BHST;
+#ifdef CYRUS_SASL
+    sasl_inbuffer = malloc(SASL_MAXRECVBUF);
+    if (!sasl_inbuffer)
+       return sm_ierror("Unable to allocate %d bytes for read buffer",
+                        SASL_MAXRECVBUF);
+#endif /* CYRUS_SASL */
 
-#ifdef MPOP
-    if (sm_ispool) {
-       if (sm_rfp) {
-           alarm (SM_CLOS);
-           fclose (sm_rfp);
-           alarm (0);
-           sm_rfp = NULL;
-       }
-       if ((sm_wfp = fdopen (sd1, "w")) == NULL) {
-           unlink (sm_tmpfil);
-           close (sd1);
-           return sm_ierror ("unable to fdopen");
-       }
-all_done: ;
-       sm_reply.text[sm_reply.length = 0] = NULL;
-       return (sm_reply.code = RP_OK);
-    }
-#endif /* MPOP */
+    if ((sd1 = rclient (server, port)) == NOTOK)
+       return RP_BHST;
 
     if ((sd2 = dup (sd1)) == NOTOK) {
        close (sd1);
@@ -453,54 +431,16 @@ sendmail_init (char *client, char *server, int watch, int verbose,
     }
 }
 
-#ifdef MPOP
-# define MAXARGS  1000
-#endif /* MPOP */
-
 static int
-rclient (char *server, char *protocol, char *service)
+rclient (char *server, char *service)
 {
     int sd;
     char response[BUFSIZ];
-#ifdef MPOP
-    char *cp;
-#endif /* MPOP */
 
-    if ((sd = client (server, protocol, service, FALSE, response, sizeof(response))) != NOTOK)
+    if ((sd = client (server, service, response, sizeof(response),
+                     sm_debug)) != NOTOK)
        return sd;
 
-#ifdef MPOP
-    if (!server && servers && (cp = strchr(servers, '/'))) {
-       char **ap;
-       char *arguments[MAXARGS];
-
-       smail_copyip (smail_brkstring (cp = getcpy (servers), " ", "\n"), arguments, MAXARGS);
-
-       for (ap = arguments; *ap; ap++)
-           if (**ap == '/') {
-               char *dp;
-
-               if ((dp = strrchr(*ap, '/')) && *++dp == NULL)
-                   *--dp = NULL;
-               snprintf (sm_tmpfil, sizeof(sm_tmpfil), "%s/smtpXXXXXX", *ap);
-#ifdef HAVE_MKSTEMP
-               sd = mkstemp (sm_tmpfil);
-#else
-               mktemp (sm_tmpfil);
-
-               if ((sd = creat (sm_tmpfil, 0600)) != NOTOK) {
-                   sm_ispool = 1;
-                   break;
-               }
-#endif
-           }
-
-       free (cp);
-       if (sd != NOTOK)
-           return sd;
-    }
-#endif /* MPOP */
-
     sm_ierror ("%s", response);
     return NOTOK;
 }
@@ -510,14 +450,6 @@ sm_winit (int mode, char *from)
 {
     char *smtpcom;
 
-#ifdef MPOP
-    if (sm_ispool && !sm_wfp) {
-       sm_reply.length = strlen (strcpy (sm_reply.text, "unable to create new spool file"));
-       sm_reply.code = NOTOK;
-       return RP_BHST;
-    }
-#endif /* MPOP */
-
     switch (mode) {
        case S_MAIL:
            smtpcom = "MAIL";
@@ -704,18 +636,6 @@ sm_end (int type)
            break;
     }
 
-#ifdef MPOP
-    if (sm_ispool) {
-       sm_ispool = 0;
-
-       if (sm_wfp) {
-           unlink (sm_tmpfil);
-           fclose (sm_wfp);
-           sm_wfp = NULL;
-       }
-    }
-#endif /* MPOP */
-
     if (sm_rfp != NULL) {
        alarm (SM_CLOS);
        fclose (sm_rfp);
@@ -730,8 +650,14 @@ sm_end (int type)
     if (sm_mts == MTS_SMTP) {
        status = 0;
 #ifdef CYRUS_SASL
-       if (conn)
+       if (conn) {
            sasl_dispose(&conn);
+           if (sasl_outbuffer) {
+               free(sasl_outbuffer);
+           }
+       }
+       if (sasl_inbuffer)
+           free(sasl_inbuffer);
 #endif /* CYRUS_SASL */
     } else {
        status = pidwait (sm_child, OK);
@@ -742,337 +668,18 @@ sm_end (int type)
     return (status ? RP_BHST : RP_OK);
 }
 
-
-#ifdef MPOP
-
-int
-sm_bulk (char *file)
-{
-    int        cc, i, j, k, result;
-    long pos;
-    char *dp, *bp, *cp, s;
-    char buffer[BUFSIZ], sender[BUFSIZ];
-    FILE *fp, *gp;
-
-    gp = NULL;
-    k = strlen (file) - sizeof(".bulk");
-    if ((fp = fopen (file, "r")) == NULL) {
-       return sm_perror("unable to read %s: ", file);
-    }
-    if (sm_debug) {
-       printf ("reading file %s\n", file);
-       fflush (stdout);
-    }
-
-    i = j = 0;
-    while (fgets (buffer, sizeof(buffer), fp)) {
-       if (j++ == 0)
-           strncpy (sender, buffer + sizeof("MAIL FROM:") - 1, sizeof(sender));
-       if (strcmp (buffer, "DATA\r\n") == 0) {
-           i = 1;
-           break;
-       }
-    }
-    if (i == 0) {
-       if (sm_debug) {
-           printf ("no DATA...\n");
-           fflush (stdout);
-       }
-losing0:
-       snprintf (buffer, sizeof(buffer), "%s.bad", file);
-       rename (file, buffer);
-       if (gp) {
-           snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
-           unlink (buffer);
-           fclose (gp);
-       }
-       fclose (fp);
-       return RP_OK;
-    }
-    if (j < 3) {
-       if (sm_debug) {
-           printf ("no %srecipients...\n", j < 1 ? "sender or " : "");
-           fflush (stdout);
-       }
-       goto losing0;
-    }
-
-    if ((cp = malloc ((size_t) (cc = (pos = ftell (fp)) + 1))) == NULL) {
-       sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
-losing1: ;
-       sm_reply.code = NOTOK;
-       fclose (fp);
-       return RP_BHST;
-    }
-    fseek (fp, 0L, SEEK_SET);
-    for (dp = cp, i = 0; i++ < j; dp += strlen (dp))
-       if (fgets (dp, cc - (dp - cp), fp) == NULL) {
-           sm_reply.length = strlen (strcpy (sm_reply.text, "premature eof"));
-losing2:
-           free (cp);
-           goto losing1;
-       }
-    *dp = NULL;
-
-    for (dp = cp, i = cc - 1; i > 0; dp += cc, i -= cc)
-       if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) {
-           int len;
-losing3:
-           sm_perror("error writing to server: ");
-           goto losing2;
-       }
-       else
-           if (sm_debug) {
-               printf ("wrote %d octets to server\n", cc);
-               fflush (stdout);
-           }
-
-    for (dp = cp, i = 0; i++ < j; dp = strchr(dp, '\n'), dp++) {
-       if (sm_debug) {
-           if (bp = strchr(dp, '\r'))
-               *bp = NULL;
-           printf ("=> %s\n", dp);
-           fflush (stdout);
-           if (bp)
-               *bp = '\r';
-       }
-
-       switch (smhear () + (i == 1 ? 1000 : i != j ? 2000 : 3000)) {
-           case 1000 + 250:
-               sm_addrs = 0;
-               result = RP_OK;
-               break;
-
-           case 1000 + 500: 
-           case 1000 + 501: 
-           case 1000 + 552: 
-           case 2000 + 500: 
-           case 2000 + 501:
-               result = RP_PARM;
-               smtalk (SM_RSET, "RSET");
-               free (cp);
-               goto losing0;
-
-           case 2000 + 250:
-           case 2000 + 251:
-               sm_addrs++;
-               result = RP_OK;
-               break;
-
-           case 2000 + 451: 
-#ifdef SENDMAILBUG
-               sm_addrs++;
-               result = RP_OK;
-               break;
-#endif
-           case 2000 + 421: 
-           case 2000 + 450: 
-           case 2000 + 452: 
-               result = RP_NO;
-               goto bad_addr;
-
-           case 2000 + 550: 
-           case 2000 + 551: 
-           case 2000 + 552: 
-           case 2000 + 553: 
-               result = RP_USER;
-bad_addr:
-               if (k <= 0 || strcmp (sender, "<>\r\n") == 0)
-                   break;
-               if (gp == NULL) {
-                   int     l;
-                   snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
-                   if ((gp = fopen (buffer, "w+")) == NULL)
-                       goto bad_data;
-                   fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
-                   l = strlen (sender);
-                   fprintf (gp,
-                            "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n",
-                            l - 4, l - 4, sender + 1, file);
-                   fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
-                            dtimenow (0), LocalName ());
-               }
-               if (bp = strchr(dp, '\r'))
-                   *bp = NULL;
-               fprintf (gp, "=>        %s\r\n", dp);
-               if (bp)
-                   *bp = '\r';
-               fprintf (gp, "<= %s\r\n", rp_string (result));
-               fflush (gp);
-               break;
-
-           case 3000 + 354: 
-#ifdef SENDMAILBUG
-ok_data:
-#endif
-               result = RP_OK;
-               break;
-
-           case 3000 + 451: 
-#ifdef SENDMAILBUG
-               goto ok_data;
-#endif
-           case 3000 + 421:
-               result = RP_NO;
-bad_data:
-               smtalk (SM_RSET, "RSET");
-               free (cp);
-               if (gp) {
-                   snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
-                   unlink (buffer);
-                   fclose (gp);
-               }
-               fclose (fp);
-               return result;
-
-           case 3000 + 500: 
-           case 3000 + 501: 
-           case 3000 + 503: 
-           case 3000 + 554: 
-               smtalk (SM_RSET, "RSET");
-               free (cp);
-               goto no_dice;
-
-           default:
-               result = RP_RPLY;
-               goto bad_data;
-       }
-    }
-    free (cp);
-
-    {
-#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
-       struct stat st;
-
-       if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ)
-           cc = BUFSIZ;
-#else
-       cc = BUFSIZ;
-#endif
-       if ((cp = malloc ((size_t) cc)) == NULL) {
-           smtalk (SM_RSET, "RSET");
-           sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
-           goto losing1;
-       }
-    }
-
-    fseek (fp, pos, SEEK_SET);
-    for (;;) {
-       int eof = 0;
-
-       for (dp = cp, i = cc; i > 0; dp += j, i -= j)
-           if ((j = fread (cp, sizeof(*cp), i, fp)) == OK) {
-               if (ferror (fp)) {
-                   sm_perror("error reading %s: ", file);
-                   goto losing2;
-               }
-               cc = dp - cp;
-               eof = 1;
-               break;
-           }
-
-       for (dp = cp, i = cc; i > 0; dp += j, i -= j)
-           if ((j = write (fileno (sm_wfp), dp, i)) == NOTOK)
-               goto losing3;
-           else
-               if (sm_debug) {
-                   printf ("wrote %d octets to server\n", j);
-                   fflush (stdout);
-               }
-
-       if (eof)
-           break;
-    }
-    free (cp);
-
-    switch (smhear ()) {
-       case 250: 
-       case 251: 
-#ifdef SENDMAILBUG
-ok_dot:
-#endif
-           result = RP_OK;
-           unlink (file);
-           break;
-
-       case 451: 
-#ifdef SENDMAILBUG
-           goto ok_dot;
-#endif
-       case 452: 
-       default: 
-           result = RP_NO;
-           if (gp) {
-               snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
-               unlink (buffer);
-               fclose (gp);
-               gp = NULL;
-           }
-           break;
-
-       case 552: 
-       case 554: 
-no_dice:
-           result = RP_NDEL;
-           if (k <= 0 || strcmp (sender, "<>\r\n") == 0) {
-               unlink (file);
-               break;
-           }
-           if (gp) {
-               fflush (gp);
-               ftruncate (fileno (gp), 0L);
-               fseek (gp, 0L, SEEK_SET);
-           }
-           else {
-               snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
-               if ((gp = fopen (buffer, "w")) == NULL)
-                   break;
-           }
-           fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
-           i = strlen (sender);
-           fprintf (gp, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n",
-                    i - 4, i - 4, sender + 1, file);
-            fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
-                    dtimenow (0), LocalName ());
-           break;
-    }
-
-    if (gp) {
-       fputs ("\r\n------- Begin Returned message\r\n\r\n", gp);
-       fseek (fp, pos, SEEK_SET);
-       while (fgets (buffer, sizeof(buffer), fp)) {
-           if (buffer[0] == '-')
-               fputs ("- ", gp);
-           if (strcmp (buffer, ".\r\n"))
-               fputs (buffer, gp);
-       }
-       fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp);
-       fflush (gp);
-       if (!ferror (gp))
-           unlink (file);
-       fclose (gp);
-    }
-    fclose (fp);
-
-    return result;
-}
-#endif /* MPOP */
-
-
 #ifdef CYRUS_SASL
 /*
  * This function implements SASL authentication for SMTP.  If this function
  * completes successfully, then authentication is successful and we've
  * (optionally) negotiated a security layer.
- *
- * Right now we don't support session encryption.
  */
 static int
-sm_auth_sasl(char *user, char *mechlist, char *host)
+sm_auth_sasl(char *user, char *mechlist, char *inhost)
 {
     int result, status;
     unsigned int buflen, outlen;
-    char *buf, outbuf[BUFSIZ];
+    char *buf, outbuf[BUFSIZ], host[NI_MAXHOST];
     const char *chosen_mech;
     sasl_security_properties_t secprops;
     sasl_ssf_t *ssf;
@@ -1094,10 +701,12 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
      * reverse-address lookup on the IP address to get the name.
      */
 
-    if (!host) {
-       struct sockaddr_in sin;
-       int len = sizeof(sin);
-       struct hostent *hp;
+    memset(host, 0, sizeof(host));
+
+    if (!inhost) {
+       struct sockaddr_storage sin;
+       socklen_t len = sizeof(sin);
+       int result;
 
        if (getpeername(fileno(sm_wfp), (struct sockaddr *) &sin, &len) < 0) {
            sm_ierror("getpeername on SMTP socket failed: %s",
@@ -1105,14 +714,15 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
            return NOTOK;
        }
 
-       if ((hp = gethostbyaddr((void *) &sin.sin_addr, sizeof(sin.sin_addr),
-                               sin.sin_family)) == NULL) {
-           sm_ierror("DNS lookup on IP address %s failed",
-                     inet_ntoa(sin.sin_addr));
+       result = getnameinfo((struct sockaddr *) &sin, len, host, sizeof(host),
+                            NULL, 0, NI_NAMEREQD);
+       if (result != 0) {
+           sm_ierror("Unable to look up name of connected host: %s",
+                     gai_strerror(result));
            return NOTOK;
        }
-
-       host = strdup(hp->h_name);
+    } else {
+       strncpy(host, inhost, sizeof(host) - 1);
     }
 
     sasl_pw_context[0] = host;
@@ -1141,8 +751,8 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
      */
 
     memset(&secprops, 0, sizeof(secprops));
-    secprops.maxbufsize = BUFSIZ;
-    secprops.max_ssf = 0;      /* XXX change this when we do encryption */
+    secprops.maxbufsize = SASL_MAXRECVBUF;
+    secprops.max_ssf = UINT_MAX;
 
     result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
 
@@ -1161,8 +771,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
                               &buflen, (const char **) &chosen_mech);
 
     if (result != SASL_OK && result != SASL_CONTINUE) {
-       sm_ierror("SASL client start failed: %s",
-                 sasl_errstring(result, NULL, NULL));
+       sm_ierror("SASL client start failed: %s", sasl_errdetail(conn));
        return NOTOK;
     }
 
@@ -1279,8 +888,30 @@ sm_auth_sasl(char *user, char *mechlist, char *host)
        return NOTOK;
     }
 
-    if (maxoutbuf == 0 || maxoutbuf > BUFSIZ)
-       maxoutbuf = BUFSIZ;
+    if (sasl_ssf > 0) {
+       sasl_outbuffer = malloc(maxoutbuf);
+
+       if (sasl_outbuffer == NULL) {
+               sm_ierror("Unable to allocate %d bytes for SASL output "
+                         "buffer", maxoutbuf);
+               return NOTOK;
+       }
+       sasl_outbuflen = 0;
+
+       sasl_inbuffer = malloc(SASL_MAXRECVBUF);
+
+       if (sasl_inbuffer == NULL) {
+               sm_ierror("Unable to allocate %d bytes for SASL input "
+                         "buffer", SASL_MAXRECVBUF);
+               free(sasl_outbuffer);
+               return NOTOK;
+       }
+       sasl_inbuflen = 0;
+       sasl_inptr = sasl_inbuffer;
+    } else {
+       sasl_outbuffer = NULL;
+       sasl_inbuffer = NULL;
+    }
 
     sasl_complete = 1;
 
@@ -1351,37 +982,6 @@ sm_ierror (char *fmt, ...)
     return RP_BHST;
 }
 
-#ifdef MPOP
-static int
-sm_perror (char *fmt, ...)
-{
-    /* Fill in sm_reply with a suitable error string based on errno.
-     * This isn't particularly MPOP specific, it just happens that that's
-     * the only code that uses it currently.
-     */
-    char *bp, *s;
-    int len, eno = errno;
-
-    va_list ap;
-    va_start(ap,fmt);
-    vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap);
-    va_end(ap);
-
-    bp = sm_reply.text;
-    len = strlen(bp);
-    bp += len;
-    if ((s = strerror(eno)))
-       snprintf(bp, sizeof(sm_reply.text) - len, "%s", s);
-    else
-       snprintf(bp, sizeof(sm_reply.text) - len, "unknown error %d", eno);
-    
-    sm_reply.length = strlen (sm_reply.text);
-    sm_reply.code = NOTOK;
-
-    return RP_BHST;
-}
-#endif
-
 static int
 smtalk (int time, char *fmt, ...)
 {
@@ -1394,69 +994,14 @@ smtalk (int time, char *fmt, ...)
     va_end(ap);
 
     if (sm_debug) {
+#ifdef CYRUS_SASL
+       if (sasl_ssf)
+               printf("(encrypted) ");
+#endif /* CYRUS_SASL */
        printf ("=> %s\n", buffer);
        fflush (stdout);
     }
 
-#ifdef MPOP
-    if (sm_ispool) {
-       char file[BUFSIZ];
-
-       if (strcmp (buffer, ".") == 0)
-           time = SM_DOT;
-       fprintf (sm_wfp, "%s\r\n", buffer);
-       switch (time) {
-           case SM_DOT:
-               fflush (sm_wfp);
-               if (ferror (sm_wfp))
-                   return sm_werror ();
-               snprintf (file, sizeof(file), "%s%c.bulk", sm_tmpfil,
-                               (char) (sm_ispool + 'a' - 1));
-               if (rename (sm_tmpfil, file) == NOTOK) {
-                   return sm_perror("error renaming %s to %s: ", sm_tmpfil, file);
-               }
-               fclose (sm_wfp);
-               if (sm_wfp = fopen (sm_tmpfil, "w"))
-                   chmod (sm_tmpfil, 0600);
-               sm_ispool++;
-               /* and fall... */
-
-           case SM_MAIL:
-           case SM_RCPT:
-               result = 250;
-               break;
-
-           case SM_RSET:
-               fflush (sm_wfp);
-               ftruncate (fileno (sm_wfp), 0L);
-               fseek (sm_wfp, 0L, SEEK_SET);
-               result = 250;
-               break;
-
-           case SM_DATA:
-               result = 354;
-               break;
-
-           case SM_QUIT:
-               unlink (sm_tmpfil);
-               sm_ispool = 0;
-               result = 221;
-               break;
-
-           default:
-               result = 500;
-               break;
-       }
-       if (sm_debug) {
-           printf ("<= %d\n", result);
-           fflush (stdout);
-       }
-
-       sm_reply.text[sm_reply.length = 0] = NULL;
-       return (sm_reply.code = result);
-    }
-#endif /* MPOP */
-
     sm_alarmed = 0;
     alarm ((unsigned) time);
     if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
@@ -1477,9 +1022,9 @@ sm_wrecord (char *buffer, int len)
     if (sm_wfp == NULL)
        return sm_werror ();
 
-    fwrite (buffer, sizeof(*buffer), len, sm_wfp);
-    fputs ("\r\n", sm_wfp);
-    fflush (sm_wfp);
+    sm_fwrite (buffer, len);
+    sm_fputs ("\r\n");
+    sm_fflush ();
 
     return (ferror (sm_wfp) ? sm_werror () : OK);
 }
@@ -1496,7 +1041,7 @@ sm_wstream (char *buffer, int len)
 
     if (buffer == NULL && len == 0) {
        if (lc != '\n')
-           fputs ("\r\n", sm_wfp);
+           sm_fputs ("\r\n");
        lc = '\0';
        return (ferror (sm_wfp) ? sm_werror () : OK);
     }
@@ -1505,16 +1050,16 @@ sm_wstream (char *buffer, int len)
        switch (*bp) {
            case '\n': 
                sm_nl = TRUE;
-               fputc ('\r', sm_wfp);
+               sm_fputc ('\r');
                break;
 
            case '.': 
                if (sm_nl)
-                   fputc ('.', sm_wfp);/* FALL THROUGH */
+                   sm_fputc ('.');/* FALL THROUGH */
            default: 
                sm_nl = FALSE;
        }
-       fputc (*bp, sm_wfp);
+       sm_fputc (*bp);
        if (ferror (sm_wfp))
            return sm_werror ();
     }
@@ -1524,18 +1069,93 @@ sm_wstream (char *buffer, int len)
     return (ferror (sm_wfp) ? sm_werror () : OK);
 }
 
+/*
+ * Write out to the network, but do buffering for SASL (if enabled)
+ */
+
+static int
+sm_fwrite(char *buffer, int len)
+{
+#ifdef CYRUS_SASL
+    const char *output;
+    unsigned int outputlen;
+
+    if (sasl_complete == 0 || sasl_ssf == 0)
+#endif /* CYRUS_SASL */
+       fwrite(buffer, sizeof(*buffer), len, sm_wfp);
+#ifdef CYRUS_SASL
+    else {
+       while (len >= maxoutbuf - sasl_outbuflen) {
+           memcpy(sasl_outbuffer + sasl_outbuflen, buffer,
+                  maxoutbuf - sasl_outbuflen);
+           len -= maxoutbuf - sasl_outbuflen;
+           sasl_outbuflen = 0;
+
+           if (sasl_encode(conn, sasl_outbuffer, maxoutbuf,
+                           &output, &outputlen) != SASL_OK) {
+               sm_ierror("Unable to SASL encode connection data: %s",
+                         sasl_errdetail(conn));
+               return NOTOK;
+           }
+
+           fwrite(output, sizeof(*output), outputlen, sm_wfp);
+       }
+
+       if (len > 0) {
+           memcpy(sasl_outbuffer + sasl_outbuflen, buffer, len);
+           sasl_outbuflen += len;
+       }
+    }
+#endif /* CYRUS_SASL */
+    return ferror(sm_wfp) ? NOTOK : RP_OK;
+}
 
 /*
- * On some systems, strlen and strcpy are defined as preprocessor macros.  This
- * causes compile problems with the #ifdef MPOP in the middle.  Should the
- * #ifdef MPOP be removed, remove these #undefs.
+ * Convenience functions to replace occurences of fputs() and fputc()
  */
-#ifdef strlen
-# undef strlen
-#endif
-#ifdef strcpy
-# undef strcpy
-#endif
+
+static int
+sm_fputs(char *buffer)
+{
+    return sm_fwrite(buffer, strlen(buffer));
+}
+
+static int
+sm_fputc(int c)
+{
+    char h = c;
+
+    return sm_fwrite(&h, 1);
+}
+
+/*
+ * Flush out any pending data on the connection
+ */
+
+static void
+sm_fflush(void)
+{
+#ifdef CYRUS_SASL
+    const char *output;
+    unsigned int outputlen;
+    int result;
+
+    if (sasl_complete == 1 && sasl_ssf > 0 && sasl_outbuflen > 0) {
+       result = sasl_encode(conn, sasl_outbuffer, sasl_outbuflen,
+                            &output, &outputlen);
+       if (result != SASL_OK) {
+           sm_ierror("Unable to SASL encode connection data: %s",
+                     sasl_errdetail(conn));
+           return;
+       }
+
+       fwrite(output, sizeof(*output), outputlen, sm_wfp);
+       sasl_outbuflen = 0;
+    }
+#endif /* CYRUS_SASL */
+
+    fflush(sm_wfp);
+}
 
 static int
 sm_werror (void)
@@ -1543,9 +1163,6 @@ sm_werror (void)
     sm_reply.length =
        strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
            : sm_alarmed ? "write to socket timed out"
-#ifdef MPOP
-           : sm_ispool ? "error writing to spool file"
-#endif
            : "error writing to socket"));
 
     return (sm_reply.code = NOTOK);
@@ -1585,8 +1202,13 @@ again: ;
     rp = sm_reply.text;
     rc = sizeof(sm_reply.text) - 1;
 
-    for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
+    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 ("<= %s\n", buffer);
            fflush (stdout);
        }
@@ -1613,7 +1235,7 @@ again: ;
            continue;
 
        cont = FALSE;
-       code = atoi (bp);
+       code = atoi ((char *) bp);
        bp += 3, bc -= 3;
        for (; bc > 0 && isspace (*bp); bp++, bc--)
            continue;
@@ -1634,7 +1256,7 @@ again: ;
            if (bc <= 0) {
                /* can never fail to 0-terminate because of size of buffer vs fixed string */
                strncpy (buffer, sm_noreply, sizeof(buffer));
-               bp = buffer;
+               bp = (unsigned char *) buffer;
                bc = strlen (sm_noreply);
            }
        }
@@ -1671,18 +1293,22 @@ again: ;
 static int
 sm_rrecord (char *buffer, int *len)
 {
+    int retval;
+
     if (sm_rfp == NULL)
-       return sm_rerror ();
+       return sm_rerror(0);
 
     buffer[*len = 0] = 0;
 
-    fgets (buffer, BUFSIZ, sm_rfp);
+    if ((retval = sm_fgets (buffer, BUFSIZ, sm_rfp)) != RP_OK)
+       return retval;
     *len = strlen (buffer);
     /* *len should be >0 except on EOF, but check for safety's sake */
-    if (ferror (sm_rfp) || feof (sm_rfp) || (*len == 0))
-       return sm_rerror ();
+    if (*len == 0)
+       return sm_rerror (RP_EOF);
     if (buffer[*len - 1] != '\n')
-       while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
+       while ((retval = sm_fgetc (sm_rfp)) != '\n' && retval != EOF &&
+              retval != -2)
            continue;
     else
        if ((*len > 1) && (buffer[*len - 2] == '\r'))
@@ -1693,21 +1319,118 @@ sm_rrecord (char *buffer, int *len)
     return OK;
 }
 
+/*
+ * Our version of fgets, which calls our private fgetc function
+ */
+
+static int
+sm_fgets(char *buffer, int size, FILE *f)
+{
+    int c;
+
+     do {
+       c = sm_fgetc(f);
+
+       if (c == EOF)
+           return RP_EOF;
+
+       if (c == -2)
+           return NOTOK;
+
+       *buffer++ = c;
+     } while (size > 1 && c != '\n');
+
+     *buffer = '\0';
+
+     return RP_OK;
+}
+
+
+#ifdef CYRUS_SASL
+/*
+ * Read from the network, but do SASL encryption
+ */
 
 static int
-sm_rerror (void)
+sm_fgetc(FILE *f)
+{
+    char tmpbuf[BUFSIZ], *retbuf;
+    unsigned int retbufsize = 0;
+    int cc, result;
+
+    /*
+     * If we have leftover data, return it
+     */
+
+    if (sasl_inbuflen) {
+       sasl_inbuflen--;
+       return (int) *sasl_inptr++;
+    }
+
+    /*
+     * If not, read from the network until we have some data to return
+     */
+
+    while (retbufsize == 0) {
+
+       cc = read(fileno(f), tmpbuf, sizeof(tmpbuf));
+
+       if (cc == 0)
+           return EOF;
+
+       if (cc < 0) {
+           sm_ierror("Unable to read from network: %s", strerror(errno));
+           return -2;
+       }
+
+       /*
+        * Don't call sasl_decode unless sasl is complete and we have
+        * encryption working
+        */
+
+       if (sasl_complete == 0 || sasl_ssf == 0) {
+           retbuf = tmpbuf;
+           retbufsize = cc;
+       } else {
+           result = sasl_decode(conn, tmpbuf, cc, (const char **) &retbuf,
+                                &retbufsize);
+
+           if (result != SASL_OK) {
+               sm_ierror("Unable to decode SASL network data: %s",
+                         sasl_errdetail(conn));
+               return -2;
+           }
+       }
+    }
+
+    if (retbufsize > SASL_MAXRECVBUF) {
+       sm_ierror("Received data (%d bytes) is larger than the buffer "
+                 "size (%d bytes)", retbufsize, SASL_MAXRECVBUF);
+       return -2;
+    }
+
+    memcpy(sasl_inbuffer, retbuf, retbufsize);
+    sasl_inptr = sasl_inbuffer + 1;
+    sasl_inbuflen = retbufsize - 1;
+
+    return (int) sasl_inbuffer[0];
+}
+#endif /* CYRUS_SASL */
+
+static int
+sm_rerror (int rc)
 {
     if (sm_mts == MTS_SMTP)
        sm_reply.length =
            strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
                : sm_alarmed ? "read from socket timed out"
-               : feof (sm_rfp) ? "premature end-of-file on socket"
+               : rc == RP_EOF ? "premature end-of-file on socket"
                : "error reading from socket"));
     else
        sm_reply.length =
            strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
                : sm_alarmed ? "read from pipe timed out"
-               : feof (sm_rfp) ? "premature end-of-file on pipe"
+               : rc == RP_EOF ? "premature end-of-file on pipe"
                : "error reading from pipe"));
 
     return (sm_reply.code = NOTOK);
@@ -1780,70 +1503,6 @@ rp_string (int code)
     return buffer;
 }
 
-
-#ifdef MPOP
-
-static char *broken[MAXARGS + 1];
-
-static char **
-smail_brkstring (char *strg, char *brksep, char *brkterm)
-{
-    int bi;
-    char c, *sp;
-
-    sp = strg;
-
-    for (bi = 0; bi < MAXARGS; bi++) {
-       while (smail_brkany (c = *sp, brksep))
-           *sp++ = 0;
-       if (!c || smail_brkany (c, brkterm)) {
-           *sp = 0;
-           broken[bi] = 0;
-           return broken;
-       }
-
-       broken[bi] = sp;
-       while ((c = *++sp) && !smail_brkany (c, brksep) && !smail_brkany (c, brkterm))
-           continue;
-    }
-    broken[MAXARGS] = 0;
-
-    return broken;
-}
-
-
-/*
- * returns 1 if chr in strg, 0 otherwise
- */
-static int
-smail_brkany (char chr, char *strg)
-{
-    char *sp;
-    if (strg)
-       for (sp = strg; *sp; sp++)
-           if (chr == *sp)
-               return 1;
-    return 0;
-}
-
-/*
- * copy a string array and return pointer to end
- */
-char **
-smail_copyip (char **p, char **q, int len_q)
-{
-    while (*p && --len_q > 0)
-       *q++ = *p++;
-
-    *q = NULL;
-    return q;
-}
-
-#endif /* MPOP */
-
-
 static char *
 EHLOset (char *s)
 {
index 73eb5de..4fdcdfe 100644 (file)
@@ -24,7 +24,7 @@ struct smtp {
  * prototypes
  */
 /* int client (); */
-int sm_init (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 sm_winit (int, char *);
 int sm_wadr (char *, char *, char *);
 int sm_waend (void);
@@ -33,11 +33,6 @@ int sm_wtend (void);
 int sm_end (int);
 char *rp_string (int);
 
-#ifdef MPOP
-int sm_bulk (char *);
-#endif
-
-
 /* The remainder of this file is derived from "mmdf.h" */
 
 /*
index 0d0454c..ae6968f 100644 (file)
 # include <arpa/inet.h>
 #endif
 
-#ifdef HESIOD
-# include <hesiod.h>
-#endif
-
-#ifdef KPOP
-# include <krb.h>
-# include <ctype.h>
-#endif /* KPOP */
-
 #define        TRUE         1
 #define        FALSE        0
 
-#define        OOPS1      (-2)
-#define        OOPS2      (-3)
-
 #define        MAXARGS   1000
-#define        MAXNETS      5
-#define        MAXHOSTS    25
-
-struct addrent {
-    int a_addrtype;            /* assumes AF_INET for inet_netof () */
-    union {
-       int un_net;
-       char un_addr[14];
-    } un;
-};
-
-#define        a_net  un.un_net
-#define        a_addr un.un_addr
-
-static struct addrent *n1, *n2;
-static struct addrent nets[MAXNETS];
-static struct addrent *h1, *h2;
-static struct addrent hosts[MAXHOSTS];
-
-#ifdef KPOP
-static CREDENTIALS cred;
-static MSG_DAT msg_data;
-static KTEXT ticket = (KTEXT) NULL;
-static Key_schedule schedule;
-static char *kservice;                 /* "pop" if using kpop */
-char krb_realm[REALM_SZ];
-char *PrincipalHostname();
-#endif /* KPOP */
-
-#if !defined(h_addr)
-# define h_addr h_addr_list[0]
-#endif
-
-#define        inaddr_copy(hp,sin) \
-    memcpy(&((sin)->sin_addr), (hp)->h_addr, (hp)->h_length)
 
 /*
  * static prototypes
  */
-static int rcaux (struct servent *, struct hostent *, int, char *, int);
-static int getport (int, int, char *, int);
-static int inet (struct hostent *, int);
-struct hostent *gethostbystring (char *s);
 
 /* 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 char *client_getcpy (char *);
+static void client_freelist(char **);
 
 
 int
-client (char *args, char *protocol, char *service, int rproto,
-               char *response, int len_response)
+client (char *args, char *service, char *response, int len_response, int debug)
 {
-    int sd;
-    register char **ap;
-    char *arguments[MAXARGS];
-    register struct hostent *hp;
-    register struct servent *sp;
-#ifndef        HAVE_GETHOSTBYNAME
-    register struct netent *np;
-#endif
-
-#ifdef KPOP
-    char *cp;
-
-    kservice = service;
-    if (cp = strchr (service, '/')) {  /* "pop/kpop" */
-       *cp++ = '\0';           /* kservice = "pop" */
-       service = cp;           /* service  = "kpop" */
-    } else {
-       kservice = NULL;        /* not using KERBEROS */
-    }
-#endif /* KPOP */
-    
-
-    if ((sp = getservbyname (service, protocol)) == NULL) {
-#ifdef HESIOD
-       if ((sp = hes_getservbyname (service, protocol)) == NULL) {
-           snprintf (response, len_response, "%s/%s: unknown service", protocol, service);
-           return NOTOK;
-       }
-#else
-       snprintf (response, len_response, "%s/%s: unknown service", protocol, service);
-       return NOTOK;
-#endif
-    }
+    int sd, rc;
+    char **ap, *arguments[MAXARGS];
+    struct addrinfo hints, *res, *ai;
 
     ap = arguments;
     if (args != NULL && *args != 0) {
@@ -140,267 +59,76 @@ client (char *args, char *protocol, char *service, int rproto,
        *ap = NULL;
     }
 
-    n1 = nets;
-    n2 = nets + sizeof(nets) / sizeof(nets[0]);
-
-    h1 = hosts;
-    h2 = hosts + sizeof(hosts) / sizeof(hosts[0]);
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG;
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
 
     for (ap = arguments; *ap; ap++) {
-       if (**ap == '\01') {
-/*
- * the assumption here is that if the system doesn't have a
- * gethostbyname() function, it must not use DNS. So we need to look
- * into the /etc/hosts using gethostent(). There probablly aren't any
- * systems still like this, but you never know. On every system I have
- * access to, this section is ignored.
- */
-#ifndef        HAVE_GETHOSTBYNAME
-           if ((np = getnetbyname (*ap + 1))) {
-#ifdef HAVE_SETHOSTENT
-               sethostent (1);
-#endif /* HAVE_SETHOSTENT */
-               while ((hp = gethostent()))
-                   if (np->n_addrtype == hp->h_addrtype
-                           && inet (hp, np->n_net)) {
-                       switch (sd = rcaux (sp, hp, rproto, response, len_response)) {
-                           case NOTOK: 
-                               continue;
-                           case OOPS1: 
-                               break;
-                           case OOPS2: 
-                               return NOTOK;
-
-                           default: 
-                               return sd;
-                       }
-                       break;
-                   }
-           }
-#endif /* don't HAVE_GETHOSTBYNAME */
-           continue;
+
+       if (debug) {
+           fprintf(stderr, "Trying to connect to \"%s\" ...\n", *ap);
        }
 
-       if ((hp = gethostbystring (*ap))) {
-           switch (sd = rcaux (sp, hp, rproto, response, len_response)) {
-               case NOTOK: 
-               case OOPS1: 
-                   break;
-               case OOPS2: 
-                   return NOTOK;
+       rc = getaddrinfo(*ap, service, &hints, &res);
 
-               default: 
-                   return sd;
+       if (rc) {
+           if (debug) {
+               fprintf(stderr, "Lookup of \"%s\" failed: %s\n", *ap,
+                       gai_strerror(rc));
            }
            continue;
        }
-    }
 
-    strncpy (response, "no servers available", len_response);
-    return NOTOK;
-}
-
-
-static int
-rcaux (struct servent *sp, struct hostent *hp, int rproto,
-               char *response, int len_response)
-{
-    int sd;
-    struct in_addr in;
-    register struct addrent *ap;
-    struct sockaddr_in in_socket;
-    register struct sockaddr_in *isock = &in_socket;
-
-#ifdef KPOP
-    int rem;
-    struct hostent *hp2;
-#endif /* KPOP */
-
-    for (ap = nets; ap < n1; ap++)
-       if (ap->a_addrtype == hp->h_addrtype && inet (hp, ap->a_net))
-           return NOTOK;
-
-    for (ap = hosts; ap < h1; ap++)
-       if (ap->a_addrtype == hp->h_addrtype
-               && memcmp(ap->a_addr, hp->h_addr, hp->h_length) == 0)
-           return NOTOK;
-
-    if ((sd = getport (rproto, hp->h_addrtype, response, len_response)) == NOTOK)
-       return OOPS2;
-
-    memset (isock, 0, sizeof(*isock));
-    isock->sin_family = hp->h_addrtype;
-    inaddr_copy (hp, isock);
-    isock->sin_port = sp->s_port;
-
-    if (connect (sd, (struct sockaddr *) isock, sizeof(*isock)) == NOTOK)
-       switch (errno) {
-           case ENETDOWN: 
-           case ENETUNREACH: 
-               close (sd);
-               if (n1 < n2) {
-                   n1->a_addrtype = hp->h_addrtype;
-                   memcpy(&in, hp->h_addr, sizeof(in));
-                   n1->a_net = inet_netof (in);
-                   n1++;
-               }
-               return OOPS1;
-
-           case ETIMEDOUT: 
-           case ECONNREFUSED: 
-           default: 
-               close (sd);
-               if (h1 < h2) {
-                   h1->a_addrtype = hp->h_addrtype;
-                   memcpy(h1->a_addr, hp->h_addr, hp->h_length);
-                   h1++;
-               }
-               return NOTOK;
-       }
+       for (ai = res; ai != NULL; ai = ai->ai_next) {
+           if (debug) {
+               char address[NI_MAXHOST];
 
-#ifdef KPOP
-    if (kservice) {    /* "pop" */
-       char *instance;
+               rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
+                                sizeof(address), NULL, NULL, NI_NUMERICHOST);
 
-       if (( hp2 = gethostbyaddr( hp->h_addr, hp->h_length, hp->h_addrtype ))
-               == NULL ) {
-           return NOTOK;
-       }
-       if ((instance = strdup (hp2->h_name)) == NULL) {
-           close (sd);
-           strncpy (response, "Out of memory.", len_response);
-           return OOPS2;
-       }
-       ticket = (KTEXT) mh_xmalloc (sizeof(KTEXT_ST));
-       rem = krb_sendauth (0L, sd, ticket, kservice, instance,
-                          (char *) krb_realmofhost (instance),
-                          (unsigned long) 0, &msg_data, &cred, schedule,
-                          (struct sockaddr_in *) NULL,
-                          (struct sockaddr_in *) NULL,
-                          "KPOPV0.1");
-       free (instance);
-       if (rem != KSUCCESS) {
-           close (sd);
-           strncpy (response, "Post office refused connection: ", len_response);
-           strncat (response, krb_err_txt[rem], len_response - strlen(response));
-           return OOPS2;
-       }
-    }
-#endif /* KPOP */
+               fprintf(stderr, "Connecting to %s...\n",
+                       rc ? "unknown" : address);
+           }
 
-    return sd;
-}
+           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;
+           }
 
-static int
-getport (int rproto, int addrtype, char *response, int len_response)
-{
-    int sd, port;
-    struct sockaddr_in in_socket, *isock;
-
-    isock = &in_socket;
-    if (rproto && addrtype != AF_INET) {
-       snprintf (response, len_response, "reserved ports not supported for af=%d", addrtype);
-       errno = ENOPROTOOPT;
-       return NOTOK;
-    }
+           if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
+               freeaddrinfo(res);
+               client_freelist(ap);
+               return sd;
+           }
 
-    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK) {
-       char *s;
+           if (debug) {
+               fprintf(stderr, "Connection failed: %s\n", strerror(errno));
+           }
 
-       if ((s = strerror (errno)))
-           snprintf (response, len_response, "unable to create socket: %s", s);
-       else
-           snprintf (response, len_response, "unable to create socket: unknown error");
-       return NOTOK;
-    }
-#ifdef KPOP
-    if (kservice)      /* "pop" */
-       return(sd);
-#endif /* KPOP */
-    if (!rproto)
-       return sd;
-
-    memset(isock, 0, sizeof(*isock));
-    isock->sin_family = addrtype;
-    for (port = IPPORT_RESERVED - 1;;) {
-       isock->sin_port = htons ((unsigned short) port);
-       if (bind (sd, (struct sockaddr *) isock, sizeof(*isock)) != NOTOK)
-           return sd;
-
-       switch (errno) {
-           char *s;
-
-           case EADDRINUSE: 
-           case EADDRNOTAVAIL: 
-               if (--port <= IPPORT_RESERVED / 2) {
-                   strncpy (response, "ports available", len_response);
-                   return NOTOK;
-               }
-               break;
-
-           default: 
-               if ((s = strerror (errno)))
-                   snprintf (response, len_response, "unable to bind socket: %s", s);
-               else
-                   snprintf (response, len_response, "unable to bind socket: unknown error");
-               return NOTOK;
+           close(sd);
        }
     }
-}
 
-
-static int
-inet (struct hostent *hp, int net)
-{
-    struct in_addr in;
-
-    memcpy(&in, hp->h_addr, sizeof(in));
-    return (inet_netof (in) == net);
+    freeaddrinfo(res);
+    client_freelist(ap);
+    strncpy (response, "no servers available", len_response);
+    return NOTOK;
 }
 
 
 /*
- * taken from ISODE's compat/internet.c
+ * Free a list of strings
  */
 
-static char *empty = NULL;
-
-#ifdef h_addr
-static char *addrs[2] = { NULL };
-#endif
-
-struct hostent *
-gethostbystring (char *s)
+static void
+client_freelist(char **list)
 {
-    register struct hostent *h;
-    static struct hostent hs;
-#ifdef DG
-    static struct in_addr iaddr;
-#else
-    static unsigned long iaddr;
-#endif
-
-    iaddr = inet_addr (s);
-#ifdef DG
-    if (iaddr.s_addr == NOTOK && strcmp (s, "255.255.255.255"))
-#else
-    if (((int) iaddr == NOTOK) && strcmp (s, "255.255.255.255"))
-#endif
-       return gethostbyname (s);
-
-    h = &hs;
-    h->h_name = s;
-    h->h_aliases = &empty;
-    h->h_addrtype = AF_INET;
-    h->h_length = sizeof(iaddr);
-#ifdef h_addr
-    h->h_addr_list = addrs;
-    memset(addrs, 0, sizeof(addrs));
-#endif
-    h->h_addr = (char *) &iaddr;
-
-    return h;
+    while (*list++ != NULL)
+       free(*list);
 }
 
 
index cc5ff8e..de7518c 100644 (file)
--- a/sbr/mts.c
+++ b/sbr/mts.c
@@ -287,8 +287,7 @@ char *
 LocalName (void)
 {
     static char buffer[BUFSIZ] = "";
-    struct hostent *hp;
-
+    struct addrinfo hints, *res;
 #ifdef HAVE_UNAME
     struct utsname name;
 #endif
@@ -303,20 +302,24 @@ LocalName (void)
     if (*localname) {
        strncpy (buffer, localname, sizeof(buffer));
     } else {
+       memset(buffer, 0, sizeof(buffer));
 #ifdef HAVE_UNAME
        /* first get our local name */
        uname (&name);
-       strncpy (buffer, name.nodename, sizeof(buffer));
+       strncpy (buffer, name.nodename, sizeof(buffer) - 1);
 #else
        /* first get our local name */
-       gethostname (buffer, sizeof(buffer));
+       gethostname (buffer, sizeof(buffer) - 1);
 #endif
-#ifdef HAVE_SETHOSTENT
-       sethostent (1);
-#endif 
        /* now fully qualify our name */
-       if ((hp = gethostbyname (buffer)))
-           strncpy (buffer, hp->h_name, sizeof(buffer));
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_CANONNAME;
+       hints.ai_family = PF_UNSPEC;
+       if (getaddrinfo(buffer, NULL, &hints, &res) == 0) {
+           strncpy(buffer, res->ai_canonname, sizeof(buffer) - 1);
+           freeaddrinfo(res);
+       }
     }
 
     /*
index 5b079ba..2fc3fb7 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * ftpsbr.c -- simple FTP client library
  *
@@ -33,23 +32,15 @@ extern int v_verbose;
 #include <netdb.h>
 #include <errno.h>
 
-#if !defined(h_addr)
-# define h_addr        h_addr_list[0]
-#endif
-
-#define        inaddr_copy(hp,sin) \
-    memcpy((char *) &((sin)->sin_addr), (hp)->h_addr, (hp)->h_length)
-
-#define        start_tcp_client(sock,priv) \
-       socket (AF_INET, SOCK_STREAM, 0)
+#define        start_tcp_client(res) \
+       socket (res->ai_family, res->ai_socktype, res->ai_protocol)
 
-#define        join_tcp_server(fd, sock) \
-       connect ((fd), (struct sockaddr *) (sock), sizeof *(sock))
+#define        join_tcp_server(fd, sock, len) \
+       connect ((fd), (struct sockaddr *) (sock), len)
 
 /*
  * prototypes
  */
-struct hostent *gethostbystring ();
 int ftp_get (char *, char *, char *, char *, char *, char *, int, int);
 int ftp_trans (char *, char *, char *, char *, char *, char *, char *, int, int);
 
@@ -157,32 +148,32 @@ ftp_trans (char *host, char *user, char *password, char *cwd, char *remote,
     }
 
     if (ftp_fd == NOTOK) {
-       struct sockaddr_in in_socket;
-       register struct hostent *hp;
-       register struct servent *sp;
+       struct addrinfo hints, *res;
 
-       if ((sp = getservbyname ("ftp", "tcp")) == NULL) {
-           fprintf (stderr, "tcp/ftp: unknown service");
-           return NOTOK;
-       }
-       if ((hp = gethostbystring (host)) == NULL) {
-           fprintf (stderr, "%s: unknown host\n", host);
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_ADDRCONFIG;
+       hints.ai_family = PF_INET;
+       hints.ai_socktype = SOCK_STREAM;
+
+       result = getaddrinfo(host, "ftp", &hints, &res);
+
+       if (result) {
+           fprintf(stderr, "%s/ftp: %s\n", host, gai_strerror(result));
            return NOTOK;
        }
-       in_socket.sin_family = hp->h_addrtype;
-       inaddr_copy (hp, &in_socket);
-       in_socket.sin_port = sp->s_port;
 
-       if ((ftp_fd = start_tcp_client ((struct sockaddr_in *) NULL, 0))
-               == NOTOK) {
+       if ((ftp_fd = start_tcp_client (res)) == NOTOK) {
            perror (host);
+           freeaddrinfo(res);
            return NOTOK;
        }
-       if (join_tcp_server (ftp_fd, &in_socket) == NOTOK) {
+       if (join_tcp_server (ftp_fd, res->ai_addr, res->ai_addrlen) == NOTOK) {
            perror (host);
+           freeaddrinfo(res);
            close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
            return NOTOK;
        }
+       freeaddrinfo(res);
        getreply (1, 0);
 
        if (v_verbose) {
index acf21de..9f1ebdd 100644 (file)
@@ -291,7 +291,6 @@ int SOprintf (char *, ...);           /* from termsbr.c */
 int sc_width (void);                  /* from termsbr.c */
 int sc_length (void);                 /* from termsbr.c */
 int sc_hardcopy (void);               /* from termsbr.c */
-struct hostent *gethostbystring ();
 
 
 int
@@ -1526,17 +1525,16 @@ static int
 doface (struct mcomp *c1)
 {
     int        result, sd;
-    struct sockaddr_in in_socket;
-    struct sockaddr_in *isock = &in_socket;
     static int inited = OK;
-    static int addrlen;
-    static struct in_addr addr;
-    static unsigned short portno;
+    static struct sockaddr_storage ss;
+    static socklen_t socklen;
+    static int socktype;
+    static int protocol;
 
     if (inited == OK) {
        char *cp;
        char **ap = brkstring (cp = getcpy (faceproc), " ", "\n");
-       struct hostent *hp;
+       struct addrinfo hints, *res;
 
        if (ap[0] == NULL || ap[1] == NULL) {
 bad_faceproc: ;
@@ -1544,27 +1542,30 @@ bad_faceproc: ;
            return (inited = NOTOK);
        }
 
-       if (!(hp = gethostbystring (ap[0])))
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_ADDRCONFIG;
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+
+       if (getaddrinfo(ap[0], ap[1], &hints, &res) != 0)
            goto bad_faceproc;
-       memcpy((char *) &addr, hp->h_addr, addrlen = hp->h_length);
 
-       portno = htons ((unsigned short) atoi (ap[1]));
-       free (cp);
+       memcpy(&ss, res->ai_addr, res->ai_addrlen);
+       socklen = res->ai_addrlen;
+       socktype = res->ai_socktype;
+       protocol = res->ai_protocol;
+       freeaddrinfo(res);
 
        inited = DONE;
     }
     if (inited == NOTOK)
        return NOTOK;
 
-    isock->sin_family = AF_INET;
-    isock->sin_port = portno;
-    memcpy((char *) &isock->sin_addr, (char *) &addr, addrlen);
-
-    if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) == NOTOK)
+    if ((sd = socket (ss.ss_family, socktype, protocol)) == NOTOK)
        return NOTOK;
 
     result = sendto (sd, c1->c_text, strlen (c1->c_text), 0,
-               (struct sockaddr *) isock, sizeof(*isock));
+               (struct sockaddr *) &ss, socklen);
 
     close (sd);
 
index 8e14d52..839e3d3 100644 (file)
@@ -11,9 +11,6 @@
 #include <h/mh.h>
 #include <h/utils.h>
 
-extern int  client(char *args, char *protocol, char *service, int rproto,
-                  char *response, int len_response);
-
 #if defined(NNTP) && !defined(PSHSBR)
 # undef NNTP
 #endif
@@ -81,6 +78,8 @@ static sasl_callback_t callbacks[] = {
 #define POP_SASL_CB_N_PASS 1
     { SASL_CB_LOG, NULL, NULL },
     { SASL_CB_LIST_END, NULL, NULL },
+
+#define SASL_BUFFER_SIZE 262144
 };
 #else /* CYRUS_SASL */
 # define sasl_fgetc fgetc
@@ -255,7 +254,7 @@ pop_auth_sasl(char *user, char *host, char *mech)
      */
 
     memset(&secprops, 0, sizeof(secprops));
-    secprops.maxbufsize = BUFSIZ;
+    secprops.maxbufsize = SASL_BUFFER_SIZE;
     secprops.max_ssf = UINT_MAX;
 
     result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
@@ -384,7 +383,8 @@ pop_auth_sasl(char *user, char *host, char *mech)
     }
 
     /*
-     * Limit this to what we can deal with.
+     * Limit this to what we can deal with.  Shouldn't matter much because
+     * this is only outgoing data (which should be small)
      */
 
     if (maxoutbuf == 0 || maxoutbuf > BUFSIZ)
@@ -459,7 +459,7 @@ parse_proxy(char *proxy, char *host)
     char *c;
     
     /* skip any initial space */
-    for (pro = proxy; isspace(*pro); pro++)
+    for (pro = (unsigned char *) proxy; isspace(*pro); pro++)
         continue;
     
     /* calculate required size for argument array */
@@ -566,12 +566,12 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop,
            return NOTOK;
 # endif /* KPOP */
        } else {
-           if ((fd1 = client (host, "tcp", POPSERVICE, rpop, response, sizeof(response))) == NOTOK) {
+           if ((fd1 = client (host, POPSERVICE, response, sizeof(response), snoop)) == NOTOK) {
                return NOTOK;
            }
        }
 #else  /* NNTP */
-       if ((fd1 = client (host, "tcp", "nntp", rpop, response, sizeof(response))) == NOTOK)
+       if ((fd1 = client (host, "nntp", response, sizeof(response), snoop)) == NOTOK)
            return NOTOK;
 #endif
 
@@ -1186,7 +1186,7 @@ sasl_fgetc(FILE *f)
     static int cnt = 0;
     unsigned int retbufsize = 0;
     int cc, result;
-    char *retbuf, tmpbuf[BUFSIZ];
+    char *retbuf, tmpbuf[SASL_BUFFER_SIZE];
 
     /*
      * If we have some leftover data, return that
index e3b6229..7546818 100644 (file)
@@ -138,6 +138,8 @@ static struct swit switches[] = {
     { "saslmech", SASLminc(-5) },
 #define USERSW                   39
     { "user", SASLminc(-4) },
+#define PORTSW                  40
+    { "port server port name/number", 4 },
     { NULL, 0 }
 };
 
@@ -236,6 +238,7 @@ static int nameoutput=0;    /* putadr() has output header name       */
 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 unsigned msgflags = 0;  /* what we've seen */
 
@@ -518,6 +521,11 @@ main (int argc, char **argv)
                    if (!(user = *argp++) || *user == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
                    continue;
+
+               case PORTSW:
+                   if (!(port = *argp++) || *port == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   continue;
            }
        }
        if (msg)
@@ -1403,7 +1411,7 @@ post (char *file, int bccque, int talk)
 
     sigon ();
 
-    if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose,
+    if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose,
                                    snoop, onex, queued, sasl, saslmech,
                                    user))
            || rp_isbad (retval = sm_winit (smtpmode, from)))
@@ -1442,8 +1450,9 @@ verify_all_addresses (int talk)
     sigon ();
 
     if (!whomsw || checksw)
-       if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose, snoop, 0,
-                                       queued, sasl, saslmech, user))
+       if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
+                                       verbose, snoop, 0, queued, sasl,
+                                       saslmech, user))
                || rp_isbad (retval = sm_winit (smtpmode, from)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
index 196af62..43f4c02 100644 (file)
@@ -93,19 +93,21 @@ static struct swit switches[] = {
 #define        CLIESW                34
     { "client host", -6 },
 #define        SERVSW                35
-    { "server host", -6 },
+    { "server host", 6 },
 #define        SNOOPSW               36
-    { "snoop", -5 },
+    { "snoop", 5 },
 #define SASLSW                37
-    { "sasl", SASLminc(-4) },
+    { "sasl", SASLminc(4) },
 #define SASLMECHSW            38
-    { "saslmech", SASLminc(-5) },
+    { "saslmech mechanism", SASLminc(-5) },
 #define USERSW                39
-    { "user", SASLminc(-4) },
+    { "user username", SASLminc(-4) },
 #define ATTACHSW              40
     { "attach", 6 },
 #define ATTACHFORMATSW        41
     { "attachformat", 7 },
+#define PORTSW               42
+    { "port server-port-name/number" , 4 },
     { NULL, 0 }
 };
 
@@ -273,6 +275,7 @@ main (int argc, char **argv)
                case SERVSW: 
                case SASLMECHSW:
                case USERSW:
+               case PORTSW:
                    vec[vecp++] = --cp;
                    if (!(cp = *argp++) || *cp == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
index a719431..42e0d61 100644 (file)
@@ -1044,7 +1044,7 @@ static struct swit  sendswitches[] = {
 #define        CLIESW           30
     { "client host", -6 },
 #define        SERVSW           31
-    { "server host", -6 },
+    { "server host", 6 },
 #define        SNOOPSW          32
     { "snoop", -5 },
 #define SDRFSW           33
@@ -1058,11 +1058,13 @@ 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 },
     { NULL, 0 }
 };