2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

postfix-2.3-20060403

This commit is contained in:
Wietse Venema 2006-04-03 00:00:00 -05:00 committed by Viktor Dukhovni
parent 303c7c57dd
commit ee4ef8eeb6
18 changed files with 282 additions and 95 deletions

View File

@ -12064,6 +12064,34 @@ Apologies for any names omitted.
test. A filter timeout was mis-reported as lost connection.
Found in code review. File: smtpd/smtpd_proxy.c.
20060327
Cleanup: the SQL and LDAP clients now log a warning when
they skip an empty lookup result, so that humans don't have
to wonder why Postfix doesn't find all the database entries.
File: global/db_common.c.
20060328
Feature: configurable chroot directive for the pipe(8)
delivery agent, by Przemyslaw Wegrzyn. Files:
global/pipe_command.c, pipe/pipe.c.
Bugfix: cut-and-paste error: lmtp_connection_cache_limit
was left with the name of smtp_connection_cache_limit.
Reported by Victor? File: src/global/mail_params.h.
20060403
Cleanup: made fcntl/flock handling consistent with respect
to EINTR (reported by Carlo Contavalli). However, Postfix
is not meant to be signal safe. Only the master daemon
handles signals without terminating, and it uses only a
small subset of Postfix library routines. File: util/myflock.c.
Bugfix: the pipe-to-command error message was lost when the
command could not be executed. File: global/pipe_command.c.
Wish list:
Don't send xforward attributes to every site that announces

View File

@ -181,11 +181,17 @@ that the Postfix queue is under /var/spool/postfix/.
/some/where/dovecot.conf:
auth default {
..
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0666
mode = 0660
user = postfix
group = postfix
}
}
}
@ -447,7 +453,7 @@ CCrreeddiittss
reject_authenticated_sender_login_mismatch and
reject_unauthenticated_sender_login_mismatch, and revised the docs.
* Wietse made another iteration through the code to add plug-in support for
multiple implementations.
* The Dovecot SMTP server plug-in was originally implemented by Timo Sirainen
of Procontrol, Finland.
multiple SASL implementations.
* The Dovecot SMTP server-only plug-in was originally implemented by Timo
Sirainen of Procontrol, Finland.

View File

@ -140,7 +140,7 @@ in the Postfix top-level directory: </p>
<li> <p> The "-DDEF_SASL_SERVER" stuff is not necessary; it just
makes Postfix configuration a little more convenient because you
don't have to specify the SASL plug-in type in the Postfix main.cf
don't have to specify the SASL plug-in type in the Postfix <a href="postconf.5.html">main.cf</a>
file. </p>
<li> <p> If you also want support for LDAP or TLS, you will have to merge
@ -229,7 +229,7 @@ SMTP server</a></h2>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_sasl_auth_enable">smtpd_sasl_auth_enable</a> = yes
</pre>
</blockquote>
@ -238,7 +238,7 @@ SMTP server</a></h2>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a> <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a> ...
</pre>
@ -249,7 +249,7 @@ SMTP server</a></h2>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_sasl_authenticated_header">smtpd_sasl_authenticated_header</a> = yes
</pre>
</blockquote>
@ -265,7 +265,7 @@ clients) use the following: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#broken_sasl_auth_clients">broken_sasl_auth_clients</a> = yes
</pre>
</blockquote>
@ -281,7 +281,7 @@ Postfix runs chrooted: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a> = dovecot
<a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a> = private/auth
</pre>
@ -296,11 +296,17 @@ Postfix queue is under /var/spool/postfix/. </p>
<pre>
/some/where/dovecot.conf:
auth default {
..
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0666
mode = 0660
user = postfix
group = postfix
}
}
}
@ -352,7 +358,7 @@ library for configuration can be set with: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
smtpd_sasl_application_name = smtpd
</pre>
</blockquote>
@ -449,7 +455,7 @@ realm used by smtpd: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_sasl_local_domain">smtpd_sasl_local_domain</a> = $<a href="postconf.5.html#myhostname">myhostname</a>
</pre>
</blockquote>
@ -593,7 +599,7 @@ table. </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> = yes
<a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> = hash:/etc/postfix/sasl_passwd
<a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a> = cyrus
@ -612,7 +618,7 @@ before it searches by destination, specify: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a> = yes
<a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> = yes
<a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> = hash:/etc/postfix/sasl_passwd
@ -634,7 +640,7 @@ for example: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> = noanonymous
</pre>
</blockquote>
@ -652,7 +658,7 @@ into consideration: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> = !gssapi, !external, static:all
</pre>
</blockquote>
@ -682,9 +688,9 @@ of SuSE Rhein/Main AG.
<a href="postconf.5.html#reject_unauthenticated_sender_login_mismatch">reject_unauthenticated_sender_login_mismatch</a>, and revised the docs.
<li> Wietse made another iteration through the code to add
plug-in support for multiple implementations.
plug-in support for multiple SASL implementations.
<li> The Dovecot SMTP server plug-in was originally implemented by
<li> The Dovecot SMTP server-only plug-in was originally implemented by
Timo Sirainen of Procontrol, Finland.
</ul>

