Prereq: "Postfix-20010228-pl03" diff -cr --new-file ../postfix-20010228-pl03/src/global/mail_version.h ./src/global/mail_version.h *** ../postfix-20010228-pl03/src/global/mail_version.h Tue May 1 12:58:10 2001 --- ./src/global/mail_version.h Tue Jul 31 14:47:45 2001 *************** *** 15,21 **** * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" ! #define DEF_MAIL_VERSION "Postfix-20010228-pl03" extern char *var_mail_version; /* LICENSE --- 15,21 ---- * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" ! #define DEF_MAIL_VERSION "Postfix-20010228-pl04" extern char *var_mail_version; /* LICENSE diff -cr --new-file ../postfix-20010228-pl03/HISTORY ./HISTORY *** ../postfix-20010228-pl03/HISTORY Sat May 26 19:03:33 2001 --- ./HISTORY Tue Jul 31 17:13:42 2001 *************** *** 5063,5065 **** --- 5063,5098 ---- 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 -cr --new-file ../postfix-20010228-pl03/MYSQL_README ./MYSQL_README *** ../postfix-20010228-pl03/MYSQL_README Thu Mar 29 13:57:38 2001 --- ./MYSQL_README Sun Jul 29 09:48:29 2001 *************** *** 12,20 **** make -f Makefile.init makefiles \ 'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \ ! 'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lm' ! then, just run 'make'. Postfix installations which may benefit from using mysql map types include sites that have a need for instantaneous updates of --- 12,21 ---- make -f Makefile.init makefiles \ 'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \ ! 'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lz -lm' ! 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 -cr --new-file ../postfix-20010228-pl03/conf/sample-ldap.cf ./conf/sample-ldap.cf *** ../postfix-20010228-pl03/conf/sample-ldap.cf Mon May 21 20:04:52 2001 --- ./conf/sample-ldap.cf Fri Jul 20 13:07:50 2001 *************** *** 23,28 **** --- 23,35 ---- #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) *************** *** 30,35 **** --- 37,49 ---- # the search. # #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. # diff -cr --new-file ../postfix-20010228-pl03/html/faq.html ./html/faq.html *** ../postfix-20010228-pl03/html/faq.html Sat May 19 11:08:25 2001 --- ./html/faq.html Tue Jun 12 07:19:44 2001 *************** *** 1027,1033 ****
!

sendmail has set-uid root file permissions, or is run from a set-uid root process

