mirror of
https://github.com/opnsense/src.git
synced 2026-02-18 18:20:26 -05:00
dma: import snapshot 2021-07-10
This commit is contained in:
commit
fbe95b885f
16 changed files with 379 additions and 130 deletions
|
|
@ -17,7 +17,7 @@ CC?= gcc
|
|||
CFLAGS?= -O -pipe
|
||||
LDADD?= -lssl -lcrypto -lresolv
|
||||
|
||||
CFLAGS+= -Wall -DDMA_VERSION='"${version}"' -DLIBEXEC_PATH='"${LIBEXEC}"' -DCONF_PATH='"${CONFDIR}"'
|
||||
CFLAGS+= -Wall -Wno-format-truncation -DDMA_VERSION='"${version}"' -DLIBEXEC_PATH='"${LIBEXEC}"' -DCONF_PATH='"${CONFDIR}"'
|
||||
|
||||
INSTALL?= install -p
|
||||
CHGRP?= chgrp
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v0.11
|
||||
v0.13
|
||||
|
|
|
|||
|
|
@ -218,10 +218,26 @@ parse_conf(const char *config_path)
|
|||
config.masquerade_user = user;
|
||||
} else if (strcmp(word, "STARTTLS") == 0 && data == NULL)
|
||||
config.features |= STARTTLS;
|
||||
else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL)
|
||||
else if (strcmp(word, "FINGERPRINT") == 0) {
|
||||
if (strlen(data) != SHA256_DIGEST_LENGTH * 2) {
|
||||
errlogx(EX_CONFIG, "invalid sha256 fingerprint length");
|
||||
}
|
||||
unsigned char *fingerprint = malloc(SHA256_DIGEST_LENGTH);
|
||||
if (fingerprint == NULL) {
|
||||
errlogx(EX_CONFIG, "fingerprint allocation failed");
|
||||
}
|
||||
unsigned int i;
|
||||
for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||||
if(sscanf(data + 2 * i, "%02hhx", &fingerprint[i]) != 1) {
|
||||
errlogx(EX_CONFIG, "failed to read fingerprint");
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
config.fingerprint = fingerprint;
|
||||
} else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL)
|
||||
config.features |= TLS_OPP;
|
||||
else if (strcmp(word, "SECURETRANSFER") == 0 && data == NULL)
|
||||
config.features |= SECURETRANS;
|
||||
config.features |= SECURETRANSFER;
|
||||
else if (strcmp(word, "DEFER") == 0 && data == NULL)
|
||||
config.features |= DEFER;
|
||||
else if (strcmp(word, "INSECURE") == 0 && data == NULL)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
|
|
@ -77,8 +78,31 @@ init_cert_file(SSL_CTX *ctx, const char *path)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
verify_server_fingerprint(const X509 *cert)
|
||||
{
|
||||
unsigned char fingerprint[EVP_MAX_MD_SIZE] = {0};
|
||||
unsigned int fingerprint_len = 0;
|
||||
if(!X509_digest(cert, EVP_sha256(), fingerprint, &fingerprint_len)) {
|
||||
syslog(LOG_WARNING, "failed to load fingerprint of server certicate: %s",
|
||||
ssl_errstr());
|
||||
return (1);
|
||||
}
|
||||
if(fingerprint_len != SHA256_DIGEST_LENGTH) {
|
||||
syslog(LOG_WARNING, "sha256 fingerprint has unexpected length of %d bytes",
|
||||
fingerprint_len);
|
||||
return (1);
|
||||
}
|
||||
if(memcmp(fingerprint, config.fingerprint, SHA256_DIGEST_LENGTH) != 0) {
|
||||
syslog(LOG_WARNING, "fingerprints do not match");
|
||||
return (1);
|
||||
}
|
||||
syslog(LOG_DEBUG, "successfully verified server certificate fingerprint");
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
smtp_init_crypto(int fd, int feature)
|
||||
smtp_init_crypto(int fd, int feature, struct smtp_features* features)
|
||||
{
|
||||
SSL_CTX *ctx = NULL;
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00909000L)
|
||||
|
|
@ -119,13 +143,12 @@ smtp_init_crypto(int fd, int feature)
|
|||
/*
|
||||
* If the user wants STARTTLS, we have to send EHLO here
|
||||
*/
|
||||
if (((feature & SECURETRANS) != 0) &&
|
||||
if (((feature & SECURETRANSFER) != 0) &&
|
||||
(feature & STARTTLS) != 0) {
|
||||
/* TLS init phase, disable SSL_write */
|
||||
config.features |= NOSSL;
|
||||
|
||||
send_remote_command(fd, "EHLO %s", hostname());
|
||||
if (read_remote(fd, 0, NULL) == 2) {
|
||||
if (perform_server_greeting(fd, features) == 0) {
|
||||
send_remote_command(fd, "STARTTLS");
|
||||
if (read_remote(fd, 0, NULL) != 2) {
|
||||
if ((feature & TLS_OPP) == 0) {
|
||||
|
|
@ -136,7 +159,12 @@ smtp_init_crypto(int fd, int feature)
|
|||
return (0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
syslog(LOG_ERR, "remote delivery deferred: could not perform server greeting: %s",
|
||||
neterr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* End of TLS init phase, enable SSL_write/read */
|
||||
config.features &= ~NOSSL;
|
||||
}
|
||||
|
|
@ -161,7 +189,7 @@ smtp_init_crypto(int fd, int feature)
|
|||
|
||||
/* Open SSL connection */
|
||||
error = SSL_connect(config.ssl);
|
||||
if (error < 0) {
|
||||
if (error != 1) {
|
||||
syslog(LOG_ERR, "remote delivery deferred: SSL handshake failed fatally: %s",
|
||||
ssl_errstr());
|
||||
return (1);
|
||||
|
|
@ -172,6 +200,11 @@ smtp_init_crypto(int fd, int feature)
|
|||
if (cert == NULL) {
|
||||
syslog(LOG_WARNING, "remote delivery deferred: Peer did not provide certificate: %s",
|
||||
ssl_errstr());
|
||||
return (1);
|
||||
}
|
||||
if(config.fingerprint != NULL && verify_server_fingerprint(cert)) {
|
||||
X509_free(cert);
|
||||
return (1);
|
||||
}
|
||||
X509_free(cert);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $
|
||||
* $FreeBSD$
|
||||
* $FreeBSD: src/lib/libc/string/strlcpy.c,v 1.10 2008/10/19 10:11:35 delphij Exp $
|
||||
* $DragonFly: src/lib/libc/string/strlcpy.c,v 1.4 2005/09/18 16:32:34 asmodai Exp $
|
||||
*/
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ strlcpy(char *dst, const char *src, size_t siz)
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
* $FreeBSD: src/lib/libc/stdlib/reallocf.c,v 1.3 1999/08/28 00:01:37 peter Exp $
|
||||
* $DragonFly: src/lib/libc/stdlib/reallocf.c,v 1.2 2003/06/17 04:26:46 dillon Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
|
@ -96,7 +96,7 @@ reallocf(void *ptr, size_t size)
|
|||
void *nptr;
|
||||
|
||||
nptr = realloc(ptr, size);
|
||||
if (!nptr && ptr)
|
||||
if (!nptr && ptr && size != 0)
|
||||
free(ptr);
|
||||
return (nptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,8 +89,11 @@ Useful for debugging.
|
|||
.It Fl f Ar sender
|
||||
Set sender address (envelope-from) to
|
||||
.Ar sender .
|
||||
This overrides the value of the environment variable
|
||||
.Ev EMAIL .
|
||||
This overrides the value of the
|
||||
.Ev EMAIL
|
||||
environment variable, but is overridden by the
|
||||
.Sq MASQUERADE
|
||||
config file setting.
|
||||
.It Fl i
|
||||
Ignore dots alone on lines by themselves in incoming messages.
|
||||
This should be set if you are reading data from a file.
|
||||
|
|
@ -223,6 +226,11 @@ Uncomment if you want TLS/SSL secured transfer.
|
|||
Uncomment if you want to use STARTTLS.
|
||||
Only useful together with
|
||||
.Sq SECURETRANSFER .
|
||||
.It Ic FINGERPRINT Xo
|
||||
(string, default=empty)
|
||||
.Xc
|
||||
Pin the server certificate by specifying its SHA256 fingerprint.
|
||||
Only makes sense if you use a smarthost.
|
||||
.It Ic OPPORTUNISTIC_TLS Xo
|
||||
(boolean, default=commented)
|
||||
.Xc
|
||||
|
|
@ -283,7 +291,7 @@ as the hostname.
|
|||
Masquerade the envelope-from addresses with this address/hostname.
|
||||
Use this setting if mails are not accepted by destination mail servers
|
||||
because your sender domain is invalid.
|
||||
This setting is overridden by the
|
||||
This setting overrides the
|
||||
.Fl f
|
||||
flag and the
|
||||
.Ev EMAIL
|
||||
|
|
@ -309,6 +317,7 @@ will send all mails as
|
|||
.Ql Va username @percolator .
|
||||
.Sm on
|
||||
.It Ic NULLCLIENT Xo
|
||||
(boolean, default=commented)
|
||||
.Xc
|
||||
Bypass aliases and local delivery, and instead forward all mails to
|
||||
the defined
|
||||
|
|
@ -329,6 +338,8 @@ Used to set the sender address (envelope-from).
|
|||
Use a plain address, in the form of
|
||||
.Li user@example.com .
|
||||
This value will be overridden when the
|
||||
.Sq MASQUERADE
|
||||
config file setting or the
|
||||
.Fl f
|
||||
flag is used.
|
||||
.El
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ struct config config = {
|
|||
.mailname = NULL,
|
||||
.masquerade_host = NULL,
|
||||
.masquerade_user = NULL,
|
||||
.fingerprint = NULL,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -100,15 +101,14 @@ set_from(struct queue *queue, const char *osender)
|
|||
const char *addr;
|
||||
char *sender;
|
||||
|
||||
if (osender) {
|
||||
if (config.masquerade_user) {
|
||||
addr = config.masquerade_user;
|
||||
} else if (osender) {
|
||||
addr = osender;
|
||||
} else if (getenv("EMAIL") != NULL) {
|
||||
addr = getenv("EMAIL");
|
||||
} else {
|
||||
if (config.masquerade_user)
|
||||
addr = config.masquerade_user;
|
||||
else
|
||||
addr = username;
|
||||
addr = username;
|
||||
}
|
||||
|
||||
if (!strchr(addr, '@')) {
|
||||
|
|
@ -422,9 +422,10 @@ main(int argc, char **argv)
|
|||
{
|
||||
struct sigaction act;
|
||||
char *sender = NULL;
|
||||
char *own_name = NULL;
|
||||
struct queue queue;
|
||||
int i, ch;
|
||||
int nodot = 0, showq = 0, queue_only = 0;
|
||||
int nodot = 0, showq = 0, queue_only = 0, newaliases = 0;
|
||||
int recp_from_header = 0;
|
||||
|
||||
set_username();
|
||||
|
|
@ -458,19 +459,17 @@ main(int argc, char **argv)
|
|||
bzero(&queue, sizeof(queue));
|
||||
LIST_INIT(&queue.queue);
|
||||
|
||||
if (strcmp(basename(argv[0]), "mailq") == 0) {
|
||||
own_name = basename(argv[0]);
|
||||
|
||||
if (strcmp(own_name, "mailq") == 0) {
|
||||
argv++; argc--;
|
||||
showq = 1;
|
||||
if (argc != 0)
|
||||
errx(EX_USAGE, "invalid arguments");
|
||||
goto skipopts;
|
||||
} else if (strcmp(argv[0], "newaliases") == 0) {
|
||||
logident_base = "dma";
|
||||
setlogident("%s", logident_base);
|
||||
|
||||
if (read_aliases() != 0)
|
||||
errx(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases);
|
||||
exit(EX_OK);
|
||||
} else if (strcmp(own_name, "newaliases") == 0) {
|
||||
newaliases = 1;
|
||||
goto skipopts;
|
||||
}
|
||||
|
||||
opterr = 0;
|
||||
|
|
@ -481,7 +480,7 @@ main(int argc, char **argv)
|
|||
if (optarg[0] == 'c' || optarg[0] == 'm') {
|
||||
break;
|
||||
}
|
||||
/* else FALLTRHOUGH */
|
||||
/* Else FALLTHROUGH */
|
||||
case 'b':
|
||||
/* -bX is being ignored, except for -bp */
|
||||
if (optarg[0] == 'p') {
|
||||
|
|
@ -491,7 +490,7 @@ main(int argc, char **argv)
|
|||
queue_only = 1;
|
||||
break;
|
||||
}
|
||||
/* else FALLTRHOUGH */
|
||||
/* Else FALLTHROUGH */
|
||||
case 'D':
|
||||
daemonize = 0;
|
||||
break;
|
||||
|
|
@ -511,7 +510,7 @@ main(int argc, char **argv)
|
|||
/* -oX is being ignored, except for -oi */
|
||||
if (optarg[0] != 'i')
|
||||
break;
|
||||
/* else FALLTRHOUGH */
|
||||
/* Else FALLTHROUGH */
|
||||
case 'O':
|
||||
break;
|
||||
case 'i':
|
||||
|
|
@ -545,7 +544,7 @@ main(int argc, char **argv)
|
|||
doqueue = 1;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
/* Else FALLTHROUGH */
|
||||
|
||||
default:
|
||||
fprintf(stderr, "invalid argument: `-%c'\n", optopt);
|
||||
|
|
@ -596,6 +595,9 @@ skipopts:
|
|||
if (read_aliases() != 0)
|
||||
errlog(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases);
|
||||
|
||||
if (newaliases)
|
||||
return(0);
|
||||
|
||||
if ((sender = set_from(&queue, sender)) == NULL)
|
||||
errlog(EX_SOFTWARE, "set_from()");
|
||||
|
||||
|
|
|
|||
|
|
@ -18,13 +18,17 @@
|
|||
# SMTP authentication
|
||||
#AUTHPATH /etc/dma/auth.conf
|
||||
|
||||
# Uncomment if yout want TLS/SSL support
|
||||
# Uncomment if you want TLS/SSL support
|
||||
#SECURETRANSFER
|
||||
|
||||
# Uncomment if you want STARTTLS support (only used in combination with
|
||||
# SECURETRANSFER)
|
||||
#STARTTLS
|
||||
|
||||
# Pin the server certificate by specifying its SHA256 fingerprint.
|
||||
# Only makes sense if you use a smarthost.
|
||||
#FINGERPRINT 1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
|
||||
|
||||
# Uncomment if you have specified STARTTLS above and it should be allowed
|
||||
# to fail ("opportunistic TLS", use an encrypted connection when available
|
||||
# but allow an unencrypted one to servers that do not support it)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
#define BUF_SIZE 2048
|
||||
#define ERRMSG_SIZE 1024
|
||||
#define USERNAME_SIZE 50
|
||||
#define EHLO_RESPONSE_SIZE BUF_SIZE
|
||||
#define MIN_RETRY 300 /* 5 minutes */
|
||||
#define MAX_RETRY (3*60*60) /* retry at least every 3 hours */
|
||||
#define MAX_TIMEOUT (5*24*60*60) /* give up after 5 days */
|
||||
|
|
@ -62,7 +63,7 @@
|
|||
#define CON_TIMEOUT (5*60) /* Connection timeout per RFC5321 */
|
||||
|
||||
#define STARTTLS 0x002 /* StartTLS support */
|
||||
#define SECURETRANS 0x004 /* SSL/TLS in general */
|
||||
#define SECURETRANSFER 0x004 /* SSL/TLS in general */
|
||||
#define NOSSL 0x008 /* Do not use SSL */
|
||||
#define DEFER 0x010 /* Defer mails */
|
||||
#define INSECURE 0x020 /* Allow plain login w/o encryption */
|
||||
|
|
@ -137,6 +138,7 @@ struct config {
|
|||
const char *mailname;
|
||||
const char *masquerade_host;
|
||||
const char *masquerade_user;
|
||||
const unsigned char *fingerprint;
|
||||
|
||||
/* XXX does not belong into config */
|
||||
SSL *ssl;
|
||||
|
|
@ -160,6 +162,15 @@ struct mx_hostentry {
|
|||
struct sockaddr_storage sa;
|
||||
};
|
||||
|
||||
struct smtp_auth_mechanisms {
|
||||
int cram_md5;
|
||||
int login;
|
||||
};
|
||||
|
||||
struct smtp_features {
|
||||
struct smtp_auth_mechanisms auth;
|
||||
int starttls;
|
||||
};
|
||||
|
||||
/* global variables */
|
||||
extern struct aliases aliases;
|
||||
|
|
@ -187,7 +198,7 @@ void parse_authfile(const char *);
|
|||
/* crypto.c */
|
||||
void hmac_md5(unsigned char *, int, unsigned char *, int, unsigned char *);
|
||||
int smtp_auth_md5(int, char *, char *);
|
||||
int smtp_init_crypto(int, int);
|
||||
int smtp_init_crypto(int, int, struct smtp_features*);
|
||||
|
||||
/* dns.c */
|
||||
int dns_get_mx_list(const char *, int, struct mx_hostentry **, int);
|
||||
|
|
@ -196,6 +207,7 @@ int dns_get_mx_list(const char *, int, struct mx_hostentry **, int);
|
|||
char *ssl_errstr(void);
|
||||
int read_remote(int, int, char *);
|
||||
ssize_t send_remote_command(int, const char*, ...) __attribute__((__nonnull__(2), __format__ (__printf__, 2, 3)));
|
||||
int perform_server_greeting(int, struct smtp_features*);
|
||||
int deliver_remote(struct qitem *);
|
||||
|
||||
/* base64.c */
|
||||
|
|
@ -227,6 +239,7 @@ int readmail(struct queue *, int, int);
|
|||
|
||||
/* util.c */
|
||||
const char *hostname(void);
|
||||
const char *systemhostname(void);
|
||||
void setlogident(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
||||
void errlog(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
||||
void errlogx(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
||||
|
|
|
|||
|
|
@ -271,11 +271,6 @@ err:
|
|||
|
||||
*he = hosts;
|
||||
return (err);
|
||||
|
||||
free(ans);
|
||||
if (hosts != NULL)
|
||||
free(hosts);
|
||||
return (err);
|
||||
}
|
||||
|
||||
#if defined(TESTING)
|
||||
|
|
|
|||
0
contrib/dma/get-version.sh
Executable file → Normal file
0
contrib/dma/get-version.sh
Executable file → Normal file
|
|
@ -44,6 +44,7 @@
|
|||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -81,7 +82,7 @@ create_mbox(const char *name)
|
|||
for (i = 3; i <= maxfd; ++i)
|
||||
close(i);
|
||||
|
||||
execl(LIBEXEC_PATH "/dma-mbox-create", "dma-mbox-create", name, NULL);
|
||||
execl(LIBEXEC_PATH "/dma-mbox-create", "dma-mbox-create", name, (char *)NULL);
|
||||
syslog(LOG_ERR, "cannot execute "LIBEXEC_PATH"/dma-mbox-create: %m");
|
||||
exit(EX_SOFTWARE);
|
||||
|
||||
|
|
@ -219,7 +220,7 @@ retry:
|
|||
/*
|
||||
* mboxro processing:
|
||||
* - escape lines that start with "From " with a > sign.
|
||||
* - be reversable by escaping lines that contain an arbitrary
|
||||
* - be reversible by escaping lines that contain an arbitrary
|
||||
* number of > signs, followed by "From ", i.e. />*From / in regexp.
|
||||
* - strict mbox processing only requires escaping after empty lines,
|
||||
* yet most MUAs seem to relax this requirement and will treat any
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -73,7 +74,7 @@ bounce(struct qitem *it, const char *reason)
|
|||
error = fprintf(bounceq.mailf,
|
||||
"Received: from MAILER-DAEMON\n"
|
||||
"\tid %s\n"
|
||||
"\tby %s (%s);\n"
|
||||
"\tby %s (%s on %s);\n"
|
||||
"\t%s\n"
|
||||
"X-Original-To: <%s>\n"
|
||||
"From: MAILER-DAEMON <>\n"
|
||||
|
|
@ -91,7 +92,7 @@ bounce(struct qitem *it, const char *reason)
|
|||
"%s\n"
|
||||
"\n",
|
||||
bounceq.id,
|
||||
hostname(), VERSION,
|
||||
hostname(), VERSION, systemhostname(),
|
||||
rfc822date(),
|
||||
it->addr,
|
||||
it->sender,
|
||||
|
|
@ -191,8 +192,7 @@ again:
|
|||
switch (*s) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
s++;
|
||||
/* continue */
|
||||
ps->state = MAIN;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -201,6 +201,7 @@ again:
|
|||
goto newaddr;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIT:
|
||||
return (0);
|
||||
|
|
@ -383,6 +384,8 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
|
|||
int had_from = 0;
|
||||
int had_messagid = 0;
|
||||
int had_date = 0;
|
||||
int had_first_line = 0;
|
||||
int had_last_line = 0;
|
||||
int nocopy = 0;
|
||||
int ret = -1;
|
||||
|
||||
|
|
@ -392,12 +395,12 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
|
|||
"Received: from %s (uid %d)\n"
|
||||
"\t(envelope-from %s)\n"
|
||||
"\tid %s\n"
|
||||
"\tby %s (%s);\n"
|
||||
"\tby %s (%s on %s);\n"
|
||||
"\t%s\n",
|
||||
username, useruid,
|
||||
queue->sender,
|
||||
queue->id,
|
||||
hostname(), VERSION,
|
||||
hostname(), VERSION, systemhostname(),
|
||||
rfc822date());
|
||||
if ((ssize_t)error < 0)
|
||||
return (-1);
|
||||
|
|
@ -406,7 +409,30 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
|
|||
newline[0] = '\0';
|
||||
if ((linelen = getline(&line, &linecap, stdin)) <= 0)
|
||||
break;
|
||||
|
||||
if (had_last_line)
|
||||
errlogx(EX_DATAERR, "bad mail input format:"
|
||||
" from %s (uid %d) (envelope-from %s)",
|
||||
username, useruid, queue->sender);
|
||||
linelen = strlen(line);
|
||||
if (linelen == 0 || line[linelen - 1] != '\n') {
|
||||
/*
|
||||
* This line did not end with a newline character.
|
||||
* If we fix it, it better be the last line of
|
||||
* the file.
|
||||
*/
|
||||
line[linelen] = '\n';
|
||||
line[linelen + 1] = 0;
|
||||
had_last_line = 1;
|
||||
}
|
||||
if (!had_first_line) {
|
||||
/*
|
||||
* Ignore a leading RFC-976 From_ or >From_ line mistakenly
|
||||
* inserted by some programs.
|
||||
*/
|
||||
if (strprefixcmp(line, "From ") == 0 || strprefixcmp(line, ">From ") == 0)
|
||||
continue;
|
||||
had_first_line = 1;
|
||||
}
|
||||
if (!had_headers) {
|
||||
if (linelen > MAX_LINE_RFC822) {
|
||||
/* XXX also split headers */
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include <netdb.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -94,13 +95,13 @@ send_remote_command(int fd, const char* fmt, ...)
|
|||
strcat(cmd, "\r\n");
|
||||
len = strlen(cmd);
|
||||
|
||||
if (((config.features & SECURETRANS) != 0) &&
|
||||
if (((config.features & SECURETRANSFER) != 0) &&
|
||||
((config.features & NOSSL) == 0)) {
|
||||
while ((s = SSL_write(config.ssl, (const char*)cmd, len)) <= 0) {
|
||||
s = SSL_get_error(config.ssl, s);
|
||||
if (s != SSL_ERROR_WANT_READ &&
|
||||
s != SSL_ERROR_WANT_WRITE) {
|
||||
strncpy(neterr, ssl_errstr(), sizeof(neterr));
|
||||
strlcpy(neterr, ssl_errstr(), sizeof(neterr));
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
|
@ -147,15 +148,15 @@ read_remote(int fd, int extbufsize, char *extbuf)
|
|||
memmove(buff, buff + pos, len - pos);
|
||||
len -= pos;
|
||||
pos = 0;
|
||||
if (((config.features & SECURETRANS) != 0) &&
|
||||
if (((config.features & SECURETRANSFER) != 0) &&
|
||||
(config.features & NOSSL) == 0) {
|
||||
if ((rlen = SSL_read(config.ssl, buff + len, sizeof(buff) - len)) == -1) {
|
||||
strncpy(neterr, ssl_errstr(), sizeof(neterr));
|
||||
strlcpy(neterr, ssl_errstr(), sizeof(neterr));
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if ((rlen = read(fd, buff + len, sizeof(buff) - len)) == -1) {
|
||||
strncpy(neterr, strerror(errno), sizeof(neterr));
|
||||
strlcpy(neterr, strerror(errno), sizeof(neterr));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
@ -248,64 +249,70 @@ error:
|
|||
* Handle SMTP authentication
|
||||
*/
|
||||
static int
|
||||
smtp_login(int fd, char *login, char* password)
|
||||
smtp_login(int fd, char *login, char* password, const struct smtp_features* features)
|
||||
{
|
||||
char *temp;
|
||||
int len, res = 0;
|
||||
|
||||
res = smtp_auth_md5(fd, login, password);
|
||||
if (res == 0) {
|
||||
return (0);
|
||||
} else if (res == -2) {
|
||||
/*
|
||||
* If the return code is -2, then then the login attempt failed,
|
||||
* do not try other login mechanisms
|
||||
*/
|
||||
return (1);
|
||||
// CRAM-MD5
|
||||
if (features->auth.cram_md5) {
|
||||
res = smtp_auth_md5(fd, login, password);
|
||||
if (res == 0) {
|
||||
return (0);
|
||||
} else if (res == -2) {
|
||||
/*
|
||||
* If the return code is -2, then then the login attempt failed,
|
||||
* do not try other login mechanisms
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((config.features & INSECURE) != 0 ||
|
||||
(config.features & SECURETRANS) != 0) {
|
||||
/* Send AUTH command according to RFC 2554 */
|
||||
send_remote_command(fd, "AUTH LOGIN");
|
||||
if (read_remote(fd, 0, NULL) != 3) {
|
||||
syslog(LOG_NOTICE, "remote delivery deferred:"
|
||||
" AUTH login not available: %s",
|
||||
neterr);
|
||||
return (1);
|
||||
}
|
||||
// LOGIN
|
||||
if (features->auth.login) {
|
||||
if ((config.features & INSECURE) != 0 ||
|
||||
(config.features & SECURETRANSFER) != 0) {
|
||||
/* Send AUTH command according to RFC 2554 */
|
||||
send_remote_command(fd, "AUTH LOGIN");
|
||||
if (read_remote(fd, 0, NULL) != 3) {
|
||||
syslog(LOG_NOTICE, "remote delivery deferred:"
|
||||
" AUTH login not available: %s",
|
||||
neterr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
len = base64_encode(login, strlen(login), &temp);
|
||||
if (len < 0) {
|
||||
len = base64_encode(login, strlen(login), &temp);
|
||||
if (len < 0) {
|
||||
encerr:
|
||||
syslog(LOG_ERR, "can not encode auth reply: %m");
|
||||
syslog(LOG_ERR, "can not encode auth reply: %m");
|
||||
return (1);
|
||||
}
|
||||
|
||||
send_remote_command(fd, "%s", temp);
|
||||
free(temp);
|
||||
res = read_remote(fd, 0, NULL);
|
||||
if (res != 3) {
|
||||
syslog(LOG_NOTICE, "remote delivery %s: AUTH login failed: %s",
|
||||
res == 5 ? "failed" : "deferred", neterr);
|
||||
return (res == 5 ? -1 : 1);
|
||||
}
|
||||
|
||||
len = base64_encode(password, strlen(password), &temp);
|
||||
if (len < 0)
|
||||
goto encerr;
|
||||
|
||||
send_remote_command(fd, "%s", temp);
|
||||
free(temp);
|
||||
res = read_remote(fd, 0, NULL);
|
||||
if (res != 2) {
|
||||
syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s",
|
||||
res == 5 ? "failed" : "deferred", neterr);
|
||||
return (res == 5 ? -1 : 1);
|
||||
}
|
||||
} else {
|
||||
syslog(LOG_WARNING, "non-encrypted SMTP login is disabled in config, so skipping it. ");
|
||||
return (1);
|
||||
}
|
||||
|
||||
send_remote_command(fd, "%s", temp);
|
||||
free(temp);
|
||||
res = read_remote(fd, 0, NULL);
|
||||
if (res != 3) {
|
||||
syslog(LOG_NOTICE, "remote delivery %s: AUTH login failed: %s",
|
||||
res == 5 ? "failed" : "deferred", neterr);
|
||||
return (res == 5 ? -1 : 1);
|
||||
}
|
||||
|
||||
len = base64_encode(password, strlen(password), &temp);
|
||||
if (len < 0)
|
||||
goto encerr;
|
||||
|
||||
send_remote_command(fd, "%s", temp);
|
||||
free(temp);
|
||||
res = read_remote(fd, 0, NULL);
|
||||
if (res != 2) {
|
||||
syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s",
|
||||
res == 5 ? "failed" : "deferred", neterr);
|
||||
return (res == 5 ? -1 : 1);
|
||||
}
|
||||
} else {
|
||||
syslog(LOG_WARNING, "non-encrypted SMTP login is disabled in config, so skipping it. ");
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
|
@ -340,7 +347,7 @@ static void
|
|||
close_connection(int fd)
|
||||
{
|
||||
if (config.ssl != NULL) {
|
||||
if (((config.features & SECURETRANS) != 0) &&
|
||||
if (((config.features & SECURETRANSFER) != 0) &&
|
||||
((config.features & NOSSL) == 0))
|
||||
SSL_shutdown(config.ssl);
|
||||
SSL_free(config.ssl);
|
||||
|
|
@ -349,11 +356,116 @@ close_connection(int fd)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
static void parse_auth_line(char* line, struct smtp_auth_mechanisms* auth) {
|
||||
// Skip the auth prefix
|
||||
line += strlen("AUTH ");
|
||||
|
||||
char* method = strtok(line, " ");
|
||||
while (method) {
|
||||
if (strcmp(method, "CRAM-MD5") == 0)
|
||||
auth->cram_md5 = 1;
|
||||
|
||||
else if (strcmp(method, "LOGIN") == 0)
|
||||
auth->login = 1;
|
||||
|
||||
method = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
int perform_server_greeting(int fd, struct smtp_features* features) {
|
||||
/*
|
||||
Send EHLO
|
||||
XXX allow HELO fallback
|
||||
*/
|
||||
send_remote_command(fd, "EHLO %s", hostname());
|
||||
|
||||
char buffer[EHLO_RESPONSE_SIZE];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
int res = read_remote(fd, sizeof(buffer) - 1, buffer);
|
||||
|
||||
// Got an unexpected response
|
||||
if (res != 2)
|
||||
return -1;
|
||||
|
||||
// Reset all features
|
||||
memset(features, 0, sizeof(*features));
|
||||
|
||||
// Run through the buffer line by line
|
||||
char linebuffer[EHLO_RESPONSE_SIZE];
|
||||
char* p = buffer;
|
||||
|
||||
while (*p) {
|
||||
char* line = linebuffer;
|
||||
while (*p && *p != '\n') {
|
||||
*line++ = *p++;
|
||||
}
|
||||
|
||||
// p should never point to NULL after the loop
|
||||
// above unless we reached the end of the buffer.
|
||||
// In that case we will raise an error.
|
||||
if (!*p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise p points to the newline character which
|
||||
// we will skip.
|
||||
p++;
|
||||
|
||||
// Terminte the string (and remove the carriage-return character)
|
||||
*--line = '\0';
|
||||
line = linebuffer;
|
||||
|
||||
// End main loop for empty lines
|
||||
if (*line == '\0')
|
||||
break;
|
||||
|
||||
// Process the line
|
||||
// - Must start with 250, followed by dash or space
|
||||
// - We won't check for the correct usage of space and dash because
|
||||
// that is already done in read_remote().
|
||||
if ((strncmp(line, "250-", 4) != 0) && (strncmp(line, "250 ", 4) != 0)) {
|
||||
syslog(LOG_ERR, "Invalid line: %s\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Skip the prefix
|
||||
line += 4;
|
||||
|
||||
// Check for STARTTLS
|
||||
if (strcmp(line, "STARTTLS") == 0)
|
||||
features->starttls = 1;
|
||||
|
||||
// Parse authentication mechanisms
|
||||
else if (strncmp(line, "AUTH ", 5) == 0)
|
||||
parse_auth_line(line, &features->auth);
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, "Server greeting successfully completed");
|
||||
|
||||
// STARTTLS
|
||||
if (features->starttls)
|
||||
syslog(LOG_DEBUG, " Server supports STARTTLS");
|
||||
else
|
||||
syslog(LOG_DEBUG, " Server does not support STARTTLS");
|
||||
|
||||
// Authentication
|
||||
if (features->auth.cram_md5) {
|
||||
syslog(LOG_DEBUG, " Server supports CRAM-MD5 authentication");
|
||||
}
|
||||
if (features->auth.login) {
|
||||
syslog(LOG_DEBUG, " Server supports LOGIN authentication");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
||||
{
|
||||
struct authuser *a;
|
||||
char line[1000];
|
||||
struct smtp_features features;
|
||||
char line[1000], *addrtmp = NULL, *to_addr;
|
||||
size_t linelen;
|
||||
int fd, error = 0, do_auth = 0, res = 0;
|
||||
|
||||
|
|
@ -366,24 +478,26 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
if (fd < 0)
|
||||
return (1);
|
||||
|
||||
#define READ_REMOTE_CHECK(c, exp) \
|
||||
res = read_remote(fd, 0, NULL); \
|
||||
if (res == 5) { \
|
||||
syslog(LOG_ERR, "remote delivery to %s [%s] failed after %s: %s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
error = -1; \
|
||||
goto out; \
|
||||
} else if (res != exp) { \
|
||||
syslog(LOG_NOTICE, "remote delivery deferred: %s [%s] failed after %s: %s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
error = 1; \
|
||||
goto out; \
|
||||
}
|
||||
#define READ_REMOTE_CHECK(c, exp) \
|
||||
do { \
|
||||
res = read_remote(fd, 0, NULL); \
|
||||
if (res == 5) { \
|
||||
syslog(LOG_ERR, "remote delivery to %s [%s] failed after %s: %s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
error = -1; \
|
||||
goto out; \
|
||||
} else if (res != exp) { \
|
||||
syslog(LOG_NOTICE, "remote delivery deferred: %s [%s] failed after %s: %s", \
|
||||
host->host, host->addr, c, neterr); \
|
||||
error = 1; \
|
||||
goto out; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Check first reply from remote host */
|
||||
if ((config.features & SECURETRANS) == 0 ||
|
||||
if ((config.features & SECURETRANSFER) == 0 ||
|
||||
(config.features & STARTTLS) != 0) {
|
||||
config.features |= NOSSL;
|
||||
READ_REMOTE_CHECK("connect", 2);
|
||||
|
|
@ -391,8 +505,8 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
config.features &= ~NOSSL;
|
||||
}
|
||||
|
||||
if ((config.features & SECURETRANS) != 0) {
|
||||
error = smtp_init_crypto(fd, config.features);
|
||||
if ((config.features & SECURETRANSFER) != 0) {
|
||||
error = smtp_init_crypto(fd, config.features, &features);
|
||||
if (error == 0)
|
||||
syslog(LOG_DEBUG, "SSL initialization successful");
|
||||
else
|
||||
|
|
@ -402,10 +516,12 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
READ_REMOTE_CHECK("connect", 2);
|
||||
}
|
||||
|
||||
/* XXX allow HELO fallback */
|
||||
/* XXX record ESMTP keywords */
|
||||
send_remote_command(fd, "EHLO %s", hostname());
|
||||
READ_REMOTE_CHECK("EHLO", 2);
|
||||
// Say EHLO
|
||||
if (perform_server_greeting(fd, &features) != 0) {
|
||||
syslog(LOG_ERR, "Could not perform server greeting at %s [%s]: %s",
|
||||
host->host, host->addr, neterr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use SMTP authentication if the user defined an entry for the remote
|
||||
|
|
@ -424,7 +540,7 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
* encryption.
|
||||
*/
|
||||
syslog(LOG_INFO, "using SMTP authentication for user %s", a->login);
|
||||
error = smtp_login(fd, a->login, a->password);
|
||||
error = smtp_login(fd, a->login, a->password, &features);
|
||||
if (error < 0) {
|
||||
syslog(LOG_ERR, "remote delivery failed:"
|
||||
" SMTP login failed: %m");
|
||||
|
|
@ -443,8 +559,17 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
READ_REMOTE_CHECK("MAIL FROM", 2);
|
||||
|
||||
/* XXX send ESMTP ORCPT */
|
||||
send_remote_command(fd, "RCPT TO:<%s>", it->addr);
|
||||
READ_REMOTE_CHECK("RCPT TO", 2);
|
||||
if ((addrtmp = strdup(it->addr)) == NULL) {
|
||||
syslog(LOG_CRIT, "remote delivery deferred: unable to allocate memory");
|
||||
error = 1;
|
||||
goto out;
|
||||
}
|
||||
to_addr = strtok(addrtmp, ",");
|
||||
while (to_addr != NULL) {
|
||||
send_remote_command(fd, "RCPT TO:<%s>", to_addr);
|
||||
READ_REMOTE_CHECK("RCPT TO", 2);
|
||||
to_addr = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
send_remote_command(fd, "DATA");
|
||||
READ_REMOTE_CHECK("DATA", 3);
|
||||
|
|
@ -486,6 +611,7 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
|
|||
syslog(LOG_INFO, "remote delivery succeeded but QUIT failed: %s", neterr);
|
||||
out:
|
||||
|
||||
free(addrtmp);
|
||||
close_connection(fd);
|
||||
return (error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -98,6 +99,25 @@ hostname(void)
|
|||
}
|
||||
|
||||
local:
|
||||
snprintf(name, sizeof(name), "%s", systemhostname());
|
||||
|
||||
initialized = 1;
|
||||
return (name);
|
||||
}
|
||||
|
||||
const char *
|
||||
systemhostname(void)
|
||||
{
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 255
|
||||
#endif
|
||||
static char name[HOST_NAME_MAX+1];
|
||||
static int initialized = 0;
|
||||
char *s;
|
||||
|
||||
if (initialized)
|
||||
return (name);
|
||||
|
||||
if (gethostname(name, sizeof(name)) != 0)
|
||||
*name = 0;
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue