# 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))
])
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)
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
--- /dev/null
+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.
+++ /dev/null
-/*
- * 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 */
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 *);
.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
.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
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 ^ ~
.IR seconds ]
.RB [ \-verbose " | " \-noverbose ]
.RB [ \-watch " | " \-nowatch ]
+.RB [ \-server
+.IR servername ]
+.RB [ \-port
+.IR port-name/number ]
.RB [ \-sasl ]
.RB [ \-saslmech
.IR mechanism ]
.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
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
{
unsigned char *p;
char *q, site[BUFSIZ];
- struct hostent *hp;
+ struct addrinfo hints, *res;
static char buffer[BUFSIZ];
char **r;
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 ()) {
#include <h/mts.h>
#include <signal.h>
#include <h/signals.h>
-#ifdef MPOP
-#include <errno.h>
-#endif
#ifdef CYRUS_SASL
#include <sasl/sasl.h>
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
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 },
#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";
/*
* 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);
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
/*
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,
}
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)
{
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;
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);
}
}
-#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;
}
{
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";
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);
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);
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;
* 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",
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;
*/
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);
&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;
}
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;
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, ...)
{
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)
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);
}
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);
}
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 ();
}
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)
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);
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);
}
continue;
cont = FALSE;
- code = atoi (bp);
+ code = atoi ((char *) bp);
bp += 3, bc -= 3;
for (; bc > 0 && isspace (*bp); bp++, bc--)
continue;
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);
}
}
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'))
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);
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)
{
* 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);
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" */
/*
# 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) {
*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 = ∅
- 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);
}
LocalName (void)
{
static char buffer[BUFSIZ] = "";
- struct hostent *hp;
-
+ struct addrinfo hints, *res;
#ifdef HAVE_UNAME
struct utsname name;
#endif
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);
+ }
}
/*
-
/*
* ftpsbr.c -- simple FTP client library
*
#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);
}
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) {
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
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: ;
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);
#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
#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
*/
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);
}
/*
- * 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)
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 */
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
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
{ "saslmech", SASLminc(-5) },
#define USERSW 39
{ "user", SASLminc(-4) },
+#define PORTSW 40
+ { "port server port name/number", 4 },
{ NULL, 0 }
};
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 */
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)
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)))
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));
#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 }
};
case SERVSW:
case SASLMECHSW:
case USERSW:
+ case PORTSW:
vec[vecp++] = --cp;
if (!(cp = *argp++) || *cp == '-')
adios (NULL, "missing argument to %s", argp[-2]);
#define CLIESW 30
{ "client host", -6 },
#define SERVSW 31
- { "server host", -6 },
+ { "server host", 6 },
#define SNOOPSW 32
{ "snoop", -5 },
#define SDRFSW 33
#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 }
};