From fd122dde8c51855b0c3a70081bf40b25c312b92b Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sat, 31 Oct 2015 00:00:00 -0500 Subject: [PATCH] postfix-3.1-20151031 --- postfix/.indent.pro | 1 - postfix/HISTORY | 21 ++++++++++ postfix/README_FILES/TUNING_README | 4 ++ postfix/html/TUNING_README.html | 5 +++ postfix/html/anvil.8.html | 13 ++++++ postfix/html/lmtp.8.html | 1 + postfix/html/postconf.5.html | 31 +++++++++++++++ postfix/html/smtp.8.html | 1 + postfix/html/smtpd.8.html | 12 +++++- postfix/man/man5/postconf.5 | 15 +++++++ postfix/man/man8/anvil.8 | 21 ++++++++++ postfix/man/man8/smtp.8 | 1 + postfix/man/man8/smtpd.8 | 9 ++++- postfix/mantools/postlink | 1 + postfix/proto/TUNING_README.html | 5 +++ postfix/proto/postconf.proto | 27 +++++++++++++ postfix/src/anvil/anvil.c | 58 +++++++++++++++++++++++++++ postfix/src/global/anvil_clnt.c | 63 ++++++++++++++++++++++++++---- postfix/src/global/anvil_clnt.h | 5 ++- postfix/src/global/mail_params.h | 4 ++ postfix/src/global/mail_version.h | 2 +- postfix/src/smtp/smtp.c | 1 + postfix/src/smtpd/smtpd.c | 41 +++++++++++++++++-- postfix/src/tls/tls.h | 12 +++++- postfix/src/tls/tls_dane.c | 10 ++--- postfix/src/tls/tls_fprint.c | 2 +- postfix/src/tls/tls_misc.c | 4 +- postfix/src/tls/tls_server.c | 4 +- postfix/src/tls/tls_verify.c | 2 +- 29 files changed, 345 insertions(+), 31 deletions(-) diff --git a/postfix/.indent.pro b/postfix/.indent.pro index c15aa6353..0e9462f19 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -404,5 +404,4 @@ -Tssl_comp_stack_t -Ttime_t -Ttlsa_filter --Tx509_extension_stack_t -Tx509_stack_t diff --git a/postfix/HISTORY b/postfix/HISTORY index ec3762e54..5b06aab4f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -21989,3 +21989,24 @@ Apologies for any names omitted. warnings, and skip the failing pattern as in dict_regexp.c. Also, fixed the error text when running into the matcher's backtracking limit. File: util/dict_pcre.c. + +20151017 + + Feature: smtpd_client_auth_rate_limit enforces a rate + limit on the number of AUTH commands per client IP address. + mantools/postlink, proto/postconf.proto, anvil/anvil.c, + global/anvil_clnt.c, global/anvil_clnt.h, global/mail_params.h, + smtpd/smtpd.c. + +20151018 + + Added RFC 7672 (SMTP security via opportunistic DANE TLS) + and RFC 7505 ("Null MX" No Service Resource Record) to the + lists of supported RFCs in manpages. Viktor Dukhovni. Files: + smtp/smtp.c, smtpd/smtpd.c. + +20151031 + + Bitrot: OpenSSL API cleanups. Viktor Dukhovni. Files: + .indent.pro, tls/tls.h, tls/tls_dane.c, tls/tls_fprint.c, + tls/tls_misc.c, tls/tls_server.c, tls/tls_verify.c. diff --git a/postfix/README_FILES/TUNING_README b/postfix/README_FILES/TUNING_README index b7a3f3a3d..c1176617a 100644 --- a/postfix/README_FILES/TUNING_README +++ b/postfix/README_FILES/TUNING_README @@ -173,6 +173,10 @@ the smtpd(8) server against abuse by out-of-control clients. The maximum number of new TLS sessions (without using the TLS session cache) that an SMTP client may negotiate in the time interval specified with anvil_rate_time_unit (default: 60s). + smtpd_client_auth_rate_limit (default: no limit) + The maximum number of AUTH commands that an SMTP client may send in the + time interval specified with anvil_rate_time_unit (default: 60s). + Available in Postfix 3.1 and later. smtpd_client_event_limit_exceptions (default: $mynetworks) SMTP clients that are excluded from connection and rate limits specified above. diff --git a/postfix/html/TUNING_README.html b/postfix/html/TUNING_README.html index a851a225d..9a378d03c 100644 --- a/postfix/html/TUNING_README.html +++ b/postfix/html/TUNING_README.html @@ -267,6 +267,11 @@ the TLS session cache) that an SMTP client may negotiate in the time interval specified with anvil_rate_time_unit (default: 60s). +
smtpd_client_auth_rate_limit (default: no limit)
+The maximum number of AUTH commands that an SMTP client may send +in the time interval specified with anvil_rate_time_unit (default: +60s). Available in Postfix 3.1 and later.
+
smtpd_client_event_limit_exceptions (default: $mynetworks)
SMTP clients that are excluded from connection and rate limits specified above.
diff --git a/postfix/html/anvil.8.html b/postfix/html/anvil.8.html index 0bd441baa..84e5843e7 100644 --- a/postfix/html/anvil.8.html +++ b/postfix/html/anvil.8.html @@ -106,6 +106,19 @@ ANVIL(8) ANVIL(8) status=0 rate=number +AUTH RATE CONTROL + To register an AUTH request send the following request to the anvil(8) + server: + + request=auth + ident=string + + The anvil(8) server answers with the number of auth requests per unit + time for the (service, client) combination specified with ident: + + status=0 + rate=number + SECURITY The anvil(8) server does not talk to the network or to local users, and can run chrooted at fixed low privilege. diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index 2401c43b9..946f64b7f 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -109,6 +109,7 @@ SMTP(8) SMTP(8) RFC 5321 (SMTP protocol) RFC 6531 (Internationalized SMTP) RFC 6533 (Internationalized Delivery Status Notifications) + RFC 7672 (SMTP security via opportunistic DANE TLS) DIAGNOSTICS Problems and transactions are logged to syslogd(8). Corrupted message diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 4d5fd17f9..67edf42b6 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -13240,6 +13240,37 @@ Example: + + +
smtpd_client_auth_rate_limit +(default: 0)
+ +