View File

@ -48,9 +48,22 @@ PIPE(8) PIPE(8)
file at the end of a service definition. The syntax is as
follows:
<b>directory=</b><i>pathname</i> (optional, default: <b>$<a href="postconf.5.html#queue_directory">queue_directory</a></b>)
Change to the named directory before executing the
external command. Delivery is deferred in case of
<b>chroot=</b><i>pathname</i> (optional)
Change the process root directory and working
directory to the named directory. This happens
before switching to the privileges specified with
the <b>user</b> attribute, and before executing the
optional <b>directory=</b><i>pathname</i> directive. Delivery is
deferred in case of failure.
This feature is available as of Postfix 2.3.
<b>directory=</b><i>pathname</i> (optional)
Change to the named directory before executing the
external command. The directory must be accessible
for the user specified with the <b>user</b> attribute (see
below). The default working directory is
<b>$<a href="postconf.5.html#queue_directory">queue_directory</a></b>. Delivery is deferred in case of
failure.
This feature is available as of Postfix 2.2.
@ -162,9 +175,9 @@ PIPE(8) PIPE(8)
<b>user</b>=<i>username</i> (required)
<b>user</b>=<i>username</i>:<i>groupname</i>
The external command is executed with the rights of
the specified <i>username</i>. The software refuses to
execute commands with root privileges, or with the
Execute the external command with the rights of the
specified <i>username</i>. The software refuses to exe-
cute commands with root privileges, or with the
privileges of the mail system owner. If <i>groupname</i>
is specified, the corresponding group ID is used
instead of the group ID of <i>username</i>.

View File

@ -3154,6 +3154,18 @@ configuration parameter. See there for details. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
</DD>
<DT><b><a name="lmtp_connection_cache_time_limit">lmtp_connection_cache_time_limit</a>
(default: 2s)</b></DT><DD>
<p> The LMTP-specific version of the
<a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> configuration parameter.
See there for details. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
</DD>
<DT><b><a name="lmtp_connection_reuse_time_limit">lmtp_connection_reuse_time_limit</a>

View File

@ -1705,6 +1705,12 @@ The LMTP-specific version of the smtp_connection_cache_on_demand
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.3 and later.
.SH lmtp_connection_cache_time_limit (default: 2s)
The LMTP-specific version of the
smtp_connection_cache_time_limit configuration parameter.
See there for details.
.PP
This feature is available in Postfix 2.3 and later.
.SH lmtp_connection_reuse_time_limit (default: 300s)
The LMTP-specific version of the smtp_connection_reuse_time_limit
configuration parameter. See there for details.

View File

@ -51,8 +51,19 @@ entry for the pipe-based delivery transport.
.fi
The external command attributes are given in the \fBmaster.cf\fR
file at the end of a service definition. The syntax is as follows:
.IP "\fBdirectory=\fIpathname\fR (optional, default: \fB$queue_directory\fR)"
.IP "\fBchroot=\fIpathname\fR (optional)"
Change the process root directory and working directory to
the named directory. This happens before switching to the
privileges specified with the \fBuser\fR attribute, and
before executing the optional \fBdirectory=\fIpathname\fR
directive. Delivery is deferred in case of failure.
.sp
This feature is available as of Postfix 2.3.
.IP "\fBdirectory=\fIpathname\fR (optional)"
Change to the named directory before executing the external command.
The directory must be accessible for the user specified with the
\fBuser\fR attribute (see below).
The default working directory is \fB$queue_directory\fR.
Delivery is deferred in case of failure.
.sp
This feature is available as of Postfix 2.2.
@ -148,7 +159,7 @@ Messages greater in size than this limit (in bytes) will
be returned to the sender as undeliverable.
.IP "\fBuser\fR=\fIusername\fR (required)"
.IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
The external command is executed with the rights of the
Execute the external command with the rights of the
specified \fIusername\fR. The software refuses to execute
commands with root privileges, or with the privileges of the
mail system owner. If \fIgroupname\fR is specified, the

