postfix 20010228-pl04

This commit is contained in:
itojun 2001-08-09 07:59:02 +00:00
parent ed97fbd98d
commit 48a8a26166
19 changed files with 902 additions and 20 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -1027,7 +1027,7 @@ Berkeley DB library version.
<hr>
<a name="nosuid"><h1>sendmail has set-uid root file permissions, or is run from a
<a name="nosuid"><h3>sendmail has set-uid root file permissions, or is run from a
set-uid root process</h3></a>
Traditionally, the UNIX <b>sendmail</b> command is installed with

View File

@ -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

View File

@ -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_acl.in >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.in >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

107
gnu/dist/postfix/src/smtpd/smtpd_acl.in vendored Normal file
View File

@ -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

164
gnu/dist/postfix/src/smtpd/smtpd_acl.ref vendored Normal file
View File

@ -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 <foo.dunno.com>: Helo command rejected: Access denied
554 <foo.dunno.com>: 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 <foo.dunno.com[131.155.210.17]>: Client host rejected: Access denied
554 <foo.dunno.com[131.155.210.17]>: 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 <bar.duno.com[131.155.210.19]>: Client host rejected: Access denied
554 <bar.duno.com[131.155.210.19]>: 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 <bar.duno.com[44.33.22.11]>: Client host rejected: Access denied
554 <bar.duno.com[44.33.22.11]>: 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 <bar.duno.com[44.33.44.33]>: Client host rejected: Access denied
554 <bar.duno.com[44.33.44.33]>: 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 <reject@dunno.domain>: Sender address rejected: Access denied; from=<reject@dunno.domain>
554 <reject@dunno.domain>: 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 <reject@reject.domain>: Sender address rejected: Access denied; from=<reject@reject.domain>
554 <reject@reject.domain>: 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 <anyone@reject.domain>: Sender address rejected: Access denied; from=<anyone@reject.domain>
554 <anyone@reject.domain>: 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 <good-sender@reject.domain>: Sender address rejected: Access denied; from=<good-sender@reject.domain>
554 <good-sender@reject.domain>: 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 <reject@ok.domain>: Sender address rejected: Access denied; from=<reject@ok.domain>
554 <reject@ok.domain>: 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 <reject@dunno.domain>: Recipient address rejected: Access denied; from=<bad-sender@ok.domain> to=<reject@dunno.domain>
554 <reject@dunno.domain>: 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 <reject@reject.domain>: Recipient address rejected: Access denied; from=<bad-sender@ok.domain> to=<reject@reject.domain>
554 <reject@reject.domain>: 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 <anyone@reject.domain>: Recipient address rejected: Access denied; from=<bad-sender@ok.domain> to=<anyone@reject.domain>
554 <anyone@reject.domain>: 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 <good-sender@reject.domain>: Recipient address rejected: Access denied; from=<bad-sender@ok.domain> to=<good-sender@reject.domain>
554 <good-sender@reject.domain>: 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 <reject@ok.domain>: Recipient address rejected: Access denied; from=<bad-sender@ok.domain> to=<reject@ok.domain>
554 <reject@ok.domain>: 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

View File

@ -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

273
gnu/dist/postfix/src/util/ctable.c vendored Normal file
View File

@ -0,0 +1,273 @@
/*++
/* NAME
/* ctable 3
/* SUMMARY
/* cache manager
/* SYNOPSIS
/* #include <ctable.h>
/*
/* 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 <sys_defs.h>
#include <stdlib.h>
#include <stddef.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <ring.h>
#include <htable.h>
#include <ctable.h>
/*
* 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 <unistd.h>
#include <vstream.h>
#include <vstring.h>
#include <vstring_vstream.h>
#include <msg_vstream.h>
#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

39
gnu/dist/postfix/src/util/ctable.h vendored Normal file
View File

@ -0,0 +1,39 @@
#ifndef _CTABLE_H_INCLUDED_
#define _CTABLE_H_INCLUDED_
/*++
/* NAME
/* ctable 5
/* SUMMARY
/* cache manager
/* SYNOPSIS
/* #include <ctable.h>
/* 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

39
gnu/dist/postfix/src/util/ctable.in vendored Normal file
View File

@ -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

99
gnu/dist/postfix/src/util/ctable.ref vendored Normal file
View File

@ -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 =

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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