From d2c73aa0fe46a0c80fc5fe276188e5fb6e62f451 Mon Sep 17 00:00:00 2001
From: Wietse Venema
Each restriction list is evaluated from left to right until diff --git a/postfix/html/TLS_README.html b/postfix/html/TLS_README.html index 1bb15cf60..8030a819d 100644 --- a/postfix/html/TLS_README.html +++ b/postfix/html/TLS_README.html @@ -580,7 +580,7 @@ recommends a maximum of 24 hours.
Postfix TLS support introduces two additional features for +
Postfix TLS support introduces three additional features for Postfix SMTP server access control:
@@ -596,6 +596,10 @@ and if its fingerprint is listed in the list of client certificates client SMTP request if the client certificate passes verification. +diff --git a/postfix/html/cleanup.8.html b/postfix/html/cleanup.8.html index b6b385270..479ffa21e 100644 --- a/postfix/html/cleanup.8.html +++ b/postfix/html/cleanup.8.html @@ -243,8 +243,8 @@ CLEANUP(8) CLEANUP(8) RESOURCE AND RATE CONTROLS duplicate_filter_limit (1000) The maximal number of addresses remembered by the - address duplicate filter for aliases(5) or vir- - tual(5) alias expansion, or for showq(8) queue dis- + address duplicate filter for aliases(5) or vir- + tual(5) alias expansion, or for showq(8) queue dis- plays. header_size_limit (102400) diff --git a/postfix/html/local.8.html b/postfix/html/local.8.html index d1e0b9631..5b96131e6 100644 --- a/postfix/html/local.8.html +++ b/postfix/html/local.8.html @@ -445,8 +445,8 @@ LOCAL(8) LOCAL(8) duplicate_filter_limit (1000) The maximal number of addresses remembered by the - address duplicate filter for aliases(5) or vir- - tual(5) alias expansion, or for showq(8) queue dis- + address duplicate filter for aliases(5) or vir- + tual(5) alias expansion, or for showq(8) queue dis- plays. local_destination_concurrency_limit (2) diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 601e20791..f78f41b1e 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -46,10 +46,12 @@ that starts with whitespace continues a logical line. recursively replaced by the value of the named parameter.check_ccert_access type:table + +If the client certificate passes verification, use its fingerprint +as a key for the specified access(5) table.
The expression "${name?value}" expands to "value" when -"$name" is non-empty.
+"$name" is non-empty. This form is supported with Postfix version +2.2 and later.The expression "${name:value}" expands to "value" when -"$name" is empty.
+"$name" is empty. This form is supported with Postfix version 2.2 +and later. @@ -5073,6 +5075,12 @@ D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home relay_clientcerts = hash:/etc/postfix/relay_clientcerts +For more fine-grained control, use check_ccert_access to select +an appropriate access(5) policy for each client. +See RESTRICTION_CLASS_README.
+ +This feature is available with Postfix 2.2.
+ @@ -7050,6 +7058,12 @@ client network address information.Each restriction list is evaluated from left to right until diff --git a/postfix/proto/TLS_README.html b/postfix/proto/TLS_README.html index c284b7513..6b2165685 100644 --- a/postfix/proto/TLS_README.html +++ b/postfix/proto/TLS_README.html @@ -580,7 +580,7 @@ recommends a maximum of 24 hours.
Postfix TLS support introduces two additional features for +
Postfix TLS support introduces three additional features for Postfix SMTP server access control:
@@ -596,6 +596,10 @@ and if its fingerprint is listed in the list of client certificates client SMTP request if the client certificate passes verification.
If the client certificate passes verification, use its fingerprint +as a key for the specified access(5) table.
The expression "${name?value}" expands to "value" when -"$name" is non-empty.
+"$name" is non-empty. This form is supported with Postfix version +2.2 and later.The expression "${name:value}" expands to "value" when -"$name" is empty.
+"$name" is empty. This form is supported with Postfix version 2.2 +and later. diff --git a/postfix/proto/postconf.man.prolog b/postfix/proto/postconf.man.prolog index 702d3206e..a3f50bf14 100644 --- a/postfix/proto/postconf.man.prolog +++ b/postfix/proto/postconf.man.prolog @@ -36,10 +36,12 @@ The expressions "$name", "${name}" or "$(name)" are recursively replaced by the value of the named parameter. .IP \(bu The expression "${name?value}" expands to "value" when -"$name" is non-empty. +"$name" is non-empty. This form is supported with Postfix +version 2.2 and later. .IP \(bu The expression "${name:value}" expands to "value" when -"$name" is empty. +"$name" is empty. This form is supported with Postfix +version 2.2 and later. .RE .IP \(bu When the same parameter is defined multiple times, only the last diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 3cd47a66e..8009bd1ba 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -4313,6 +4313,12 @@ client network address information.For more fine-grained control, use check_ccert_access to select +an appropriate access(5) policy for each client. +See RESTRICTION_CLASS_README.
+ +This feature is available with Postfix 2.2.
+ %PARAM smtpd_tls_cipherlistControls the Postfix SMTP server TLS cipher selection scheme. diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 5f6f9dd89..f6c089296 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1662,6 +1662,7 @@ extern char *var_perm_mx_networks; extern int var_access_map_code; #define CHECK_CLIENT_ACL "check_client_access" +#define CHECK_CCERT_ACL "check_ccert_access" #define CHECK_HELO_ACL "check_helo_access" #define CHECK_SENDER_ACL "check_sender_access" #define CHECK_RECIP_ACL "check_recipient_access" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 06af3306e..6990a2dcc 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only. */ -#define MAIL_RELEASE_DATE "20050207" +#define MAIL_RELEASE_DATE "20050208" #define MAIL_VERSION_NUMBER "2.2" #define VAR_MAIL_VERSION "mail_version" diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c index 88f0e9ff4..413b6fdce 100644 --- a/postfix/src/local/local.c +++ b/postfix/src/local/local.c @@ -790,7 +790,7 @@ static void pre_init(char *unused_name, char **unused_argv) * file. */ if (var_mailbox_limit) { - if (var_mailbox_limit < var_message_limit) + if (var_mailbox_limit < var_message_limit || var_message_limit == 0) msg_fatal("main.cf configuration error: %s is smaller than %s", VAR_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT); set_file_limit(var_mailbox_limit); diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index 68efdc25b..d502db114 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -19,15 +19,15 @@ /* /* The following commands are implemented: /* .IP \fBcheck\fR -/* Validate the Postfix mail system configuration. Warn about bad -/* directory/file ownership or permissions, and create missing -/* directories. +/* Warn about bad directory/file ownership or permissions, +/* and create missing directories. /* .IP \fBstart\fR /* Start the Postfix mail system. This also runs the configuration /* check described above. /* .IP \fBstop\fR -/* Stop the Postfix mail system in an orderly fashion. Running processes -/* are allowed to terminate at their earliest convenience. +/* Stop the Postfix mail system in an orderly fashion. If +/* possible, running processes are allowed to terminate at +/* their earliest convenience. /* .sp /* Note: in order to refresh the Postfix mail system after a /* configuration change, do not use the \fBstart\fR and \fBstop\fR diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index f523a5dfe..eba72e685 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -31,6 +31,7 @@ /* Delete one message with the named queue ID from the named /* mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and /* \fBdeferred\fR). +/* /* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads /* queue IDs from standard input. For example, to delete all mail /* with exactly one recipient \fBuser@example.com\fR: @@ -76,6 +77,7 @@ /* Move one message with the named queue ID from the named /* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and /* \fBdeferred\fR) to the \fBhold\fR queue. +/* /* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads /* queue IDs from standard input. /* .sp @@ -92,6 +94,7 @@ /* Release mail that was put "on hold". /* Move one message with the named queue ID from the named /* mail queue(s) (default: \fBhold\fR) to the \fBdeferred\fR queue. +/* /* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads /* queue IDs from standard input. /* .sp @@ -111,6 +114,7 @@ /* \fBdeferred\fR). /* To requeue multiple messages, specify multiple \fB-r\fR /* command-line options. +/* /* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, /* the program reads queue IDs from standard input. /* .sp diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 9b0718bf0..7875146b0 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -336,6 +336,7 @@ static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *); * Reject context. */ #define SMTPD_NAME_CLIENT "Client host" +#define SMTPD_NAME_CCERT "Client certificate" #define SMTPD_NAME_HELO "Helo command" #define SMTPD_NAME_SENDER "Sender address" #define SMTPD_NAME_RECIPIENT "Recipient address" @@ -2341,6 +2342,39 @@ static int check_server_access(SMTPD_STATE *state, const char *table, CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO); } +/* check_ccert_access - access for TLS clients by certificate fingerprint */ + +#ifdef USE_TLS + +static int check_ccert_access(SMTPD_STATE *state, const char *table, + const char *def_acl) +{ + char *myname = "check_ccert_access"; + int found; + + if (state->tls_info.peer_verified && state->tls_info.peer_fingerprint) { + if (msg_verbose) + msg_info("%s: %s", myname, state->tls_info.peer_fingerprint); + + /* + * Regexp tables don't make sense for certificate fingerprints. That + * may be so, but we can't ignore the entire check_ccert_access + * request without logging a warning. + * + * Log the peer CommonName when access is denied. Non-printable + * characters will be neutered by smtpd_check_reject(). The SMTP + * client name and address are always syslogged as part of a "reject" + * event. + */ + return (check_access(state, table, state->tls_info.peer_fingerprint, + DICT_FLAG_NONE, &found, state->tls_info.peer_CN, + SMTPD_NAME_CCERT, def_acl)); + } + return (SMTPD_CHECK_DUNNO); +} + +#endif + /* check_mail_access - OK/FAIL based on mail address lookup */ static int check_mail_access(SMTPD_STATE *state, const char *table, @@ -3204,6 +3238,10 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, status = reject_rbl_domain(state, *cpp, state->name, SMTPD_NAME_CLIENT); } +#ifdef USE_TLS + } else if (is_map_command(state, name, CHECK_CCERT_ACL, &cpp)) { + status = check_ccert_access(state, *cpp, def_acl); +#endif } /* diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 91b3a57b5..d20eb2fd0 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -117,8 +117,8 @@ /* dict_eval() expands macro references in the specified string. /* The result is owned by the dictionary manager. Make a copy if the /* result is to survive multiple dict_eval() calls. When the -/* \fIrecursive\fR argument is non-zero, macros references are -/* expanded recursively. +/* \fIrecursive\fR argument is non-zero, macro references in macro +/* lookup results are expanded recursively. /* /* dict_walk() iterates over all registered dictionaries in some /* arbitrary order, and invokes the specified action routine with @@ -183,7 +183,7 @@ #include "vstream.h" #include "vstring.h" #include "readlline.h" -#include "mac_parse.h" +#include "mac_expand.h" #include "stringops.h" #include "iostuff.h" #include "dict.h" @@ -410,94 +410,52 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp) vstring_free(buf); } - /* - * Helper for macro expansion callback. - */ -struct dict_eval_context { - const char *dict_name; /* where to look */ - VSTRING *buf; /* result buffer */ - int recursive; /* recursive or not */ -}; - -/* dict_eval_action - macro parser call-back routine */ +/* dict_eval_lookup - macro parser call-back routine */ -static int dict_eval_action(int type, VSTRING *buf, char *ptr) +static const char *dict_eval_lookup(const char *key, int unused_type, + char *dict_name) { - struct dict_eval_context *ctxt = (struct dict_eval_context *) ptr; - char *myname = "dict_eval_action"; const char *pp; - if (msg_verbose > 1) - msg_info("%s: type %s buf %s context %s \"%s\" %s", - myname, type == MAC_PARSE_VARNAME ? "variable" : "literal", - STR(buf), ctxt->dict_name, STR(ctxt->buf), - ctxt->recursive ? "recursive" : "non-recursive"); - /* - * In order to support recursion, we must save the dict_lookup() result. - * We use the input buffer since it will not be needed anymore. + * XXX how would one recover? */ - if (type == MAC_PARSE_VARNAME) { - if ((pp = dict_lookup(ctxt->dict_name, STR(buf))) == 0) { - if (dict_errno) /* XXX how would one recover? */ - msg_fatal("dictionary %s: lookup %s: temporary error", - ctxt->dict_name, STR(buf)); - } else if (ctxt->recursive) { - vstring_strcpy(buf, pp); /* XXX clobber input */ - dict_eval(ctxt->dict_name, STR(buf), ctxt->recursive); - } else { - vstring_strcat(ctxt->buf, pp); - } - } else { - vstring_strcat(ctxt->buf, STR(buf)); - } - return (0); + if ((pp = dict_lookup(dict_name, key)) == 0 && dict_errno != 0) + msg_fatal("dictionary %s: lookup %s: temporary error", dict_name, key); + + return (pp); } /* dict_eval - expand embedded dictionary references */ const char *dict_eval(const char *dict_name, const char *value, int recursive) { + const char *myname = "dict_eval"; static VSTRING *buf; - static struct dict_eval_context ctxt; - static int loop = 0; - - /* - * Sanity check. - */ - if (loop > 100) - msg_fatal("unreasonable macro nesting: \"%s\"", value); + int status; /* * Initialize. */ if (buf == 0) buf = vstring_alloc(10); - if (loop++ == 0) { - VSTRING_RESET(buf); - VSTRING_TERMINATE(buf); - } - ctxt.buf = buf; - ctxt.recursive = recursive; - ctxt.dict_name = dict_name; /* * Expand macros, possibly recursively. */ - if (msg_verbose > 1) - msg_info("dict_eval[%d] %s", loop, value); - - mac_parse(value, dict_eval_action, (char *) &ctxt); - - if (msg_verbose > 1) - msg_info("dict_eval[%d] result %s", loop, STR(buf)); - - /* - * Cleanup. - */ - loop--; - VSTRING_TERMINATE(buf); - +#define DONT_FILTER (char *) 0 + + status = mac_expand(buf, value, + recursive ? MAC_EXP_FLAG_RECURSE : MAC_EXP_FLAG_NONE, + DONT_FILTER, dict_eval_lookup, (char *) dict_name); + if (status & MAC_PARSE_ERROR) + msg_fatal("dictionary %s: macro processing error", dict_name); + if (msg_verbose) { + if (strcmp(value, STR(buf)) != 0) + msg_info("%s: expand %s -> %s", myname, value, STR(buf)); + else + msg_info("%s: const %s", myname, value); + } return (STR(buf)); } diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index 0a1ff93ab..fc892f05b 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -88,9 +88,14 @@ /* into the right-hand side. /* .IP DICT_FLAG_NO_PROXY /* Disallow access through the \fBproxymap\fR service. +/* .IP DICT_FLAG_NO_UNAUTH +/* Disallow network lookup mechanisms that lack any form of +/* authentication (example: tcp_table; even NIS can be secured +/* to some extent by requiring that the server binds to a +/* privileged port). /* .IP DICT_FLAG_PARANOID -/* A combination of all the paranoia flags: DICT_FLAG_NO_REGSUB -/* and DICT_FLAG_NO_PROXY. +/* A combination of all the paranoia flags: DICT_FLAG_NO_REGSUB, +/* DICT_FLAG_NO_PROXY and DICT_FLAG_NO_UNAUTH. /* .PP /* Specify DICT_FLAG_NONE for no special processing. /* diff --git a/postfix/src/util/mac_expand.c b/postfix/src/util/mac_expand.c index 922244c61..44724785a 100644 --- a/postfix/src/util/mac_expand.c +++ b/postfix/src/util/mac_expand.c @@ -45,7 +45,7 @@ /* Bit-wise OR of zero or more of the following: /* .RS /* .IP MAC_EXP_FLAG_RECURSE -/* Expand $name recursively. This should never be done with +/* Expand macros in lookup results. This should never be done with /* data whose origin is untrusted. /* .PP /* The constant MAC_EXP_FLAG_NONE specifies a manifest null value. @@ -59,7 +59,7 @@ /* MAC_EXP_MODE_TEST to test the existence of the named attribute /* or MAC_EXP_MODE_USE to use the value of the named attribute, /* and the caller context that was given to mac_expand(). A null -/* result means that the requested attribute was not defined. +/* result value means that the requested attribute was not defined. /* .IP context /* Caller context that is passed on to the attribute lookup routine. /* DIAGNOSTICS @@ -136,8 +136,11 @@ static int mac_expand_callback(int type, VSTRING *buf, char *ptr) /* * $Name etc. reference. + * + * In order to support expansion of lookup results, we must save the lookup + * result. We use the input buffer since it will not be needed anymore. */ - if (type == MAC_PARSE_VARNAME) { + if (type == MAC_PARSE_EXPR) { /* * Look for the ? or : delimiter. In case of a syntax error, return @@ -183,7 +186,8 @@ static int mac_expand_callback(int type, VSTRING *buf, char *ptr) } else if (*text == 0) { /* void */ ; } else if (mc->flags & MAC_EXP_FLAG_RECURSE) { - mac_parse(text, mac_expand_callback, (char *) mc); + vstring_strcpy(buf, text); + mac_parse(vstring_str(buf), mac_expand_callback, (char *) mc); } else { len = VSTRING_LEN(mc->result); vstring_strcat(mc->result, text); @@ -201,17 +205,9 @@ static int mac_expand_callback(int type, VSTRING *buf, char *ptr) * Literal text. */ else { - text = vstring_str(buf); - vstring_strcat(mc->result, text); + vstring_strcat(mc->result, vstring_str(buf)); } - /* - * Give the poor tester a clue of what is going on. - */ - if (msg_verbose) - msg_info("%s: %s = %s", myname, vstring_str(buf), - text ? text : "(undef)"); - mc->level--; return (mc->status); diff --git a/postfix/src/util/mac_parse.c b/postfix/src/util/mac_parse.c index b21f8b21f..6bd638d42 100644 --- a/postfix/src/util/mac_parse.c +++ b/postfix/src/util/mac_parse.c @@ -23,9 +23,11 @@ /* found, and \fIcontext\fR is passed on unmodified from the caller. /* The application is at liberty to clobber \fIbuf\fR. /* .IP MAC_PARSE_LITERAL -/* The text in \fIbuf\fR is literal text. -/* .IP MAC_PARSE_VARNAME -/* The text in \fIbuf\fR is a macro expression. +/* The content of \fIbuf\fR is literal text. +/* .IP MAC_PARSE_EXPR +/* The content of \fIbuf\fR is a macro expression: either a +/* bare macro name without the preceding "$", or all the text +/* inside $() or ${}. /* .PP /* The action routine result value is the bit-wise OR of zero or more /* of the following: @@ -72,11 +74,11 @@ * execute the action, and reset the temporary buffer for re-use. */ #define MAC_PARSE_ACTION(status, type, buf, context) \ - { \ + do { \ VSTRING_TERMINATE(buf); \ - status |= action(type, buf, context); \ + status |= action((type), (buf), (context)); \ VSTRING_RESET(buf); \ - } + } while(0) /* mac_parse - split string into literal text and macro references */ @@ -138,7 +140,7 @@ int mac_parse(const char *value, MAC_PARSE_FN action, char *context) msg_warn("empty macro name: \"%s\"", value); break; } - MAC_PARSE_ACTION(status, MAC_PARSE_VARNAME, buf, context); + MAC_PARSE_ACTION(status, MAC_PARSE_EXPR, buf, context); } } if (VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0) @@ -167,8 +169,8 @@ static int mac_parse_print(int type, VSTRING *buf, char *unused_context) char *type_name; switch (type) { - case MAC_PARSE_VARNAME: - type_name = "MAC_PARSE_VARNAME"; + case MAC_PARSE_EXPR: + type_name = "MAC_PARSE_EXPR"; break; case MAC_PARSE_LITERAL: type_name = "MAC_PARSE_LITERAL"; diff --git a/postfix/src/util/mac_parse.h b/postfix/src/util/mac_parse.h index b702fcaf0..7a9411e77 100644 --- a/postfix/src/util/mac_parse.h +++ b/postfix/src/util/mac_parse.h @@ -20,7 +20,8 @@ * External interface. */ #define MAC_PARSE_LITERAL 1 -#define MAC_PARSE_VARNAME 2 +#define MAC_PARSE_EXPR 2 +#define MAC_PARSE_VARNAME MAC_PARSE_EXPR /* 2.1 compatibility */ #define MAC_PARSE_OK 0 #define MAC_PARSE_ERROR (1<<0) diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c index ceeabd8a0..a36cb1769 100644 --- a/postfix/src/virtual/virtual.c +++ b/postfix/src/virtual/virtual.c @@ -457,7 +457,7 @@ static void pre_init(char *unused_name, char **unused_argv) * file. */ if (var_virt_mailbox_limit) { - if (var_virt_mailbox_limit < var_message_limit) + if (var_virt_mailbox_limit < var_message_limit || var_message_limit == 0) msg_fatal("main.cf configuration error: %s is smaller than %s", VAR_VIRT_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT); set_file_limit(var_virt_mailbox_limit); -- 2.47.3