+The maximal number of AUTH commands that any client is allowed to +send to this service per time unit, regardless of whether or not +Postfix actually accepts those commands. The time unit is specified +with the anvil_rate_time_unit configuration parameter. +

+ +

+By default, there is no limit on the number AUTH commands that a +client may send. +

+ +

+To disable this feature, specify a limit of 0. +

+ +

+WARNING: The purpose of this feature is to limit abuse. It must +not be used to regulate legitimate mail traffic. +

+ +

+This feature is available in Postfix 3.1 and later. +

+ +
smtpd_client_connection_count_limit diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 2401c43b9..946f64b7f 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -109,6 +109,7 @@ SMTP(8) SMTP(8) RFC 5321 (SMTP protocol) RFC 6531 (Internationalized SMTP) RFC 6533 (Internationalized Delivery Status Notifications) + RFC 7672 (SMTP security via opportunistic DANE TLS) DIAGNOSTICS Problems and transactions are logged to syslogd(8). Corrupted message diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 3a8587fc6..87d9a2e10 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -59,6 +59,7 @@ SMTPD(8) SMTPD(8) RFC 5321 (SMTP protocol) RFC 6531 (Internationalized SMTP) RFC 6533 (Internationalized Delivery Status Notifications) + RFC 7505 ("Null MX" No Service Resource Record) DIAGNOSTICS Problems and transactions are logged to syslogd(8). @@ -339,8 +340,8 @@ SMTPD(8) SMTPD(8) tation that is selected with smtpd_sasl_type. smtpd_sender_login_maps (empty) - Optional lookup table with the SASL login names that own sender - (MAIL FROM) addresses. + Optional lookup table with the SASL login names that own the + sender (MAIL FROM) addresses. Available in Postfix version 2.1 and later: @@ -840,6 +841,13 @@ SMTPD(8) SMTPD(8) record (an SMTP command line, SMTP response line, SMTP message content line, or TLS protocol message). + Available in Postfix version 3.1 and later: + + smtpd_client_auth_rate_limit (0) + The maximal number of AUTH commands that any client is allowed + to send to this service per time unit, regardless of whether or + not Postfix actually accepts those commands. + TARPIT CONTROLS When a remote SMTP client makes errors, the Postfix SMTP server can insert delays before responding. This can help to slow down run-away diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index b767f2884..24cdf21e0 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -8764,6 +8764,21 @@ smtpd_banner = $myhostname ESMTP $mail_name ($mail_version) .fi .ad .ft R +.SH smtpd_client_auth_rate_limit (default: 0) +The maximal number of AUTH commands that any client is allowed to +send to this service per time unit, regardless of whether or not +Postfix actually accepts those commands. The time unit is specified +with the anvil_rate_time_unit configuration parameter. +.PP +By default, there is no limit on the number AUTH commands that a +client may send. +.PP +To disable this feature, specify a limit of 0. +.PP +WARNING: The purpose of this feature is to limit abuse. It must +not be used to regulate legitimate mail traffic. +.PP +This feature is available in Postfix 3.1 and later. .SH smtpd_client_connection_count_limit (default: 50) How many simultaneous connections any client is allowed to make to this service. By default, the limit is set to half diff --git a/postfix/man/man8/anvil.8 b/postfix/man/man8/anvil.8 index 4aff7adcf..17e1f89cd 100644 --- a/postfix/man/man8/anvil.8 +++ b/postfix/man/man8/anvil.8 @@ -140,6 +140,27 @@ The \fBanvil\fR(8) server answers with the number of new TLS session requests per unit time for the (service, client) combination specified with \fBident\fR: +.nf + \fBstatus=0\fR + \fBrate=\fInumber\fR +.fi +.SH "AUTH RATE CONTROL" +.na +.nf +.ad +.fi +To register an AUTH request send the following request +to the \fBanvil\fR(8) server: + +.nf + \fBrequest=auth\fR + \fBident=\fIstring\fR +.fi + +The \fBanvil\fR(8) server answers with the number of auth +requests per unit time for the (service, client) combination +specified with \fBident\fR: + .nf \fBstatus=0\fR \fBrate=\fInumber\fR diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 08c512f68..933151b65 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -112,6 +112,7 @@ RFC 4954 (AUTH command) RFC 5321 (SMTP protocol) RFC 6531 (Internationalized SMTP) RFC 6533 (Internationalized Delivery Status Notifications) +RFC 7672 (SMTP security via opportunistic DANE TLS) .SH DIAGNOSTICS .ad .fi diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 80fece96d..5e4b86a56 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -65,6 +65,7 @@ RFC 4954 (AUTH command) RFC 5321 (SMTP protocol) RFC 6531 (Internationalized SMTP) RFC 6533 (Internationalized Delivery Status Notifications) +RFC 7505 ("Null MX" No Service Resource Record) .SH DIAGNOSTICS .ad .fi @@ -329,7 +330,7 @@ the list of available features depends on the SASL server implementation that is selected with \fBsmtpd_sasl_type\fR. .IP "\fBsmtpd_sender_login_maps (empty)\fR" -Optional lookup table with the SASL login names that own sender +Optional lookup table with the SASL login names that own the sender (MAIL FROM) addresses. .PP Available in Postfix version 2.1 and later: @@ -745,6 +746,12 @@ time limits, from a time limit per read or write system call, to a time limit to send or receive a complete record (an SMTP command line, SMTP response line, SMTP message content line, or TLS protocol message). +.PP +Available in Postfix version 3.1 and later: +.IP "\fBsmtpd_client_auth_rate_limit (0)\fR" +The maximal number of AUTH commands that any client is allowed to +send to this service per time unit, regardless of whether or not +Postfix actually accepts those commands. .SH "TARPIT CONTROLS" .na .nf diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index f3aa2b6af..82ec6bece 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -521,6 +521,7 @@ while (<>) { s;\bsmtpd_autho[-]*\n*[ ]*rized_xclient_hosts\b;$&;g; s;\bsmtpd_autho[-]*\n*[ ]*rized_xforward_hosts\b;$&;g; s;\bsmtpd_ban[-]*\n*[ ]*ner\b;$&;g; + s;\bsmtpd_client_auth_rate_limit\b;$&;g; s;\bsmtpd_client_connec[-]*\n*[ ]*tion_count_limit\b;$&;g; s;\bsmtpd_client_event_limit_exceptions\b;$&;g; s;\bsmtpd_client_connec[-]*\n*[ ]*tion_rate_limit\b;$&;g; diff --git a/postfix/proto/TUNING_README.html b/postfix/proto/TUNING_README.html index ca3d7d7c9..c5641f2ce 100644 --- a/postfix/proto/TUNING_README.html +++ b/postfix/proto/TUNING_README.html @@ -267,6 +267,11 @@ the TLS session cache) that an SMTP client may negotiate in the time interval specified with anvil_rate_time_unit (default: 60s). +
smtpd_client_auth_rate_limit (default: no limit)
+The maximum number of AUTH commands that an SMTP client may send +in the time interval specified with anvil_rate_time_unit (default: +60s). Available in Postfix 3.1 and later.
+
smtpd_client_event_limit_exceptions (default: $mynetworks)
SMTP clients that are excluded from connection and rate limits specified above.
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 53dbdad06..7097015fd 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -5022,6 +5022,33 @@ Example: smtpd_client_new_tls_session_rate_limit = 100 +%PARAM smtpd_client_auth_rate_limit 0 + +