Traditionally, the UNIX sendmail command is installed with --- 1027,1033 ----
!

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 -cr --new-file ../postfix-20010228-pl03/src/global/own_inet_addr.c ./src/global/own_inet_addr.c *** ../postfix-20010228-pl03/src/global/own_inet_addr.c Sat Feb 24 20:51:39 2001 --- ./src/global/own_inet_addr.c Tue Jul 31 14:38:29 2001 *************** *** 107,112 **** --- 107,120 ---- VAR_INET_INTERFACES, host); myfree(hosts); + /* + * Weed out duplicate IP addresses. Duplicates happen when the same + * IP address is listed under multiple hostnames. If we don't weed + * out duplicates, Postfix can suddenly stop working after the DNS is + * changed. + */ + inet_addr_list_uniq(addr_list); + inet_addr_list_init(&local_addrs); inet_addr_list_init(&local_masks); if (inet_addr_local(&local_addrs, &local_masks) == 0) diff -cr --new-file ../postfix-20010228-pl03/src/smtp/smtp_connect.c ./src/smtp/smtp_connect.c *** ../postfix-20010228-pl03/src/smtp/smtp_connect.c Sat Jan 20 18:36:00 2001 --- ./src/smtp/smtp_connect.c Sun Jul 8 15:41:03 2001 *************** *** 394,400 **** char *save; char *dest; char *cp; ! int found_myself; /* * First try to deliver to the indicated destination, then try to deliver --- 394,400 ---- char *save; char *dest; char *cp; ! int found_myself = 0; /* * First try to deliver to the indicated destination, then try to deliver diff -cr --new-file ../postfix-20010228-pl03/src/smtpd/Makefile.in ./src/smtpd/Makefile.in *** ../postfix-20010228-pl03/src/smtpd/Makefile.in Fri Apr 27 15:16:03 2001 --- ./src/smtpd/Makefile.in Tue Jul 31 10:43:31 2001 *************** *** 67,73 **** 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 smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref ../postmap/postmap smtpd_check_access --- 67,73 ---- done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in @$(EXPORT) make -f Makefile.in Makefile 1>&2 ! 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,86 **** --- 81,92 ---- 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,169 **** --- 170,176 ---- 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 -cr --new-file ../postfix-20010228-pl03/src/smtpd/smtpd_acl.in ./src/smtpd/smtpd_acl.in *** ../postfix-20010228-pl03/src/smtpd/smtpd_acl.in Wed Dec 31 19:00:00 1969 --- ./src/smtpd/smtpd_acl.in Mon Jul 30 18:37:25 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/smtpd/smtpd_acl.ref ./src/smtpd/smtpd_acl.ref *** ../postfix-20010228-pl03/src/smtpd/smtpd_acl.ref Wed Dec 31 19:00:00 1969 --- ./src/smtpd/smtpd_acl.ref Mon Jul 30 18:37:59 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/smtpd/smtpd_check.c ./src/smtpd/smtpd_check.c *** ../postfix-20010228-pl03/src/smtpd/smtpd_check.c Mon May 7 18:27:58 2001 --- ./src/smtpd/smtpd_check.c Tue Jul 31 10:26:41 2001 *************** *** 269,274 **** --- 269,275 ---- #include #include #include + #include /* DNS library. */ *************** *** 310,318 **** * Intermediate results. These are static to avoid unnecessary stress on the * memory manager routines. */ - static RESOLVE_REPLY reply; - static VSTRING *query; static VSTRING *error_text; /* * Pre-opened SMTP recipient maps so we can reject mail for unknown users. --- 311,318 ---- * Intermediate results. These are static to avoid unnecessary stress on the * memory manager routines. */ static VSTRING *error_text; + static CTABLE *smtpd_resolve_cache; /* * Pre-opened SMTP recipient maps so we can reject mail for unknown users. *************** *** 345,351 **** /* * The routine that recursively applies restrictions. */ ! static int generic_checks(SMTPD_STATE *, ARGV *, char *, char *, char *); /* * Reject context. --- 345,351 ---- /* * The routine that recursively applies restrictions. */ ! static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, const char *); /* * Reject context. *************** *** 360,365 **** --- 360,408 ---- * YASLM. */ #define STR vstring_str + #define CONST_STR(x) ((const char *) vstring_str(x)) + + /* resolve_pagein - page in an address resolver result */ + + static void *resolve_pagein(const char *addr, void *unused_context) + { + static VSTRING *query; + RESOLVE_REPLY *reply; + + /* + * Initialize on the fly. + */ + if (query == 0) + query = vstring_alloc(10); + + /* + * Initialize. + */ + reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply)); + resolve_clnt_init(reply); + + /* + * Resolve the address. + */ + canon_addr_internal(query, addr); + resolve_clnt_query(STR(query), reply); + lowercase(STR(reply->recipient)); + + /* + * Save the result. + */ + return ((void *) reply); + } + + /* resolve_pageout - page out an address resolver result */ + + static void resolve_pageout(void *data, void *unused_context) + { + RESOLVE_REPLY *reply = (RESOLVE_REPLY *) data; + + resolve_clnt_free(reply); + myfree((void *) reply); + } /* smtpd_check_parse - pre-parse restrictions */ *************** *** 471,484 **** DICT_FLAG_LOCK); /* ! * Reply is used as a cache for resolved addresses, and error_text is ! * used for returning error responses. */ - resolve_clnt_init(&reply); - query = vstring_alloc(10); error_text = vstring_alloc(10); /* * Pre-parse the restriction lists. At the same time, pre-open tables * before going to jail. */ --- 514,530 ---- DICT_FLAG_LOCK); /* ! * error_text is used for returning error responses. */ error_text = vstring_alloc(10); /* + * Initialize the resolved address cache. + */ + smtpd_resolve_cache = ctable_create(100, resolve_pagein, + resolve_pageout, (void *) 0); + + /* * Pre-parse the restriction lists. At the same time, pre-open tables * before going to jail. */ *************** *** 620,627 **** /* check_mail_addr_find - reject with temporary failure if dict lookup fails */ ! static const char *check_mail_addr_find(SMTPD_STATE *state, const char *reply_name, ! MAPS *maps, const char *key, char **ext) { const char *result; --- 666,675 ---- /* check_mail_addr_find - reject with temporary failure if dict lookup fails */ ! static const char *check_mail_addr_find(SMTPD_STATE *state, ! const char *reply_name, ! MAPS *maps, const char *key, ! char **ext) { const char *result; *************** *** 816,823 **** /* reject_unknown_mailhost - fail if name has no A or MX record */ ! static int reject_unknown_mailhost(SMTPD_STATE *state, char *name, ! char *reply_name, char *reply_class) { char *myname = "reject_unknown_mailhost"; int dns_status; --- 864,871 ---- /* reject_unknown_mailhost - fail if name has no A or MX record */ ! static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name, ! const char *reply_name, const char *reply_class) { char *myname = "reject_unknown_mailhost"; int dns_status; *************** *** 873,879 **** static int permit_auth_destination(SMTPD_STATE *state, char *recipient) { char *myname = "permit_auth_destination"; ! char *domain; if (msg_verbose) msg_info("%s: %s", myname, recipient); --- 921,928 ---- static int permit_auth_destination(SMTPD_STATE *state, char *recipient) { char *myname = "permit_auth_destination"; ! const RESOLVE_REPLY *reply; ! const char *domain; if (msg_verbose) msg_info("%s: %s", myname, recipient); *************** *** 881,894 **** /* * Resolve the address. */ ! canon_addr_internal(query, recipient); ! resolve_clnt_query(STR(query), &reply); ! lowercase(STR(reply.recipient)); /* * Handle special case that is not supposed to happen. */ ! if ((domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; --- 930,942 ---- /* * Resolve the address. */ ! reply = (const RESOLVE_REPLY *) ! ctable_locate(smtpd_resolve_cache, recipient); /* * Handle special case that is not supposed to happen. */ ! if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; *************** *** 904,910 **** /* * Skip source-routed mail (uncertain destination). */ ! if (var_allow_untrust_route == 0 && (reply.flags & RESOLVE_FLAG_ROUTED)) return (SMTPD_CHECK_DUNNO); /* --- 952,958 ---- /* * Skip source-routed mail (uncertain destination). */ ! if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED)) return (SMTPD_CHECK_DUNNO); /* *************** *** 963,969 **** /* has_my_addr - see if this host name lists one of my network addresses */ ! static int has_my_addr(char *host) { char *myname = "has_my_addr"; struct in_addr addr; --- 1011,1017 ---- /* has_my_addr - see if this host name lists one of my network addresses */ ! static int has_my_addr(const char *host) { char *myname = "has_my_addr"; struct in_addr addr; *************** *** 1007,1013 **** static int permit_mx_backup(SMTPD_STATE *state, const char *recipient) { char *myname = "permit_mx_backup"; ! char *domain; DNS_RR *mx_list; DNS_RR *mx; --- 1055,1062 ---- static int permit_mx_backup(SMTPD_STATE *state, const char *recipient) { char *myname = "permit_mx_backup"; ! const RESOLVE_REPLY *reply; ! const char *domain; DNS_RR *mx_list; DNS_RR *mx; *************** *** 1019,1033 **** /* * Resolve the address. */ ! canon_addr_internal(query, recipient); ! resolve_clnt_query(STR(query), &reply); ! lowercase(STR(reply.recipient)); /* * If the destination is local, it is acceptable, because we are * supposedly MX for our own address. */ ! if ((domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; if (resolve_local(domain) --- 1068,1081 ---- /* * Resolve the address. */ ! reply = (const RESOLVE_REPLY *) ! ctable_locate(smtpd_resolve_cache, recipient); /* * If the destination is local, it is acceptable, because we are * supposedly MX for our own address. */ ! if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; if (resolve_local(domain) *************** *** 1041,1047 **** /* * Skip source-routed mail (uncertain destination). */ ! if (var_allow_untrust_route == 0 && (reply.flags & RESOLVE_FLAG_ROUTED)) return (SMTPD_CHECK_DUNNO); /* --- 1089,1095 ---- /* * Skip source-routed mail (uncertain destination). */ ! if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED)) return (SMTPD_CHECK_DUNNO); /* *************** *** 1150,1160 **** /* reject_unknown_address - fail if address does not resolve */ ! static int reject_unknown_address(SMTPD_STATE *state, char *addr, ! char *reply_name, char *reply_class) { char *myname = "reject_unknown_address"; ! char *domain; if (msg_verbose) msg_info("%s: %s", myname, addr); --- 1198,1209 ---- /* reject_unknown_address - fail if address does not resolve */ ! static int reject_unknown_address(SMTPD_STATE *state, const char *addr, ! const char *reply_name, const char *reply_class) { char *myname = "reject_unknown_address"; ! const RESOLVE_REPLY *reply; ! const char *domain; if (msg_verbose) msg_info("%s: %s", myname, addr); *************** *** 1162,1175 **** /* * Resolve the address. */ ! canon_addr_internal(query, addr); ! resolve_clnt_query(STR(query), &reply); ! lowercase(STR(reply.recipient)); /* * Skip local destinations and non-DNS forms. */ ! if ((domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_DUNNO); domain += 1; if (resolve_local(domain) --- 1211,1222 ---- /* * Resolve the address. */ ! reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr); /* * Skip local destinations and non-DNS forms. */ ! if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) return (SMTPD_CHECK_DUNNO); domain += 1; if (resolve_local(domain) *************** *** 1189,1198 **** /* check_table_result - translate table lookup result into pass/reject */ ! static int check_table_result(SMTPD_STATE *state, char *table, const char *value, const char *datum, ! char *reply_name, char *reply_class, ! char *def_acl) { char *myname = "check_table_result"; int code; --- 1236,1246 ---- /* check_table_result - translate table lookup result into pass/reject */ ! static int check_table_result(SMTPD_STATE *state, const char *table, const char *value, const char *datum, ! const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "check_table_result"; int code; *************** *** 1287,1303 **** /* check_access - table lookup without substring magic */ ! static int check_access(SMTPD_STATE *state, char *table, char *name, int flags, ! char *reply_name, char *reply_class, char *def_acl) { char *myname = "check_access"; char *low_name = lowercase(mystrdup(name)); const char *value; DICT *dict; ! #define CHK_ACCESS_RETURN(x) { myfree(low_name); return(x); } #define FULL 0 #define PARTIAL DICT_FLAG_FIXED if (msg_verbose) msg_info("%s: %s", myname, name); --- 1335,1354 ---- /* check_access - table lookup without substring magic */ ! static int check_access(SMTPD_STATE *state, const char *table, const char *name, ! int flags, int *found, const char *reply_name, ! const char *reply_class, const char *def_acl) { char *myname = "check_access"; char *low_name = lowercase(mystrdup(name)); const char *value; DICT *dict; ! #define CHK_ACCESS_RETURN(x,y) { *found = y; myfree(low_name); return(x); } #define FULL 0 #define PARTIAL DICT_FLAG_FIXED + #define FOUND 1 + #define MISSED 0 if (msg_verbose) msg_info("%s: %s", myname, name); *************** *** 1308,1326 **** if ((value = dict_get(dict, low_name)) != 0) CHK_ACCESS_RETURN(check_table_result(state, table, value, name, reply_name, reply_class, ! def_acl)); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } ! CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO); } /* check_domain_access - domainname-based table lookup */ ! static int check_domain_access(SMTPD_STATE *state, char *table, ! char *domain, int flags, ! char *reply_name, char *reply_class, ! char *def_acl) { char *myname = "check_domain_access"; char *low_domain = lowercase(mystrdup(domain)); --- 1359,1378 ---- if ((value = dict_get(dict, low_name)) != 0) CHK_ACCESS_RETURN(check_table_result(state, table, value, name, reply_name, reply_class, ! def_acl), FOUND); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } ! CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO, MISSED); } /* check_domain_access - domainname-based table lookup */ ! static int check_domain_access(SMTPD_STATE *state, const char *table, ! const char *domain, int flags, ! int *found, const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "check_domain_access"; char *low_domain = lowercase(mystrdup(domain)); *************** *** 1335,1341 **** /* * Try the name and its parent domains. Including top-level domains. */ ! #define CHK_DOMAIN_RETURN(x) { myfree(low_domain); return(x); } if ((dict = dict_handle(table)) == 0) msg_panic("%s: dictionary not found: %s", myname, table); --- 1387,1393 ---- /* * Try the name and its parent domains. Including top-level domains. */ ! #define CHK_DOMAIN_RETURN(x,y) { *found = y; myfree(low_domain); return(x); } if ((dict = dict_handle(table)) == 0) msg_panic("%s: dictionary not found: %s", myname, table); *************** *** 1344,1350 **** if ((value = dict_get(dict, name)) != 0) CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain, reply_name, reply_class, ! def_acl)); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } --- 1396,1402 ---- if ((value = dict_get(dict, name)) != 0) CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain, reply_name, reply_class, ! def_acl), FOUND); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } *************** *** 1352,1366 **** break; flags = PARTIAL; } ! CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO); } /* check_addr_access - address-based table lookup */ ! static int check_addr_access(SMTPD_STATE *state, char *table, ! char *address, int flags, ! char *reply_name, char *reply_class, ! char *def_acl) { char *myname = "check_addr_access"; char *addr; --- 1404,1419 ---- break; flags = PARTIAL; } ! CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO, MISSED); } /* check_addr_access - address-based table lookup */ ! static int check_addr_access(SMTPD_STATE *state, const char *table, ! const char *address, int flags, ! int *found, const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "check_addr_access"; char *addr; *************** *** 1373,1378 **** --- 1426,1433 ---- /* * Try the address and its parent networks. */ + #define CHK_ADDR_RETURN(x,y) { *found = y; return(x); } + addr = STR(vstring_strcpy(error_text, address)); if ((dict = dict_handle(table)) == 0) *************** *** 1380,1403 **** do { if (flags == 0 || (flags & dict->flags) != 0) { if ((value = dict_get(dict, addr)) != 0) ! return (check_table_result(state, table, value, address, ! reply_name, reply_class, ! def_acl)); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } flags = PARTIAL; } while (split_at_right(addr, '.')); ! return (SMTPD_CHECK_DUNNO); } /* check_namadr_access - OK/FAIL based on host name/address lookup */ ! static int check_namadr_access(SMTPD_STATE *state, char *table, ! char *name, char *addr, int flags, ! char *reply_name, char *reply_class, ! char *def_acl) { char *myname = "check_namadr_access"; int status; --- 1435,1460 ---- do { if (flags == 0 || (flags & dict->flags) != 0) { if ((value = dict_get(dict, addr)) != 0) ! CHK_ADDR_RETURN(check_table_result(state, table, value, address, ! reply_name, reply_class, ! def_acl), FOUND); if (dict_errno != 0) msg_fatal("%s: table lookup problem", table); } flags = PARTIAL; } while (split_at_right(addr, '.')); ! CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO, MISSED); } /* check_namadr_access - OK/FAIL based on host name/address lookup */ ! static int check_namadr_access(SMTPD_STATE *state, const char *table, ! const char *name, const char *addr, ! int flags, int *found, ! const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "check_namadr_access"; int status; *************** *** 1410,1425 **** * wildcard may pre-empt a more specific address table entry. */ if ((status = check_domain_access(state, table, name, flags, ! reply_name, reply_class, ! def_acl)) != 0) return (status); /* * Look up the network address, or parent networks thereof. */ if ((status = check_addr_access(state, table, addr, flags, ! reply_name, reply_class, ! def_acl)) != 0) return (status); /* --- 1467,1482 ---- * wildcard may pre-empt a more specific address table entry. */ if ((status = check_domain_access(state, table, name, flags, ! found, reply_name, reply_class, ! def_acl)) != 0 || *found) return (status); /* * Look up the network address, or parent networks thereof. */ if ((status = check_addr_access(state, table, addr, flags, ! found, reply_name, reply_class, ! def_acl)) != 0 || *found) return (status); /* *************** *** 1430,1441 **** /* check_mail_access - OK/FAIL based on mail address lookup */ ! static int check_mail_access(SMTPD_STATE *state, char *table, char *addr, ! char *reply_name, char *reply_class, ! char *def_acl) { char *myname = "check_mail_access"; ! char *ratsign; int status; char *local_at; --- 1487,1501 ---- /* check_mail_access - OK/FAIL based on mail address lookup */ ! static int check_mail_access(SMTPD_STATE *state, const char *table, ! const char *addr, int *found, ! const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "check_mail_access"; ! const RESOLVE_REPLY *reply; ! const char *ratsign; int status; char *local_at; *************** *** 1445,1486 **** /* * Resolve the address. */ ! canon_addr_internal(query, addr); ! resolve_clnt_query(STR(query), &reply); ! lowercase(STR(reply.recipient)); /* * Garbage in, garbage out. Every address from canon_addr_internal() and * from resolve_clnt_query() must be fully qualified. */ ! if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) { ! msg_warn("%s: no @domain in address: %s", myname, STR(reply.recipient)); return (0); } /* * Look up the full address. */ ! if ((status = check_access(state, table, STR(reply.recipient), FULL, ! reply_name, reply_class, def_acl)) != 0) return (status); /* * Look up the domain name, or parent domains thereof. */ if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL, ! reply_name, reply_class, def_acl)) != 0) return (status); /* * Look up localpart@ */ ! local_at = mystrndup(STR(reply.recipient), ! ratsign - STR(reply.recipient) + 1); ! status = check_access(state, table, local_at, PARTIAL, reply_name, reply_class, def_acl); myfree(local_at); ! if (status != 0) return (status); /* --- 1505,1546 ---- /* * Resolve the address. */ ! reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr); /* * Garbage in, garbage out. Every address from canon_addr_internal() and * from resolve_clnt_query() must be fully qualified. */ ! if ((ratsign = strrchr(CONST_STR(reply->recipient), '@')) == 0) { ! msg_warn("%s: no @domain in address: %s", myname, CONST_STR(reply->recipient)); return (0); } /* * Look up the full address. */ ! if ((status = check_access(state, table, CONST_STR(reply->recipient), FULL, ! found, reply_name, reply_class, def_acl)) != 0 ! || *found) return (status); /* * Look up the domain name, or parent domains thereof. */ if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL, ! found, reply_name, reply_class, def_acl)) != 0 ! || *found) return (status); /* * Look up localpart@ */ ! local_at = mystrndup(CONST_STR(reply->recipient), ! ratsign - CONST_STR(reply->recipient) + 1); ! status = check_access(state, table, local_at, PARTIAL, found, reply_name, reply_class, def_acl); myfree(local_at); ! if (status != 0 || *found) return (status); /* *************** *** 1573,1579 **** /* is_map_command - restriction has form: check_xxx_access type:name */ ! static int is_map_command(char *name, char *command, char ***argp) { /* --- 1633,1639 ---- /* is_map_command - restriction has form: check_xxx_access type:name */ ! static int is_map_command(const char *name, const char *command, char ***argp) { /* *************** *** 1596,1608 **** /* generic_checks - generic restrictions */ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, ! char *reply_name, char *reply_class, char *def_acl) { char *myname = "generic_checks"; char **cpp; ! char *name; int status = 0; ARGV *list; if (msg_verbose) msg_info("%s: START", myname); --- 1656,1671 ---- /* generic_checks - generic restrictions */ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, ! const char *reply_name, ! const char *reply_class, ! const char *def_acl) { char *myname = "generic_checks"; char **cpp; ! const char *name; int status = 0; ARGV *list; + int found; if (msg_verbose) msg_info("%s: START", myname); *************** *** 1649,1655 **** status = permit_mynetworks(state); } else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) { status = check_namadr_access(state, *cpp, state->name, state->addr, ! FULL, state->namaddr, SMTPD_NAME_CLIENT, def_acl); } else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) { status = reject_maps_rbl(state); --- 1712,1718 ---- status = permit_mynetworks(state); } else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) { status = check_namadr_access(state, *cpp, state->name, state->addr, ! FULL, &found, state->namaddr, SMTPD_NAME_CLIENT, def_acl); } else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) { status = reject_maps_rbl(state); *************** *** 1661,1667 **** else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) { if (state->helo_name) status = check_domain_access(state, *cpp, state->helo_name, ! FULL, state->helo_name, SMTPD_NAME_HELO, def_acl); } else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) { if (state->helo_name) { --- 1724,1730 ---- else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) { if (state->helo_name) status = check_domain_access(state, *cpp, state->helo_name, ! FULL, &found, state->helo_name, SMTPD_NAME_HELO, def_acl); } else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) { if (state->helo_name) { *************** *** 1705,1711 **** else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) { if (state->sender && *state->sender) status = check_mail_access(state, *cpp, state->sender, ! state->sender, SMTPD_NAME_SENDER, def_acl); } else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) { if (state->sender && *state->sender) --- 1768,1774 ---- else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) { if (state->sender && *state->sender) status = check_mail_access(state, *cpp, state->sender, ! &found, state->sender, SMTPD_NAME_SENDER, def_acl); } else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) { if (state->sender && *state->sender) *************** *** 1727,1733 **** else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) { if (state->recipient) status = check_mail_access(state, *cpp, state->recipient, ! state->recipient, SMTPD_NAME_RECIPIENT, def_acl); } else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) { if (state->recipient) --- 1790,1796 ---- else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) { if (state->recipient) status = check_mail_access(state, *cpp, state->recipient, ! &found, state->recipient, SMTPD_NAME_RECIPIENT, def_acl); } else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) { if (state->recipient) *************** *** 1767,1773 **** else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) { if (state->etrn_name) status = check_domain_access(state, *cpp, state->etrn_name, ! FULL, state->etrn_name, SMTPD_NAME_ETRN, def_acl); } --- 1830,1836 ---- else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) { if (state->etrn_name) status = check_domain_access(state, *cpp, state->etrn_name, ! FULL, &found, state->etrn_name, SMTPD_NAME_ETRN, def_acl); } *************** *** 2002,2008 **** { char *myname = "smtpd_check_rcptmap"; char *saved_recipient; ! char *domain; int status; /* --- 2065,2072 ---- { char *myname = "smtpd_check_rcptmap"; char *saved_recipient; ! const RESOLVE_REPLY *reply; ! const char *domain; int status; /* *************** *** 2029,2042 **** /* * Resolve the address. */ ! canon_addr_internal(query, recipient); ! resolve_clnt_query(STR(query), &reply); ! lowercase(STR(reply.recipient)); /* * Skip non-DNS forms. Skip non-local numerical forms. */ ! if ((domain = strrchr(STR(reply.recipient), '@')) == 0) SMTPD_CHECK_RCPT_RETURN(0); domain += 1; if (domain[0] == '#' || domain[0] == '[') --- 2093,2105 ---- /* * Resolve the address. */ ! reply = (const RESOLVE_REPLY *) ! ctable_locate(smtpd_resolve_cache, recipient); /* * Skip non-DNS forms. Skip non-local numerical forms. */ ! if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) SMTPD_CHECK_RCPT_RETURN(0); domain += 1; if (domain[0] == '#' || domain[0] == '[') *************** *** 2051,2060 **** */ if (*var_virtual_maps && (check_maps_find(state, recipient, virtual_maps, domain, 0))) { ! if (NOMATCH(rcpt_canon_maps, STR(reply.recipient)) ! && NOMATCH(canonical_maps, STR(reply.recipient)) ! && NOMATCH(relocated_maps, STR(reply.recipient)) ! && NOMATCH(virtual_maps, STR(reply.recipient))) { (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE, "%d <%s>: User unknown", 550, recipient); SMTPD_CHECK_RCPT_RETURN(STR(error_text)); --- 2114,2123 ---- */ if (*var_virtual_maps && (check_maps_find(state, recipient, virtual_maps, domain, 0))) { ! if (NOMATCH(rcpt_canon_maps, CONST_STR(reply->recipient)) ! && NOMATCH(canonical_maps, CONST_STR(reply->recipient)) ! && NOMATCH(relocated_maps, CONST_STR(reply->recipient)) ! && NOMATCH(virtual_maps, CONST_STR(reply->recipient))) { (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE, "%d <%s>: User unknown", 550, recipient); SMTPD_CHECK_RCPT_RETURN(STR(error_text)); *************** *** 2067,2077 **** * Sendmail-style virtual domains. */ if (*var_local_rcpt_maps && resolve_local(domain)) { ! if (NOMATCH(rcpt_canon_maps, STR(reply.recipient)) ! && NOMATCH(canonical_maps, STR(reply.recipient)) ! && NOMATCH(relocated_maps, STR(reply.recipient)) ! && NOMATCH(virtual_maps, STR(reply.recipient)) ! && NOMATCH(local_rcpt_maps, STR(reply.recipient))) { (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE, "%d <%s>: User unknown", 550, recipient); SMTPD_CHECK_RCPT_RETURN(STR(error_text)); --- 2130,2140 ---- * Sendmail-style virtual domains. */ if (*var_local_rcpt_maps && resolve_local(domain)) { ! if (NOMATCH(rcpt_canon_maps, CONST_STR(reply->recipient)) ! && NOMATCH(canonical_maps, CONST_STR(reply->recipient)) ! && NOMATCH(relocated_maps, CONST_STR(reply->recipient)) ! && NOMATCH(virtual_maps, CONST_STR(reply->recipient)) ! && NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient))) { (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE, "%d <%s>: User unknown", 550, recipient); SMTPD_CHECK_RCPT_RETURN(STR(error_text)); *************** *** 2336,2346 **** --- 2399,2417 ---- void resolve_clnt_init(RESOLVE_REPLY *reply) { + reply->flags = 0; reply->transport = vstring_alloc(100); reply->nexthop = vstring_alloc(100); reply->recipient = vstring_alloc(100); } + void resolve_clnt_free(RESOLVE_REPLY *reply) + { + vstring_free(reply->transport); + vstring_free(reply->nexthop); + vstring_free(reply->recipient); + } + #ifdef USE_SASL_AUTH bool var_smtpd_sasl_enable = 0; *************** *** 2383,2389 **** void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) { ! if (addr == STR(reply->recipient)) msg_panic("resolve_clnt_query: result clobbers input"); vstring_strcpy(reply->transport, "foo"); vstring_strcpy(reply->nexthop, "foo"); --- 2454,2460 ---- void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) { ! if (addr == CONST_STR(reply->recipient)) msg_panic("resolve_clnt_query: result clobbers input"); vstring_strcpy(reply->transport, "foo"); vstring_strcpy(reply->nexthop, "foo"); *************** *** 2405,2411 **** msg_fatal("usage: %s", myname); } ! main(int argc, char **argv) { VSTRING *buf = vstring_alloc(100); SMTPD_STATE state; --- 2476,2482 ---- msg_fatal("usage: %s", myname); } ! int main(int argc, char **argv) { VSTRING *buf = vstring_alloc(100); SMTPD_STATE state; diff -cr --new-file ../postfix-20010228-pl03/src/smtpd/smtpd_check_access ./src/smtpd/smtpd_check_access *** ../postfix-20010228-pl03/src/smtpd/smtpd_check_access Sat Nov 20 20:08:31 1999 --- ./src/smtpd/smtpd_check_access Mon Jul 30 18:37:01 2001 *************** *** 2,10 **** --- 2,31 ---- 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 -cr --new-file ../postfix-20010228-pl03/src/util/Makefile.in ./src/util/Makefile.in *** ../postfix-20010228-pl03/src/util/Makefile.in Fri Apr 27 15:14:30 2001 --- ./src/util/Makefile.in Tue Jul 31 14:26:11 2001 *************** *** 23,29 **** clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \ sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \ hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \ ! sane_socketpair.c OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \ dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \ --- 23,29 ---- clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \ sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \ hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \ ! sane_socketpair.c ctable.c OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \ dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \ *************** *** 48,54 **** clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \ sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \ hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \ ! sane_socketpair.o HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \ dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \ --- 48,54 ---- clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \ sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \ hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \ ! sane_socketpair.o ctable.o HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \ dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \ *************** *** 64,70 **** vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \ watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \ ! sane_time.h sane_socketpair.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ --- 64,70 ---- vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \ watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \ ! sane_time.h sane_socketpair.h ctable.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ *************** *** 80,86 **** inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \ mystrtok sigdelay translit valid_hostname vstream_popen \ vstring vstring_vstream doze select_bug stream_test mac_expand \ ! watchdog unescape hex_quote name_mask rand_sleep sane_time LIB_DIR = ../../lib INC_DIR = ../../include --- 80,87 ---- inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \ mystrtok sigdelay translit valid_hostname vstream_popen \ vstring vstring_vstream doze select_bug stream_test mac_expand \ ! watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \ ! inet_addr_list LIB_DIR = ../../lib INC_DIR = ../../include *************** *** 274,279 **** --- 275,290 ---- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o + ctable: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + + inet_addr_list: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ *************** *** 286,292 **** $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) tests: valid_hostname_test mac_expand_test dict_test unescape_test \ ! hex_quote_test valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref ./valid_hostname valid_hostname.tmp --- 297,303 ---- $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) tests: valid_hostname_test mac_expand_test dict_test unescape_test \ ! hex_quote_test ctable_test inet_addr_list_test valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref ./valid_hostname valid_hostname.tmp *************** *** 309,314 **** --- 320,335 ---- cmp hex_quote.ref hex_quote.tmp rm -f hex_quote.ref hex_quote.tmp + ctable_test: ctable + ./ctable ctable.tmp 2>&1 + diff ctable.ref ctable.tmp + rm -f ctable.tmp + + inet_addr_list_test: inet_addr_list + ./inet_addr_list `cat inet_addr_list.in` >inet_addr_list.tmp 2>&1 + diff inet_addr_list.ref inet_addr_list.tmp + rm -f inet_addr_list.tmp + DB_TYPE = `../postconf/postconf -h default_database_type` dict_test: dict_open testdb dict_test.in dict_test.ref *************** *** 368,373 **** --- 389,401 ---- concatenate.o: stringops.h concatenate.o: vstring.h concatenate.o: vbuf.h + ctable.o: ctable.c + ctable.o: sys_defs.h + ctable.o: msg.h + ctable.o: mymalloc.h + ctable.o: ring.h + ctable.o: htable.h + ctable.o: ctable.h dict.o: dict.c dict.o: sys_defs.h dict.o: msg.h diff -cr --new-file ../postfix-20010228-pl03/src/util/ctable.c ./src/util/ctable.c *** ../postfix-20010228-pl03/src/util/ctable.c Wed Dec 31 19:00:00 1969 --- ./src/util/ctable.c Sun Jul 29 17:23:01 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/util/ctable.h ./src/util/ctable.h *** ../postfix-20010228-pl03/src/util/ctable.h Wed Dec 31 19:00:00 1969 --- ./src/util/ctable.h Sun Jul 29 14:31:44 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/util/ctable.in ./src/util/ctable.in *** ../postfix-20010228-pl03/src/util/ctable.in Wed Dec 31 19:00:00 1969 --- ./src/util/ctable.in Sun Jul 29 12:15:18 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/util/ctable.ref ./src/util/ctable.ref *** ../postfix-20010228-pl03/src/util/ctable.ref Wed Dec 31 19:00:00 1969 --- ./src/util/ctable.ref Sun Jul 29 12:15:20 2001 *************** *** 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 = diff -cr --new-file ../postfix-20010228-pl03/src/util/dict_ldap.c ./src/util/dict_ldap.c *** ../postfix-20010228-pl03/src/util/dict_ldap.c Thu May 24 15:36:42 2001 --- ./src/util/dict_ldap.c Tue Jul 17 15:56:27 2001 *************** *** 151,156 **** --- 151,160 ---- 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,168 **** msg_info("%s: Connecting to server %s", myname, dict_ldap->server_host); ! #ifdef UNTESTED_LDAP_OPT_NETWORK_TIMEOUT dict_ldap->ld = ldap_init(dict_ldap->server_host, (int) dict_ldap->server_port); if (dict_ldap->ld == NULL) { --- 166,172 ---- msg_info("%s: Connecting to server %s", myname, dict_ldap->server_host); ! #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,252 **** --- 251,277 ---- 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,263 **** --- 283,290 ---- 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,321 **** 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); break; } } --- 342,348 ---- if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0) { if (msg_verbose) ! msg_info("%s: search returned %d value(s) for requested result attribute %s", myname, i, attr); break; } } *************** *** 390,396 **** * load on the LDAP server. */ if (dict_ldap->domain) { ! char *p=strrchr(name,'@'); if (p != 0) p=p+1; else --- 417,423 ---- * load on the LDAP server. */ if (dict_ldap->domain) { ! const char *p=strrchr(name,'@'); if (p != 0) p=p+1; else *************** *** 482,488 **** /* * Does the supplied query_filter even include a substitution? */ ! if ((char *) strstr(dict_ldap->query_filter, "%s") == NULL) { /* * No, log the fact and continue. --- 509,515 ---- /* * Does the supplied query_filter even include a substitution? */ ! if ((char *) strchr(dict_ldap->query_filter, '%') == NULL) { /* * No, log the fact and continue. *************** *** 494,514 **** /* * Yes, replace all instances of %s with the address to look up. */ 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. */ 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)); sub++; } else vstring_strncat(filter_buf, sub, 1); --- 521,560 ---- /* * 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 %[sud] and not something else. For backward ! * compatibilty, treat anything other than %u or %d as %s, with ! * a warning. */ if (*(sub) == '%') { ! 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,613 **** myfree(dict_ldap->ldapsource); myfree(dict_ldap->server_host); myfree(dict_ldap->search_base); ! match_list_free(dict_ldap->domain); myfree(dict_ldap->query_filter); argv_free(dict_ldap->result_attributes); myfree(dict_ldap->bind_dn); --- 653,660 ---- myfree(dict_ldap->ldapsource); myfree(dict_ldap->server_host); myfree(dict_ldap->search_base); ! 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,639 **** char *scope; char *attr; 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); --- 673,686 ---- 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; dict_ldap->ldapsource = mystrdup(ldapsource); diff -cr --new-file ../postfix-20010228-pl03/src/util/dict_pcre.c ./src/util/dict_pcre.c *** ../postfix-20010228-pl03/src/util/dict_pcre.c Sun Feb 4 13:09:48 2001 --- ./src/util/dict_pcre.c Mon Jul 30 13:51:56 2001 *************** *** 266,271 **** --- 266,272 ---- continue; p = vstring_str(line_buffer); + trimblanks(p, 0)[0] = 0; /* Trim space at end */ re_delimiter = *p++; regexp = p; diff -cr --new-file ../postfix-20010228-pl03/src/util/dict_regexp.c ./src/util/dict_regexp.c *** ../postfix-20010228-pl03/src/util/dict_regexp.c Sun Feb 4 13:09:52 2001 --- ./src/util/dict_regexp.c Mon Jul 30 13:51:15 2001 *************** *** 365,370 **** --- 365,372 ---- 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 -cr --new-file ../postfix-20010228-pl03/src/util/inet_addr_list.c ./src/util/inet_addr_list.c *** ../postfix-20010228-pl03/src/util/inet_addr_list.c Mon Nov 20 13:06:30 2000 --- ./src/util/inet_addr_list.c Tue Jul 31 14:13:41 2001 *************** *** 13,18 **** --- 13,21 ---- /* INET_ADDR_LIST *list; /* struct in_addr *addr; /* + /* void inet_addr_list_uniq(list) + /* INET_ADDR_LIST *list; + /* /* void inet_addr_list_free(list) /* INET_ADDR_LIST *list; /* DESCRIPTION *************** *** 25,30 **** --- 28,36 ---- /* inet_addr_list_append() appends the specified address to /* the specified list, extending the list on the fly. /* + /* inet_addr_list_uniq() sorts the specified address list and + /* eliminates duplicates. + /* /* inet_addr_list_free() reclaims memory used for the /* specified address list. /* LICENSE *************** *** 43,48 **** --- 49,55 ---- #include #include #include + #include /* Utility library. */ *************** *** 77,85 **** --- 84,164 ---- list->addrs[list->used++] = *addr; } + /* inet_addr_list_comp - compare addresses */ + + static int inet_addr_list_comp(const void *a, const void *b) + { + const struct in_addr *a_addr = (const struct in_addr *) a; + const struct in_addr *b_addr = (const struct in_addr *) b; + + return (a_addr->s_addr - b_addr->s_addr); + } + + /* inet_addr_list_uniq - weed out duplicates */ + + void inet_addr_list_uniq(INET_ADDR_LIST *list) + { + int n; + int m; + + /* + * Put the identical members right next to each other. + */ + qsort((void *) list->addrs, list->used, + sizeof(list->addrs[0]), inet_addr_list_comp); + + /* + * Nuke the duplicates. Postcondition after while loop: m is the largest + * index for which list->addrs[n] == list->addrs[m]. + */ + for (m = n = 0; m < list->used; m++, n++) { + if (m != n) + list->addrs[n] = list->addrs[m]; + while (m + 1 < list->used + && inet_addr_list_comp((void *) &(list->addrs[n]), + (void *) &(list->addrs[m + 1])) == 0) + m += 1; + } + list->used = n; + } + /* inet_addr_list_free - destroy internet address list */ void inet_addr_list_free(INET_ADDR_LIST *list) { myfree((char *) list->addrs); } + + #ifdef TEST + + /* + * Duplicate elimination needs to be tested. + */ + #include + + static void inet_addr_list_print(INET_ADDR_LIST *list) + { + int n; + + for (n = 0; n < list->used; n++) + msg_info("%s", inet_ntoa(list->addrs[n])); + } + + int main(int argc, char **argv) + { + INET_ADDR_LIST list; + + inet_addr_list_init(&list); + while (--argc && *++argv) + if (inet_addr_host(&list, *argv) == 0) + msg_fatal("host not found: %s", *argv); + msg_info("list before sort/uniq"); + inet_addr_list_print(&list); + inet_addr_list_uniq(&list); + msg_info("list after sort/uniq"); + inet_addr_list_print(&list); + inet_addr_list_free(&list); + return (0); + } + + #endif diff -cr --new-file ../postfix-20010228-pl03/src/util/inet_addr_list.h ./src/util/inet_addr_list.h *** ../postfix-20010228-pl03/src/util/inet_addr_list.h Fri Dec 11 13:55:35 1998 --- ./src/util/inet_addr_list.h Tue Jul 31 13:56:47 2001 *************** *** 27,32 **** --- 27,33 ---- extern void inet_addr_list_init(INET_ADDR_LIST *); extern void inet_addr_list_free(INET_ADDR_LIST *); + extern void inet_addr_list_uniq(INET_ADDR_LIST *); extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *); /* LICENSE diff -cr --new-file ../postfix-20010228-pl03/src/util/inet_addr_list.in ./src/util/inet_addr_list.in *** ../postfix-20010228-pl03/src/util/inet_addr_list.in Wed Dec 31 19:00:00 1969 --- ./src/util/inet_addr_list.in Tue Jul 31 13:55:21 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/util/inet_addr_list.ref ./src/util/inet_addr_list.ref *** ../postfix-20010228-pl03/src/util/inet_addr_list.ref Wed Dec 31 19:00:00 1969 --- ./src/util/inet_addr_list.ref Tue Jul 31 13:59:49 2001 *************** *** 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 -cr --new-file ../postfix-20010228-pl03/src/util/ring.h ./src/util/ring.h *** ../postfix-20010228-pl03/src/util/ring.h Fri Dec 11 13:55:30 1998 --- ./src/util/ring.h Sun Jul 29 11:35:58 2001 *************** *** 29,34 **** --- 29,45 ---- #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