|
--- freebsd/contrib/dma/conf.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/conf.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -121,7 +121,7 @@ |
|
|
|
au = calloc(1, sizeof(*au)); |
|
if (au == NULL) |
|
- errlog(EX_OSERR, "calloc()"); |
|
+ errlog(EX_OSERR, NULL); |
|
|
|
data = strdup(line); |
|
au->login = strsep(&data, "|"); |
|
@@ -218,7 +218,22 @@ |
|
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"); |
|
+ } |
|
+ for (unsigned int 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; |
|
--- freebsd/contrib/dma/crypto.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/crypto.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -40,6 +40,7 @@ |
|
#include <openssl/pem.h> |
|
#include <openssl/rand.h> |
|
|
|
+#include <strings.h> |
|
#include <string.h> |
|
#include <syslog.h> |
|
|
|
@@ -78,7 +79,30 @@ |
|
} |
|
|
|
int |
|
-smtp_init_crypto(int fd, int feature) |
|
+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, struct smtp_features* features) |
|
{ |
|
SSL_CTX *ctx = NULL; |
|
#if (OPENSSL_VERSION_NUMBER >= 0x00909000L) |
|
@@ -124,8 +148,7 @@ |
|
/* 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) { |
|
@@ -137,6 +160,7 @@ |
|
} |
|
} |
|
} |
|
+ |
|
/* End of TLS init phase, enable SSL_write/read */ |
|
config.features &= ~NOSSL; |
|
} |
|
@@ -161,7 +185,7 @@ |
|
|
|
/* 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 +196,11 @@ |
|
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); |
|
|
|
--- freebsd/contrib/dma/dfcompat.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/dfcompat.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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 @@ |
|
* 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> |
|
--- freebsd/contrib/dma/dma-mbox-create.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/dma-mbox-create.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -38,18 +38,9 @@ |
|
* user-supplied information. Keep the root window as small as possible. |
|
*/ |
|
|
|
-#ifdef __FreeBSD__ |
|
-#define USE_CAPSICUM 1 |
|
-#endif |
|
- |
|
#include <sys/param.h> |
|
-#if USE_CAPSICUM |
|
-#include <sys/capsicum.h> |
|
-#endif |
|
#include <sys/stat.h> |
|
|
|
-#include <capsicum_helpers.h> |
|
-#include <err.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <grp.h> |
|
@@ -94,9 +85,6 @@ |
|
int |
|
main(int argc, char **argv) |
|
{ |
|
-#if USE_CAPSICUM |
|
- cap_rights_t rights; |
|
-#endif |
|
const char *user; |
|
struct passwd *pw; |
|
struct group *gr; |
|
@@ -104,10 +92,7 @@ |
|
gid_t mail_gid; |
|
int f, maildirfd; |
|
|
|
- /* |
|
- * Open log fd now for capability sandbox. |
|
- */ |
|
- openlog("dma-mbox-create", LOG_NDELAY, LOG_MAIL); |
|
+ openlog("dma-mbox-create", 0, LOG_MAIL); |
|
|
|
errno = 0; |
|
gr = getgrnam(DMA_GROUP); |
|
@@ -149,28 +134,6 @@ |
|
if (maildirfd < 0) |
|
logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR); |
|
|
|
- /* |
|
- * Cache NLS data, for strerror, for err(3), before entering capability |
|
- * mode. |
|
- */ |
|
- caph_cache_catpages(); |
|
- |
|
- /* |
|
- * Cache local time before entering Capsicum capability sandbox. |
|
- */ |
|
- caph_cache_tzdata(); |
|
- |
|
-#if USE_CAPSICUM |
|
- cap_rights_init(&rights, CAP_CREATE, CAP_FCHMOD, CAP_FCHOWN, |
|
- CAP_LOOKUP, CAP_READ); |
|
- if (cap_rights_limit(maildirfd, &rights) < 0 && errno != ENOSYS) |
|
- err(EX_OSERR, "can't limit maildirfd rights"); |
|
- |
|
- /* Enter Capsicum capability sandbox */ |
|
- if (caph_enter() < 0) |
|
- err(EX_OSERR, "cap_enter"); |
|
-#endif |
|
- |
|
user_uid = pw->pw_uid; |
|
|
|
f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600); |
|
--- freebsd/contrib/dma/dma.8 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/dma.8 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -30,7 +30,7 @@ |
|
.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
.\" SUCH DAMAGE. |
|
.\" |
|
-.Dd May 20, 2017 |
|
+.Dd February 13, 2014 |
|
.Dt DMA 8 |
|
.Os |
|
.Sh NAME |
|
@@ -74,7 +74,7 @@ |
|
.It Fl bp |
|
List all mails currently stored in the mail queue. |
|
.It Fl bq |
|
-Queue the mail, but do not attempt to deliver it. |
|
+Queue the mail, but don't attempt to deliver it. |
|
See also the |
|
.Sq DEFER |
|
config file setting below. |
|
@@ -82,15 +82,18 @@ |
|
.Pp |
|
All other |
|
.Ar mode Ns |
|
-s are ignored. |
|
+s are are ignored. |
|
.It Fl D |
|
-Do not run in the background. |
|
+Don't run in the background. |
|
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. |
|
@@ -198,7 +201,7 @@ |
|
.Ql * |
|
can be used to create a catch-all alias, which gets used if no other |
|
matching alias is found. |
|
-Use the catch-all alias only if you do not want any local mail to be |
|
+Use the catch-all alias only if you don't want any local mail to be |
|
delivered. |
|
.It Ic SPOOLDIR Xo |
|
(string, default=/var/spool/dma) |
|
@@ -213,7 +216,7 @@ |
|
Path to the |
|
.Sq auth.conf |
|
file. |
|
-.It Ic SECURETRANSFER Xo |
|
+.It Ic SECURETRANS Xo |
|
(boolean, default=commented) |
|
.Xc |
|
Uncomment if you want TLS/SSL secured transfer. |
|
@@ -222,7 +225,10 @@ |
|
.Xc |
|
Uncomment if you want to use STARTTLS. |
|
Only useful together with |
|
-.Sq SECURETRANSFER . |
|
+.Sq SECURETRANS . |
|
+.It Ic FINGERPRINT Xo |
|
+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 |
|
@@ -234,7 +240,7 @@ |
|
be encrypted if the remote server supports STARTTLS, but an unencrypted |
|
delivery will still be made if the negotiation fails. |
|
Only useful together with |
|
-.Sq SECURETRANSFER |
|
+.Sq SECURETRANS |
|
and |
|
.Sq STARTTLS . |
|
.It Ic CERTFILE Xo |
|
@@ -283,7 +289,7 @@ |
|
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 |
|
@@ -305,8 +311,7 @@ |
|
setting it to |
|
.Ql percolator |
|
will send all mails as |
|
-.Sm off |
|
-.Ql Va username @percolator . |
|
+.Ql Sm off Va username @percolator . |
|
.Sm on |
|
.It Ic NULLCLIENT Xo |
|
.Xc |
|
@@ -329,6 +334,8 @@ |
|
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 |
|
--- freebsd/contrib/dma/dma.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/dma.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -85,6 +85,7 @@ |
|
.mailname = NULL, |
|
.masquerade_host = NULL, |
|
.masquerade_user = NULL, |
|
+ .fingerprint = NULL, |
|
}; |
|
|
|
|
|
@@ -100,15 +101,14 @@ |
|
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, '@')) { |
|
@@ -331,8 +331,8 @@ |
|
|
|
switch (error) { |
|
case 0: |
|
- syslog(LOG_INFO, "<%s> delivery successful", it->addr); |
|
delqueue(it); |
|
+ syslog(LOG_INFO, "<%s> delivery successful", it->addr); |
|
exit(EX_OK); |
|
|
|
case 1: |
|
@@ -466,7 +466,7 @@ |
|
goto skipopts; |
|
} else if (strcmp(argv[0], "newaliases") == 0) { |
|
logident_base = "dma"; |
|
- setlogident("%s", logident_base); |
|
+ setlogident(NULL); |
|
|
|
if (read_aliases() != 0) |
|
errx(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); |
|
@@ -565,7 +565,7 @@ |
|
skipopts: |
|
if (logident_base == NULL) |
|
logident_base = "dma"; |
|
- setlogident("%s", logident_base); |
|
+ setlogident(NULL); |
|
|
|
act.sa_handler = sighup_handler; |
|
act.sa_flags = 0; |
|
@@ -597,7 +597,7 @@ |
|
errlog(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); |
|
|
|
if ((sender = set_from(&queue, sender)) == NULL) |
|
- errlog(EX_SOFTWARE, "set_from()"); |
|
+ errlog(EX_SOFTWARE, NULL); |
|
|
|
if (newspoolf(&queue) != 0) |
|
errlog(EX_CANTCREAT, "can not create temp file in `%s'", config.spooldir); |
|
--- freebsd/contrib/dma/dma.h 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/dma.h 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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 */ |
|
@@ -137,6 +138,7 @@ |
|
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 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 @@ |
|
/* 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 @@ |
|
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 */ |
|
--- freebsd/contrib/dma/local.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/local.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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> |
|
@@ -219,7 +220,7 @@ |
|
/* |
|
* 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 |
|
--- freebsd/contrib/dma/mail.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/mail.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -36,14 +36,13 @@ |
|
#include <errno.h> |
|
#include <inttypes.h> |
|
#include <signal.h> |
|
+#include <strings.h> |
|
#include <string.h> |
|
#include <syslog.h> |
|
#include <unistd.h> |
|
|
|
#include "dma.h" |
|
|
|
-#define MAX_LINE_RFC822 1000 |
|
- |
|
void |
|
bounce(struct qitem *it, const char *reason) |
|
{ |
|
@@ -336,7 +335,7 @@ |
|
ps->pos = 0; |
|
addr = strdup(ps->addr); |
|
if (addr == NULL) |
|
- errlog(EX_SOFTWARE, "strdup"); |
|
+ errlog(EX_SOFTWARE, NULL); |
|
|
|
if (add_recp(queue, addr, EXPAND_WILDCARD) != 0) |
|
errlogx(EX_DATAERR, "invalid recipient `%s'", addr); |
|
@@ -344,47 +343,20 @@ |
|
goto again; |
|
} |
|
|
|
-static int |
|
-writeline(struct queue *queue, const char *line, ssize_t linelen) |
|
-{ |
|
- ssize_t len; |
|
- |
|
- while (linelen > 0) { |
|
- len = linelen; |
|
- if (linelen > MAX_LINE_RFC822) { |
|
- len = MAX_LINE_RFC822 - 10; |
|
- } |
|
- |
|
- if (fwrite(line, len, 1, queue->mailf) != 1) |
|
- return (-1); |
|
- |
|
- if (linelen <= MAX_LINE_RFC822) |
|
- break; |
|
- |
|
- if (fwrite("\n", 1, 1, queue->mailf) != 1) |
|
- return (-1); |
|
- |
|
- line += MAX_LINE_RFC822 - 10; |
|
- linelen = strlen(line); |
|
- } |
|
- return (0); |
|
-} |
|
- |
|
int |
|
readmail(struct queue *queue, int nodot, int recp_from_header) |
|
{ |
|
struct parse_state parse_state; |
|
- char *line = NULL; |
|
- ssize_t linelen; |
|
- size_t linecap = 0; |
|
- char newline[MAX_LINE_RFC822]; |
|
+ char line[1000]; /* by RFC2822 */ |
|
+ size_t linelen; |
|
size_t error; |
|
int had_headers = 0; |
|
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; |
|
|
|
parse_state.state = NONE; |
|
|
|
@@ -403,17 +375,33 @@ |
|
return (-1); |
|
|
|
while (!feof(stdin)) { |
|
- newline[0] = '\0'; |
|
- if ((linelen = getline(&line, &linecap, stdin)) <= 0) |
|
+ if (fgets(line, sizeof(line) - 1, stdin) == NULL) |
|
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 */ |
|
- errlogx(EX_DATAERR, "bad mail input format:" |
|
- " from %s (uid %d) (envelope-from %s)", |
|
- username, useruid, queue->sender); |
|
- } |
|
/* |
|
* Unless this is a continuation, switch of |
|
* the Bcc: nocopy flag. |
|
@@ -454,39 +442,31 @@ |
|
while (!had_date || !had_messagid || !had_from) { |
|
if (!had_date) { |
|
had_date = 1; |
|
- snprintf(newline, sizeof(newline), "Date: %s\n", rfc822date()); |
|
+ snprintf(line, sizeof(line), "Date: %s\n", rfc822date()); |
|
} else if (!had_messagid) { |
|
/* XXX msgid, assign earlier and log? */ |
|
had_messagid = 1; |
|
- snprintf(newline, sizeof(newline), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n", |
|
+ snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n", |
|
(uintmax_t)time(NULL), |
|
queue->id, |
|
(uintmax_t)random(), |
|
hostname()); |
|
} else if (!had_from) { |
|
had_from = 1; |
|
- snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender); |
|
+ snprintf(line, sizeof(line), "From: <%s>\n", queue->sender); |
|
} |
|
- if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1) |
|
- goto fail; |
|
+ if (fwrite(line, strlen(line), 1, queue->mailf) != 1) |
|
+ return (-1); |
|
} |
|
- strlcpy(newline, "\n", sizeof(newline)); |
|
+ strcpy(line, "\n"); |
|
} |
|
if (!nodot && linelen == 2 && line[0] == '.') |
|
break; |
|
if (!nocopy) { |
|
- if (newline[0]) { |
|
- if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1) |
|
- goto fail; |
|
- } else { |
|
- if (writeline(queue, line, linelen) != 0) |
|
- goto fail; |
|
- } |
|
+ if (fwrite(line, strlen(line), 1, queue->mailf) != 1) |
|
+ return (-1); |
|
} |
|
} |
|
|
|
- ret = 0; |
|
-fail: |
|
- free(line); |
|
- return (ret); |
|
+ return (0); |
|
} |
|
--- freebsd/contrib/dma/net.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/net.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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> |
|
@@ -100,7 +101,7 @@ |
|
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); |
|
} |
|
} |
|
@@ -150,12 +151,12 @@ |
|
if (((config.features & SECURETRANS) != 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 @@ |
|
* 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); |
|
@@ -349,11 +356,116 @@ |
|
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,21 +478,23 @@ |
|
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 || |
|
@@ -392,7 +506,7 @@ |
|
} |
|
|
|
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 |
|
@@ -402,10 +516,12 @@ |
|
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 @@ |
|
* 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 @@ |
|
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 @@ |
|
syslog(LOG_INFO, "remote delivery succeeded but QUIT failed: %s", neterr); |
|
out: |
|
|
|
+ free(addrtmp); |
|
close_connection(fd); |
|
return (error); |
|
} |
|
--- freebsd/contrib/dma/spool.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/spool.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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> |
|
|
|
@@ -417,7 +419,7 @@ |
|
return (0); |
|
|
|
/* Did the flush file get touched within the last period seconds? */ |
|
- if (st.st_mtim.tv_sec + (int)period >= now.tv_sec) |
|
+ if (st.st_mtim.tv_sec + period >= now.tv_sec) |
|
return (1); |
|
else |
|
return (0); |
|
--- freebsd/contrib/dma/util.c 2020-03-06 11:33:23.000000000 +0100 |
|
+++ ../d/dma/util.c 2020-03-06 11:30:13.000000000 +0100 |
|
@@ -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> |