exit status codes. Files: sendmail/sendmail.c,
postdrop/postdrop.c.
+20011129
+
+ Maintenance: dict_ldap.c wasn't updated after the revision
+ of the string matching routines. File: util/dict_ldap.c.
+
+20011208
+
+ Maintenance: LDAP module and documentation from LaMont
+ Jones. This version adds verbose logging for LDAP library
+ routines. Files: src/util/dict_ldap.[hc], LDAP_README,
+ conf/sample-ldap.cf
+
+ Portability: made memory alignment restrictions configurable.
+ File: util/mymalloc.c.
+
+ Bugfix? Avoid surprises with source routed destinations
+ and OK entries in SMTPD access maps. File: smtpd/smtpd_access.c.
+
+ Security: "postfix check" now looks for common stupidity
+ such as "chown -R postfix /var/spool/postfix" which makes
+ chrooted Postfix less secure than non-chrooted. These extra
+ tests are bound to raise a stink with third-party patches
+ such as TLS that introduce their own files into the jail.
+
Open problems:
+ Low: log queue ID when enabling PIX workaround.
+
+ Low: disable PIX workaround for mail < configurable age.
+
+ Low: replace null sender address internal representation
+ by <> so that it can be looked up reliably in maps. Must
+ prevent attempts to rewrite this address with canonical
+ maps, or else accidents are bound to happen.
+
Medium: need in-process caching for map lookups. LDAP
servers seem to need this in particular.
other possible values, please bring it to the attention of the
postfix-users@postfix.org mailing list.
+ debuglevel (0)
+ What level to set for debugging in the the OpenLDAP libraries.
+
Don't use quotes in these variables; at least, not until the Postfix
configuration routines understand how to deal with quoted strings.
library (Perl Compatible Regular Expressions), which can be obtained
from:
- ftp://ftp.cus.cam.ac.uk/pub/software/programs/pcre/
+ ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre
You will need to add -DHAS_PCRE and a -I for the PCRE header to CCARGS,
and add the path to the PCRE library to AUXLIBS, for example:
-exec $WARN not owned by root: {} \;
find $daemon_directory/. $config_directory/. \
- \( -perm -020 -o -perm -002 \) \
+ \( -perm -020 -o -perm -002 \) -type f \
-exec $WARN group or other writable: {} \;
test -d maildrop || {
chown $mail_owner private
}
find `ls -d $queue_directory/* | \
- egrep '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private)$'` \
+ egrep '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private|flush)$'` \
! \( -type p -o -type s \) ! -user $mail_owner \
-exec $WARN not owned by $mail_owner: {} \;
+ find `ls -d $queue_directory/* | \
+ egrep -v '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private|flush|pid|maildrop)$'` \
+ ! -user root \
+ -exec $WARN not owned by root: {} \;
+
for dir in $queue_directory/maildrop
do
ls -lLd $dir | (grep " $mail_owner " >/dev/null ||
-exec $WARN not owned by root: {} \;
find $daemon_directory/. $config_directory/. \
- \( -perm -020 -o -perm -002 \) \
+ \( -perm -020 -o -perm -002 \) -type f \
-exec $WARN group or other writable: {} \;
test -d maildrop || {
chown $mail_owner private
}
find `ls -d $queue_directory/* | \
- egrep '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private)$'` \
+ egrep '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private|flush)$'` \
! \( -type p -o -type s \) ! -user $mail_owner \
-exec $WARN not owned by $mail_owner: {} \;
+ find `ls -d $queue_directory/* | \
+ egrep -v '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private|flush|pid|maildrop)$'` \
+ ! -user root \
+ -exec $WARN not owned by root: {} \;
+
for dir in $queue_directory/maildrop
do
ls -lLd $dir | (grep " $mail_owner " >/dev/null ||
# The entries referenced by these links are (recursively) treated as if
# they were contained in the referencing entity.
#
-# ldap_special_result_attribute =
+#ldap_special_result_attribute =
# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one.
#
# (exactly) the specified list of domains.
#
#ldap_domain =
+
+# The ldap_debuglevel parameter sets the debug level in the OpenLDAP
+# libraries.
+#ldap_debuglevel = 0
#
-# Sample pcre (PERL-compatible regular expression) map file
+# Sample pcre (PERL-compatible regular expression) map file for
+# SMTPD access control. See pcre_table(5) for syntax description.
#
# The first field is a perl-like regular expression. The expression
# delimiter can be any character except whitespace, or characters
-# Sample regexp lookup "table".
+# Sample regexp SMTPD access lookup "table". See regexp_table(5)
+# for a description of the syntax.
#
# Format is /regexp/flags or /regexp/flags!/regexp/flags
# where regexp is a regular expression as found in regexp(5), and flags are
A little background is in order. With the SMTP protocol, the HELO,
MAIL FROM and RCPT TO commands and responses are relatively short.
-When you're talking to sendmail, every command and every response
-is sent as a separate packet, because sendmail cannot implement
-ESMTP command pipelining.
+When you're talking to old versions of sendmail, every command and
+every response is sent as a separate packet, because sendmail didn't
+implement ESMTP command pipelining until recently.
<p>
<b>DESCRIPTION</b>
The <b>pickup</b> daemon waits for hints that new mail has been
- dropped into the world-writable <b>maildrop</b> directory, and
- feeds it into the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon. Ill-formatted files
- are deleted without notifying the originator. This pro-
- gram expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
+ dropped into the <b>maildrop</b> directory, and feeds it into the
+ <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon. Ill-formatted files are deleted with-
+ out notifying the originator. This program expects to be
+ run from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
<b>STANDARDS</b>
None. The <b>pickup</b> daemon does not interact with the outside
world.
<b>SECURITY</b>
- The <b>pickup</b> daemon runs with superuser privileges so that
+ The <b>pickup</b> daemon runs with superuser privileges so that
it 1) can open a queue file with the rights of the submit-
- ting user and 2) can access the Postfix private IPC chan-
+ ting user and 2) can access the Postfix private IPC chan-
nels. On the positive side, the program can run chrooted,
opens no files for writing, is careful about what files it
- opens for reading, and does not actually touch any data
+ opens for reading, and does not actually touch any data
that is sent to its public service endpoint.
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
<b>BUGS</b>
- The <b>pickup</b> daemon copies mail from file to the <a href="cleanup.8.html"><b>cleanup</b>(8)</a>
- daemon. It could avoid message copying overhead by send-
- ing a file descriptor instead of file data, but then the
- already complex <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon would have to deal with
+ The <b>pickup</b> daemon copies mail from file to the <a href="cleanup.8.html"><b>cleanup</b>(8)</a>
+ daemon. It could avoid message copying overhead by send-
+ ing a file descriptor instead of file data, but then the
+ already complex <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon would have to deal with
unfiltered user data.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Content</b> <b>inspection</b> <b>controls</b>
<b>content</b><i>_</i><b>filter</b>
- The name of a mail delivery transport that filters
+ The name of a mail delivery transport that filters
mail and that either bounces mail or re-injects the
- result back into Postfix. This parameter uses the
- same syntax as the right-hand side of a Postfix
+ result back into Postfix. This parameter uses the
+ same syntax as the right-hand side of a Postfix
transport table.
<b>Miscellaneous</b>
<b>always</b><i>_</i><b>bcc</b>
- Address to send a copy of each message that enters
+ Address to send a copy of each message that enters
the system.
<b>mail</b><i>_</i><b>owner</b>
- The process privileges used while not opening a
+ The process privileges used while not opening a
<b>maildrop</b> file.
<b>queue</b><i>_</i><b>directory</b>
<b>SEE</b> <b>ALSO</b>
<a href="cleanup.8.html">cleanup(8)</a> message canonicalization
<a href="master.8.html">master(8)</a> process manager
+ <a href="sendmail.1.html">sendmail(1)</a>, postdrop(8) mail posting agent
syslogd(8) system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
.ad
.fi
The \fBpickup\fR daemon waits for hints that new mail has been
-dropped into the world-writable \fBmaildrop\fR directory, and
-feeds it into the \fBcleanup\fR(8) daemon.
+dropped into the \fBmaildrop\fR directory, and feeds it into the
+\fBcleanup\fR(8) daemon.
Ill-formatted files are deleted without notifying the originator.
This program expects to be run from the \fBmaster\fR(8) process
manager.
.nf
cleanup(8) message canonicalization
master(8) process manager
+sendmail(1), postdrop(8) mail posting agent
syslogd(8) system logging
.SH LICENSE
.na
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011128"
+#define DEF_MAIL_VERSION "Snapshot-20011208"
extern char *var_mail_version;
/* LICENSE
/* \fBpickup\fR [generic Postfix daemon options]
/* DESCRIPTION
/* The \fBpickup\fR daemon waits for hints that new mail has been
-/* dropped into the world-writable \fBmaildrop\fR directory, and
-/* feeds it into the \fBcleanup\fR(8) daemon.
+/* dropped into the \fBmaildrop\fR directory, and feeds it into the
+/* \fBcleanup\fR(8) daemon.
/* Ill-formatted files are deleted without notifying the originator.
/* This program expects to be run from the \fBmaster\fR(8) process
/* manager.
/* SEE ALSO
/* cleanup(8) message canonicalization
/* master(8) process manager
+/* sendmail(1), postdrop(8) mail posting agent
/* syslogd(8) system logging
/* LICENSE
/* .ad
*/
static char *sendmail_path;
static void sendmail_cleanup(void);
-static NORETURN fatal_error(int, const char *,...);
+static NORETURN PRINTFLIKE(2, 3) fatal_error(int, const char *,...);
/*
* Flag parade.
postdrop_command = concatenate(var_command_dir, "/postdrop",
msg_verbose ? " -v" : (char *) 0, (char *) 0);
if ((handle = mail_stream_command(postdrop_command)) == 0)
- msg_fatal("%s(%ld): unable to execute %s",
+ msg_fatal("%s(%ld): unable to execute %s: %m",
saved_sender, (long) uid, postdrop_command);
myfree(postdrop_command);
}
* Sender to login name mapping.
*/
smtpd_sender_login_maps = maps_create(VAR_SMTPD_SND_AUTH_MAPS,
- var_smtpd_snd_auth_maps,
- DICT_FLAG_LOCK);
+ var_smtpd_snd_auth_maps,
+ DICT_FLAG_LOCK);
/*
* error_text is used for returning error responses.
msg_warn("%s: no @domain in address: %s", myname, CONST_STR(reply->recipient));
return (0);
}
+ if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED))
+ return (SMTPD_CHECK_DUNNO);
/*
* Look up the full address.
/* The cache size in bytes. Does nothing if the cache is off, of course.
/* .IP \fIldapsource_\fRdereference
/* How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
+/* .IP \fIldapsource_\fRdebuglevel
+/* Debug level. See 'loglevel' option in slapd.conf(5) man page.
+/* Currently only in openldap libraries (and derivatives).
/* SEE ALSO
/* dict(3) generic dictionary manager
/* AUTHOR(S)
/* John Hensley
/* john@sunislelodge.com
/*
+/* LaMont Jones
+/* lamont@hp.com
+/*
/*--*/
/* System library. */
long cache_expiry;
long cache_size;
int dereference;
+ int debuglevel;
LDAP *ld;
} DICT_LDAP;
*/
static jmp_buf env;
+static void dict_ldap_logprint(LDAP_CONST char *data) {
+ char *myname = "dict_ldap_debug";
+ msg_info("%s: %s", myname, data);
+}
+
static void dict_ldap_timeout(int unused_sig)
{
longjmp(env, 1);
dict_ldap->ld = ldap_init(dict_ldap->server_host,
(int) dict_ldap->server_port);
if (dict_ldap->ld == NULL) {
- msg_warn("%s: Unable to int LDAP server %s",
+ msg_warn("%s: Unable to init LDAP server %s",
myname, dict_ldap->server_host);
dict_errno = DICT_ERR_RETRY;
return (-1);
}
mytimeval.tv_sec = dict_ldap->timeout;
mytimeval.tv_usec = 0;
- ldap_set_option(dict_ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &mytimeval);
+ if (ldap_set_option(dict_ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &mytimeval) !=
+ LDAP_OPT_SUCCESS)
+ msg_warn("%s: Unable to set network timeout.", myname);
#else
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
msg_warn("%s: Error setting signal handler for open timeout: %m",
* Mattice for this, and to Hery Rakotoarisoa for the v3 update.
*/
#if (LDAP_API_VERSION >= 2000)
- ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF, &(dict_ldap->dereference));
+ if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF,
+ &(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
+ msg_warn("%s: Unable to set dereference option.", myname);
#else
dict_ldap->ld->ld_deref = dict_ldap->dereference;
#endif
+#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
+ if(ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
+ (LDAP_CONST *)dict_ldap_logprint) != LBER_OPT_SUCCESS)
+ msg_warn("%s: Unable to set ber logprint function.", myname);
+ if(ldap_set_option(dict_ldap->ld, LDAP_OPT_DEBUG_LEVEL,
+ &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
+ msg_warn("%s: Unable to set LDAP debug level.", myname);
+#endif
+
+
/*
* If this server requires a bind, do so. Thanks to Sam Tardieu for
* noticing that the original bind call was broken.
if (strcasecmp(dict_ldap->result_attributes->argv[i],
attr) == 0) {
if (msg_verbose)
- msg_info("%s: search returned %d value(s) for requested result attribute %s", myname, i, attr);
+ msg_info("%s: search returned %ld value(s) for requested result attribute %s", myname, i, attr);
break;
}
}
if (dict_ldap->ld == NULL) {
if (msg_verbose)
msg_info
- ("%s: No existing connection for ldapsource %s, reopening",
+ ("%s: No existing connection for LDAP source %s, reopening",
myname, dict_ldap->ldapsource);
dict_ldap_connect(dict_ldap);
if (dict_errno)
return (0);
} else if (msg_verbose)
- msg_info("%s: Using existing connection for ldapsource %s",
+ msg_info("%s: Using existing connection for LDAP source %s",
myname, dict_ldap->ldapsource);
msg_info("%s: Searching with filter %s", myname,
vstring_str(filter_buf));
- if ((rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
- dict_ldap->scope,
- vstring_str(filter_buf),
- dict_ldap->result_attributes->argv,
- 0, &tv, &res)) == LDAP_SUCCESS) {
+ rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
+ dict_ldap->scope,
+ vstring_str(filter_buf),
+ dict_ldap->result_attributes->argv,
+ 0, &tv, &res);
+
+ if (rc == LDAP_SERVER_DOWN) {
+ if (msg_verbose)
+ msg_info("%s: Lost connection for LDAP source %s, reopening",
+ myname, dict_ldap->ldapsource);
+
+ ldap_unbind(dict_ldap->ld);
+ dict_ldap->ld = NULL;
+ dict_ldap_connect(dict_ldap);
+
+ /*
+ * if dict_ldap_connect() set dict_errno, abort.
+ */
+ if (dict_errno)
+ return (0);
+
+ rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
+ dict_ldap->scope,
+ vstring_str(filter_buf),
+ dict_ldap->result_attributes->argv,
+ 0, &tv, &res);
+
+ }
+
+ if (rc == LDAP_SUCCESS) {
/*
* Search worked; extract the requested result_attribute.
*/
#if (LDAP_API_VERSION >= 2000)
- ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc);
+ if (ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc) !=
+ LDAP_OPT_SUCCESS)
+ msg_warn("%s: Unable to get last error number.", myname);
if (rc != LDAP_SUCCESS && rc != LDAP_DECODING_ERROR)
msg_warn("%s: Had some trouble with entries returned by search: %s", myname, ldap_err2string(rc));
#else
mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
"", 0, 0));
if (*domainlist) {
+#ifdef MATCH_FLAG_NONE
+ dict_ldap->domain = match_list_init(MATCH_FLAG_NONE,
+ domainlist, 1, match_string);
+#else
dict_ldap->domain = match_list_init(domainlist, 1, match_string);
+#endif
if (dict_ldap->domain == NULL)
msg_warn("%s: domain match list creation using \"%s\" failed, will continue without it", myname, domainlist);
if (msg_verbose)
msg_info("%s: %s is %d", myname, vstring_str(config_param),
dict_ldap->dereference);
+ /*
+ * Debug level.
+ */
+#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
+ vstring_sprintf(config_param, "%s_debuglevel", ldapsource);
+ dict_ldap->debuglevel = get_mail_conf_int(vstring_str(config_param), 0, 0,
+ 0);
+ if (msg_verbose)
+ msg_info("%s: %s is %d", myname, vstring_str(config_param),
+ dict_ldap->debuglevel);
+#endif
+
dict_ldap_connect(dict_ldap);
/*
typedef struct MBLOCK {
int signature; /* set when block is active */
int length; /* user requested length */
- char payload[1]; /* actually a bunch of bytes */
+ union {
+ ALIGN_TYPE align;
+ char payload[1]; /* actually a bunch of bytes */
+ } u;
} MBLOCK;
#define SIGNATURE 0xdead
#define CHECK_IN_PTR(ptr, real_ptr, len, fname) { \
if (ptr == 0) \
msg_panic("%s: null pointer input", fname); \
- real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, payload[0])); \
+ real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, u.payload[0])); \
if (real_ptr->signature != SIGNATURE) \
msg_panic("%s: corrupt or unallocated memory block", fname); \
real_ptr->signature = 0; \
#define CHECK_OUT_PTR(ptr, real_ptr, len) { \
real_ptr->signature = SIGNATURE; \
real_ptr->length = len; \
- ptr = real_ptr->payload; \
+ ptr = real_ptr->u.payload; \
}
-#define SPACE_FOR(len) (offsetof(MBLOCK, payload[0]) + len)
+#define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len)
/* mymalloc - allocate memory or bust */
#define S_IXGRP 0000010
#define S_IXOTH 0000001
#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
+
+ /*
+ * Memory alignment of memory allocator results. By default we align for
+ * doubles.
+ */
+#ifndef ALIGN_TYPE
+#define ALIGN_TYPE double
#endif
/*