dma: update to 0.12

All of the dma patches in src/patches/ were merged into its upstream
repository by now, thus becoming obsolete and deleted by this patch.

Cc: Michael Tremer <michael.tremer@ipfire.org>
Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
Reviewed-by: Michael Tremer <michael.tremer@ipfire.org>
Signed-off-by: Arne Fitzenreiter <arne_f@ipfire.org>
This commit is contained in:
Peter Müller
2020-02-01 20:26:00 +00:00
committed by Arne Fitzenreiter
parent 2d599cca34
commit 59b2a70f7a
4 changed files with 3 additions and 434 deletions

View File

@@ -1,7 +1,7 @@
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2018 IPFire Team <info@ipfire.org> #
# Copyright (C) 2007-2020 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
@@ -24,7 +24,7 @@
include Config
VER = 0.11
VER = 0.12
THISAPP = dma-$(VER)
DL_FILE = $(THISAPP).tar.gz
@@ -40,7 +40,7 @@ objects = $(DL_FILE)
$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
$(DL_FILE)_MD5 = 4090572921fc33be0977f4010881b501
$(DL_FILE)_MD5 = 58cb2a286995381c92dc557e639622d6
install : $(TARGET)
@@ -73,9 +73,6 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
mkdir -pv /var/ipfire/dma
touch /var/ipfire/dma/mail.conf
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dma-0.10-better-authentication.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dma-0.10-better-tls.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dma-0.11-compile-fixes.patch
cd $(DIR_APP) && sed -i '/PREFIX/s/usr\/local/usr/g' Makefile
cd $(DIR_APP) && sed -i '/CONFDIR/s/etc\/dma/var\/ipfire\/dma/g' Makefile
cd $(DIR_APP) && make

View File

@@ -1,373 +0,0 @@
From 1fa7a882dd22d5f619b3645c6597a419034e9b4e Mon Sep 17 00:00:00 2001
From: Michael Tremer <michael.tremer@ipfire.org>
Date: Mon, 9 Nov 2015 21:52:08 +0000
Subject: [PATCH] Implement better authentication
DMA tries to authenticate by simply trying various authentication
mechanisms. This is obviously not conforming to RFC and some mail
providers detect this is spam and reject all emails.
This patch parses the EHLO response and reads various keywords
from it that can then later in the program be used to jump into
certain code paths.
Currently this is used to only authenticate with CRAM-MD5 and/or
LOGIN if the server supports one or both of these. The
implementation can be easily be extended though.
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
---
crypto.c | 6 +-
dma.h | 13 +++-
net.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++----------------
3 files changed, 181 insertions(+), 57 deletions(-)
diff --git a/crypto.c b/crypto.c
index 897b55b..8048f20 100644
--- a/crypto.c
+++ b/crypto.c
@@ -77,7 +77,7 @@ init_cert_file(SSL_CTX *ctx, const char *path)
}
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)
@@ -118,8 +118,7 @@ smtp_init_crypto(int fd, int feature)
/* 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) {
@@ -131,6 +130,7 @@ smtp_init_crypto(int fd, int feature)
}
}
}
+
/* End of TLS init phase, enable SSL_write/read */
config.features &= ~NOSSL;
}
diff --git a/dma.h b/dma.h
index acf5e44..ee749d8 100644
--- a/dma.h
+++ b/dma.h
@@ -51,6 +51,7 @@
#define BUF_SIZE 2048
#define ERRMSG_SIZE 200
#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 */
@@ -160,6 +161,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 +197,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 +206,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 */
diff --git a/net.c b/net.c
index 26935a8..33ff8f5 100644
--- a/net.c
+++ b/net.c
@@ -247,64 +247,70 @@ read_remote(int fd, int extbufsize, char *extbuf)
* 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);
- }
-
- 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);
+ // 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);
}
+ }
- len = base64_encode(login, strlen(login), &temp);
- if (len < 0) {
+ // LOGIN
+ if (features->auth.login) {
+ 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);
+ }
+
+ len = base64_encode(login, strlen(login), &temp);
+ if (len < 0) {
encerr:
- syslog(LOG_ERR, "can not encode auth reply: %m");
- return (1);
- }
+ 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);
- }
+ 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);
+ 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);
}
- } else {
- syslog(LOG_WARNING, "non-encrypted SMTP login is disabled in config, so skipping it. ");
- return (1);
}
return (0);
@@ -348,10 +354,115 @@ 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;
+ struct smtp_features features;
char line[1000];
size_t linelen;
int fd, error = 0, do_auth = 0, res = 0;
@@ -389,7 +500,7 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
}
if ((config.features & SECURETRANS) != 0) {
- error = smtp_init_crypto(fd, config.features);
+ error = smtp_init_crypto(fd, config.features, &features);
if (error == 0)
syslog(LOG_DEBUG, "SSL initialization successful");
else
@@ -399,10 +510,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
@@ -421,7 +534,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");

View File

@@ -1,26 +0,0 @@
commit e94f50bbbe7318eec5b6b165ff73d94bbc9d20b0
Author: Michael Tremer <michael.tremer@ipfire.org>
Date: Sun Feb 11 11:05:43 2018 +0000
crypto: Don't limit to TLSv1 only
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
diff --git a/crypto.c b/crypto.c
index 897b55bfdcfc..440c882880b5 100644
--- a/crypto.c
+++ b/crypto.c
@@ -93,7 +93,12 @@ smtp_init_crypto(int fd, int feature)
SSL_library_init();
SSL_load_error_strings();
- meth = TLSv1_client_method();
+ // Allow any possible version
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ meth = TLS_client_method();
+#else
+ meth = SSLv23_client_method();
+#endif
ctx = SSL_CTX_new(meth);
if (ctx == NULL) {

View File

@@ -1,29 +0,0 @@
From 60cf6f03a4b13ec0e491a282ab5233a1619a7a66 Mon Sep 17 00:00:00 2001
From: Michael Tremer <michael.tremer@ipfire.org>
Date: Tue, 24 Apr 2018 12:30:13 +0100
Subject: [PATCH] net.c: Include string.h
Various functions that have been used come from string.h. GCC compiled
dma without this header, but unfortunately the binary segfaulted at random
times.
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
---
net.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net.c b/net.c
index a1cc3e3bfd79..221dda131a23 100644
--- a/net.c
+++ b/net.c
@@ -53,6 +53,7 @@
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
+#include <string.h>
#include <syslog.h>
#include <unistd.h>
--
2.14.3