View File

@ -201,6 +201,7 @@ while (<>) {
s;\blmtp_sasl_mechanism_filter\b;<a href="postconf.5.html#lmtp_sasl_mechanism_filter">$&</a>;g;
s;\blmtp_host_lookup\b;<a href="postconf.5.html#lmtp_host_lookup">$&</a>;g;
s;\blmtp_connection_cache_destinations\b;<a href="postconf.5.html#lmtp_connection_cache_destinations">$&</a>;g;
s;\blmtp_connection_cache_time_limit\b;<a href="postconf.5.html#lmtp_connection_cache_time_limit">$&</a>;g;
s;\blmtp_tls_per_site\b;<a href="postconf.5.html#lmtp_tls_per_site">$&</a>;g;
s;\blmtp_generic_maps\b;<a href="postconf.5.html#lmtp_generic_maps">$&</a>;g;
s;\blmtp_pix_workaround_threshold_time\b;<a href="postconf.5.html#lmtp_pix_workaround_threshold_time">$&</a>;g;

View File

@ -296,11 +296,17 @@ Postfix queue is under /var/spool/postfix/. </p>
<pre>
/some/where/dovecot.conf:
auth default {
..
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0666
mode = 0660
user = postfix
group = postfix
}
}
}
@ -682,9 +688,9 @@ reject_authenticated_sender_login_mismatch and
reject_unauthenticated_sender_login_mismatch, and revised the docs.
<li> Wietse made another iteration through the code to add
plug-in support for multiple implementations.
plug-in support for multiple SASL implementations.
<li> The Dovecot SMTP server plug-in was originally implemented by
<li> The Dovecot SMTP server-only plug-in was originally implemented by
Timo Sirainen of Procontrol, Finland.
</ul>

View File

@ -9243,6 +9243,14 @@ See there for details. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
%PARAM lmtp_connection_cache_time_limit 2s
<p> The LMTP-specific version of the
smtp_connection_cache_time_limit configuration parameter.
See there for details. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
%PARAM smtpd_delay_open_until_valid_rcpt yes
<p> Postpone the start of an SMTP mail transaction until a valid

View File

@ -1415,10 +1415,12 @@ own_inet_addr.o: mail_params.h
own_inet_addr.o: own_inet_addr.c
own_inet_addr.o: own_inet_addr.h
pipe_command.o: ../../include/argv.h
pipe_command.o: ../../include/chroot_uid.h
pipe_command.o: ../../include/clean_env.h
pipe_command.o: ../../include/exec_command.h
pipe_command.o: ../../include/iostuff.h
pipe_command.o: ../../include/msg.h
pipe_command.o: ../../include/msg_vstream.h
pipe_command.o: ../../include/set_eugid.h
pipe_command.o: ../../include/set_ugid.h
pipe_command.o: ../../include/stringops.h

View File

