mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
postfix-2.0.7-20030317
This commit is contained in:
parent
bab3a35113
commit
e57de0df68
1
postfix/.indent.pro
vendored
1
postfix/.indent.pro
vendored
@ -136,6 +136,7 @@
|
||||
-TSINK_STATE
|
||||
-TSMTPD_CMD
|
||||
-TSMTPD_DEFER
|
||||
-TSMTPD_MSG_ACTION
|
||||
-TSMTPD_RBL_EXPAND_CONTEXT
|
||||
-TSMTPD_RBL_STATE
|
||||
-TSMTPD_STATE
|
||||
|
@ -7895,6 +7895,24 @@ Apologies for any names omitted.
|
||||
systems against exploitation of the remote buffer overflow
|
||||
vulnerability described in CERT advisory CA-2003-07.
|
||||
|
||||
20030311-17
|
||||
|
||||
Bugfix: the access map actions HOLD, DISCARD, FILTER and
|
||||
REDIRECT were broken with smtpd_delay_reject=no. This
|
||||
required re-architecting of the actions code. Files:
|
||||
smtpd/smtpd.[hc], smtpd/smtpd_check.c, smtpd/smtpd_state.c.
|
||||
|
||||
20030315
|
||||
|
||||
Bugfix: the postsuper manual page documented support for
|
||||
the -c command line option, but it was not implemented.
|
||||
File: postsuper/postsuper.c.
|
||||
|
||||
Bugfix: the Postfix 2.0 recipient map checking code broke
|
||||
the VRFY command, causing it to reply with status code 252
|
||||
for non-existent addresses. This required re-architecting
|
||||
the recipient table lookup code. File: smtpd/smtpd_check.c.
|
||||
|
||||
Open problems:
|
||||
|
||||
Med: make qmgr recipient bounce/defer activity asynchronous
|
||||
|
@ -26,6 +26,8 @@
|
||||
# directory (pathname is controlled by the queue_directory configuration
|
||||
# variable in the main.cf file). Presently, all Postfix daemons can run
|
||||
# chrooted, except for the pipe, virtual and local delivery daemons.
|
||||
# The proxymap server can run chrooted, but doing so defeats most of
|
||||
# the purpose of having that service in the first place.
|
||||
# The files in the examples/chroot-setup subdirectory describe how
|
||||
# to set up a Postfix chroot environment for your type of machine.
|
||||
#
|
||||
|
@ -88,7 +88,9 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
The proxymap server opens only tables that are approved
|
||||
via the <b>proxy</b><i>_</i><b>read</b><i>_</i><b>maps</b> configuration parameter, does not
|
||||
talk to users, and can run at fixed low privilege,
|
||||
chrooted or not.
|
||||
chrooted or not. However, running the proxymap server
|
||||
chrooted severely limits usability, because it can open
|
||||
only chrooted tables.
|
||||
|
||||
The proxymap server is not a trusted daemon process, and
|
||||
must not be used to look up sensitive information such as
|
||||
|
@ -880,7 +880,7 @@ and the address contains no sender-specified routing
|
||||
<li>Postfix is the final destination: any destination that matches
|
||||
<a href="basic.html#mydestination">$mydestination</a>, <a
|
||||
href="basic.html#inet_interfaces">$inet_interfaces</a>, <a
|
||||
href="virtual.5.html">$virtual_alias_domains</a>, or
|
||||
href="virtual.5.html">$virtual_alias_domains</a>, or <a
|
||||
href="virtual.8.html">$virtual_mailbox_domains</a>.
|
||||
|
||||
</ul>
|
||||
|
@ -88,6 +88,8 @@ of idle time.
|
||||
The proxymap server opens only tables that are approved via the
|
||||
\fBproxy_read_maps\fR configuration parameter, does not talk to
|
||||
users, and can run at fixed low privilege, chrooted or not.
|
||||
However, running the proxymap server chrooted severely limits
|
||||
usability, because it can open only chrooted tables.
|
||||
|
||||
The proxymap server is not a trusted daemon process, and must
|
||||
not be used to look up sensitive information such as user or
|
||||
|
@ -1251,6 +1251,7 @@ tok822_parse.o: ../../include/sys_defs.h
|
||||
tok822_parse.o: ../../include/vstring.h
|
||||
tok822_parse.o: ../../include/vbuf.h
|
||||
tok822_parse.o: ../../include/msg.h
|
||||
tok822_parse.o: ../../include/stringops.h
|
||||
tok822_parse.o: lex_822.h
|
||||
tok822_parse.o: quote_822_local.h
|
||||
tok822_parse.o: quote_flags.h
|
||||
|
@ -20,10 +20,10 @@
|
||||
* Patches change the patchlevel and the release date. Snapshots change the
|
||||
* release date only, unless they include the same bugfix as a patch release.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20030305"
|
||||
#define MAIL_RELEASE_DATE "20030317"
|
||||
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "2.0.6-" MAIL_RELEASE_DATE
|
||||
#define DEF_MAIL_VERSION "2.0.7-" MAIL_RELEASE_DATE
|
||||
extern char *var_mail_version;
|
||||
|
||||
/*
|
||||
|
@ -172,14 +172,15 @@ const char *maps_find(MAPS *maps, const char *name, int flags)
|
||||
continue;
|
||||
if ((expansion = dict_get(dict, name)) != 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: %s = %s", myname, *map_name, name, expansion);
|
||||
msg_info("%s: %s: %s: %s = %s", myname, maps->title,
|
||||
*map_name, name, expansion);
|
||||
return (expansion);
|
||||
} else if (dict_errno != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: %s", myname, name, dict_errno ?
|
||||
msg_info("%s: %s: %s: %s", myname, maps->title, name, dict_errno ?
|
||||
"search aborted" : "not found");
|
||||
return (0);
|
||||
}
|
||||
|
@ -126,6 +126,7 @@
|
||||
|
||||
#include <vstring.h>
|
||||
#include <msg.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@ -250,7 +251,7 @@ static void strip_address(VSTRING *vp, int start, TOK822 *addr)
|
||||
* Emit plain <address>. Discard any comments or phrases.
|
||||
*/
|
||||
msg_warn("stripping too many comments from address: %.100s...",
|
||||
vstring_str(vp) + start);
|
||||
printable(vstring_str(vp) + start, '?'));
|
||||
vstring_truncate(vp, start);
|
||||
VSTRING_ADDCH(vp, '<');
|
||||
if (addr) {
|
||||
@ -263,7 +264,6 @@ static void strip_address(VSTRING *vp, int start, TOK822 *addr)
|
||||
VSTRING_ADDCH(vp, '>');
|
||||
}
|
||||
|
||||
|
||||
/* tok822_externalize - token tree to string, external form */
|
||||
|
||||
VSTRING *tok822_externalize(VSTRING *vp, TOK822 *tree, int flags)
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
|
@ -987,16 +987,13 @@ int main(int argc, char **argv)
|
||||
msg_fatal("open /dev/null: %m");
|
||||
|
||||
/*
|
||||
* Process environment options as early as we can. We might be called
|
||||
* from a set-uid (set-gid) program, so be careful with importing
|
||||
* environment variables.
|
||||
* Process this environment option as early as we can, to aid debugging.
|
||||
*/
|
||||
if (safe_getenv(CONF_ENV_VERB))
|
||||
msg_verbose = 1;
|
||||
|
||||
/*
|
||||
* Initialize. Set up logging, read the global configuration file and
|
||||
* extract configuration information.
|
||||
* Initialize logging.
|
||||
*/
|
||||
if ((slash = strrchr(argv[0], '/')) != 0)
|
||||
argv[0] = slash + 1;
|
||||
@ -1004,47 +1001,37 @@ int main(int argc, char **argv)
|
||||
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
|
||||
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
|
||||
|
||||
mail_conf_read();
|
||||
if (chdir(var_queue_dir))
|
||||
msg_fatal("chdir %s: %m", var_queue_dir);
|
||||
|
||||
/*
|
||||
* Be sure to log a warning if we do not finish structural repair. Maybe
|
||||
* we should have an fsck-style "clean" flag so Postfix will not start
|
||||
* with a broken queue.
|
||||
*/
|
||||
signal(SIGHUP, interrupted);
|
||||
signal(SIGINT, interrupted);
|
||||
signal(SIGQUIT, interrupted);
|
||||
signal(SIGTERM, interrupted);
|
||||
msg_cleanup(fatal_exit);
|
||||
|
||||
/*
|
||||
* All file/directory updates must be done as the mail system owner. This
|
||||
* is because Postfix daemons manipulate the queue with those same
|
||||
* privileges, so directories must be created with the right ownership.
|
||||
*
|
||||
* Running as a non-root user is also required for security reasons. When
|
||||
* the Postfix queue hierarchy is compromised, an attacker could trick us
|
||||
* into entering other file hierarchies and afflicting damage. Running as
|
||||
* a non-root user limits the damage to the already compromised mail
|
||||
* owner.
|
||||
* Disallow unsafe practices, and refuse to run set-uid (or as the child
|
||||
* of a set-uid process). Whenever a privileged wrapper program is
|
||||
* needed, it must properly sanitize the real/effective/saved UID/GID,
|
||||
* the secondary groups, the process environment, and so on. Otherwise,
|
||||
* accidents can happen. If not with Postfix, then with other software.
|
||||
*/
|
||||
if (unsafe() != 0)
|
||||
msg_fatal("this postfix command must not run as a set-uid process");
|
||||
if (getuid())
|
||||
msg_fatal("use of this command is reserved for the superuser");
|
||||
set_ugid(var_owner_uid, var_owner_gid);
|
||||
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
while ((c = GETOPT(argc, argv, "d:h:H:pr:sv")) > 0) {
|
||||
while ((c = GETOPT(argc, argv, "c:d:h:H:pr:sv")) > 0) {
|
||||
switch (c) {
|
||||
default:
|
||||
msg_fatal("usage: %s [-d queue_id (delete)] "
|
||||
msg_fatal("usage: %s "
|
||||
"[-c config_dir] "
|
||||
"[-d queue_id (delete)] "
|
||||
"[-h queue_id (hold)] [-H queue_id (un-hold)] "
|
||||
"[-p (purge temporary files)] [-r queue_id (requeue)] "
|
||||
"[-s (structure fix)] [-v (verbose)] "
|
||||
"[queue...]", argv[0]);
|
||||
case 'c':
|
||||
if (*optarg != '/')
|
||||
msg_fatal("-c requires absolute pathname");
|
||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||
msg_fatal("setenv: %m");
|
||||
break;
|
||||
case 'd':
|
||||
if (delete_names == 0)
|
||||
delete_names = argv_alloc(1);
|
||||
@ -1085,6 +1072,42 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the global configuration file and extract configuration
|
||||
* information. The -c command option can override the default
|
||||
* configuration directory location.
|
||||
*/
|
||||
mail_conf_read();
|
||||
if (chdir(var_queue_dir))
|
||||
msg_fatal("chdir %s: %m", var_queue_dir);
|
||||
|
||||
/*
|
||||
* All file/directory updates must be done as the mail system owner. This
|
||||
* is because Postfix daemons manipulate the queue with those same
|
||||
* privileges, so directories must be created with the right ownership.
|
||||
*
|
||||
* Running as a non-root user is also required for security reasons. When
|
||||
* the Postfix queue hierarchy is compromised, an attacker could trick us
|
||||
* into entering other file hierarchies and afflicting damage. Running as
|
||||
* a non-root user limits the damage to the already compromised mail
|
||||
* owner.
|
||||
*/
|
||||
set_ugid(var_owner_uid, var_owner_gid);
|
||||
|
||||
/*
|
||||
* Be sure to log a warning if we do not finish structural repair. Maybe
|
||||
* we should have an fsck-style "clean" flag so Postfix will not start
|
||||
* with a broken queue.
|
||||
*
|
||||
* Set up signal handlers after permanently dropping super-user privileges,
|
||||
* so that signal handlers will always run with the correct privileges.
|
||||
*/
|
||||
signal(SIGHUP, interrupted);
|
||||
signal(SIGINT, interrupted);
|
||||
signal(SIGQUIT, interrupted);
|
||||
signal(SIGTERM, interrupted);
|
||||
msg_cleanup(fatal_exit);
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
|
@ -78,6 +78,8 @@
|
||||
/* The proxymap server opens only tables that are approved via the
|
||||
/* \fBproxy_read_maps\fR configuration parameter, does not talk to
|
||||
/* users, and can run at fixed low privilege, chrooted or not.
|
||||
/* However, running the proxymap server chrooted severely limits
|
||||
/* usability, because it can open only chrooted tables.
|
||||
/*
|
||||
/* The proxymap server is not a trusted daemon process, and must
|
||||
/* not be used to look up sensitive information such as user or
|
||||
|
@ -495,6 +495,8 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "501 Syntax: HELO hostname");
|
||||
return (-1);
|
||||
}
|
||||
if (state->helo_name != 0)
|
||||
helo_reset(state);
|
||||
if (argc > 2)
|
||||
collapse_args(argc - 1, argv + 1);
|
||||
if (SMTPD_STAND_ALONE(state) == 0
|
||||
@ -503,8 +505,6 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
if (state->helo_name != 0)
|
||||
helo_reset(state);
|
||||
chat_reset(state, var_smtpd_hist_thrsh);
|
||||
mail_reset(state);
|
||||
rcpt_reset(state);
|
||||
@ -531,6 +531,8 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
|
||||
return (-1);
|
||||
}
|
||||
if (state->helo_name != 0)
|
||||
helo_reset(state);
|
||||
if (argc > 2)
|
||||
collapse_args(argc - 1, argv + 1);
|
||||
if (SMTPD_STAND_ALONE(state) == 0
|
||||
@ -539,8 +541,6 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
if (state->helo_name != 0)
|
||||
helo_reset(state);
|
||||
chat_reset(state, var_smtpd_hist_thrsh);
|
||||
mail_reset(state);
|
||||
rcpt_reset(state);
|
||||
@ -576,6 +576,26 @@ static void helo_reset(SMTPD_STATE *state)
|
||||
if (state->helo_name)
|
||||
myfree(state->helo_name);
|
||||
state->helo_name = 0;
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_helo_restrictions is evaluated at
|
||||
* RCPT TO time, and may be evaluated multiple times per message.
|
||||
* Per-message smtpd_helo_restrictions side effects (HOLD, DISCARD, etc.)
|
||||
* accumulate from one evaluation to the next, and may also depend on
|
||||
* client, sender or recipient information. Therefore, any per-message
|
||||
* helo restriction side effects need to be reset at the end of a mail
|
||||
* delivery transaction.
|
||||
*
|
||||
* With smtpd_delay_reject=no, smtpd_helo_restrictions is evaluated when
|
||||
* HELO/EHLO is issued, and its per-message side effects change only when
|
||||
* another HELO/EHLO command is issued. Therefore, any per-message helo
|
||||
* restriction side effects must be reset before smtpd_helo_restrictions
|
||||
* is evaluated.
|
||||
*/
|
||||
if (var_smtpd_delay_reject == 0) {
|
||||
SMTPD_MSG_ACT_FREE(state->action_helo);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_helo);
|
||||
}
|
||||
}
|
||||
|
||||
/* mail_open_stream - open mail destination */
|
||||
@ -903,6 +923,20 @@ static void mail_reset(SMTPD_STATE *state)
|
||||
if (var_smtpd_sasl_enable)
|
||||
smtpd_sasl_mail_reset(state);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_sender_restrictions is evaluated at
|
||||
* RCPT TO time, and may be evaluated multiple times per message.
|
||||
* Per-message smtpd_sender_restrictions side effects (HOLD, DISCARD,
|
||||
* etc.) accumulate from one evaluation to the next, and may also depend
|
||||
* on client, helo or recipient information.
|
||||
*
|
||||
* The action_mailrcpt member accumulates both sender and recipient side
|
||||
* effects. It needs to be reset after each mail delivery, whether or not
|
||||
* it is actually completed.
|
||||
*/
|
||||
SMTPD_MSG_ACT_FREE(state->action_mailrcpt);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_mailrcpt);
|
||||
}
|
||||
|
||||
/* rcpt_cmd - process RCPT TO command */
|
||||
@ -961,10 +995,6 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
if ((err = smtpd_check_rcptmap(state, argv[2].strval)) != 0) {
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -987,6 +1017,26 @@ static void rcpt_reset(SMTPD_STATE *state)
|
||||
state->recipient = 0;
|
||||
}
|
||||
state->rcpt_count = 0;
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_{client,helo}_restrictions are
|
||||
* evaluated at RCPT TO time. They may be evaluated multiple times per
|
||||
* message delivery. Per-message {client,helo} restriction side effects
|
||||
* (HOLD, DISCARD, etc.) accumulate from one evaluation to the next, and
|
||||
* the result may also depend on sender or recipient information.
|
||||
* Therefore, per-message {client,helo} restriction side effects need to
|
||||
* be reset between deliveries.
|
||||
*
|
||||
* With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
|
||||
* evaluated once and take effect over multiple deliveries. Therefore,
|
||||
* their per-message side effects must not be reset between deliveries.
|
||||
*/
|
||||
if (var_smtpd_delay_reject) {
|
||||
SMTPD_MSG_ACT_FREE(state->action_client);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_client);
|
||||
SMTPD_MSG_ACT_FREE(state->action_helo);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_helo);
|
||||
}
|
||||
}
|
||||
|
||||
/* data_cmd - process DATA command */
|
||||
@ -1001,6 +1051,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
int first = 1;
|
||||
VSTRING *why = 0;
|
||||
int saved_err;
|
||||
char *act_value;
|
||||
|
||||
/*
|
||||
* Sanity checks. With ESMTP command pipelining the client can send DATA
|
||||
@ -1033,6 +1084,18 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
*/
|
||||
if (*var_always_bcc)
|
||||
rec_fputs(state->cleanup, REC_TYPE_RCPT, var_always_bcc);
|
||||
if (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_DISCARD) {
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
|
||||
CLEANUP_FLAG_DISCARD);
|
||||
} else {
|
||||
if (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_HOLD)
|
||||
rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d",
|
||||
CLEANUP_FLAG_HOLD);
|
||||
if ((act_value = SMTPD_MSG_ACT_VALUE(state, filter)) != 0)
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", act_value);
|
||||
if ((act_value = SMTPD_MSG_ACT_VALUE(state, redirect)) != 0)
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", act_value);
|
||||
}
|
||||
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
|
||||
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||
"Received: from %s (%s [%s])",
|
||||
@ -1269,7 +1332,7 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
return (-1);
|
||||
}
|
||||
if (SMTPD_STAND_ALONE(state) == 0
|
||||
&& (err = smtpd_check_rcptmap(state, argv[1].strval)) != 0) {
|
||||
&& (err = smtpd_check_vrfy(state, argv[1].strval)) != 0) {
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -45,6 +45,43 @@ typedef struct SMTPD_DEFER {
|
||||
int class; /* error notification class */
|
||||
} SMTPD_DEFER;
|
||||
|
||||
/*
|
||||
* Actions that affect all recipients of a given message. That is, we don't
|
||||
* "undo" results from one recipient when evaluating the next recipient.
|
||||
*/
|
||||
typedef struct SMTPD_MSG_ACTION {
|
||||
int flags; /* see below */
|
||||
char *filter; /* filter destination */
|
||||
char *redirect; /* redirect destination */
|
||||
} SMTPD_MSG_ACTION;
|
||||
|
||||
#define SMTPD_MSG_ACT_HOLD (1<<0) /* place message on hold */
|
||||
#define SMTPD_MSG_ACT_DISCARD (1<<1) /* discard message */
|
||||
#define SMTPD_MSG_ACT_FILTER (1<<2) /* filter message */
|
||||
#define SMTPD_MSG_ACT_REDIRECT (1<<3) /* redirect message */
|
||||
|
||||
/*
|
||||
* Short-hand for when to stop searching restriction lists.
|
||||
*/
|
||||
#define SMTPD_MSG_ACT_FINAL (SMTPD_MSG_ACT_DISCARD)
|
||||
|
||||
#define SMTPD_MSG_ACT_ZERO(a) do { \
|
||||
(a).flags = 0; \
|
||||
(a).filter = 0; \
|
||||
(a).redirect = 0; \
|
||||
} while (0)
|
||||
|
||||
#define SMTPD_MSG_ACT_FREE(a) do { \
|
||||
if ((a).filter) myfree((a).filter); \
|
||||
if ((a).redirect) myfree((a).redirect); \
|
||||
} while (0)
|
||||
|
||||
#define SMTPD_MSG_ACT_COPY(d, s) do { \
|
||||
SMTPD_MSG_ACT_FREE(d); \
|
||||
(d).filter = ((s).filter ? mystrdup((s).filter) : 0); \
|
||||
(d).redirect = ((s).redirect ? mystrdup((s).redirect) : 0); \
|
||||
} while (0)
|
||||
|
||||
typedef struct SMTPD_STATE {
|
||||
int err;
|
||||
VSTREAM *client;
|
||||
@ -86,6 +123,10 @@ typedef struct SMTPD_STATE {
|
||||
VSTRING *sasl_encoded;
|
||||
VSTRING *sasl_decoded;
|
||||
#endif
|
||||
SMTPD_MSG_ACTION *action; /* action from access map */
|
||||
SMTPD_MSG_ACTION action_client; /* action after connect */
|
||||
SMTPD_MSG_ACTION action_helo; /* action after helo/ehlo */
|
||||
SMTPD_MSG_ACTION action_mailrcpt; /* action after mail from/rcpt to */
|
||||
int rcptmap_checked;
|
||||
int warn_if_reject; /* force reject into warning */
|
||||
SMTPD_DEFER defer_if_reject; /* force reject into deferral */
|
||||
@ -96,6 +137,15 @@ typedef struct SMTPD_STATE {
|
||||
VSTRING *expand_buf; /* scratch space for $name expansion */
|
||||
} SMTPD_STATE;
|
||||
|
||||
#define SMTPD_MSG_ACT_FLAGS(s) \
|
||||
((s)->action_client.flags | (s)->action_helo.flags \
|
||||
| (s)->action_mailrcpt.flags)
|
||||
|
||||
#define SMTPD_MSG_ACT_VALUE(s,m) \
|
||||
((s)->action_mailrcpt.m ? (s)->action_mailrcpt.m : \
|
||||
(s)->action_helo.m ? (s)->action_helo.m : \
|
||||
(s)->action_client.m)
|
||||
|
||||
extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
|
||||
extern void smtpd_state_reset(SMTPD_STATE *);
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
/* SMTPD_STATE *state;
|
||||
/* char *recipient;
|
||||
/*
|
||||
/* char *smtpd_check_rcptmap(state, recipient)
|
||||
/* char *smtpd_check_vrfy(state, recipient)
|
||||
/* SMTPD_STATE *state;
|
||||
/* char *recipient;
|
||||
/*
|
||||
@ -202,11 +202,13 @@
|
||||
/* .IP smtpd_recipient_restrictions
|
||||
/* Restrictions on the recipient address that is sent with the RCPT
|
||||
/* TO command.
|
||||
/* .IP local_recipient_maps
|
||||
/* Tables of user names (not addresses) that exist in $mydestination.
|
||||
/* Mail for local users not in these tables is rejected.
|
||||
/* .PP
|
||||
/* smtpd_check_rcptmap() validates the recipient address provided
|
||||
/* with an RCPT TO request and sets the rcptmap_checked flag.
|
||||
/* Relevant configuration parameters:
|
||||
/* .IP local_recipients_map
|
||||
/* smtpd_check_vrfy() validates the recipient address provided
|
||||
/* with a VRFY request. Relevant configuration parameters:
|
||||
/* .IP local_recipient_maps
|
||||
/* Tables of user names (not addresses) that exist in $mydestination.
|
||||
/* Mail for local users not in these tables is rejected.
|
||||
/* .PP
|
||||
@ -1751,6 +1753,8 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
* mind, and reject/discard the message for other reasons.
|
||||
*/
|
||||
if (STREQUAL(value, "FILTER", cmd_len)) {
|
||||
if (state->action == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
if (*cmd_text == 0) {
|
||||
msg_warn("access map %s entry \"%s\" has FILTER entry without value",
|
||||
table, datum);
|
||||
@ -1763,9 +1767,10 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
vstring_sprintf(error_text, "<%s>: %s triggers FILTER %s",
|
||||
reply_name, reply_class, cmd_text);
|
||||
log_whatsup(state, "filter", STR(error_text));
|
||||
#ifndef TEST
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", cmd_text);
|
||||
#endif
|
||||
state->action->flags |= SMTPD_MSG_ACT_FILTER;
|
||||
if (state->action->filter)
|
||||
myfree(state->action->filter);
|
||||
state->action->filter = mystrdup(cmd_text);
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
}
|
||||
@ -1775,30 +1780,25 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
* reject/discard the message for other reasons.
|
||||
*/
|
||||
if (STREQUAL(value, "HOLD", cmd_len)) {
|
||||
if (state->action == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
|
||||
*cmd_text ? cmd_text : "triggers HOLD action");
|
||||
log_whatsup(state, "hold", STR(error_text));
|
||||
#ifndef TEST
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
|
||||
CLEANUP_FLAG_HOLD);
|
||||
#endif
|
||||
state->action->flags |= SMTPD_MSG_ACT_HOLD;
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
|
||||
/*
|
||||
* DISCARD means silently discard and claim successful delivery.
|
||||
*
|
||||
* XXX Set some global flag that disables all further restrictions.
|
||||
* Triggering a "reject" or "hold" action after "discard" is silly.
|
||||
*/
|
||||
if (STREQUAL(value, "DISCARD", cmd_len)) {
|
||||
if (state->action == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
|
||||
*cmd_text ? cmd_text : "triggers DISCARD action");
|
||||
log_whatsup(state, "discard", STR(error_text));
|
||||
#ifndef TEST
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
|
||||
CLEANUP_FLAG_DISCARD);
|
||||
#endif
|
||||
state->action->flags |= SMTPD_MSG_ACT_DISCARD;
|
||||
return (SMTPD_CHECK_OK);
|
||||
}
|
||||
|
||||
@ -1807,6 +1807,8 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
* change our mind, and reject/discard the message for other reasons.
|
||||
*/
|
||||
if (STREQUAL(value, "REDIRECT", cmd_len)) {
|
||||
if (state->action == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
if (strchr(cmd_text, '@') == 0) {
|
||||
msg_warn("access map %s entry \"%s\" requires user@domain target",
|
||||
table, datum);
|
||||
@ -1815,9 +1817,10 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
vstring_sprintf(error_text, "<%s>: %s triggers REDIRECT %s",
|
||||
reply_name, reply_class, cmd_text);
|
||||
log_whatsup(state, "redirect", STR(error_text));
|
||||
#ifndef TEST
|
||||
rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", cmd_text);
|
||||
#endif
|
||||
state->action->flags |= SMTPD_MSG_ACT_REDIRECT;
|
||||
if (state->action->redirect)
|
||||
myfree(state->action->redirect);
|
||||
state->action->redirect = mystrdup(cmd_text);
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
}
|
||||
@ -2646,6 +2649,9 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
|
||||
for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
|
||||
|
||||
if (state->action && SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_FINAL)
|
||||
break;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: name=%s", myname, name);
|
||||
|
||||
@ -2966,6 +2972,20 @@ char *smtpd_check_client(SMTPD_STATE *state)
|
||||
*/
|
||||
state->defer_if_permit.active = 0;
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_client_restrictions is evaluated at
|
||||
* RCPT TO time, and may be evaluated multiple times. Per-message side
|
||||
* effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
|
||||
* next, and may also depend on helo, sender or recipient information.
|
||||
*
|
||||
* With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
|
||||
* evaluated immediately, and HELO may be given multiple times. The same
|
||||
* {client,helo} per-message side effects (HOLD, DISCARD, etc.) apply to
|
||||
* multiple deliveries. Therefore, we need separate per-message side
|
||||
* effect storage for client, helo, and for sender+recipients.
|
||||
*/
|
||||
state->action = &state->action_client;
|
||||
|
||||
/*
|
||||
* Apply restrictions in the order as specified.
|
||||
*/
|
||||
@ -3020,6 +3040,20 @@ char *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
|
||||
*/
|
||||
state->defer_if_permit.active = state->defer_if_permit_client;
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_helo_restrictions is evaluated at
|
||||
* RCPT TO time, and may be evaluated multiple times. Per-message side
|
||||
* effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
|
||||
* next, and may also depend on sender or recipient information.
|
||||
*
|
||||
* With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
|
||||
* evaluated immediately, and HELO may be given multiple times. The same
|
||||
* {client,helo} per-message side effects (HOLD, DISCARD, etc.) apply to
|
||||
* multiple deliveries. Therefore, we need separate per-message side
|
||||
* effect storage for client, helo, and for sender+recipients.
|
||||
*/
|
||||
state->action = &state->action_helo;
|
||||
|
||||
/*
|
||||
* Apply restrictions in the order as specified.
|
||||
*/
|
||||
@ -3065,6 +3099,14 @@ char *smtpd_check_mail(SMTPD_STATE *state, char *sender)
|
||||
state->defer_if_permit.active = state->defer_if_permit_client
|
||||
| state->defer_if_permit_helo;
|
||||
|
||||
/*
|
||||
* With smtpd_delay_reject=yes, smtpd_sender_restrictions is evaluated at
|
||||
* RCPT TO time, and may be evaluated multiple times. Per-message side
|
||||
* effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
|
||||
* next, and may also depend on client, helo or recipient information.
|
||||
*/
|
||||
state->action = &state->action_mailrcpt;
|
||||
|
||||
/*
|
||||
* Apply restrictions in the order as specified.
|
||||
*/
|
||||
@ -3152,6 +3194,13 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|
||||
*/
|
||||
state->defer_if_permit.active = state->defer_if_permit_sender;
|
||||
|
||||
/*
|
||||
* Per-message side effects (HOLD, DISCARD, etc.) accumulate from one
|
||||
* recipient to the next, and may also depend on client, helo or sender
|
||||
* information.
|
||||
*/
|
||||
state->action = &state->action_mailrcpt;
|
||||
|
||||
/*
|
||||
* Apply restrictions in the order as specified.
|
||||
*/
|
||||
@ -3169,6 +3218,14 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|
||||
status = smtpd_check_reject(state, state->defer_if_permit.class,
|
||||
"%s", STR(state->defer_if_permit.reason));
|
||||
|
||||
/*
|
||||
* If the "check_recipient_maps" restriction was not applied, and if mail
|
||||
* is not being rejected or discarded, validate the recipient here.
|
||||
*/
|
||||
if (status == 0 && state->rcptmap_checked == 0
|
||||
&& (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_FINAL) == 0)
|
||||
status = check_rcpt_maps(state, recipient);
|
||||
|
||||
SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
|
||||
}
|
||||
|
||||
@ -3213,6 +3270,11 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
|
||||
state->defer_if_permit.active = state->defer_if_permit_client
|
||||
| state->defer_if_permit_helo;
|
||||
|
||||
/*
|
||||
* HOLD, DISCARD, FILTER, etc. are meaningless.
|
||||
*/
|
||||
state->action = 0;
|
||||
|
||||
/*
|
||||
* Apply restrictions in the order as specified.
|
||||
*/
|
||||
@ -3233,11 +3295,11 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
|
||||
SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
|
||||
}
|
||||
|
||||
/* smtpd_check_rcptmap - permit if recipient address matches lookup table */
|
||||
/* smtpd_check_vrfy - permit if recipient address matches lookup table */
|
||||
|
||||
char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
||||
char *smtpd_check_vrfy(SMTPD_STATE *state, char *recipient)
|
||||
{
|
||||
char *myname = "smtpd_check_rcptmap";
|
||||
char *myname = "smtpd_check_vrfy";
|
||||
int status;
|
||||
|
||||
if (msg_verbose)
|
||||
@ -3246,6 +3308,7 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
||||
/*
|
||||
* Return here in case of serious trouble.
|
||||
*/
|
||||
SMTPD_CHECK_RESET();
|
||||
if ((status = setjmp(smtpd_check_buf)) == 0)
|
||||
status = check_rcpt_maps(state, recipient);
|
||||
|
||||
@ -3258,14 +3321,6 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient)
|
||||
{
|
||||
const RESOLVE_REPLY *reply;
|
||||
|
||||
/*
|
||||
* Duplicate suppression. There's an implicit check_recipient_maps
|
||||
* restriction at the end of all recipient restrictions.
|
||||
*/
|
||||
if (state->rcptmap_checked == 1)
|
||||
return (0);
|
||||
state->rcptmap_checked = 1;
|
||||
|
||||
/*
|
||||
* Resolve the address.
|
||||
*/
|
||||
@ -3622,6 +3677,7 @@ int var_local_rcpt_code;
|
||||
int var_relay_rcpt_code;
|
||||
int var_virt_mailbox_code;
|
||||
int var_virt_alias_code;
|
||||
int var_show_unk_rcpt_table;
|
||||
|
||||
static INT_TABLE int_table[] = {
|
||||
"msg_verbose", 0, &msg_verbose,
|
||||
@ -3644,6 +3700,7 @@ static INT_TABLE int_table[] = {
|
||||
VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code,
|
||||
VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
|
||||
VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code,
|
||||
VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table,
|
||||
0,
|
||||
};
|
||||
|
||||
@ -3902,6 +3959,8 @@ int main(int argc, char **argv)
|
||||
state.namaddr = concatenate(state.name, "[", state.addr,
|
||||
"]", (char *) 0);
|
||||
resp = smtpd_check_client(&state);
|
||||
SMTPD_MSG_ACT_FREE(state.action_client);
|
||||
SMTPD_MSG_ACT_ZERO(state.action_client);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4013,17 +4072,22 @@ int main(int argc, char **argv)
|
||||
if (strcasecmp(args->argv[0], "helo") == 0) {
|
||||
state.where = "HELO";
|
||||
resp = smtpd_check_helo(&state, args->argv[1]);
|
||||
SMTPD_MSG_ACT_FREE(state.action_helo);
|
||||
SMTPD_MSG_ACT_ZERO(state.action_helo);
|
||||
UPDATE_STRING(state.helo_name, args->argv[1]);
|
||||
} else if (strcasecmp(args->argv[0], "mail") == 0) {
|
||||
state.where = "MAIL";
|
||||
TRIM_ADDR(args->argv[1], addr);
|
||||
UPDATE_STRING(state.sender, addr);
|
||||
resp = smtpd_check_mail(&state, addr);
|
||||
SMTPD_MSG_ACT_FREE(state.action_mailrcpt);
|
||||
SMTPD_MSG_ACT_ZERO(state.action_mailrcpt);
|
||||
} else if (strcasecmp(args->argv[0], "rcpt") == 0) {
|
||||
state.where = "RCPT";
|
||||
TRIM_ADDR(args->argv[1], addr);
|
||||
(resp = smtpd_check_rcpt(&state, addr))
|
||||
|| (resp = smtpd_check_rcptmap(&state, addr));
|
||||
resp = smtpd_check_rcpt(&state, addr);
|
||||
SMTPD_MSG_ACT_FREE(state.action_mailrcpt);
|
||||
SMTPD_MSG_ACT_ZERO(state.action_mailrcpt);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -16,7 +16,7 @@ extern void smtpd_check_init(void);
|
||||
extern char *smtpd_check_client(SMTPD_STATE *);
|
||||
extern char *smtpd_check_helo(SMTPD_STATE *, char *);
|
||||
extern char *smtpd_check_mail(SMTPD_STATE *, char *);
|
||||
extern char *smtpd_check_rcptmap(SMTPD_STATE *, char *);
|
||||
extern char *smtpd_check_vrfy(SMTPD_STATE *, char *);
|
||||
extern char *smtpd_check_size(SMTPD_STATE *, off_t);
|
||||
extern char *smtpd_check_rcpt(SMTPD_STATE *, char *);
|
||||
extern char *smtpd_check_etrn(SMTPD_STATE *, char *);
|
||||
|
@ -11,6 +11,7 @@ sender_restrictions hash:./smtpd_check_access
|
||||
mail rejecttext@bad.domain
|
||||
mail filter@filter.domain
|
||||
mail filtertext@filter.domain
|
||||
mail filtertexttext@filter.domain
|
||||
mail hold@hold.domain
|
||||
mail holdtext@hold.domain
|
||||
mail discard@hold.domain
|
||||
|
@ -14,10 +14,13 @@ OK
|
||||
./smtpd_check: <queue id>: reject: MAIL from localhost[127.0.0.1]: 554 <rejecttext@bad.domain>: Sender address rejected: text; from=<rejecttext@bad.domain> proto=SMTP
|
||||
554 <rejecttext@bad.domain>: Sender address rejected: text
|
||||
>>> mail filter@filter.domain
|
||||
./smtpd_check: warning: access map hash:./smtpd_check_access entry filter@filter.domain has FILTER entry without value
|
||||
./smtpd_check: warning: access map hash:./smtpd_check_access entry "filter@filter.domain" has FILTER entry without value
|
||||
OK
|
||||
>>> mail filtertext@filter.domain
|
||||
./smtpd_check: <queue id>: filter: MAIL from localhost[127.0.0.1]: <filtertext@filter.domain>: Sender address triggers FILTER text; from=<filtertext@filter.domain> proto=SMTP
|
||||
./smtpd_check: warning: access map hash:./smtpd_check_access entry "filtertext@filter.domain" requires transport:destination
|
||||
OK
|
||||
>>> mail filtertexttext@filter.domain
|
||||
./smtpd_check: <queue id>: filter: MAIL from localhost[127.0.0.1]: <filtertexttext@filter.domain>: Sender address triggers FILTER text:text; from=<filtertexttext@filter.domain> proto=SMTP
|
||||
OK
|
||||
>>> mail hold@hold.domain
|
||||
./smtpd_check: <queue id>: hold: MAIL from localhost[127.0.0.1]: <hold@hold.domain>: Sender address triggers HOLD action; from=<hold@hold.domain> proto=SMTP
|
||||
|
@ -50,6 +50,7 @@ dsn.rfc-ignorant.org $rbl_code client=$client
|
||||
rejecttext@bad.domain reject text
|
||||
filter@filter.domain filter
|
||||
filtertext@filter.domain filter text
|
||||
filtertexttext@filter.domain filter text:text
|
||||
hold@hold.domain hold
|
||||
holdtext@hold.domain hold text
|
||||
discard@hold.domain discard
|
||||
|
@ -92,6 +92,9 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
|
||||
state->recursion = 0;
|
||||
state->msg_size = 0;
|
||||
state->junk_cmds = 0;
|
||||
SMTPD_MSG_ACT_ZERO(state->action_client);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_helo);
|
||||
SMTPD_MSG_ACT_ZERO(state->action_mailrcpt);
|
||||
state->defer_if_permit_client = 0;
|
||||
state->defer_if_permit_helo = 0;
|
||||
state->defer_if_permit_sender = 0;
|
||||
@ -136,6 +139,9 @@ void smtpd_state_reset(SMTPD_STATE *state)
|
||||
vstring_free(state->defer_if_reject.reason);
|
||||
if (state->expand_buf)
|
||||
vstring_free(state->expand_buf);
|
||||
SMTPD_MSG_ACT_FREE(state->action_client);
|
||||
SMTPD_MSG_ACT_FREE(state->action_helo);
|
||||
SMTPD_MSG_ACT_FREE(state->action_mailrcpt);
|
||||
|
||||
#ifdef USE_SASL_AUTH
|
||||
if (var_smtpd_sasl_enable)
|
||||
|
Loading…
x
Reference in New Issue
Block a user