diff --git a/gnu/dist/postfix/HISTORY b/gnu/dist/postfix/HISTORY
index 13a9bcfad571..ab2d0fbb550c 100644
--- a/gnu/dist/postfix/HISTORY
+++ b/gnu/dist/postfix/HISTORY
@@ -5063,3 +5063,36 @@ Apologies for any names omitted.
sending QUIT after process idle timeout while the LMTP
server had disconnected. Files: smtp/smtp_proto.c,
lmtp/lmtp_proto.c.
+
+20010727
+
+ Bugfix: updated LDAP client module from LaMont Jones, HP.
+ This also introduces new LDAP query filter patterns: %u
+ (address localpart) and %d (domain part). Files:
+ conf/sample-ldap.cf, util/dict_ldap.c.
+
+20010729
+
+ Bugfix: recursive smtpd_whatever_restrictions clobbered
+ intermediate results when switching between sender and
+ recipient address restrictions. Problem found by Victor
+ Duchovni, morganstanley.com. In order to fix, introduced
+ address resolver result caching, which should also help to
+ speed up sender/recipient address restriction processing.
+
+ Bugfix: the not yet announced DUNNO access table lookup
+ result did not prevent lookups with substrings of the same
+ lookup key. Found by Victor Duchovni, morganstanley.com.
+
+20010730
+
+ Robustness: trim trailing whitespace from regexp and pcre
+ right-hand sides, for consistency with DB/DBM tables.
+ Files: util/dict_pcre.c, util/dict_regexp.c.
+
+20010731
+
+ Robustness: eliminate duplicate IP addresses after expansion
+ of hostnames in $inet_interfaces, so that Postfix does not
+ suddenly refuse to start up after someone changes the DNS.
+ Files: util/inet_addr_list.c global/own_inet_addr.c.
diff --git a/gnu/dist/postfix/MYSQL_README b/gnu/dist/postfix/MYSQL_README
index faecf80a2631..2f11bd9566eb 100644
--- a/gnu/dist/postfix/MYSQL_README
+++ b/gnu/dist/postfix/MYSQL_README
@@ -12,9 +12,10 @@ the mysqlclient library (and libm) to AUXLIBS, for example:
make -f Makefile.init makefiles \
'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \
- 'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lm'
+ 'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lz -lm'
-then, just run 'make'.
+then, just run 'make'. This requires libz, the compression library.
+Older mysql implementations build without libz.
Postfix installations which may benefit from using mysql map types
include sites that have a need for instantaneous updates of
diff --git a/gnu/dist/postfix/conf/sample-ldap.cf b/gnu/dist/postfix/conf/sample-ldap.cf
index c503df0bc66c..8badb4026091 100644
--- a/gnu/dist/postfix/conf/sample-ldap.cf
+++ b/gnu/dist/postfix/conf/sample-ldap.cf
@@ -23,6 +23,13 @@
#ldap_server_port = 389
# The ldap_query_filter parameter specifies the filter used for queries.
+# The replacement for "%s" is the address input into the map; e.g.
+# for alias maps, the "user" part (the RFC 2822 local-part) of
+# "user@domain.com" for To: addresses destined for local delivery
+# (those matching $mydestination or a virtual domain), and all of
+# "user@domain.com" (the RFC 2822 addr-spec) for other addresses.
+# "%u" provides just the user portion of the input, and "%d" provides
+# just the hostname.
#
#ldap_query_filter = (mailacceptinggeneralid=%s)
@@ -31,6 +38,13 @@
#
#ldap_result_attribute = maildrop
+# The ldap_special_result_attribute lists the attribute(s) of an
+# entry which contain links, either ldap url's or distinguished names.
+# The entries referenced by these links are (recursively) treated as if
+# they were contained in the referencing entity.
+#
+# ldap_special_result_attribute =
+
# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one.
#
#ldap_scope = sub
diff --git a/gnu/dist/postfix/html/faq.html b/gnu/dist/postfix/html/faq.html
index a2b8b627a8f1..425304fddb95 100644
--- a/gnu/dist/postfix/html/faq.html
+++ b/gnu/dist/postfix/html/faq.html
@@ -1027,7 +1027,7 @@ Berkeley DB library version.
-sendmail has set-uid root file permissions, or is run from a
+sendmail has set-uid root file permissions, or is run from a
set-uid root process
Traditionally, the UNIX sendmail command is installed with
diff --git a/gnu/dist/postfix/src/global/mail_version.h b/gnu/dist/postfix/src/global/mail_version.h
index f725dbca0f66..4ccf192f8c4e 100644
--- a/gnu/dist/postfix/src/global/mail_version.h
+++ b/gnu/dist/postfix/src/global/mail_version.h
@@ -15,7 +15,7 @@
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Postfix-20010228-pl03"
+#define DEF_MAIL_VERSION "Postfix-20010228-pl04"
extern char *var_mail_version;
/* LICENSE
diff --git a/gnu/dist/postfix/src/smtpd/Makefile.in b/gnu/dist/postfix/src/smtpd/Makefile.in
index 90d9aa96bbc2..aebfcaeac19b 100644
--- a/gnu/dist/postfix/src/smtpd/Makefile.in
+++ b/gnu/dist/postfix/src/smtpd/Makefile.in
@@ -67,7 +67,7 @@ depend: $(MAKES)
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
@$(EXPORT) make -f Makefile.in Makefile 1>&2
-tests: smtpd_check_test smtpd_check_test2 smtpd_token_test
+tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_token_test
smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref
../postmap/postmap smtpd_check_access
@@ -81,6 +81,12 @@ smtpd_check_test2: smtpd_check smtpd_check.in2 smtpd_check.ref2
diff smtpd_check.ref2 smtpd_check.tmp
rm -f smtpd_check.tmp smtpd_check_access.*
+smtpd_acl_test: smtpd_check smtpd_acl.in smtpd_acl.ref
+ ../postmap/postmap smtpd_check_access
+ ./smtpd_check smtpd_check.tmp 2>&1
+ diff smtpd_acl.ref smtpd_check.tmp
+ rm -f smtpd_check.tmp smtpd_check_access.*
+
smtpd_token_test: smtpd_token smtpd_token.in smtpd_token.ref
./smtpd_token smtpd_token.tmp 2>&1
diff smtpd_token.ref smtpd_token.tmp
@@ -164,6 +170,7 @@ smtpd_check.o: ../../include/mymalloc.h
smtpd_check.o: ../../include/dict.h
smtpd_check.o: ../../include/vstream.h
smtpd_check.o: ../../include/htable.h
+smtpd_check.o: ../../include/ctable.h
smtpd_check.o: ../../include/dns.h
smtpd_check.o: ../../include/namadr_list.h
smtpd_check.o: ../../include/domain_list.h
diff --git a/gnu/dist/postfix/src/smtpd/smtpd_acl.in b/gnu/dist/postfix/src/smtpd/smtpd_acl.in
new file mode 100644
index 000000000000..e633c48d5610
--- /dev/null
+++ b/gnu/dist/postfix/src/smtpd/smtpd_acl.in
@@ -0,0 +1,107 @@
+#
+# Initialize
+#
+smtpd_delay_reject 0
+mynetworks 127.0.0.0/8,168.100.189.0/28
+relay_domains porcupine.org
+#
+# Test check_domain_access()
+#
+helo_restrictions hash:./smtpd_check_access
+# Expect: REJECT
+helo foo.dunno.com
+# Expect: OK
+helo bar.dunno.com
+# Expect: OK
+helo foo.duuno.com
+#
+# Test check_namadr_access(), domain part
+#
+client_restrictions hash:./smtpd_check_access
+# Expect: REJECT
+client foo.dunno.com 131.155.210.17
+# Expect: OK
+client bar.dunno.com 131.155.210.17
+# Expect: OK
+client bar.dunno.com 131.155.210.19
+#
+# Test check_namadr_access(), address part
+#
+# Expect: OK
+client bar.duno.com 131.155.210.17
+# Expect: REJECT
+client bar.duno.com 131.155.210.19
+# Expect: REJECT
+client bar.duno.com 44.33.22.11
+# Expect: OK
+client bar.duno.com 44.33.22.55
+# Expect: REJECT
+client bar.duno.com 44.33.44.33
+#
+# Test check_mail_access()
+#
+sender_restrictions hash:./smtpd_check_access
+# Expect: REJECT
+mail reject@dunno.domain
+# Expect: OK
+mail ok@dunno.domain
+# Expect: OK
+mail anyone@dunno.domain
+# Expect: OK
+mail bad-sender@dunno.domain
+#
+# Again, with a domain that rejects by default
+#
+# Expect: REJECT
+mail reject@reject.domain
+# Expect: OK
+mail ok@reject.domain
+# Expect: REJECT
+mail anyone@reject.domain
+# Expect: REJECT
+mail good-sender@reject.domain
+#
+# Again, with a domain that accepts by default
+#
+# Expect: REJECT
+mail reject@ok.domain
+# Expect: OK
+mail ok@ok.domain
+# Expect: OK
+mail anyone@ok.domain
+# Expect: OK
+mail bad-sender@ok.domain
+#
+# Test check_mail_access()
+#
+recipient_restrictions hash:./smtpd_check_access
+# Expect: REJECT
+rcpt reject@dunno.domain
+# Expect: OK
+rcpt ok@dunno.domain
+# Expect: OK
+rcpt anyone@dunno.domain
+# Expect: OK
+rcpt bad-sender@dunno.domain
+#
+# Again, with a domain that rejects by default
+#
+# Expect: REJECT
+rcpt reject@reject.domain
+# Expect: OK
+rcpt ok@reject.domain
+# Expect: REJECT
+rcpt anyone@reject.domain
+# Expect: REJECT
+rcpt good-sender@reject.domain
+#
+# Again, with a domain that accepts by default
+#
+# Expect: REJECT
+rcpt reject@ok.domain
+# Expect: OK
+rcpt ok@ok.domain
+# Expect: OK
+rcpt anyone@ok.domain
+# Expect: OK
+rcpt bad-sender@ok.domain
diff --git a/gnu/dist/postfix/src/smtpd/smtpd_acl.ref b/gnu/dist/postfix/src/smtpd/smtpd_acl.ref
new file mode 100644
index 000000000000..34e351866272
--- /dev/null
+++ b/gnu/dist/postfix/src/smtpd/smtpd_acl.ref
@@ -0,0 +1,164 @@
+>>> #
+>>> # Initialize
+>>> #
+>>> smtpd_delay_reject 0
+OK
+>>> mynetworks 127.0.0.0/8,168.100.189.0/28
+OK
+>>> relay_domains porcupine.org
+OK
+>>> #
+>>> # Test check_domain_access()
+>>> #
+>>> helo_restrictions hash:./smtpd_check_access
+OK
+>>> # Expect: REJECT
+>>> helo foo.dunno.com
+./smtpd_check: reject: HELO from localhost[127.0.0.1]: 554 : Helo command rejected: Access denied
+554 : Helo command rejected: Access denied
+>>> # Expect: OK
+>>> helo bar.dunno.com
+OK
+>>> # Expect: OK
+>>> helo foo.duuno.com
+OK
+>>> #
+>>> # Test check_namadr_access(), domain part
+>>> #
+>>> client_restrictions hash:./smtpd_check_access
+OK
+>>> # Expect: REJECT
+>>> client foo.dunno.com 131.155.210.17
+./smtpd_check: reject: CONNECT from foo.dunno.com[131.155.210.17]: 554 : Client host rejected: Access denied
+554 : Client host rejected: Access denied
+>>> # Expect: OK
+>>> client bar.dunno.com 131.155.210.17
+OK
+>>> # Expect: OK
+>>> client bar.dunno.com 131.155.210.19
+OK
+>>> #
+>>> # Test check_namadr_access(), address part
+>>> #
+>>> # Expect: OK
+>>> client bar.duno.com 131.155.210.17
+OK
+>>> # Expect: REJECT
+>>> client bar.duno.com 131.155.210.19
+./smtpd_check: reject: CONNECT from bar.duno.com[131.155.210.19]: 554 : Client host rejected: Access denied
+554 : Client host rejected: Access denied
+>>> # Expect: REJECT
+>>> client bar.duno.com 44.33.22.11
+./smtpd_check: reject: CONNECT from bar.duno.com[44.33.22.11]: 554 : Client host rejected: Access denied
+554 : Client host rejected: Access denied
+>>> # Expect: OK
+>>> client bar.duno.com 44.33.22.55
+OK
+>>> # Expect: REJECT
+>>> client bar.duno.com 44.33.44.33
+./smtpd_check: reject: CONNECT from bar.duno.com[44.33.44.33]: 554 : Client host rejected: Access denied
+554 : Client host rejected: Access denied
+>>> #
+>>> # Test check_mail_access()
+>>> #
+>>> sender_restrictions hash:./smtpd_check_access
+OK
+>>> # Expect: REJECT
+>>> mail reject@dunno.domain
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 554 : Sender address rejected: Access denied; from=
+554 : Sender address rejected: Access denied
+>>> # Expect: OK
+>>> mail ok@dunno.domain
+OK
+>>> # Expect: OK
+>>> mail anyone@dunno.domain
+OK
+>>> # Expect: OK
+>>> mail bad-sender@dunno.domain
+OK
+>>> #
+>>> # Again, with a domain that rejects by default
+>>> #
+>>> # Expect: REJECT
+>>> mail reject@reject.domain
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 554 : Sender address rejected: Access denied; from=
+554 : Sender address rejected: Access denied
+>>> # Expect: OK
+>>> mail ok@reject.domain
+OK
+>>> # Expect: REJECT
+>>> mail anyone@reject.domain
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 554 : Sender address rejected: Access denied; from=
+554 : Sender address rejected: Access denied
+>>> # Expect: REJECT
+>>> mail good-sender@reject.domain
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 554 : Sender address rejected: Access denied; from=
+554 : Sender address rejected: Access denied
+>>> #
+>>> # Again, with a domain that accepts by default
+>>> #
+>>> # Expect: REJECT
+>>> mail reject@ok.domain
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 554 : Sender address rejected: Access denied; from=
+554 : Sender address rejected: Access denied
+>>> # Expect: OK
+>>> mail ok@ok.domain
+OK
+>>> # Expect: OK
+>>> mail anyone@ok.domain
+OK
+>>> # Expect: OK
+>>> mail bad-sender@ok.domain
+OK
+>>> #
+>>> # Test check_mail_access()
+>>> #
+>>> recipient_restrictions hash:./smtpd_check_access
+OK
+>>> # Expect: REJECT
+>>> rcpt reject@dunno.domain
+./smtpd_check: reject: RCPT from bar.duno.com[44.33.44.33]: 554 : Recipient address rejected: Access denied; from= to=
+554 : Recipient address rejected: Access denied
+>>> # Expect: OK
+>>> rcpt ok@dunno.domain
+OK
+>>> # Expect: OK
+>>> rcpt anyone@dunno.domain
+OK
+>>> # Expect: OK
+>>> rcpt bad-sender@dunno.domain
+OK
+>>> #
+>>> # Again, with a domain that rejects by default
+>>> #
+>>> # Expect: REJECT
+>>> rcpt reject@reject.domain
+./smtpd_check: reject: RCPT from bar.duno.com[44.33.44.33]: 554 : Recipient address rejected: Access denied; from= to=
+554 : Recipient address rejected: Access denied
+>>> # Expect: OK
+>>> rcpt ok@reject.domain
+OK
+>>> # Expect: REJECT
+>>> rcpt anyone@reject.domain
+./smtpd_check: reject: RCPT from bar.duno.com[44.33.44.33]: 554 : Recipient address rejected: Access denied; from= to=
+554 : Recipient address rejected: Access denied
+>>> # Expect: REJECT
+>>> rcpt good-sender@reject.domain
+./smtpd_check: reject: RCPT from bar.duno.com[44.33.44.33]: 554 : Recipient address rejected: Access denied; from= to=
+554 : Recipient address rejected: Access denied
+>>> #
+>>> # Again, with a domain that accepts by default
+>>> #
+>>> # Expect: REJECT
+>>> rcpt reject@ok.domain
+./smtpd_check: reject: RCPT from bar.duno.com[44.33.44.33]: 554 : Recipient address rejected: Access denied; from= to=
+554 : Recipient address rejected: Access denied
+>>> # Expect: OK
+>>> rcpt ok@ok.domain
+OK
+>>> # Expect: OK
+>>> rcpt anyone@ok.domain
+OK
+>>> # Expect: OK
+>>> rcpt bad-sender@ok.domain
+OK
diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check_access b/gnu/dist/postfix/src/smtpd/smtpd_check_access
index f7f6e42d7fc3..afb5487c9656 100644
--- a/gnu/dist/postfix/src/smtpd/smtpd_check_access
+++ b/gnu/dist/postfix/src/smtpd/smtpd_check_access
@@ -2,9 +2,30 @@ bad.domain 554 match bad.domain
friend.bad.domain OK
bad-sender@ 554 match bad-sender@
bad-sender@good.domain OK
+good-sender@ OK
131.155.210 554 match 131.155.210
131.155.210.17 OK
+131.155.210.19 REJECT
reject@this.address 554 match reject@this.address
open_user@some.site open
strict_user@some.site strict
auth_client 123456
+
+dunno.com dunno
+foo.dunno.com reject
+
+44.33.22 dunno
+44.33.22.11 REJECT
+44.33 REJECT
+
+reject@dunno.domain REJECT
+ok@dunno.domain OK
+dunno.domain DUNNO
+
+reject@reject.domain REJECT
+ok@reject.domain OK
+reject.domain REJECT
+
+reject@ok.domain REJECT
+ok@ok.domain OK
+ok.domain OK
diff --git a/gnu/dist/postfix/src/util/ctable.c b/gnu/dist/postfix/src/util/ctable.c
new file mode 100644
index 000000000000..4e6d18f5e455
--- /dev/null
+++ b/gnu/dist/postfix/src/util/ctable.c
@@ -0,0 +1,273 @@
+/*++
+/* NAME
+/* ctable 3
+/* SUMMARY
+/* cache manager
+/* SYNOPSIS
+/* #include
+/*
+/* CTABLE *ctable_create(limit, create, delete, context)
+/* int limit;
+/* void *(*create)(const char *key, void *context);
+/* void (*delete)(void *value, void *context);
+/* void *context;
+/*
+/* const void *ctable_locate(cache, key)
+/* CTABLE *cache;
+/* const char *key;
+/*
+/* void ctable_free(cache)
+/* CTABLE *cache;
+/*
+/* void ctable_walk(cache, action)
+/* CTABLE *cache;
+/* void (*action)(const char *key, const void *value);
+/* DESCRIPTION
+/* This module maintains multiple caches. Cache items are purged
+/* automatically when the number of items exceeds a configurable
+/* limit. Caches never shrink. Each cache entry consists of a
+/* string-valued lookup key and a generic data pointer value.
+/*
+/* ctable_create() creates a cache with the specified size limit, and
+/* returns a pointer to the result. The create and delete arguments
+/* specify pointers to call-back functions that create a value, given
+/* a key, and delete a given value, respectively. The context argument
+/* is passed on to the call-back routines.
+/*
+/* ctable_locate() looks up or generates the value that corresponds to
+/* the specified key, and returns that value.
+/*
+/* ctable_free() destroys the specified cache, including its contents.
+/*
+/* ctable_walk() iterates over all elements in the cache, and invokes
+/* the action function for each cache element with the corresponding
+/* key and value as arguments. This function is useful mainly for
+/* cache performance debugging.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory. Panic: interface violation.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+
+ /*
+ * Cache entries are kept in most-recently used order. We use a hash table
+ * to quickly locate cache entries.
+ */
+#define CTABLE_ENTRY struct ctable_entry
+
+struct ctable_entry {
+ RING ring; /* MRU linkage */
+ const char *key; /* lookup key */
+ void *value; /* corresponding value */
+};
+
+#define RING_TO_CTABLE_ENTRY(ring_ptr) \
+ RING_TO_APPL(ring_ptr, CTABLE_ENTRY, ring)
+#define RING_PTR_OF(x) (&((x)->ring))
+
+struct ctable {
+ HTABLE *table; /* table with key, ctable_entry pairs */
+ unsigned limit; /* max nr of entries */
+ unsigned used; /* current nr of entries */
+ CTABLE_CREATE_FN create; /* constructor */
+ CTABLE_DELETE_FN delete; /* destructor */
+ RING ring; /* MRU linkage */
+ void *context; /* application context */
+};
+
+#define CTABLE_MIN_SIZE 5
+
+/* ctable_create - create empty cache */
+
+CTABLE *ctable_create(int limit, CTABLE_CREATE_FN create,
+ CTABLE_DELETE_FN delete, void *context)
+{
+ CTABLE *cache = (CTABLE *) mymalloc(sizeof(CTABLE));
+ char *myname = "ctable_create";
+
+ if (limit < 1)
+ msg_panic("%s: bad cache limit: %d", myname, limit);
+
+ cache->table = htable_create(limit);
+ cache->limit = (limit < CTABLE_MIN_SIZE ? CTABLE_MIN_SIZE : limit);
+ cache->used = 0;
+ cache->create = create;
+ cache->delete = delete;
+ ring_init(RING_PTR_OF(cache));
+ cache->context = context;
+ return (cache);
+}
+
+/* ctable_locate - look up or create cache item */
+
+const void *ctable_locate(CTABLE *cache, const char *key)
+{
+ char *myname = "ctable_locate";
+ CTABLE_ENTRY *entry;
+
+ /*
+ * If the entry is not in the cache, make sure there is room for a new
+ * entry and install it at the front of the MRU chain. Otherwise, move
+ * the entry to the front of the MRU chain if it is not already there.
+ * All this means that the cache never shrinks.
+ */
+ if ((entry = (CTABLE_ENTRY *) htable_find(cache->table, key)) == 0) {
+ if (cache->used >= cache->limit) {
+ entry = RING_TO_CTABLE_ENTRY(ring_pred(RING_PTR_OF(cache)));
+ if (msg_verbose)
+ msg_info("%s: purge entry key %s", myname, entry->key);
+ ring_detach(RING_PTR_OF(entry));
+ cache->delete(entry->value, cache->context);
+ htable_delete(cache->table, entry->key, (void (*) (char *)) 0);
+ } else {
+ entry = (CTABLE_ENTRY *) mymalloc(sizeof(CTABLE_ENTRY));
+ cache->used++;
+ }
+ entry->value = cache->create(key, cache->context);
+ entry->key = htable_enter(cache->table, key, (char *) entry)->key;
+ ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry));
+ if (msg_verbose)
+ msg_info("%s: install entry key %s", myname, entry->key);
+ } else if (entry == RING_TO_CTABLE_ENTRY(ring_succ(RING_PTR_OF(cache)))) {
+ if (msg_verbose)
+ msg_info("%s: leave existing entry key %s", myname, entry->key);
+ } else {
+ ring_detach(RING_PTR_OF(entry));
+ ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry));
+ if (msg_verbose)
+ msg_info("%s: move existing entry key %s", myname, entry->key);
+ }
+ return (entry->value);
+}
+
+static CTABLE *ctable_free_cache;
+
+/* ctable_free_callback - callback function */
+
+static void ctable_free_callback(char *ptr)
+{
+ CTABLE_ENTRY *entry = (CTABLE_ENTRY *) ptr;
+
+ ctable_free_cache->delete(entry->value, ctable_free_cache->context);
+ myfree((char *) entry);
+}
+
+/* ctable_free - destroy cache and contents */
+
+void ctable_free(CTABLE *cache)
+{
+ CTABLE *saved_cache = ctable_free_cache;
+
+ /*
+ * XXX the hash table does not pass application context so we have to
+ * store it in a global variable.
+ */
+ ctable_free_cache = cache;
+ htable_free(cache->table, ctable_free_callback);
+ myfree((char *) cache);
+ ctable_free_cache = saved_cache;
+}
+
+/* ctable_walk - iterate over all cache entries */
+
+void ctable_walk(CTABLE *cache, void (*action) (const char *, const void *))
+{
+ RING *entry = RING_PTR_OF(cache);
+
+ /* Walking down the MRU chain is less work than using ht_walk(). */
+
+ while ((entry = ring_succ(entry)) != RING_PTR_OF(cache))
+ action((RING_TO_CTABLE_ENTRY(entry)->key),
+ (RING_TO_CTABLE_ENTRY(entry)->value));
+}
+
+#ifdef TEST
+
+ /*
+ * Proof-of-concept test program. Read keys from stdin, ask for values not
+ * in cache.
+ */
+#include
+#include
+#include
+#include
+#include
+
+#define STR(x) vstring_str(x)
+
+static void *ask(const char *key, void *context)
+{
+ VSTRING *data_buf = (VSTRING *) context;
+
+ vstream_printf("ask: %s = ", key);
+ vstream_fflush(VSTREAM_OUT);
+ if (vstring_get_nonl(data_buf, VSTREAM_IN) == VSTREAM_EOF)
+ vstream_longjmp(VSTREAM_IN, 1);
+ if (!isatty(0)) {
+ vstream_printf("%s\n", STR(data_buf));
+ vstream_fflush(VSTREAM_OUT);
+ }
+ return (mystrdup(STR(data_buf)));
+}
+
+static void drop(void *data, void *unused_context)
+{
+ myfree(data);
+}
+
+int main(int unused_argc, char **argv)
+{
+ VSTRING *key_buf;
+ VSTRING *data_buf;
+ CTABLE *cache;
+ const char *value;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ key_buf = vstring_alloc(100);
+ data_buf = vstring_alloc(100);
+ cache = ctable_create(1, ask, drop, (void *) data_buf);
+ msg_verbose = 1;
+ vstream_control(VSTREAM_IN, VSTREAM_CTL_EXCEPT, VSTREAM_CTL_END);
+
+ if (vstream_setjmp(VSTREAM_IN) == 0) {
+ for (;;) {
+ vstream_printf("key = ");
+ vstream_fflush(VSTREAM_OUT);
+ if (vstring_get_nonl(key_buf, VSTREAM_IN) == VSTREAM_EOF)
+ vstream_longjmp(VSTREAM_IN, 1);
+ if (!isatty(0)) {
+ vstream_printf("%s\n", STR(key_buf));
+ vstream_fflush(VSTREAM_OUT);
+ }
+ value = ctable_locate(cache, STR(key_buf));
+ vstream_printf("result: %s\n", value);
+ }
+ }
+ ctable_free(cache);
+ vstring_free(key_buf);
+ vstring_free(data_buf);
+ return (0);
+}
+
+#endif
diff --git a/gnu/dist/postfix/src/util/ctable.h b/gnu/dist/postfix/src/util/ctable.h
new file mode 100644
index 000000000000..7e3d899b3f0c
--- /dev/null
+++ b/gnu/dist/postfix/src/util/ctable.h
@@ -0,0 +1,39 @@
+#ifndef _CTABLE_H_INCLUDED_
+#define _CTABLE_H_INCLUDED_
+
+/*++
+/* NAME
+/* ctable 5
+/* SUMMARY
+/* cache manager
+/* SYNOPSIS
+/* #include
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Interface of the cache manager. The structure of a cache is not visible
+ * to the caller.
+ */
+
+#define CTABLE struct ctable
+typedef void *(*CTABLE_CREATE_FN) (const char *, void *);
+typedef void (*CTABLE_DELETE_FN) (void *, void *);
+
+extern CTABLE *ctable_create(int, CTABLE_CREATE_FN, CTABLE_DELETE_FN, void *);
+extern void ctable_free(CTABLE *);
+extern void ctable_walk(CTABLE *, void (*) (const char *, const void *));
+extern const void *ctable_locate(CTABLE *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/gnu/dist/postfix/src/util/ctable.in b/gnu/dist/postfix/src/util/ctable.in
new file mode 100644
index 000000000000..78763cfaf2ec
--- /dev/null
+++ b/gnu/dist/postfix/src/util/ctable.in
@@ -0,0 +1,39 @@
+a
+1
+b
+2
+c
+3
+d
+4
+e
+5
+f
+6
+f
+a
+1
+b
+2
+c
+3
+d
+4
+e
+5
+f
+6
+f
+e
+d
+c
+b
+a
+1
+b
+c
+d
+e
+f
+6
+f
diff --git a/gnu/dist/postfix/src/util/ctable.ref b/gnu/dist/postfix/src/util/ctable.ref
new file mode 100644
index 000000000000..34e8a951abd7
--- /dev/null
+++ b/gnu/dist/postfix/src/util/ctable.ref
@@ -0,0 +1,99 @@
+key = a
+ask: a = 1
+./ctable: ctable_locate: install entry key a
+result: 1
+key = b
+ask: b = 2
+./ctable: ctable_locate: install entry key b
+result: 2
+key = c
+ask: c = 3
+./ctable: ctable_locate: install entry key c
+result: 3
+key = d
+ask: d = 4
+./ctable: ctable_locate: install entry key d
+result: 4
+key = e
+ask: e = 5
+./ctable: ctable_locate: install entry key e
+result: 5
+key = f
+./ctable: ctable_locate: purge entry key a
+ask: f = 6
+./ctable: ctable_locate: install entry key f
+result: 6
+key = f
+./ctable: ctable_locate: leave existing entry key f
+result: 6
+key = a
+./ctable: ctable_locate: purge entry key b
+ask: a = 1
+./ctable: ctable_locate: install entry key a
+result: 1
+key = b
+./ctable: ctable_locate: purge entry key c
+ask: b = 2
+./ctable: ctable_locate: install entry key b
+result: 2
+key = c
+./ctable: ctable_locate: purge entry key d
+ask: c = 3
+./ctable: ctable_locate: install entry key c
+result: 3
+key = d
+./ctable: ctable_locate: purge entry key e
+ask: d = 4
+./ctable: ctable_locate: install entry key d
+result: 4
+key = e
+./ctable: ctable_locate: purge entry key f
+ask: e = 5
+./ctable: ctable_locate: install entry key e
+result: 5
+key = f
+./ctable: ctable_locate: purge entry key a
+ask: f = 6
+./ctable: ctable_locate: install entry key f
+result: 6
+key = f
+./ctable: ctable_locate: leave existing entry key f
+result: 6
+key = e
+./ctable: ctable_locate: move existing entry key e
+result: 5
+key = d
+./ctable: ctable_locate: move existing entry key d
+result: 4
+key = c
+./ctable: ctable_locate: move existing entry key c
+result: 3
+key = b
+./ctable: ctable_locate: move existing entry key b
+result: 2
+key = a
+./ctable: ctable_locate: purge entry key f
+ask: a = 1
+./ctable: ctable_locate: install entry key a
+result: 1
+key = b
+./ctable: ctable_locate: move existing entry key b
+result: 2
+key = c
+./ctable: ctable_locate: move existing entry key c
+result: 3
+key = d
+./ctable: ctable_locate: move existing entry key d
+result: 4
+key = e
+./ctable: ctable_locate: move existing entry key e
+result: 5
+key = f
+./ctable: ctable_locate: purge entry key a
+ask: f = 6
+./ctable: ctable_locate: install entry key f
+result: 6
+key = f
+./ctable: ctable_locate: leave existing entry key f
+result: 6
+key =
\ No newline at end of file
diff --git a/gnu/dist/postfix/src/util/dict_ldap.c b/gnu/dist/postfix/src/util/dict_ldap.c
index 776a437db560..528769248962 100644
--- a/gnu/dist/postfix/src/util/dict_ldap.c
+++ b/gnu/dist/postfix/src/util/dict_ldap.c
@@ -151,6 +151,10 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
void (*saved_alarm) (int);
int rc = 0;
+#ifdef LDAP_API_FEATURE_X_MEMCACHE
+ LDAPMemCache *dircache;
+#endif
+
#ifdef LDAP_OPT_NETWORK_TIMEOUT
struct timeval mytimeval;
@@ -162,7 +166,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
msg_info("%s: Connecting to server %s", myname,
dict_ldap->server_host);
-#ifdef UNTESTED_LDAP_OPT_NETWORK_TIMEOUT
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
dict_ldap->ld = ldap_init(dict_ldap->server_host,
(int) dict_ldap->server_port);
if (dict_ldap->ld == NULL) {
@@ -247,6 +251,27 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
myname, dict_ldap->cache_size, dict_ldap->ldapsource,
dict_ldap->cache_expiry);
+#ifdef LDAP_API_FEATURE_X_MEMCACHE
+ rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
+ NULL, NULL, &dircache);
+ if (rc != LDAP_SUCCESS) {
+ msg_warn
+ ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
+ myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
+ } else {
+ rc = ldap_memcache_set(dict_ldap->ld, dircache);
+ if (rc != LDAP_SUCCESS) {
+ msg_warn
+ ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
+ myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
+ } else {
+ if (msg_verbose)
+ msg_info("%s: Caching enabled for %s",
+ myname, dict_ldap->ldapsource);
+ }
+ }
+#else
+
rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
dict_ldap->cache_size);
if (rc != LDAP_SUCCESS) {
@@ -258,6 +283,8 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
msg_info("%s: Caching enabled for %s",
myname, dict_ldap->ldapsource);
}
+
+#endif
}
if (msg_verbose)
msg_info("%s: Cached connection handle for LDAP source %s",
@@ -315,7 +342,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
if (strcasecmp(dict_ldap->result_attributes->argv[i],
attr) == 0) {
if (msg_verbose)
- msg_info("%s: search returned value(s) for requested result attribute %s", myname, attr);
+ msg_info("%s: search returned %d value(s) for requested result attribute %s", myname, i, attr);
break;
}
}
@@ -390,7 +417,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
* load on the LDAP server.
*/
if (dict_ldap->domain) {
- char *p=strrchr(name,'@');
+ const char *p=strrchr(name,'@');
if (p != 0)
p=p+1;
else
@@ -482,7 +509,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
/*
* Does the supplied query_filter even include a substitution?
*/
- if ((char *) strstr(dict_ldap->query_filter, "%s") == NULL) {
+ if ((char *) strchr(dict_ldap->query_filter, '%') == NULL) {
/*
* No, log the fact and continue.
@@ -494,21 +521,40 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
/*
* Yes, replace all instances of %s with the address to look up.
+ * Replace %u with the user portion, and %d with the domain portion.
*/
sub = dict_ldap->query_filter;
end = sub + strlen(dict_ldap->query_filter);
while (sub < end) {
/*
- * Make sure it's %s and not something else, though it wouldn't
- * really matter; the token could be any single character.
+ * Make sure it's %[sud] and not something else. For backward
+ * compatibilty, treat anything other than %u or %d as %s, with
+ * a warning.
*/
if (*(sub) == '%') {
- if ((sub + 1) != end && *(sub + 1) != 's')
- msg_warn
- ("%s: Invalid lookup substitution format '%%%c'!",
- myname, *(sub + 1));
- vstring_strcat(filter_buf, vstring_str(escaped_name));
+ char *u=vstring_str(escaped_name);
+ char *p=strchr(u,'@');
+ switch (*(sub+1)) {
+ case 'd':
+ if (p)
+ vstring_strcat(filter_buf, p+1);
+ break;
+ case 'u':
+ if (p)
+ vstring_strncat(filter_buf, u, p-u);
+ else
+ vstring_strcat(filter_buf, u);
+ break;
+ default:
+ msg_warn
+ ("%s: Invalid lookup substitution format '%%%c'!",
+ myname, *(sub + 1));
+ /* fall through */
+ case 's':
+ vstring_strcat(filter_buf, u);
+ break;
+ }
sub++;
} else
vstring_strncat(filter_buf, sub, 1);
@@ -607,7 +653,8 @@ static void dict_ldap_close(DICT *dict)
myfree(dict_ldap->ldapsource);
myfree(dict_ldap->server_host);
myfree(dict_ldap->search_base);
- match_list_free(dict_ldap->domain);
+ if (dict_ldap->domain)
+ match_list_free(dict_ldap->domain);
myfree(dict_ldap->query_filter);
argv_free(dict_ldap->result_attributes);
myfree(dict_ldap->bind_dn);
@@ -626,15 +673,15 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
char *scope;
char *attr;
+ if (msg_verbose)
+ msg_info("%s: Using LDAP source %s", myname, ldapsource);
+
dict_ldap = (DICT_LDAP *) dict_alloc(DICT_TYPE_LDAP, ldapsource,
sizeof(*dict_ldap));
dict_ldap->dict.lookup = dict_ldap_lookup;
dict_ldap->dict.close = dict_ldap_close;
dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
- if (msg_verbose)
- msg_info("%s: Using LDAP source %s", myname, ldapsource);
-
dict_ldap->ldapsource = mystrdup(ldapsource);
config_param = vstring_alloc(15);
diff --git a/gnu/dist/postfix/src/util/dict_pcre.c b/gnu/dist/postfix/src/util/dict_pcre.c
index 1e8e84b6bf5a..6d3c6f523932 100644
--- a/gnu/dist/postfix/src/util/dict_pcre.c
+++ b/gnu/dist/postfix/src/util/dict_pcre.c
@@ -266,6 +266,7 @@ DICT *dict_pcre_open(const char *map, int unused_flags, int dict_flags)
continue;
p = vstring_str(line_buffer);
+ trimblanks(p, 0)[0] = 0; /* Trim space at end */
re_delimiter = *p++;
regexp = p;
diff --git a/gnu/dist/postfix/src/util/dict_regexp.c b/gnu/dist/postfix/src/util/dict_regexp.c
index 0d4eaf852352..1debbe96ff2c 100644
--- a/gnu/dist/postfix/src/util/dict_regexp.c
+++ b/gnu/dist/postfix/src/util/dict_regexp.c
@@ -365,6 +365,8 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
if (*p == 0) /* Skip blank lines */
continue;
+ trimblanks(p, 0)[0] = 0; /* Trim space at end */
+
rule = dict_regexp_parseline(lineno, p, &nsub, map_fp);
if (rule) {
if (nsub > max_nsub)
diff --git a/gnu/dist/postfix/src/util/inet_addr_list.in b/gnu/dist/postfix/src/util/inet_addr_list.in
new file mode 100644
index 000000000000..742281fae146
--- /dev/null
+++ b/gnu/dist/postfix/src/util/inet_addr_list.in
@@ -0,0 +1,9 @@
+168.100.189.2
+168.100.189.2
+168.100.189.1
+168.100.189.3
+168.100.189.3
+168.100.189.3
+168.100.189.4
+168.100.189.1
+168.100.189.4
diff --git a/gnu/dist/postfix/src/util/inet_addr_list.ref b/gnu/dist/postfix/src/util/inet_addr_list.ref
new file mode 100644
index 000000000000..0a8a56e1ad95
--- /dev/null
+++ b/gnu/dist/postfix/src/util/inet_addr_list.ref
@@ -0,0 +1,15 @@
+unknown: list before sort/uniq
+unknown: 168.100.189.2
+unknown: 168.100.189.2
+unknown: 168.100.189.1
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.4
+unknown: 168.100.189.1
+unknown: 168.100.189.4
+unknown: list after sort/uniq
+unknown: 168.100.189.1
+unknown: 168.100.189.2
+unknown: 168.100.189.3
+unknown: 168.100.189.4
diff --git a/gnu/dist/postfix/src/util/ring.h b/gnu/dist/postfix/src/util/ring.h
index a96fe2696af4..d0219cf804cc 100644
--- a/gnu/dist/postfix/src/util/ring.h
+++ b/gnu/dist/postfix/src/util/ring.h
@@ -29,6 +29,17 @@ extern void ring_detach(RING *);
#define ring_succ(c) ((c)->succ)
#define ring_pred(c) ((c)->pred)
+ /*
+ * Typically, an application will embed a RING structure into a larger
+ * structure that also contains application-specific members. This approach
+ * gives us the best of both worlds. The application can still use the
+ * generic RING primitives for manipulating RING structures. The macro below
+ * transforms a pointer from RING structure to the structure that contains
+ * it.
+ */
+#define RING_TO_APPL(ring_ptr,app_type,ring_member) \
+ ((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member)))
+
/* LICENSE
/* .ad
/* .fi