@ -278,7 +278,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
db_quote_callback_t quote_func)
{
char *myname = "db_common_expand";
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *)ctxArg;
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
const char *vdomain = 0;
const char *kdomain = 0;
char *vuser = 0;
@ -287,18 +287,28 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
int i;
const char *cp;
/* Skip NULL or empty values */
if (value == 0 || *value == 0)
return (0);
/* Skip NULL values, silently. */
if (value == 0)
return (0);
/* Don't silenty skip empty query string or empty lookup results. */
if (*value == 0) {
if (key)
msg_warn("table \"%s:%s\": empty lookup result for: \"%s\""
" -- ignored", ctx->dict->type, ctx->dict->name, key);
else
msg_warn("table \"%s:%s\": empty query string"
" -- ignored", ctx->dict->type, ctx->dict->name);
return (0);
}
if (key) {
/* This is a result template and the input value is the result */
/* This is a result template and the input value is the result */
if (ctx->flags & (DB_COMMON_VALUE_DOMAIN | DB_COMMON_VALUE_USER))
if ((vdomain = strrchr(value, '@')) != 0)
++vdomain;
if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_VALUE_DOMAIN) != 0
|| vdomain == value + 1 && (ctx->flags&DB_COMMON_VALUE_USER) != 0)
if ((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_VALUE_DOMAIN) != 0
|| vdomain == value + 1 && (ctx->flags & DB_COMMON_VALUE_USER) != 0)
return (0);
/* The result format may use the local or domain part of the key */
@ -307,50 +317,51 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
++kdomain;
/*
* The key should already be checked before the query. No harm if
* the query did not get optimized out, so we just issue a warning.
* The key should already be checked before the query. No harm if the
* query did not get optimized out, so we just issue a warning.
*/
if ((!kdomain || !*kdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
|| kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0) {
if ((!kdomain || !*kdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0
|| kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0) {
msg_warn("%s: %s: lookup key '%s' skipped after query", myname,
ctx->dict->name, value);
ctx->dict->name, value);
return (0);
}
} else {
/* This is a query template and the input value is the lookup key */
/* This is a query template and the input value is the lookup key */
if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
if ((vdomain = strrchr(value, '@')) != 0)
++vdomain;
if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
|| vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)
if ((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0
|| vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)
return (0);
}
if (ctx->nparts > 0) {
parts = argv_split(key ? kdomain : vdomain, ".");
parts = argv_split(key ? kdomain : vdomain, ".");
/*
* Filter out input keys whose domains lack enough labels
* to fill-in the query template. See below and also
* db_common_parse() which initializes ctx->nparts.
* Filter out input keys whose domains lack enough labels to fill-in
* the query template. See below and also db_common_parse() which
* initializes ctx->nparts.
*/
if (parts->argc < ctx->nparts) {
argv_free(parts);
return (0);
}
/*
* Skip domains with leading, consecutive or trailing '.'
* separators among the required labels.
* Skip domains with leading, consecutive or trailing '.' separators
* among the required labels.
*/
for (i = 0; i < ctx->nparts; i++)
if (*parts->argv[parts->argc-i-1] == 0) {
if (*parts->argv[parts->argc - i - 1] == 0) {
argv_free(parts);
return (0);
}
}
if (VSTRING_LEN(result) > 0)
VSTRING_ADDCH(result, ',');
VSTRING_ADDCH(result, ',');
#define QUOTE_VAL(d, q, v, buf) do { \
if (q) \
@ -360,9 +371,9 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
} while (0)
/*
* Replace all instances of %s with the address to look up. Replace
* %u with the user portion, and %d with the domain portion. "%%"
* expands to "%". lowercase -> addr, uppercase -> key
* Replace all instances of %s with the address to look up. Replace %u
* with the user portion, and %d with the domain portion. "%%" expands to
* "%". lowercase -> addr, uppercase -> key
*/
for (cp = format; *cp; cp++) {
if (*cp == '%') {
@ -381,8 +392,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
if (vuser == 0)
vuser = mystrndup(value, vdomain - value - 1);
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
}
else
} else
QUOTE_VAL(ctx->dict, quote_func, value, result);
break;
@ -391,7 +401,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
break;
case 'S':
if (key)
if (key)
QUOTE_VAL(ctx->dict, quote_func, key, result);
else
QUOTE_VAL(ctx->dict, quote_func, value, result);
@ -403,16 +413,14 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
if (kuser == 0)
kuser = mystrndup(key, kdomain - key - 1);
QUOTE_VAL(ctx->dict, quote_func, kuser, result);
}
else
} else
QUOTE_VAL(ctx->dict, quote_func, key, result);
} else {
if (vdomain) {
if (vuser == 0)
vuser = mystrndup(value, vdomain - value - 1);
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
}
else
} else
QUOTE_VAL(ctx->dict, quote_func, value, result);
}
break;
@ -424,18 +432,26 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
/*
* Interpolate %[1-9] components into the query string.
* By this point db_common_parse() has identified the
* highest component index, and (see above) keys with
* fewer components have been filtered out. The "parts"
* ARGV is guaranteed to be initialized and hold enough
* elements to satisfy the query template.
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*
* Interpolate %[1-9] components into the query string. By
* this point db_common_parse() has identified the highest
* component index, and (see above) keys with fewer
* components have been filtered out. The "parts" ARGV is
* guaranteed to be initialized and hold enough elements to
* satisfy the query template.
*/
QUOTE_VAL(ctx->dict, quote_func,
parts->argv[parts->argc-(*cp-'0')], result);
parts->argv[parts->argc - (*cp - '0')], result);
break;
default:
@ -449,11 +465,11 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
VSTRING_TERMINATE(result);
if (vuser)
myfree(vuser);
myfree(vuser);
if (kuser)
myfree(kuser);
myfree(kuser);
if (parts)
argv_free(parts);
argv_free(parts);
return (1);
}

View File

