2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

snapshot-19991122

This commit is contained in:
Wietse Venema 1999-11-22 00:00:00 -05:00
parent 37aa848072
commit 0504a0012e
12 changed files with 238 additions and 196 deletions

View File

@ -2,7 +2,7 @@ LINUX SYSLOGD PERFORMANCE
========================= =========================
LINUX syslogd uses synchronous writes by default, which is very LINUX syslogd uses synchronous writes by default, which is very
expensive. For services such a mail it is recommended that you expensive. For services such as mail it is recommended that you
disable synchronous logfile writes by prepending a - to the logfile disable synchronous logfile writes by prepending a - to the logfile
name: name:

View File

@ -3280,3 +3280,10 @@ Apologies for any names omitted.
Robustness: INSTALL.sh no longer uses postmap for sanity checks. Robustness: INSTALL.sh no longer uses postmap for sanity checks.
Feature: INSTALL.sh now has an install_root option. Feature: INSTALL.sh now has an install_root option.
Bugfix: INSTALL.sh now installs manual pages with proper
permissions and ownership.
Bugfix: the LDAP client did not properly escape special
characters in lookup keys (patch by John Hensley).
File: util/dict_ldap.c.

View File

@ -14,13 +14,13 @@ Make backups if you want to be able to recover.
In addition to doing a fresh install, this script can change an In addition to doing a fresh install, this script can change an
existing installation from using a world-writable maildrop to a existing installation from using a world-writable maildrop to a
group-writable one. It cannot be used to change Postfix queue group-writable one. It cannot be used to change Postfix queue
ownership. file/directory ownership.
Before installing files, this script prompts you for some definitions. Before installing files, this script prompts you for some definitions.
You can either edit this script ahead of time, or you can specify Most definitions will be remembered, so you have to specify them
your changes interactively. only once. All definitions have a reasonable default value.
install_root - prepend to installed file names (for package building) install_root - prefix for installed file names (for package building)
config_directory - directory with Postfix configuration files. config_directory - directory with Postfix configuration files.
daemon_directory - directory with Postfix daemon programs. daemon_directory - directory with Postfix daemon programs.
@ -34,12 +34,15 @@ your changes interactively.
mail_owner - owner of Postfix queue files. mail_owner - owner of Postfix queue files.
setgid - groupname, e.g., postdrop (default: no). See INSTALL section 12. setgid - groupname, e.g., postdrop (default: no). See INSTALL section 12.
manpages - path to man tree (default: no). Example: /usr/local/man. manpages - "no" or path to man tree. Example: /usr/local/man.
EOF EOF
# By now, shells must have functions. Ultrix users must use sh5 or lose. # By now, shells must have functions. Ultrix users must use sh5 or lose.
# Apparently, some broken LINUX file utilities won't move symlinks across
# file systems. Upgrade to a better system. Don't waste my time.
compare_or_replace() { compare_or_replace() {
cmp $2 $3 >/dev/null 2>&1 || { cmp $2 $3 >/dev/null 2>&1 || {
rm -f junk || exit 1 rm -f junk || exit 1
@ -71,9 +74,9 @@ case `echo -n` in
*) n=; c='\c';; *) n=; c='\c';;
esac esac
# Default settings, edit to taste or change interactively. Once this # Default settings. These are clobbered by remembered settings.
# script has run it saves settings to $config_directory/install.cf.
install_root=/
config_directory=/etc/postfix config_directory=/etc/postfix
daemon_directory=/usr/libexec/postfix daemon_directory=/usr/libexec/postfix
command_directory=/usr/sbin command_directory=/usr/sbin
@ -83,19 +86,39 @@ newaliases_path=/usr/bin/newaliases
mailq_path=/usr/bin/mailq mailq_path=/usr/bin/mailq
mail_owner=postfix mail_owner=postfix
setgid=no setgid=no
manpages=no manpages=/usr/local/man
while : # Find out the location of configuration files.
for name in install_root config_directory
do do
echo $n "install_root: [/] $c" while :
read ans do
case $ans in eval echo \$n "$name: [\$$name]\ \$c"
""|/|no) install_root=; break;; read ans
/*) install_root=$ans; break;; case $ans in
*) echo "install_root should be an absolute path name" 1>&2; exit 1;; "") break;;
esac *) eval $name=\$ans; break;;
esac
done
done done
# Sanity checks
for path in $install_root $config_directory
do
case $path in
/*) ;;
*) echo "$path should be an absolute path name" 1>&2; exit 1;;
esac
done
# In case some systems special-case pathnames beginning with //.
case $install_root in
/) install_root=
esac
# Load defaults from existing installation. # Load defaults from existing installation.
CONFIG_DIRECTORY=$install_root$config_directory CONFIG_DIRECTORY=$install_root$config_directory
@ -103,14 +126,16 @@ CONFIG_DIRECTORY=$install_root$config_directory
test -f $CONFIG_DIRECTORY/main.cf && { test -f $CONFIG_DIRECTORY/main.cf && {
for name in daemon_directory command_directory queue_directory mail_owner for name in daemon_directory command_directory queue_directory mail_owner
do do
eval "$name=\"\`bin/postconf -c $CONFIG_DIRECTORY -h $name || kill \$\$\`\"" eval $name='"`bin/postconf -c $CONFIG_DIRECTORY -h $name`"' || kill $$
done done
} }
test -f $CONFIG_DIRECTORY/install.cf && . $CONFIG_DIRECTORY/install.cf test -f $CONFIG_DIRECTORY/install.cf && . $CONFIG_DIRECTORY/install.cf
for name in config_directory daemon_directory command_directory \ # Override default settings.
queue_directory sendmail_path newaliases_path mailq_path mail_owner \
for name in daemon_directory command_directory \
queue_directory sendmail_path newaliases_path mailq_path mail_owner\
setgid manpages setgid manpages
do do
while : while :
@ -126,27 +151,7 @@ done
# Sanity checks # Sanity checks
rm -f foobar- for path in $daemon_directory $command_directory \
touch foobar-
chown $mail_owner foobar- >/dev/null 2>&1 || {
echo "Error: $mail_owner needs an entry in the passwd file" 1>&2
echo "Remember, $mail_owner must have a dedicated user id and group id." 1>&2
exit 1
}
case $setgid in
no) ;;
*) chgrp "$setgid" foobar- >/dev/null 2>&1 || {
echo "Error: $setgid needs an entry in the group file" 1>&2
echo "Remember, $setgid must have a dedicated group id." 1>&2
exit 1
}
esac
rm -f foobar-
for path in $config_directory $daemon_directory $command_directory \
$queue_directory $sendmail_path $newaliases_path $mailq_path $manpages $queue_directory $sendmail_path $newaliases_path $mailq_path $manpages
do do
case $path in case $path in
@ -156,9 +161,28 @@ do
esac esac
done done
# Create any missing directories. rm -f junk || exit 1
touch junk
chown "$mail_owner" junk >/dev/null 2>&1 || {
echo "Error: $mail_owner needs an entry in the passwd file" 1>&2
echo "Remember, $mail_owner must have a dedicated user id and group id." 1>&2
exit 1
}
case $setgid in
no) ;;
*) chgrp "$setgid" junk >/dev/null 2>&1 || {
echo "Error: $setgid needs an entry in the group file" 1>&2
echo "Remember, $setgid must have a dedicated group id." 1>&2
exit 1
}
esac
rm -f junk
# Avoid clumsiness.
CONFIG_DIRECTORY=$install_root$config_directory
DAEMON_DIRECTORY=$install_root$daemon_directory DAEMON_DIRECTORY=$install_root$daemon_directory
COMMAND_DIRECTORY=$install_root$command_directory COMMAND_DIRECTORY=$install_root$command_directory
QUEUE_DIRECTORY=$install_root$queue_directory QUEUE_DIRECTORY=$install_root$queue_directory
@ -167,9 +191,7 @@ NEWALIASES_PATH=$install_root$newaliases_path
MAILQ_PATH=$install_root$mailq_path MAILQ_PATH=$install_root$mailq_path
MANPAGES=$install_root$manpages MANPAGES=$install_root$manpages
case $install_root in # Create any missing directories.
/?*) test -d $install_root || mkdir -p $install_root || exit 1
esac
test -d $CONFIG_DIRECTORY || mkdir -p $CONFIG_DIRECTORY || exit 1 test -d $CONFIG_DIRECTORY || mkdir -p $CONFIG_DIRECTORY || exit 1
test -d $DAEMON_DIRECTORY || mkdir -p $DAEMON_DIRECTORY || exit 1 test -d $DAEMON_DIRECTORY || mkdir -p $DAEMON_DIRECTORY || exit 1
@ -182,7 +204,7 @@ done
# Install files. Be careful to not copy over running programs. # Install files. Be careful to not copy over running programs.
for file in `ls libexec` for file in `ls libexec | grep -v '^\.'`
do do
compare_or_replace a+x,go-w libexec/$file $DAEMON_DIRECTORY/$file || exit 1 compare_or_replace a+x,go-w libexec/$file $DAEMON_DIRECTORY/$file || exit 1
done done
@ -204,12 +226,14 @@ test -f $CONFIG_DIRECTORY/main.cf || {
cp conf/* $CONFIG_DIRECTORY || exit 1 cp conf/* $CONFIG_DIRECTORY || exit 1
chmod a+r,go-w $CONFIG_DIRECTORY/* || exit 1 chmod a+r,go-w $CONFIG_DIRECTORY/* || exit 1
echo "Warning: you still need to edit myorigin/mydestination in" 1>&2 test -z "$install_root" && {
echo "$CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup" 1>&2 echo "Warning: you still need to edit myorigin/mydestination in" 1>&2
echo "sites or for sites inside a firewalled network." 1>&2 echo "$CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup" 1>&2
echo "" 1>&2 echo "sites or for sites inside a firewalled network." 1>&2
echo "BTW, Edit your alias database and be sure to set up aliases" 1>&2 echo "" 1>&2
echo "for root and postmaster, then run the newaliases command." 1>&2 echo "BTW: Edit your alias database and be sure to set up aliases" 1>&2
echo "for root and postmaster, then run $NEWALIASES_PATH." 1>&2
}
} }
# Save settings. # Save settings.
@ -222,8 +246,7 @@ postconf -e \
|| exit 1 || exit 1
(echo "# This file was generated by $0" (echo "# This file was generated by $0"
for name in config_directory sendmail_path newaliases_path mailq_path \ for name in sendmail_path newaliases_path mailq_path setgid manpages
setgid manpages
do do
eval echo $name=\$$name eval echo $name=\$$name
done) >junk || exit 1 done) >junk || exit 1
@ -255,7 +278,7 @@ esac
compare_or_replace a+x,go-w $postfix_script $CONFIG_DIRECTORY/postfix-script || compare_or_replace a+x,go-w $postfix_script $CONFIG_DIRECTORY/postfix-script ||
exit 1 exit 1
# Install manual pages (optional). We just clobber whatever is there. # Install manual pages (optional).
case $manpages in case $manpages in
no) ;; no) ;;
@ -266,9 +289,11 @@ no) ;;
done done
for file in man?/* for file in man?/*
do do
rm -f $MANPAGES/$file cmp -s $file $MANPAGES/$file || {
cp $file $MANPAGES/$file || exit 1 rm -f $MANPAGES/$file
chmod 644 $MANPAGES/$file || exit 1 cp $file $MANPAGES/$file || exit 1
chmod 644 $MANPAGES/$file || exit 1
}
done done
) )
esac esac

View File

@ -67,13 +67,6 @@ Defaults are given in parentheses:
substitute for the address Postfix is trying to resolve, e.g. substitute for the address Postfix is trying to resolve, e.g.
ldapsource_query_filter = (&(mail=%s)(paid_up=true)) ldapsource_query_filter = (&(mail=%s)(paid_up=true))
lookup_wildcards (no)
Whether to search for addresses containing '*'. This has huge
potential for spammers, so by default, any address containing
'*' will cause the lookup to return nothing. Unless another
dictionary returns a valid lookup for it, the mail will bounce
with an 'unknown user' message.
result_attribute (maildrop) result_attribute (maildrop)
The attribute Postfix will read from any directory entries The attribute Postfix will read from any directory entries
returned by the lookup, to be resolved to an email address. returned by the lookup, to be resolved to an email address.

View File

@ -1,4 +1,4 @@
Incompatible changes with snapshot 19991120 Incompatible changes with snapshot 19991122
=========================================== ===========================================
- In an SMTPD access map, an all-numeric right-hand side now means - In an SMTPD access map, an all-numeric right-hand side now means
@ -13,43 +13,51 @@ main.cf.
SMTPD access control tables. Use the permit_recipient_map feature SMTPD access control tables. Use the permit_recipient_map feature
instead. The loss is compensated for (see below). instead. The loss is compensated for (see below).
Major changes with snapshot 19991120 Major changes with snapshot 19991122
==================================== ====================================
- It is now relatively safe to configure 550 status codes for the
main.cf unknown_address_reject_code or unknown_client_reject_code
parameters. The SMTP server now always sends a 450 (try again)
reply code when an UCE restriction fails due to a soft DNS error,
regardless of what main.cf specifies.
- The RBL checks now show the content of TXT records (Simon J Mudd).
- The Postfix SMTP server now understands a wider range of illegal - The Postfix SMTP server now understands a wider range of illegal
address formats in MAIL FROM and RCPT TO commands. In order to address forms in MAIL FROM and RCPT TO commands. In order to disable
disable those forms, specify "strict_rfc821_envelopes = yes". those forms, specify "strict_rfc821_envelopes = yes".
- Per-client/helo/sender/recipient UCE restrictions (fully-recursive - Per-client/helo/sender/recipient UCE restrictions (fully-recursive
UCE restriction parser). See the RESTRICTION_CLASS file for details. UCE restriction parser). See the RESTRICTION_CLASS file for details.
- Block mail for non-existent users at the SMTP port. On a non-relay - Block mail for most non-existent users at the SMTP port. Example:
host, use the following to reject mail for non-existent users and a non-relaying host could use the following to reject mail for
for non-local destinations. non-existent local users and for all non-local destinations.
smtpd_recipient_restrictions = smtpd_recipient_restrictions =
permit_recipient_map unix:passwd .byname reject_unknown_sender
permit_recipient_map unix:passwd.byname
permit_recipient_map hash:/etc/postfix/canonical permit_recipient_map hash:/etc/postfix/canonical
permit_recipient_map hash:/etc/postfix/virtual permit_recipient_map hash:/etc/postfix/virtual
permit_recipient_map hash:/etc/aliases permit_recipient_map hash:/etc/aliases
reject reject
- "postconf -e name=value..." edits the main.cf file. This is I haven't figured out yet how to use this easily on hosts that must
relay mail for other systems.
- Use "postmap -q key" or "postalias -q key" for testing Postfix
lookup tables or alias files.
- Use "postconf -e name=value..." edits the main.cf file. This is
easier and safer than editing the main.cf file by hand. The edits easier and safer than editing the main.cf file by hand. The edits
are done on a temporary copy that is renamed into place. are done on a temporary copy that is renamed into place.
- "postconf -m" displays all supported lookup table types (Scott - Use "postconf -m" to display all supported lookup table types
Cotton). (Scott Cotton).
- It is now relatively safe to configure 550 status codes for the
main.cf unknown_address_reject_code or unknown_client_reject_code
parameters. The SMTP server now always sends a 450 (try again)
reply code when an UCE restriction fails due to a soft DNS error.
- The RBL checks now show the content of TXT records (Simon J Mudd).
- New "permit_auth_destination" UCE restriction for finer-grained - New "permit_auth_destination" UCE restriction for finer-grained
control (Jesper Skriver). access control (Jesper Skriver).
Incompatible changes with postfix-19990906 Incompatible changes with postfix-19990906
========================================== ==========================================

View File

@ -1,8 +0,0 @@
#!/bin/sh
# Dummy UUCP rmail command for postfix/qmail systems
SENDMAIL="/usr/sbin/sendmail"
IFS=" " read junk from junk
exec $SENDMAIL -f "$from" -- "$@"

View File

@ -16,3 +16,11 @@
# transport_maps = hash:/etc/postfix/transport, nis:transport # transport_maps = hash:/etc/postfix/transport, nis:transport
# transport_maps = hash:/etc/postfix/transport, netinfo:/transport # transport_maps = hash:/etc/postfix/transport, netinfo:/transport
transport_maps = transport_maps =
# The local_transports parameter defines the name of the default
# transport for local mail delivery, plus zero or more names of
# additional transports that are known to deliver locally. The SMTP
# server's UCE restrictions use this list to decide if an address
# would be forwarded or not.
#
local_transports = local

View File

@ -6,7 +6,7 @@
/* SYNOPSIS /* SYNOPSIS
/* #include <local_transport.h> /* #include <local_transport.h>
/* /*
/* const char *def_local_transport() /* const char *get_def_local_transport()
/* /*
/* int match_def_local_transport(transport) /* int match_def_local_transport(transport)
/* const char *transport; /* const char *transport;
@ -19,7 +19,7 @@
/* local transport, followed by the names of zero or more other /* local transport, followed by the names of zero or more other
/* transports that deliver locally. /* transports that deliver locally.
/* /*
/* def_local_transport() returns the name of the default local /* get_def_local_transport() returns the name of the default local
/* transport, that is, the first transport name specified with /* transport, that is, the first transport name specified with
/* the "local_transports" configuration parameter. /* the "local_transports" configuration parameter.
/* /*
@ -29,7 +29,7 @@
/* match_any_local_transport() determines if the named transport is /* match_any_local_transport() determines if the named transport is
/* listed in the "local_transports" configuration parameter. /* listed in the "local_transports" configuration parameter.
/* SEE ALSO /* SEE ALSO
/* resolve_local(3), see if address resolves locally. /* resolve_local(3), see if address resolves locally
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi
@ -84,13 +84,14 @@ static void local_transport_init(void)
/* /*
* Sanity check. * Sanity check.
*/ */
if (!match_any_local_transport(local_transport_name)) if (!match_any_local_transport(local_transport_name)
|| !match_def_local_transport(local_transport_name))
msg_panic("%s: unable to intialize", myname); msg_panic("%s: unable to intialize", myname);
} }
/* def_local_transport - determine default local transport */ /* get_def_local_transport - determine default local transport */
const char *def_local_transport(void) const char *get_def_local_transport(void)
{ {
/* /*

View File

@ -14,7 +14,7 @@
/* /*
* External interface. * External interface.
*/ */
extern const char *def_local_transport(void); extern const char *get_def_local_transport(void);
extern int match_def_local_transport(const char *); extern int match_def_local_transport(const char *);
extern int match_any_local_transport(const char *); extern int match_any_local_transport(const char *);

View File

@ -15,7 +15,7 @@
* Version of this program. * Version of this program.
*/ */
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-19991120" #define DEF_MAIL_VERSION "Snapshot-19991122"
extern char *var_mail_version; extern char *var_mail_version;
/* LICENSE /* LICENSE

View File

@ -197,7 +197,7 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
* next-hop hostname (myself). * next-hop hostname (myself).
*/ */
else { else {
vstring_strcpy(channel, def_local_transport()); vstring_strcpy(channel, get_def_local_transport());
vstring_strcpy(nexthop, var_myhostname); vstring_strcpy(nexthop, var_myhostname);
} }

View File

@ -36,10 +36,8 @@
/* .IP \fIldapsource_\fRquery_filter /* .IP \fIldapsource_\fRquery_filter
/* The filter used to search for directory entries, for example /* The filter used to search for directory entries, for example
/* \fI(mailacceptinggeneralid=%s)\fR. /* \fI(mailacceptinggeneralid=%s)\fR.
/* .IP \fIldapsource_\fRlookup_wildcards
/* Whether to allow '*' in addresses to be looked up.
/* .IP \fIldapsource_\fRresult_attribute /* .IP \fIldapsource_\fRresult_attribute
/* The attribute returned by the search, in which we expect to find /* The attribute returned by the search, in which to find
/* RFC822 addresses, for example \fImaildrop\fR. /* RFC822 addresses, for example \fImaildrop\fR.
/* .IP \fIldapsource_\fRbind /* .IP \fIldapsource_\fRbind
/* Whether or not to bind to the server -- LDAP v3 implementations don't /* Whether or not to bind to the server -- LDAP v3 implementations don't
@ -49,7 +47,7 @@
/* .IP \fIldapsource_\fRbind_pw /* .IP \fIldapsource_\fRbind_pw
/* \&... and this password. /* \&... and this password.
/* BUGS /* BUGS
/* Of course not! :) /* Thrice a year, needed or not.
/* SEE ALSO /* SEE ALSO
/* dict(3) generic dictionary manager /* dict(3) generic dictionary manager
/* DIAGNOSTICS /* DIAGNOSTICS
@ -65,8 +63,7 @@
/* Yorktown Heights, NY 10532, USA /* Yorktown Heights, NY 10532, USA
/* /*
/* John Hensley /* John Hensley
/* Merit Network, Inc. /* stormroll@yahoo.com
/* hensley@merit.edu
/* /*
/*--*/ /*--*/
@ -78,6 +75,8 @@
#include <sys/time.h> #include <sys/time.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h> #include <signal.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h> #include <stdlib.h>
@ -92,12 +91,9 @@
#include "dict.h" #include "dict.h"
#include "dict_ldap.h" #include "dict_ldap.h"
/* /* Global library. */
* Grr.. this module should sit in the global library, because it interacts
* with application-specific configuration parameters. I will have to #include "../global/mail_conf.h" /* XXX Fixme. */
* generalize the manner in which new dictionary types can register
* themselves, including their configuration file parameters.
*/
/* /*
* structure containing all the configuration parameters for a given * structure containing all the configuration parameters for a given
@ -110,7 +106,6 @@ typedef struct {
int server_port; int server_port;
char *search_base; char *search_base;
char *query_filter; char *query_filter;
int lookup_wildcards;
char *result_attribute; char *result_attribute;
int bind; int bind;
char *bind_dn; char *bind_dn;
@ -139,7 +134,8 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
LDAPMessage *res = 0; LDAPMessage *res = 0;
LDAPMessage *entry = 0; LDAPMessage *entry = 0;
struct timeval tv; struct timeval tv;
VSTRING *filter_buf = 0; VSTRING *escaped_name = 0,
*filter_buf = 0;
char **attr_values; char **attr_values;
long i = 0; long i = 0;
int rc = 0; int rc = 0;
@ -149,17 +145,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
dict_errno = 0; dict_errno = 0;
/*
* Unless configured to allow them, refuse to search for a name
* containing wildcards.
*/
if (!dict_ldap->lookup_wildcards) {
if (strstr(name, "*") != NULL) {
msg_warn("%s: Address (%s) contains a wildcard; refusing to search. See the lookup_wildcards attribute in LDAP_README for more information.", myname, name);
return (0);
}
}
/* /*
* Initialize. * Initialize.
*/ */
@ -171,35 +156,43 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
if (msg_verbose) if (msg_verbose)
msg_info("%s: In dict_ldap_lookup", myname); msg_info("%s: In dict_ldap_lookup", myname);
if (dict_ldap->ld == 0) { if (dict_ldap->ld == NULL) {
msg_warn("%s: no existing connection for ldapsource %s, reopening", if (msg_verbose)
myname, dict_ldap->ldapsource); msg_info("%s: no existing connection for ldapsource %s, reopening",
myname, dict_ldap->ldapsource);
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
msg_warn("%s: error setting signal handler for open timeout: %m", myname);
dict_errno = DICT_ERR_RETRY;
return (0);
}
if (msg_verbose) if (msg_verbose)
msg_info("%s: connecting to server %s", myname, msg_info("%s: connecting to server %s", myname,
dict_ldap->server_host); dict_ldap->server_host);
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR)
msg_fatal("%s: signal: %m", myname);
alarm(dict_ldap->timeout); alarm(dict_ldap->timeout);
if (setjmp(env) == 0) if (setjmp(env) == 0)
dict_ldap->ld = ldap_open(dict_ldap->server_host, dict_ldap->ld = ldap_open(dict_ldap->server_host,
(int) dict_ldap->server_port); (int) dict_ldap->server_port);
alarm(0); alarm(0);
if (signal(SIGALRM, saved_alarm) == SIG_ERR) if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
msg_fatal("%s: signal: %m", myname); msg_warn("%s: error resetting signal handler after open: %m", myname);
dict_errno = DICT_ERR_RETRY;
return (0);
}
if (msg_verbose) if (msg_verbose)
msg_info("%s: after ldap_open", myname); msg_info("%s: after ldap_open", myname);
if (dict_ldap->ld == 0) { if (dict_ldap->ld == NULL) {
msg_fatal("%s: Unable to contact LDAP server %s", msg_warn("%s: Unable to contact LDAP server %s",
myname, dict_ldap->server_host); myname, dict_ldap->server_host);
dict_errno = DICT_ERR_RETRY;
return (0);
} else { } else {
/* /*
* If this server requires us to bind, do so. * If this server requires a bind, do so.
*/ */
if (dict_ldap->bind) { if (dict_ldap->bind) {
if (msg_verbose) if (msg_verbose)
@ -209,7 +202,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn, rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn,
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE); dict_ldap->bind_pw, LDAP_AUTH_SIMPLE);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
msg_fatal("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc)); msg_warn("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
dict_errno = DICT_ERR_RETRY;
return (0);
} else { } else {
if (msg_verbose) if (msg_verbose)
msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc)); msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
@ -220,37 +215,52 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
myname, dict_ldap->ldapsource); myname, dict_ldap->ldapsource);
} }
} }
/* /*
* Look for entries matching query_filter. * Prepare the query.
*/ */
tv.tv_sec = dict_ldap->timeout; tv.tv_sec = dict_ldap->timeout;
tv.tv_usec = 0; tv.tv_usec = 0;
escaped_name = vstring_alloc(20);
filter_buf = vstring_alloc(30); filter_buf = vstring_alloc(30);
/* Any wildcards and escapes in the supplied address should be escaped. */
if (strchr(name, '*') || strchr(name, '\\')) {
if (msg_verbose)
msg_info("%s: found wildcard in %s", myname, name);
for (sub = (char *) name; *sub != '\0'; sub++) {
if (*sub == '*' || *sub == '\\') {
vstring_strncat(escaped_name, "\\", 1);
vstring_strncat(escaped_name, sub, 1);
} else {
vstring_strncat(escaped_name, sub, 1);
}
}
if (msg_verbose)
msg_info("%s: with wildcards escaped, it's %s", myname, vstring_str(escaped_name));
} else
vstring_strcpy(escaped_name, (char *) name);
/* Does the supplied query_filter even include a substitution? */ /* Does the supplied query_filter even include a substitution? */
if (strstr(dict_ldap->query_filter, "%s") == NULL) { if (strstr(dict_ldap->query_filter, "%s") == NULL) {
/* No, log the fact and continue. */
msg_warn("%s: fixed query_filter %s is probably useless", myname, msg_warn("%s: fixed query_filter %s is probably useless", myname,
dict_ldap->query_filter); dict_ldap->query_filter);
vstring_strcpy(filter_buf, dict_ldap->query_filter); vstring_strcpy(filter_buf, dict_ldap->query_filter);
} else { } else {
/* /* Yes, replace all instances of %s with the address to look up. */
* OK, let's replace all the instances of %s with the address to look
* up.
*/
sub = dict_ldap->query_filter; sub = dict_ldap->query_filter;
end = sub + strlen(dict_ldap->query_filter); end = sub + strlen(dict_ldap->query_filter);
while (sub < end) { while (sub < end) {
/* /*
* Make sure it's %s and not something else, though it wouldn't * Make sure it's %s and not something else, though it wouldn't
* really matter; we could skip any single character. * really matter; the token could be any single character.
*/ */
if (*(sub) == '%') { if (*(sub) == '%') {
if ((sub + 1) != end && *(sub + 1) != 's') if ((sub + 1) != end && *(sub + 1) != 's')
msg_fatal("%s: invalid lookup substitution format '%%%c'!", myname, *(sub + 1)); msg_warn("%s: invalid lookup substitution format '%%%c'!", myname, *(sub + 1));
vstring_strcat(filter_buf, name); vstring_strcat(filter_buf, vstring_str(escaped_name));
sub++; sub++;
} else } else
vstring_strncat(filter_buf, sub, 1); vstring_strncat(filter_buf, sub, 1);
@ -258,6 +268,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
} }
} }
/* On to the search. */
if (msg_verbose) if (msg_verbose)
msg_info("%s: searching with filter %s", myname, msg_info("%s: searching with filter %s", myname,
vstring_str(filter_buf)); vstring_str(filter_buf));
@ -265,33 +276,24 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
if ((rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, if ((rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
LDAP_SCOPE_SUBTREE, LDAP_SCOPE_SUBTREE,
vstring_str(filter_buf), vstring_str(filter_buf),
0, 0, &tv, &res)) != LDAP_SUCCESS) { 0, 0, &tv, &res)) == LDAP_SUCCESS) {
ldap_unbind(dict_ldap->ld);
dict_ldap->ld = 0;
if (msg_verbose)
msg_info("%s: freed connection handle for LDAP source %s", myname, dict_ldap->ldapsource);
msg_fatal("%s: Unable to search base %s at server %s (%d -- %s): ",
myname, dict_ldap->search_base, dict_ldap->server_host, rc,
ldap_err2string(rc));
} else {
/* /*
* Extract the requested result_attribute. * Search worked; extract the requested result_attribute.
*/ */
if (msg_verbose) if (msg_verbose)
msg_info("%s: search found %d", myname, msg_info("%s: search found %d matches", myname,
ldap_count_entries(dict_ldap->ld, res)); ldap_count_entries(dict_ldap->ld, res));
/* There could have been lots of hits. */
for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL; entry = ldap_next_entry(dict_ldap->ld, entry)) { for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL; entry = ldap_next_entry(dict_ldap->ld, entry)) {
/* And each entry could have multiple attributes. */
attr_values = ldap_get_values(dict_ldap->ld, entry, attr_values = ldap_get_values(dict_ldap->ld, entry,
dict_ldap->result_attribute); dict_ldap->result_attribute);
if (attr_values == NULL) { if (attr_values == NULL) {
msg_warn("%s: entry doesn't have any values for %s", myname, dict_ldap->result_attribute); msg_warn("%s: entry doesn't have any values for %s", myname, dict_ldap->result_attribute);
continue; continue;
} }
/* /*
* Append each returned address to the result list. * Append each returned address to the result list.
*/ */
@ -304,18 +306,28 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
} }
if (msg_verbose) if (msg_verbose)
msg_info("%s: search returned: %s", myname, vstring_str(result)); msg_info("%s: search returned: %s", myname, vstring_str(result));
} else {
/* Rats. That didn't work. */
msg_warn("%s: search error %d: %s ", myname, rc,
ldap_err2string(rc));
/*
* Tear down the connection so it gets set up from scratch on the
* next lookup.
*/
ldap_unbind(dict_ldap->ld);
dict_ldap->ld = NULL;
/* And tell the caller to try again later. */
dict_errno = DICT_ERR_RETRY;
} }
/* /* Cleanup. */
* Cleanup. Always return with dict_errno set when we were unable to
* perform the query.
*/
if (res != 0) if (res != 0)
ldap_msgfree(res); ldap_msgfree(res);
else
dict_errno = 1;
if (filter_buf != 0) if (filter_buf != 0)
vstring_free(filter_buf); vstring_free(filter_buf);
return (VSTRING_LEN(result) > 0 ? vstring_str(result) : 0); return (VSTRING_LEN(result) > 0 ? vstring_str(result) : 0);
} }
@ -412,17 +424,6 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
msg_info("%s: %s is %s", myname, vstring_str(config_param), msg_info("%s: %s is %s", myname, vstring_str(config_param),
dict_ldap->query_filter); dict_ldap->query_filter);
/*
* get configured value of "ldapsource_lookup_wildcards"; default to
* false
*/
vstring_sprintf(config_param, "%s_lookup_wildcards", ldapsource);
dict_ldap->lookup_wildcards =
get_mail_conf_bool(vstring_str(config_param), 0);
if (msg_verbose)
msg_info("%s: %s is %d", myname, vstring_str(config_param),
dict_ldap->lookup_wildcards);
vstring_sprintf(config_param, "%s_result_attribute", ldapsource); vstring_sprintf(config_param, "%s_result_attribute", ldapsource);
dict_ldap->result_attribute = dict_ldap->result_attribute =
mystrdup((char *) get_mail_conf_str(vstring_str(config_param), mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
@ -462,28 +463,33 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
msg_info("%s: connecting to server %s", myname, msg_info("%s: connecting to server %s", myname,
dict_ldap->server_host); dict_ldap->server_host);
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
msg_fatal("%s: signal: %m", myname); msg_warn("%s: error setting signal handler for open timeout: %m", myname);
dict_errno = DICT_ERR_RETRY;
return (0);
}
alarm(dict_ldap->timeout); alarm(dict_ldap->timeout);
if (setjmp(env) == 0) if (setjmp(env) == 0)
dict_ldap->ld = ldap_open(dict_ldap->server_host, dict_ldap->ld = ldap_open(dict_ldap->server_host,
(int) dict_ldap->server_port); (int) dict_ldap->server_port);
alarm(0); alarm(0);
if (signal(SIGALRM, saved_alarm) == SIG_ERR) if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
msg_fatal("%s: signal: %m", myname); msg_warn("%s: error resetting signal handler after open: %m", myname);
dict_errno = DICT_ERR_RETRY;
if (msg_verbose) return (0);
msg_info("%s: after ldap_open", myname); }
if (dict_ldap->ld == NULL) {
if (dict_ldap->ld == 0) { msg_warn("%s: Unable to contact LDAP server %s",
msg_fatal("%s: Unable to contact LDAP server %s", myname, dict_ldap->server_host);
myname, dict_ldap->server_host); dict_errno = DICT_ERR_RETRY;
return (0);
} else { } else {
if (msg_verbose)
msg_info("%s: after ldap_open", myname);
/* /*
* If this server requires us to bind, do so. * If this server requires a bind, do so.
*/ */
if (dict_ldap->bind) { if (dict_ldap->bind) {
if (msg_verbose) if (msg_verbose)
@ -493,7 +499,9 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn, rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn,
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE); dict_ldap->bind_pw, LDAP_AUTH_SIMPLE);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
msg_fatal("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc)); msg_warn("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
dict_errno = DICT_ERR_RETRY;
return (0);
} else { } else {
if (msg_verbose) if (msg_verbose)
msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc)); msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));