+The maximal number of AUTH commands that any client is allowed to +send to this service per time unit, regardless of whether or not +Postfix actually accepts those commands. The time unit is specified +with the anvil_rate_time_unit configuration parameter. +

+ +

+By default, there is no limit on the number AUTH commands that a +client may send. +

+ +

+To disable this feature, specify a limit of 0. +

+ +

+WARNING: The purpose of this feature is to limit abuse. It must +not be used to regulate legitimate mail traffic. +

+ +

+This feature is available in Postfix 3.1 and later. +

+ %PARAM smtpd_client_restrictions

diff --git a/postfix/src/anvil/anvil.c b/postfix/src/anvil/anvil.c index ffc40d872..0b536539c 100644 --- a/postfix/src/anvil/anvil.c +++ b/postfix/src/anvil/anvil.c @@ -130,6 +130,25 @@ /* \fBstatus=0\fR /* \fBrate=\fInumber\fR /* .fi +/* AUTH RATE CONTROL +/* .ad +/* .fi +/* To register an AUTH request send the following request +/* to the \fBanvil\fR(8) server: +/* +/* .nf +/* \fBrequest=auth\fR +/* \fBident=\fIstring\fR +/* .fi +/* +/* The \fBanvil\fR(8) server answers with the number of auth +/* requests per unit time for the (service, client) combination +/* specified with \fBident\fR: +/* +/* .nf +/* \fBstatus=0\fR +/* \fBrate=\fInumber\fR +/* .fi /* SECURITY /* .ad /* .fi @@ -288,6 +307,7 @@ typedef struct { int mail; /* message rate */ int rcpt; /* recipient rate */ int ntls; /* new TLS session rate */ + int auth; /* AUTH request rate */ time_t start; /* time of first rate sample */ } ANVIL_REMOTE; @@ -318,6 +338,7 @@ typedef struct { (remote)->mail = 0; \ (remote)->rcpt = 0; \ (remote)->ntls = 0; \ + (remote)->auth = 0; \ (remote)->start = event_time(); \ } while(0) @@ -337,6 +358,7 @@ typedef struct { (remote)->mail = 0; \ (remote)->rcpt = 0; \ (remote)->ntls = 0; \ + (remote)->auth = 0; \ (remote)->start = _start; \ } while(0) @@ -365,6 +387,8 @@ typedef struct { #define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls) +#define ANVIL_REMOTE_INCR_AUTH(remote) ANVIL_REMOTE_INCR_RATE((remote), auth) + /* Drop connection from (service, client) state. */ #define ANVIL_REMOTE_DROP_ONE(remote) \ @@ -441,6 +465,7 @@ static ANVIL_MAX max_conn_rate; /* peak connection rate */ static ANVIL_MAX max_mail_rate; /* peak message rate */ static ANVIL_MAX max_rcpt_rate; /* peak recipient rate */ static ANVIL_MAX max_ntls_rate; /* peak new TLS session rate */ +static ANVIL_MAX max_auth_rate; /* peak AUTH request rate */ static int max_cache_size; /* peak cache size */ static time_t max_cache_time; /* time of peak size */ @@ -531,6 +556,7 @@ static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident) SEND_ATTR_INT(ANVIL_ATTR_MAIL, 0), SEND_ATTR_INT(ANVIL_ATTR_RCPT, 0), SEND_ATTR_INT(ANVIL_ATTR_NTLS, 0), + SEND_ATTR_INT(ANVIL_ATTR_AUTH, 0), ATTR_TYPE_END); } else { @@ -547,6 +573,7 @@ static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident) SEND_ATTR_INT(ANVIL_ATTR_MAIL, anvil_remote->mail), SEND_ATTR_INT(ANVIL_ATTR_RCPT, anvil_remote->rcpt), SEND_ATTR_INT(ANVIL_ATTR_NTLS, anvil_remote->ntls), + SEND_ATTR_INT(ANVIL_ATTR_AUTH, anvil_remote->auth), ATTR_TYPE_END); } } @@ -689,6 +716,35 @@ static void anvil_remote_rcpt(VSTREAM *client_stream, const char *ident) ANVIL_MAX_UPDATE(max_rcpt_rate, anvil_remote->rcpt, anvil_remote->ident); } +/* anvil_remote_auth - register auth request event */ + +static void anvil_remote_auth(VSTREAM *client_stream, const char *ident) +{ + ANVIL_REMOTE *anvil_remote; + + /* + * Be prepared for "postfix reload" after "connect". + */ + if ((anvil_remote = + (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) + anvil_remote = anvil_remote_conn_update(client_stream, ident); + + /* + * Update recipient address rate and respond to local server. + */ + ANVIL_REMOTE_INCR_AUTH(anvil_remote); + attr_print_plain(client_stream, ATTR_FLAG_NONE, + SEND_ATTR_INT(ANVIL_ATTR_STATUS, ANVIL_STAT_OK), + SEND_ATTR_INT(ANVIL_ATTR_RATE, anvil_remote->auth), + ATTR_TYPE_END); + + /* + * Update peak statistics. + */ + if (anvil_remote->auth > max_auth_rate.value) + ANVIL_MAX_UPDATE(max_auth_rate, anvil_remote->auth, anvil_remote->ident); +} + /* anvil_remote_newtls - register newtls event */ static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident) @@ -826,6 +882,7 @@ static void anvil_status_dump(char *unused_name, char **unused_argv) ANVIL_MAX_RATE_REPORT(max_mail_rate, "message"); ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient"); ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls"); + ANVIL_MAX_RATE_REPORT(max_auth_rate, "auth"); if (max_cache_size > 0) { msg_info("statistics: max cache size %d at %.15s", @@ -855,6 +912,7 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a ANVIL_REQ_NTLS, anvil_remote_newtls, ANVIL_REQ_DISC, anvil_remote_disconnect, ANVIL_REQ_NTLS_STAT, anvil_remote_newtls_stat, + ANVIL_REQ_AUTH, anvil_remote_auth, ANVIL_REQ_LOOKUP, anvil_remote_lookup, 0, 0, }; diff --git a/postfix/src/global/anvil_clnt.c b/postfix/src/global/anvil_clnt.c index 34d3c0f31..a681ca14c 100644 --- a/postfix/src/global/anvil_clnt.c +++ b/postfix/src/global/anvil_clnt.c @@ -43,13 +43,19 @@ /* const char *addr; /* int *newtls; /* +/* int anvil_clnt_auth(anvil_clnt, service, addr, auths) +/* ANVIL_CLNT *anvil_clnt; +/* const char *service; +/* const char *addr; +/* int *auths; +/* /* int anvil_clnt_disconnect(anvil_clnt, service, addr) /* ANVIL_CLNT *anvil_clnt; /* const char *service; /* const char *addr; /* -/* int anvil_clnt_lookup(anvil_clnt, service, addr, -/* count, rate, msgs, rcpts) +/* int anvil_clnt_lookup(anvil_clnt, service, addr, count, +/* rate, msgs, rcpts, ntls, auths) /* ANVIL_CLNT *anvil_clnt; /* const char *service; /* const char *addr; @@ -57,6 +63,8 @@ /* int *rate; /* int *msgs; /* int *rcpts; +/* int *ntls; +/* int *auths; /* DESCRIPTION /* anvil_clnt_create() instantiates a local anvil service /* client endpoint. @@ -80,6 +88,9 @@ /* anvil_clnt_newtls_stat() returns the current newtls request /* rate for the specified remote client. /* +/* anvil_clnt_auth() registers an AUTH event and returns the +/* current AUTH event rate for the specified remote client. +/* /* anvil_clnt_disconnect() informs the anvil server that a remote /* client has disconnected. /* @@ -111,6 +122,9 @@ /* .IP newtls /* Pointer to storage for the current "new TLS session" rate /* for this remote client. +/* .IP auths +/* Pointer to storage for the current AUTH event rate for this +/* remote client. /* DIAGNOSTICS /* The update and status query routines return /* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise @@ -181,7 +195,7 @@ void anvil_clnt_free(ANVIL_CLNT *anvil_clnt) int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service, const char *addr, int *count, int *rate, - int *msgs, int *rcpts, int *newtls) + int *msgs, int *rcpts, int *newtls, int *auths) { char *ident = ANVIL_IDENT(service, addr); int status; @@ -198,7 +212,8 @@ int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service, RECV_ATTR_INT(ANVIL_ATTR_MAIL, msgs), RECV_ATTR_INT(ANVIL_ATTR_RCPT, rcpts), RECV_ATTR_INT(ANVIL_ATTR_NTLS, newtls), - ATTR_TYPE_END) != 6) + RECV_ATTR_INT(ANVIL_ATTR_AUTH, auths), + ATTR_TYPE_END) != 7) status = ANVIL_STAT_FAIL; else if (status != ANVIL_STAT_OK) status = ANVIL_STAT_FAIL; @@ -327,6 +342,30 @@ int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service, return (status); } +/* anvil_clnt_auth - heads-up and status query */ + +int anvil_clnt_auth(ANVIL_CLNT *anvil_clnt, const char *service, + const char *addr, int *auths) +{ + char *ident = ANVIL_IDENT(service, addr); + int status; + + if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, + ATTR_FLAG_NONE, /* Query attributes. */ + SEND_ATTR_STR(ANVIL_ATTR_REQ, ANVIL_REQ_AUTH), + SEND_ATTR_STR(ANVIL_ATTR_IDENT, ident), + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply attributes. */ + RECV_ATTR_INT(ANVIL_ATTR_STATUS, &status), + RECV_ATTR_INT(ANVIL_ATTR_RATE, auths), + ATTR_TYPE_END) != 2) + status = ANVIL_STAT_FAIL; + else if (status != ANVIL_STAT_OK) + status = ANVIL_STAT_FAIL; + myfree(ident); + return (status); +} + /* anvil_clnt_disconnect - heads-up only */ int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service, @@ -371,6 +410,7 @@ static void usage(void) ANVIL_REQ_RCPT " service addr | " ANVIL_REQ_NTLS " service addr | " ANVIL_REQ_NTLS_STAT " service addr | " + ANVIL_REQ_AUTH " service addr | " ANVIL_REQ_LOOKUP " service addr\n"); } @@ -387,6 +427,7 @@ int main(int unused_argc, char **argv) int msgs; int rcpts; int newtls; + int auths; ANVIL_CLNT *anvil; msg_vstream_init(argv[0], VSTREAM_ERR); @@ -432,6 +473,11 @@ int main(int unused_argc, char **argv) msg_warn("error!"); else vstream_printf("rate=%d\n", newtls); + } else if (strncmp(cmd, ANVIL_REQ_AUTH, cmd_len) == 0) { + if (anvil_clnt_auth(anvil, service, addr, &auths) != ANVIL_STAT_OK) + msg_warn("error!"); + else + vstream_printf("rate=%d\n", auths); } else if (strncmp(cmd, ANVIL_REQ_NTLS_STAT, cmd_len) == 0) { if (anvil_clnt_newtls_stat(anvil, service, addr, &newtls) != ANVIL_STAT_OK) msg_warn("error!"); @@ -443,12 +489,13 @@ int main(int unused_argc, char **argv) else vstream_printf("OK\n"); } else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) { - if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, - &msgs, &rcpts, &newtls) != ANVIL_STAT_OK) + if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, &msgs, + &rcpts, &newtls, &auths) != ANVIL_STAT_OK) msg_warn("error!"); else - vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d\n", - count, rate, msgs, rcpts, newtls); + vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d " + "auths=%d\n", count, rate, msgs, rcpts, newtls, + auths); } else { vstream_printf("bad command: \"%s\"\n", cmd); usage(); diff --git a/postfix/src/global/anvil_clnt.h b/postfix/src/global/anvil_clnt.h index 0e48a42dd..f95b64800 100644 --- a/postfix/src/global/anvil_clnt.h +++ b/postfix/src/global/anvil_clnt.h @@ -34,6 +34,7 @@ #define ANVIL_REQ_RCPT "recipient" #define ANVIL_REQ_NTLS "newtls" #define ANVIL_REQ_NTLS_STAT "newtls_status" +#define ANVIL_REQ_AUTH "auth" #define ANVIL_REQ_LOOKUP "lookup" #define ANVIL_ATTR_IDENT "ident" #define ANVIL_ATTR_COUNT "count" @@ -41,6 +42,7 @@ #define ANVIL_ATTR_MAIL "mail" #define ANVIL_ATTR_RCPT "rcpt" #define ANVIL_ATTR_NTLS "newtls" +#define ANVIL_ATTR_AUTH "auth" #define ANVIL_ATTR_STATUS "status" #define ANVIL_STAT_OK 0 @@ -57,7 +59,8 @@ extern int anvil_clnt_mail(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_rcpt(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_newtls(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_newtls_stat(ANVIL_CLNT *, const char *, const char *, int *); -extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *, int *); +extern int anvil_clnt_auth(ANVIL_CLNT *, const char *, const char *, int *); +extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *, int *, int *); extern int anvil_clnt_disconnect(ANVIL_CLNT *, const char *, const char *); extern void anvil_clnt_free(ANVIL_CLNT *); diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index b4dbc21bb..91c7f126e 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -2996,6 +2996,10 @@ extern int var_smtpd_crcpt_limit; #define DEF_SMTPD_CNTLS_LIMIT 0 extern int var_smtpd_cntls_limit; +#define VAR_SMTPD_CAUTH_LIMIT "smtpd_client_auth_rate_limit" +#define DEF_SMTPD_CAUTH_LIMIT 0 +extern int var_smtpd_cauth_limit; + #define VAR_SMTPD_HOGGERS "smtpd_client_event_limit_exceptions" #define DEF_SMTPD_HOGGERS "${smtpd_client_connection_limit_exceptions:$" VAR_MYNETWORKS "}" extern char *var_smtpd_hoggers; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 0a84fd808..d2c85a7a5 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20151011" +#define MAIL_RELEASE_DATE "20151031" #define MAIL_VERSION_NUMBER "3.1" #ifdef SNAPSHOT diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 192e8b2ea..6ca453749 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -98,6 +98,7 @@ /* RFC 5321 (SMTP protocol) /* RFC 6531 (Internationalized SMTP) /* RFC 6533 (Internationalized Delivery Status Notifications) +/* RFC 7672 (SMTP security via opportunistic DANE TLS) /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* Corrupted message files are marked so that the queue manager can diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 14bdc693c..7111808cc 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -55,6 +55,7 @@ /* RFC 5321 (SMTP protocol) /* RFC 6531 (Internationalized SMTP) /* RFC 6533 (Internationalized Delivery Status Notifications) +/* RFC 7505 ("Null MX" No Service Resource Record) /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* @@ -297,7 +298,7 @@ /* features depends on the SASL server implementation that is selected /* with \fBsmtpd_sasl_type\fR. /* .IP "\fBsmtpd_sender_login_maps (empty)\fR" -/* Optional lookup table with the SASL login names that own sender +/* Optional lookup table with the SASL login names that own the sender /* (MAIL FROM) addresses. /* .PP /* Available in Postfix version 2.1 and later: @@ -699,6 +700,12 @@ /* time limit per read or write system call, to a time limit to send /* or receive a complete record (an SMTP command line, SMTP response /* line, SMTP message content line, or TLS protocol message). +/* .PP +/* Available in Postfix version 3.1 and later: +/* .IP "\fBsmtpd_client_auth_rate_limit (0)\fR" +/* The maximal number of AUTH commands that any client is allowed to +/* send to this service per time unit, regardless of whether or not +/* Postfix actually accepts those commands. /* TARPIT CONTROLS /* .ad /* .fi @@ -1292,6 +1299,7 @@ int var_smtpd_cconn_limit; int var_smtpd_cmail_limit; int var_smtpd_crcpt_limit; int var_smtpd_cntls_limit; +int var_smtpd_cauth_limit; char *var_smtpd_hoggers; char *var_local_rwr_clients; char *var_smtpd_ehlo_dis_words; @@ -1897,6 +1905,32 @@ static void helo_reset(SMTPD_STATE *state) } } +/* smtpd_sasl_auth_cmd_wrapper - smtpd_sasl_auth_cmd front-end */ + +static int smtpd_sasl_auth_cmd_wrapper(SMTPD_STATE *state, int argc, + SMTPD_TOKEN *argv) +{ + int rate; + + if (SMTPD_STAND_ALONE(state) == 0 + && !xclient_allowed + && anvil_clnt + && var_smtpd_cauth_limit > 0 + && !namadr_list_match(hogger_list, state->name, state->addr) + && anvil_clnt_auth(anvil_clnt, state->service, state->addr, + &rate) == ANVIL_STAT_OK + && rate > var_smtpd_cauth_limit) { + state->error_mask |= MAIL_ERROR_POLICY; + msg_warn("AUTH command rate limit exceeded: %d from %s for service %s", + rate, state->namaddr, state->service); + smtpd_chat_reply(state, + "450 4.7.1 Error: too many AUTH commands from %s", + state->addr); + return (-1); + } + return (smtpd_sasl_auth_cmd(state, argc, argv)); +} + /* mail_open_stream - open mail queue file or IPC stream */ static int mail_open_stream(SMTPD_STATE *state) @@ -4713,7 +4747,7 @@ static SMTPD_CMD smtpd_cmd_table[] = { {SMTPD_CMD_STARTTLS, unimpl_cmd, SMTPD_CMD_FLAG_PRE_TLS,}, #endif #ifdef USE_SASL_AUTH - {SMTPD_CMD_AUTH, smtpd_sasl_auth_cmd,}, + {SMTPD_CMD_AUTH, smtpd_sasl_auth_cmd_wrapper,}, #else {SMTPD_CMD_AUTH, unimpl_cmd,}, #endif @@ -5577,7 +5611,7 @@ static void post_jail_init(char *unused_name, char **unused_argv) */ if (var_smtpd_crate_limit || var_smtpd_cconn_limit || var_smtpd_cmail_limit || var_smtpd_crcpt_limit - || var_smtpd_cntls_limit) + || var_smtpd_cntls_limit || var_smtpd_cauth_limit) anvil_clnt = anvil_clnt_create(); } @@ -5625,6 +5659,7 @@ int main(int argc, char **argv) VAR_SMTPD_CMAIL_LIMIT, DEF_SMTPD_CMAIL_LIMIT, &var_smtpd_cmail_limit, 0, 0, VAR_SMTPD_CRCPT_LIMIT, DEF_SMTPD_CRCPT_LIMIT, &var_smtpd_crcpt_limit, 0, 0, VAR_SMTPD_CNTLS_LIMIT, DEF_SMTPD_CNTLS_LIMIT, &var_smtpd_cntls_limit, 0, 0, + VAR_SMTPD_CAUTH_LIMIT, DEF_SMTPD_CAUTH_LIMIT, &var_smtpd_cauth_limit, 0, 0, #ifdef USE_TLS VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0, #endif diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index 8efb03830..c5a6d4eb8 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -73,17 +73,27 @@ extern const NAME_CODE tls_level_table[]; #include #include #include +#include /* Legacy SSLEAY_VERSION_NUMBER */ +#include /* OPENSSL_VERSION_NUMBER */ #include /* Appease indent(1) */ #define x509_stack_t STACK_OF(X509) -#define x509_extension_stack_t STACK_OF(X509_EXTENSION) #define general_name_stack_t STACK_OF(GENERAL_NAME) #define ssl_cipher_stack_t STACK_OF(SSL_CIPHER) #define ssl_comp_stack_t STACK_OF(SSL_COMP) #if (OPENSSL_VERSION_NUMBER < 0x00090700f) #error "need OpenSSL version 0.9.7 or later" +#endif + + /* Backwards compatibility with OpenSSL < 1.1.0 */ +#ifdef SSLEAY_VERSION_NUMBER +#define OpenSSL_version_num SSLeay +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509) #endif /* SSL_CIPHER_get_name() got constified in 0.9.7g */ diff --git a/postfix/src/tls/tls_dane.c b/postfix/src/tls/tls_dane.c index 1e91aa3cb..bb882f206 100644 --- a/postfix/src/tls/tls_dane.c +++ b/postfix/src/tls/tls_dane.c @@ -551,7 +551,7 @@ static void ta_cert_insert(TLS_DANE *d, X509 *x) { TLS_CERTS *new = (TLS_CERTS *) mymalloc(sizeof(*new)); - CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + X509_up_ref(x); new->cert = x; new->next = d->certs; d->certs = new; @@ -1406,12 +1406,8 @@ int tls_dane_match(TLS_SESS_STATE *TLScontext, int usage, static int push_ext(X509 *cert, X509_EXTENSION *ext) { - x509_extension_stack_t *exts; - if (ext) { - if ((exts = cert->cert_info->extensions) == 0) - exts = cert->cert_info->extensions = sk_X509_EXTENSION_new_null(); - if (exts && sk_X509_EXTENSION_push(exts, ext)) + if (X509_add_ext(cert, ext, -1)) return 1; X509_EXTENSION_free(ext); } @@ -1542,7 +1538,7 @@ static void grow_chain(TLS_SESS_STATE *TLScontext, int trusted, X509 *cert) if (cert) { if (trusted && !X509_add1_trust_object(cert, serverAuth)) msg_fatal("out of memory"); - CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + X509_up_ref(cert); if (!sk_X509_push(*xs, cert)) msg_fatal("out of memory"); } diff --git a/postfix/src/tls/tls_fprint.c b/postfix/src/tls/tls_fprint.c index a03e3cc1e..2bb7e21be 100644 --- a/postfix/src/tls/tls_fprint.c +++ b/postfix/src/tls/tls_fprint.c @@ -188,7 +188,7 @@ char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask, msg_panic("digest algorithm \"%s\" not found", mdalg); /* Salt the session lookup key with the OpenSSL runtime version. */ - sslversion = SSLeay(); + sslversion = OpenSSL_version_num(); mdctx = EVP_MD_CTX_create(); checkok(EVP_DigestInit_ex(mdctx, md, NULL)); diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index 3497014ed..330a031db 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -935,7 +935,7 @@ void tls_check_version(void) TLS_VINFO lib_info; tls_version_split(OPENSSL_VERSION_NUMBER, &hdr_info); - tls_version_split(SSLeay(), &lib_info); + tls_version_split(OpenSSL_version_num(), &lib_info); if (lib_info.major != hdr_info.major || lib_info.minor != hdr_info.minor @@ -954,7 +954,7 @@ long tls_bug_bits(void) #if OPENSSL_VERSION_NUMBER >= 0x00908000L && \ OPENSSL_VERSION_NUMBER < 0x10000000L - long lib_version = SSLeay(); + long lib_version = OpenSSL_version_num(); /* * In OpenSSL 0.9.8[ab], enabling zlib compression breaks the padding bug diff --git a/postfix/src/tls/tls_server.c b/postfix/src/tls/tls_server.c index 190a132cc..1444a44e3 100644 --- a/postfix/src/tls/tls_server.c +++ b/postfix/src/tls/tls_server.c @@ -193,7 +193,7 @@ static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id, buf = vstring_alloc(2 * (len + strlen(service))); \ hex_encode(buf, (char *) (id), (len)); \ vstring_sprintf_append(buf, "&s=%s", (service)); \ - vstring_sprintf_append(buf, "&l=%ld", (long) SSLeay()); \ + vstring_sprintf_append(buf, "&l=%ld", (long) OpenSSL_version_num()); \ } while (0) @@ -429,7 +429,7 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props) * SSLv2), so we need to have the SSLv23 server here. If we want to limit * the protocol level, we can add an option to not use SSLv2/v3/TLSv1 * later. - * + * * OpenSSL 1.1.0-dev deprecates SSLv23_server_method() in favour of * TLS_client_method(), with the change in question signalled via a new * TLS_ANY_VERSION macro. diff --git a/postfix/src/tls/tls_verify.c b/postfix/src/tls/tls_verify.c index cbaae83cc..42bfc1033 100644 --- a/postfix/src/tls/tls_verify.c +++ b/postfix/src/tls/tls_verify.c @@ -138,7 +138,7 @@ static void update_error_state(TLS_SESS_STATE *TLScontext, int depth, if (TLScontext->errorcert != 0) X509_free(TLScontext->errorcert); if (errorcert != 0) - CRYPTO_add(&errorcert->references, 1, CRYPTO_LOCK_X509); + X509_up_ref(errorcert); TLScontext->errorcert = errorcert; TLScontext->errorcode = errorcode; TLScontext->errordepth = depth;