@ -870,7 +870,7 @@ extern char *var_bestmx_transp;
#define VAR_SMTP_CACHE_CONNT "smtp_connection_cache_time_limit"
#define DEF_SMTP_CACHE_CONNT "2s"
#define VAR_LMTP_CACHE_CONNT "smtp_connection_cache_time_limit"
#define VAR_LMTP_CACHE_CONNT "lmtp_connection_cache_time_limit"
#define DEF_LMTP_CACHE_CONNT "2s"
extern int var_smtp_cache_conn;

View File

@ -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 "20060325"
#define MAIL_RELEASE_DATE "20060403"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT

View File

@ -44,8 +44,14 @@
/* The command is specified as an argument vector. This vector is
/* passed without further inspection to the \fIexecvp\fR() routine.
/* One of PIPE_CMD_COMMAND or PIPE_CMD_ARGV must be specified.
/* .IP "PIPE_CMD_CHROOT (char *)"
/* Root and working directory for command execution. This takes
/* effect before PIPE_CMD_CWD. A null pointer means don't
/* change root and working directory anyway. Failure to change
/* directory causes mail delivery to be deferred.
/* .IP "PIPE_CMD_CWD (char *)"
/* Working directory for command execution. A null pointer means
/* Working directory for command execution, after changing process
/* privileges to PIPE_CMD_UID and PIPE_CMD_GID. A null pointer means
/* don't change directory anyway. Failure to change directory
/* causes mail delivery to be deferred.
/* .IP "PIPE_CMD_ENV (char **)"
@ -137,6 +143,7 @@
#include <msg.h>
#include <vstream.h>
#include <msg_vstream.h>
#include <vstring.h>
#include <stringops.h>
#include <iostuff.h>
@ -144,6 +151,7 @@
#include <set_ugid.h>
#include <set_eugid.h>
#include <argv.h>
#include <chroot_uid.h>
/* Global library. */
@ -172,6 +180,7 @@ struct pipe_args {
char **export; /* exportable environment */
char *shell; /* command shell */
char *cwd; /* preferred working directory */
char *chroot; /* root directory */
};
static int pipe_command_timeout; /* command has timed out */
@ -200,6 +209,7 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
args->export = 0;
args->shell = 0;
args->cwd = 0;
args->chroot = 0;
pipe_command_maxtime = var_command_maxtime;
@ -254,6 +264,9 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
case PIPE_CMD_CWD:
args->cwd = va_arg(ap, char *);
break;
case PIPE_CMD_CHROOT:
args->chroot = va_arg(ap, char *);
break;
default:
msg_panic("%s: unknown key: %d", myname, key);
}
@ -357,14 +370,22 @@ static int pipe_command_wait_or_kill(pid_t pid, WAIT_STATUS_T *statusp, int sig,
static void pipe_child_cleanup(void)
{
exit(EX_TEMPFAIL);
/*
* WARNING: don't place code here. This code may run as mail_owner, as
* root, or as the user/group specified with the "user" attribute. The
* only safe action is to terminate.
*
* Future proofing. If you need exit() here then you broke Postfix.
*/
_exit(EX_TEMPFAIL);
}
/* pipe_command - execute command with extreme prejudice */
int pipe_command(VSTREAM *src, DSN_BUF *why,...)
{
char *myname = "pipe_comand";
char *myname = "pipe_command";
va_list ap;
VSTREAM *cmd_in_stream;
VSTREAM *cmd_out_stream;
@ -448,6 +469,28 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...)
*/
case 0:
(void) msg_cleanup(pipe_child_cleanup);
/*
* In order to chroot it is necessary to switch euid back to root.
* Right after chroot we call set_ugid() so all privileges will be
* dropped again.
*
* XXX For consistency we use chroot_uid() to change root+current
* directory. However, we must not use chroot_uid() to change process
* privileges (assuming a version that accepts numeric privileges).
* That would create a maintenance problem, because we would have two
* different code paths to set the external command's privileges.
*/
if (args.chroot) {
seteuid(0);
chroot_uid(args.chroot, (char *) 0);
}
/*
* XXX If we put code before the set_ugid() call, then the code that
* changes root directory must switch back to the mail_owner UID,
* otherwise we'd be running with root privileges.
*/
set_ugid(args.uid, args.gid);
if (setsid() < 0)
msg_warn("setsid failed: %m");
@ -488,12 +531,15 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...)
/*
* Process plumbing. If possible, avoid running a shell.
*
* From this point we would like to handle fatal errors ourselves
* (ENOMEM would probably be one of the few soft error conditions).
* For that we have to update exec_command() first so it returns an
* error indication instead of terminating the process.
* As a safety for buggy libraries, we close the syslog socket.
* Otherwise we could leak a file descriptor that was created by a
* privileged process.
*
* XXX To avoid losing fatal error messages we open a VSTREAM and
* capture the output in the parent process.
*/
closelog();
msg_vstream_init(var_procname, VSTREAM_ERR);
if (args.argv) {
execvp(args.argv[0], args.argv);
msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
@ -605,7 +651,10 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...)
return (sp->dsn[0] == '4' ?
PIPE_STAT_DEFER : PIPE_STAT_BOUNCE);
}
/* No "D.S.N text" or <sysexits.h> compatible status. Fake it. */
/*
* No "D.S.N text" or <sysexits.h> compatible status. Fake it.
*/
else {
sp = sys_exits_detail(WEXITSTATUS(wait_status));
dsb_unix(why, sp->dsn,

View File

@ -41,6 +41,7 @@
#define PIPE_CMD_EXPORT 12 /* exportable environment */
#define PIPE_CMD_ORIG_RCPT 13 /* mail_copy() original recipient */
#define PIPE_CMD_CWD 14 /* working directory */
#define PIPE_CMD_CHROOT 15 /* chroot() before exec() */
/*
* Command completion status.

View File

@ -41,8 +41,19 @@
/* .fi
/* The external command attributes are given in the \fBmaster.cf\fR
/* file at the end of a service definition. The syntax is as follows:
/* .IP "\fBdirectory=\fIpathname\fR (optional, default: \fB$queue_directory\fR)"
/* .IP "\fBchroot=\fIpathname\fR (optional)"
/* Change the process root directory and working directory to
/* the named directory. This happens before switching to the
/* privileges specified with the \fBuser\fR attribute, and
/* before executing the optional \fBdirectory=\fIpathname\fR
/* directive. Delivery is deferred in case of failure.
/* .sp
/* This feature is available as of Postfix 2.3.
/* .IP "\fBdirectory=\fIpathname\fR (optional)"
/* Change to the named directory before executing the external command.
/* The directory must be accessible for the user specified with the
/* \fBuser\fR attribute (see below).
/* The default working directory is \fB$queue_directory\fR.
/* Delivery is deferred in case of failure.
/* .sp
/* This feature is available as of Postfix 2.2.
@ -138,7 +149,7 @@
/* be returned to the sender as undeliverable.
/* .IP "\fBuser\fR=\fIusername\fR (required)"
/* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
/* The external command is executed with the rights of the
/* Execute the external command with the rights of the
/* specified \fIusername\fR. The software refuses to execute
/* commands with root privileges, or with the privileges of the
/* mail system owner. If \fIgroupname\fR is specified, the
@ -474,6 +485,7 @@ typedef struct {
gid_t gid; /* command privileges */
int flags; /* mail_copy() flags */
char *exec_dir; /* working directory */
char *chroot_dir; /* chroot directory */
VSTRING *eol; /* output record delimiter */
VSTRING *null_sender; /* null sender expansion */
off_t size_limit; /* max size in bytes we will accept */
@ -728,6 +740,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
attr->command = 0;
attr->flags = 0;
attr->exec_dir = 0;
attr->chroot_dir = 0;
attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
attr->null_sender = vstring_strcpy(vstring_alloc(1), MAIL_ADDR_MAIL_DAEMON);
attr->size_limit = 0;
@ -807,6 +820,13 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
}
/*
* chroot=string
*/
else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) {
attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1);
}
/*
* eol=string
*/
@ -1105,6 +1125,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
PIPE_CMD_EOL, STR(attr.eol),
PIPE_CMD_EXPORT, export_env->argv,
PIPE_CMD_CWD, attr.exec_dir,
PIPE_CMD_CHROOT, attr.chroot_dir,
PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr,
PIPE_CMD_DELIVERED, rcpt_list->info[0].address,
PIPE_CMD_END);

View File

@ -107,7 +107,9 @@ int myflock(int fd, int lock_style, int operation)
-1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1
};
status = flock(fd, lock_ops[operation]);
while ((status = flock(fd, lock_ops[operation])) < 0
&& errno == EINTR)
sleep(1);
break;
}
#endif
@ -129,8 +131,7 @@ int myflock(int fd, int lock_style, int operation)
lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW;
while ((status = fcntl(fd, request, &lock)) < 0
&& request == F_SETLKW
&& (errno == EINTR || errno == ENOLCK || errno == EDEADLK))
&& errno == EINTR)
sleep(1);
break;
}