From 702954b400e93eb862244b238f506d5e1bcd0cc0 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sat, 27 Mar 1999 00:00:00 -0500 Subject: [PATCH] snapshot-19990327 --- postfix/.indent.pro | 2 + postfix/HISTORY | 23 +- postfix/bounce/.indent.pro | 2 + postfix/cleanup/.indent.pro | 2 + postfix/conf/sample-regexp.cf | 17 ++ postfix/dns/.indent.pro | 2 + postfix/fsstone/.indent.pro | 2 + postfix/global/.indent.pro | 2 + postfix/global/mail_copy.c | 2 +- postfix/global/mail_version.h | 2 +- postfix/global/maps.c | 2 +- postfix/global/mkmap.h | 9 +- postfix/global/mkmap_db.c | 2 +- postfix/global/mkmap_open.c | 12 +- postfix/local/.indent.pro | 2 + postfix/local/dotforward.c | 3 + postfix/local/recipient.c | 2 +- postfix/master/.indent.pro | 2 + postfix/pickup/.indent.pro | 2 + postfix/pipe/.indent.pro | 2 + postfix/postalias/.indent.pro | 2 + postfix/postalias/Makefile.in | 1 + postfix/postalias/postalias.c | 31 ++- postfix/postcat/.indent.pro | 2 + postfix/postconf/.indent.pro | 2 + postfix/postdrop/.indent.pro | 2 + postfix/postfix/.indent.pro | 2 + postfix/postkick/.indent.pro | 2 + postfix/postlock/.indent.pro | 2 + postfix/postlog/.indent.pro | 2 + postfix/postmap/.indent.pro | 2 + postfix/postmap/Makefile.in | 1 + postfix/postmap/postmap.c | 30 +- postfix/postsuper/.indent.pro | 2 + postfix/qmgr/.indent.pro | 2 + postfix/sendmail/.indent.pro | 2 + postfix/showq/.indent.pro | 2 + postfix/smtp/.indent.pro | 2 + postfix/smtpd/.indent.pro | 2 + postfix/smtpd/smtpd_check.c | 2 +- postfix/smtpstone/.indent.pro | 2 + postfix/trivial-rewrite/.indent.pro | 2 + postfix/util/.indent.pro | 2 + postfix/util/Makefile.in | 21 +- postfix/util/dict.h | 6 +- postfix/util/dict_db.c | 52 ++-- postfix/util/dict_db.h | 4 +- postfix/util/dict_dbm.c | 36 ++- postfix/util/dict_dbm.h | 2 +- postfix/util/dict_env.c | 10 +- postfix/util/dict_env.h | 2 +- postfix/util/dict_ldap.c | 6 +- postfix/util/dict_ldap.h | 2 +- postfix/util/dict_ni.c | 194 ++++++++++++- postfix/util/dict_ni.h | 32 ++- postfix/util/dict_nis.c | 20 +- postfix/util/dict_nis.h | 2 +- postfix/util/dict_nisplus.c | 6 +- postfix/util/dict_nisplus.h | 2 +- postfix/util/dict_open.c | 51 ++-- postfix/util/dict_pcre.c | 23 +- postfix/util/dict_pcre.h | 2 +- postfix/util/dict_regexp.c | 408 ++++++++++++++++++++++++++++ postfix/util/dict_regexp.h | 40 +++ postfix/util/dict_unix.c | 6 +- postfix/util/dict_unix.h | 2 +- postfix/util/environ.c | 154 ++++++++++- postfix/util/match_list.c | 2 +- postfix/util/posix_signals.c | 127 ++++++++- postfix/util/posix_signals.h | 60 +++- postfix/util/sys_defs.h | 2 + 71 files changed, 1304 insertions(+), 165 deletions(-) create mode 100644 postfix/conf/sample-regexp.cf create mode 100644 postfix/util/dict_regexp.c create mode 100644 postfix/util/dict_regexp.h diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/HISTORY b/postfix/HISTORY index 4bcd7e032..cf850012d 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -2429,7 +2429,8 @@ Apologies for any names omitted. Workaround: Solaris NIS alias maps need special entries (YP_MASTER_NAME, YP_LAST_MODIFIED). What's worse, normal keys/values include a null byte at the end, but the YP_XXX - ones don't. File: postalias/postalias.c. + ones don't. Problem reported by Walcir Fontanini, state + university of Campinas, Brazil. File: postalias/postalias.c. Compatibility: Solaris NIS apparently does include a null byte at the end of keys and values. File: util/sys_defs.h. @@ -2442,6 +2443,26 @@ Apologies for any names omitted. Bugfix: pcre didn't handle \\ right. Lamont Jones, Hewlett- Packard. File: util/dict_pcre.c. +19990326 + + Compatibility: Postfix now puts to spaces after the sender + in a "From sender date..." header. Found by John A. Martin, + fixed by Lamont Jones, Hewlett-Packard. + + Bugfix: when a recipient appeared multiple times in a local + alias or include expansion, the delivery status could be + left uninitialized, causing the mail to be deferred and + delivered again. File: local/recipient.c. + +19990327 + + Cleanup: the dictionary routines now take an extra flag + argument to control such things as warning about duplicates, + and appending null bytes to key/value. This was needed for + a clean implementation of NIS master alias maps support. + + Feature: POSIX regular expressions by Lamont Jones. + Future: Planned: must be able to list the same hash table in diff --git a/postfix/bounce/.indent.pro b/postfix/bounce/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/bounce/.indent.pro +++ b/postfix/bounce/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/cleanup/.indent.pro b/postfix/cleanup/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/cleanup/.indent.pro +++ b/postfix/cleanup/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/conf/sample-regexp.cf b/postfix/conf/sample-regexp.cf new file mode 100644 index 000000000..263c5509a --- /dev/null +++ b/postfix/conf/sample-regexp.cf @@ -0,0 +1,17 @@ +# Sample regexp lookup "table". +# +# Format is /regexp/flags or /regexp/flags!/regexp/flags +# where regexp is a regular expression as found in regexp(5), and flags are +# i: toggle ignore case (REG_ICASE - default is to ignore case) +# x: toggle extended expression (REG_EXTENDED - default is extended) +# m: toggle multiline mode (REG_NEWLINE - default is non-multiline mode) +# +# In order for a line to match, the first regexp must match, and the +# second (if present) must not match. The first matching line wins, +# terminating processing of the ruleset. + +# Postmaster is OK, that way they can talk to us about how to fix their problem. +/^postmaster@.*$/ OK + +# Protect your outgoing majordomo exploders +/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead diff --git a/postfix/dns/.indent.pro b/postfix/dns/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/dns/.indent.pro +++ b/postfix/dns/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/fsstone/.indent.pro b/postfix/fsstone/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/fsstone/.indent.pro +++ b/postfix/fsstone/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/global/.indent.pro b/postfix/global/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/global/.indent.pro +++ b/postfix/global/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/global/mail_copy.c b/postfix/global/mail_copy.c index 6e58bf046..4116270d4 100644 --- a/postfix/global/mail_copy.c +++ b/postfix/global/mail_copy.c @@ -131,7 +131,7 @@ int mail_copy(const char *sender, const char *delivered, quote_822_local(buf, sender); if (flags & MAIL_COPY_FROM) { time(&now); - vstream_fprintf(dst, "From %s %s", *sender == 0 ? + vstream_fprintf(dst, "From %s %s", *sender == 0 ? MAIL_ADDR_MAIL_DAEMON : vstring_str(buf), asctime(localtime(&now))); diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index e40ca1fb8..49562d6a8 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-19990325" +#define DEF_MAIL_VERSION "Snapshot-19990327" extern char *var_mail_version; /* LICENSE diff --git a/postfix/global/maps.c b/postfix/global/maps.c index 148ce8e56..13b9280e5 100644 --- a/postfix/global/maps.c +++ b/postfix/global/maps.c @@ -121,7 +121,7 @@ MAPS *maps_create(const char *title, const char *map_names) if (msg_verbose) msg_info("%s: %s", myname, map_type_name); if ((dict = dict_handle(map_type_name)) == 0) - dict = dict_open(map_type_name, O_RDONLY); + dict = dict_open(map_type_name, O_RDONLY, 0); dict_register(map_type_name, dict); argv_add(maps->argv, map_type_name, ARGV_END); } diff --git a/postfix/global/mkmap.h b/postfix/global/mkmap.h index d004d2faf..86384575b 100644 --- a/postfix/global/mkmap.h +++ b/postfix/global/mkmap.h @@ -11,18 +11,23 @@ /* DESCRIPTION /* .nf + /* + * Utility library. + */ +#include + /* * A database handle is an opaque structure. The user is not supposed to * know its implementation. */ typedef struct MKMAP { - struct DICT *(*open) (const char *, int); + struct DICT *(*open) (const char *, int, int); struct DICT *dict; char *lock_file; int lock_fd; } MKMAP; -extern MKMAP *mkmap_open(const char *, const char *, int); +extern MKMAP *mkmap_open(const char *, const char *, int, int); extern void mkmap_append(MKMAP *, const char *, const char *); extern void mkmap_close(MKMAP *); diff --git a/postfix/global/mkmap_db.c b/postfix/global/mkmap_db.c index cc9eff87a..d89c3b5e6 100644 --- a/postfix/global/mkmap_db.c +++ b/postfix/global/mkmap_db.c @@ -59,7 +59,7 @@ /* mkmap_db_open - create or open database */ static MKMAP *mkmap_db_open(const char *path, - DICT *(*db_open) (const char *, int)) + DICT *(*db_open) (const char *, int, int)) { MKMAP *mkmap = (MKMAP *) mymalloc(sizeof(*mkmap)); diff --git a/postfix/global/mkmap_open.c b/postfix/global/mkmap_open.c index 530653d54..899c0b65a 100644 --- a/postfix/global/mkmap_open.c +++ b/postfix/global/mkmap_open.c @@ -6,10 +6,11 @@ /* SYNOPSIS /* #include /* -/* MKMAP *mkmap_open(type, path, flags) +/* MKMAP *mkmap_open(type, path, open_flags, dict_flags) /* char *type; /* char *path; -/* int flags; +/* int open_flags; +/* int dict_flags; /* /* void mkmap_append(mkmap, key, value, lineno) /* MKMAP *mkmap; @@ -26,11 +27,13 @@ /* appending the appropriate suffixes to the specified filename. /* Before the database is updated, it is locked for exclusive /* access, and signal delivery is suspended. +/* See dict(3) for a description of \fBopen_flags\fR and \fBdict_flags\fR. /* All errors are fatal. /* /* mkmap_append() appends the named (key, value) pair to the /* database. Update errors are fatal; duplicate keys are ignored /* (but a warning is issued). +/* \fBlineno\fR is used for diagnostics. /* /* mkmap_close() closes the database, releases any locks, /* and resumes signal delivery. All errors are fatal. @@ -118,7 +121,8 @@ void mkmap_close(MKMAP *mkmap) /* mkmap_open - create or truncate database */ -MKMAP *mkmap_open(const char *type, const char *path, int flags) +MKMAP *mkmap_open(const char *type, const char *path, + int open_flags, int dict_flags) { MKMAP *mkmap; MKMAP_OPEN_INFO *mp; @@ -157,7 +161,7 @@ MKMAP *mkmap_open(const char *type, const char *path, int flags) * Truncate the database upon open, and update it. Read-write mode is * needed because the underlying routines read as well as write. */ - mkmap->dict = mkmap->open(path, flags); + mkmap->dict = mkmap->open(path, open_flags, dict_flags); mkmap->dict->fd = -1; /* XXX just in case */ mkmap->dict->flags |= DICT_FLAG_DUP_WARN; return (mkmap); diff --git a/postfix/local/.indent.pro b/postfix/local/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/local/.indent.pro +++ b/postfix/local/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/local/dotforward.c b/postfix/local/dotforward.c index 35cb9e2ea..9eea11caf 100644 --- a/postfix/local/dotforward.c +++ b/postfix/local/dotforward.c @@ -102,6 +102,9 @@ static void dotforward_parse_callback(int type, VSTRING *buf, char *context) FW_CONTEXT *fw_context = (FW_CONTEXT *) context; char *ptr; + if (fw_context->failures) + return; + /* * Find out what data to substitute. */ diff --git a/postfix/local/recipient.c b/postfix/local/recipient.c index fd09619c8..36452618f 100644 --- a/postfix/local/recipient.c +++ b/postfix/local/recipient.c @@ -91,7 +91,7 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr) { char *myname = "deliver_switch"; - int status; + int status = 0; /* * Make verbose logging easier to understand. diff --git a/postfix/master/.indent.pro b/postfix/master/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/master/.indent.pro +++ b/postfix/master/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/pickup/.indent.pro b/postfix/pickup/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/pickup/.indent.pro +++ b/postfix/pickup/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/pipe/.indent.pro b/postfix/pipe/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/pipe/.indent.pro +++ b/postfix/pipe/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postalias/.indent.pro b/postfix/postalias/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postalias/.indent.pro +++ b/postfix/postalias/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postalias/Makefile.in b/postfix/postalias/Makefile.in index 608f9f2a3..c053f4015 100644 --- a/postfix/postalias/Makefile.in +++ b/postfix/postalias/Makefile.in @@ -70,3 +70,4 @@ postalias.o: ../include/resolve_clnt.h postalias.o: ../include/config.h postalias.o: ../include/mail_params.h postalias.o: ../include/mkmap.h +postalias.o: ../include/dict.h diff --git a/postfix/postalias/postalias.c b/postfix/postalias/postalias.c index ad4a91d6d..4159a63b9 100644 --- a/postfix/postalias/postalias.c +++ b/postfix/postalias/postalias.c @@ -121,7 +121,8 @@ /* postalias - create or update alias database */ -static void postalias(char *map_type, char *path_name, int incremental) +static void postalias(char *map_type, char *path_name, + int open_flags, int dict_flags) { VSTREAM *source_fp; VSTRING *line_buffer; @@ -140,7 +141,7 @@ static void postalias(char *map_type, char *path_name, int incremental) line_buffer = vstring_alloc(100); key_buffer = vstring_alloc(100); value_buffer = vstring_alloc(100); - if (incremental) { + if ((open_flags & O_TRUNC) == 0) { source_fp = VSTREAM_IN; vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END); } else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) { @@ -151,8 +152,7 @@ static void postalias(char *map_type, char *path_name, int incremental) * Open the database, create it when it does not exist, truncate it when * it does exist, and lock out any spectators. */ - mkmap = mkmap_open(map_type, path_name, incremental ? - O_RDWR | O_CREAT : O_RDWR | O_CREAT | O_TRUNC); + mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags); /* * Add records to the database. @@ -245,8 +245,12 @@ static void postalias(char *map_type, char *path_name, int incremental) mkmap_append(mkmap, "@", "@"); /* - * NIS compatibility: add time and master info. + * NIS compatibility: add time and master info. Unlike other information, + * this information MUST be written without a trailing null appended to + * key or value. */ + mkmap->dict->flags &= ~DICT_FLAG_TRY1NULL; + mkmap->dict->flags |= DICT_FLAG_TRY0NULL; vstring_sprintf(value_buffer, "%010ld", (long) time((time_t *) 0)); mkmap_append(mkmap, "YP_LAST_MODIFIED", STR(value_buffer)); mkmap_append(mkmap, "YP_MASTER_NAME", get_hostname()); @@ -270,7 +274,7 @@ static void postalias(char *map_type, char *path_name, int incremental) static NORETURN usage(char *myname) { - msg_fatal("usage: %s [-c config_directory] [-i] [-v] [output_type:]file...", + msg_fatal("usage: %s [-c config_directory] [-i] [-v] [-w] [output_type:]file...", myname); } @@ -281,7 +285,8 @@ int main(int argc, char **argv) int fd; char *slash; struct stat st; - int incremental = 0; + int open_flags = O_RDWR | O_CREAT | O_TRUNC; + int dict_flags = DICT_FLAG_DUP_WARN; /* * Be consistent with file permissions. @@ -316,7 +321,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "c:iv")) > 0) { + while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) { switch (ch) { default: usage(argv[0]); @@ -326,11 +331,15 @@ int main(int argc, char **argv) msg_fatal("out of memory"); break; case 'i': - incremental = 1; + open_flags &= ~O_TRUNC; break; case 'v': msg_verbose++; break; + case 'w': + dict_flags &= ~DICT_FLAG_DUP_WARN; + dict_flags |= DICT_FLAG_DUP_IGNORE; + break; } } read_config(); @@ -343,9 +352,9 @@ int main(int argc, char **argv) usage(argv[0]); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { - postalias(argv[optind], path_name, incremental); + postalias(argv[optind], path_name, open_flags, dict_flags); } else { - postalias(var_db_type, argv[optind], incremental); + postalias(var_db_type, argv[optind], open_flags, dict_flags); } optind++; } diff --git a/postfix/postcat/.indent.pro b/postfix/postcat/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postcat/.indent.pro +++ b/postfix/postcat/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postconf/.indent.pro b/postfix/postconf/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postconf/.indent.pro +++ b/postfix/postconf/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postdrop/.indent.pro b/postfix/postdrop/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postdrop/.indent.pro +++ b/postfix/postdrop/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postfix/.indent.pro b/postfix/postfix/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postfix/.indent.pro +++ b/postfix/postfix/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postkick/.indent.pro b/postfix/postkick/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postkick/.indent.pro +++ b/postfix/postkick/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postlock/.indent.pro b/postfix/postlock/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postlock/.indent.pro +++ b/postfix/postlock/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postlog/.indent.pro b/postfix/postlog/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postlog/.indent.pro +++ b/postfix/postlog/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postmap/.indent.pro b/postfix/postmap/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postmap/.indent.pro +++ b/postfix/postmap/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/postmap/Makefile.in b/postfix/postmap/Makefile.in index bb6eec9f9..ef896ce48 100644 --- a/postfix/postmap/Makefile.in +++ b/postfix/postmap/Makefile.in @@ -67,3 +67,4 @@ postmap.o: ../include/split_at.h postmap.o: ../include/config.h postmap.o: ../include/mail_params.h postmap.o: ../include/mkmap.h +postmap.o: ../include/dict.h diff --git a/postfix/postmap/postmap.c b/postfix/postmap/postmap.c index 9cd698ebc..fc660d80d 100644 --- a/postfix/postmap/postmap.c +++ b/postfix/postmap/postmap.c @@ -130,7 +130,8 @@ /* postmap - create or update mapping database */ -static void postmap(char *map_type, char *path_name, int incremental) +static void postmap(char *map_type, char *path_name, + int open_flags, int dict_flags) { VSTREAM *source_fp; VSTRING *line_buffer; @@ -143,7 +144,7 @@ static void postmap(char *map_type, char *path_name, int incremental) * Initialize. */ line_buffer = vstring_alloc(100); - if (incremental) { + if ((open_flags & O_TRUNC) == 0) { source_fp = VSTREAM_IN; vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END); } else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) { @@ -151,11 +152,11 @@ static void postmap(char *map_type, char *path_name, int incremental) } /* - * Open the database, create it when it does not exist, truncate it when - * it does exist, and lock out any spectators. + * Open the database, optionally create it when it does not exist, + * optionally truncate it when it does exist, and lock out any + * spectators. */ - mkmap = mkmap_open(map_type, path_name, incremental ? - O_RDWR | O_CREAT : O_RDWR | O_CREAT | O_TRUNC); + mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags); /* * Add records to the database. @@ -227,7 +228,7 @@ static void postmap(char *map_type, char *path_name, int incremental) static NORETURN usage(char *myname) { - msg_fatal("usage: %s [-c config_directory] [-i] [-v] [output_type:]file...", + msg_fatal("usage: %s [-c config_directory] [-i] [-v] [-w] [output_type:]file...", myname); } @@ -238,7 +239,8 @@ int main(int argc, char **argv) int fd; char *slash; struct stat st; - int incremental = 0; + int open_flags = O_RDWR | O_CREAT | O_TRUNC; + int dict_flags = DICT_FLAG_DUP_WARN; /* * Be consistent with file permissions. @@ -273,7 +275,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "c:iv")) > 0) { + while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) { switch (ch) { default: usage(argv[0]); @@ -283,11 +285,15 @@ int main(int argc, char **argv) msg_fatal("out of memory"); break; case 'i': - incremental = 1; + open_flags &= ~O_TRUNC; break; case 'v': msg_verbose++; break; + case 'w': + dict_flags &= ~DICT_FLAG_DUP_WARN; + dict_flags |= DICT_FLAG_DUP_IGNORE; + break; } } read_config(); @@ -300,9 +306,9 @@ int main(int argc, char **argv) usage(argv[0]); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { - postmap(argv[optind], path_name, incremental); + postmap(argv[optind], path_name, open_flags, dict_flags); } else { - postmap(var_db_type, argv[optind], incremental); + postmap(var_db_type, argv[optind], open_flags, dict_flags); } optind++; } diff --git a/postfix/postsuper/.indent.pro b/postfix/postsuper/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/postsuper/.indent.pro +++ b/postfix/postsuper/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/qmgr/.indent.pro b/postfix/qmgr/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/qmgr/.indent.pro +++ b/postfix/qmgr/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/sendmail/.indent.pro b/postfix/sendmail/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/sendmail/.indent.pro +++ b/postfix/sendmail/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/showq/.indent.pro b/postfix/showq/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/showq/.indent.pro +++ b/postfix/showq/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/smtp/.indent.pro b/postfix/smtp/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/smtp/.indent.pro +++ b/postfix/smtp/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/smtpd/.indent.pro b/postfix/smtpd/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/smtpd/.indent.pro +++ b/postfix/smtpd/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index 705f5b4cf..88f755fc2 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -312,7 +312,7 @@ static ARGV *smtpd_check_parse(char *checks) while ((name = mystrtok(&bp, " \t\r\n,")) != 0) { argv_add(argv, name, (char *) 0); if (strchr(name, ':') && dict_handle(name) == 0) - dict_register(name, dict_open(name, 0)); + dict_register(name, dict_open(name, 0, 0)); } argv_terminate(argv); diff --git a/postfix/smtpstone/.indent.pro b/postfix/smtpstone/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/smtpstone/.indent.pro +++ b/postfix/smtpstone/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/trivial-rewrite/.indent.pro b/postfix/trivial-rewrite/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/trivial-rewrite/.indent.pro +++ b/postfix/trivial-rewrite/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/util/.indent.pro b/postfix/util/.indent.pro index 715b1fb48..f683dc2bc 100644 --- a/postfix/util/.indent.pro +++ b/postfix/util/.indent.pro @@ -27,6 +27,8 @@ -TDICT_NODE -TDICT_OPEN_INFO -TDICT_PCRE +-TDICT_REGEXP +-TDICT_REGEXP_LINE -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index b9e7a1268..3ac316ab1 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -19,7 +19,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \ unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \ vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \ write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \ - stream_connect.c stream_trigger.c + stream_connect.c stream_trigger.c dict_regexp.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_ni.o dict_nis.o \ @@ -40,7 +40,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \ vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \ write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \ - stream_connect.o stream_trigger.o + stream_connect.o stream_trigger.o dict_regexp.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_ni.h dict_nis.h \ dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \ @@ -54,7 +54,7 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \ timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \ vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ - dict_unix.h dict_pcre.h + dict_unix.h dict_pcre.h dict_regexp.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -364,10 +364,24 @@ dict_open.o: dict_nisplus.h dict_open.o: dict_ni.h dict_open.o: dict_ldap.h dict_open.o: dict_pcre.h +dict_open.o: dict_regexp.h dict_open.o: stringops.h dict_open.o: split_at.h dict_pcre.o: dict_pcre.c dict_pcre.o: sys_defs.h +dict_regexp.o: dict_regexp.c +dict_regexp.o: sys_defs.h +dict_regexp.o: mymalloc.h +dict_regexp.o: msg.h +dict_regexp.o: safe.h +dict_regexp.o: vstream.h +dict_regexp.o: vbuf.h +dict_regexp.o: vstring.h +dict_regexp.o: stringops.h +dict_regexp.o: readline.h +dict_regexp.o: dict.h +dict_regexp.o: dict_regexp.h +dict_regexp.o: mac_parse.h dict_unix.o: dict_unix.c dict_unix.o: sys_defs.h dict_unix.o: msg.h @@ -622,6 +636,7 @@ percentm.o: vbuf.h percentm.o: percentm.h posix_signals.o: posix_signals.c posix_signals.o: sys_defs.h +posix_signals.o: posix_signals.h printable.o: printable.c printable.o: sys_defs.h printable.o: stringops.h diff --git a/postfix/util/dict.h b/postfix/util/dict.h index a66962c33..73f2da441 100644 --- a/postfix/util/dict.h +++ b/postfix/util/dict.h @@ -35,6 +35,8 @@ typedef struct DICT { #define DICT_FLAG_DUP_WARN (1<<0) /* if file, warn about dups */ #define DICT_FLAG_DUP_IGNORE (1<<1) /* if file, ignore dups */ +#define DICT_FLAG_TRY0NULL (1<<2) /* do not append 0 to key/value */ +#define DICT_FLAG_TRY1NULL (1<<3) /* append 0 to key/value */ extern int dict_unknown_allowed; extern int dict_errno; @@ -58,8 +60,8 @@ extern const char *dict_eval(const char *, const char *, int); * Low-level interface, with physical dictionary handles and no implied * locking. */ -extern DICT *dict_open(const char *, int); -extern DICT *dict_open3(const char *, const char *, int); +extern DICT *dict_open(const char *, int, int); +extern DICT *dict_open3(const char *, const char *, int, int); #define dict_get(dp, key) (dp)->lookup((dp), (key)) #define dict_put(dp, key, val) (dp)->update((dp), (key), (val)) diff --git a/postfix/util/dict_db.c b/postfix/util/dict_db.c index 0e34c9375..70d50a59c 100644 --- a/postfix/util/dict_db.c +++ b/postfix/util/dict_db.c @@ -6,13 +6,15 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_hash_open(path, flags) +/* DICT *dict_hash_open(path, open_flags, dict_flags) /* const char *path; -/* int flags; +/* int open_flags; +/* int dict_flags; /* -/* DICT *dict_btree_open(path, flags) +/* DICT *dict_btree_open(path, open_flags, dict_flags) /* const char *path; -/* int flags; +/* int open_flags; +/* int dict_flags; /* DESCRIPTION /* dict_XXX_open() opens the specified DB database. The result is /* a pointer to a structure that can be used to access the dictionary @@ -21,8 +23,10 @@ /* Arguments: /* .IP path /* The database pathname, not including the ".db" suffix. -/* .IP flags -/* flags passed to dbopen(). +/* .IP open_flags +/* Flags passed to dbopen(). +/* .IP dict_flags +/* Flags used by the dictionary interface. /* SEE ALSO /* dict(3) generic dictionary manager /* DIAGNOSTICS @@ -71,9 +75,6 @@ typedef struct { char *path; /* pathname */ } DICT_DB; -#define DICT_DB_TRY0NULL (1<<0) -#define DICT_DB_TRY1NULL (1<<1) - #define DICT_DB_CACHE_SIZE (1024 * 1024) #define DICT_DB_NELM 4096 @@ -92,13 +93,13 @@ static const char *dict_db_lookup(DICT *dict, const char *name) * See if this DB file was written with one null byte appended to key and * value. */ - if (dict_db->flags & DICT_DB_TRY1NULL) { + if (dict_db->flags & DICT_FLAG_TRY1NULL) { db_key.data = (void *) name; db_key.size = strlen(name) + 1; if ((status = db->get(db, &db_key, &db_value, 0)) < 0) msg_fatal("error reading %s: %m", dict_db->path); if (status == 0) { - dict_db->flags &= ~DICT_DB_TRY0NULL; + dict_db->flags &= ~DICT_FLAG_TRY0NULL; return (db_value.data); } } @@ -107,7 +108,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name) * See if this DB file was written with no null byte appended to key and * value. */ - if (dict_db->flags & DICT_DB_TRY0NULL) { + if (dict_db->flags & DICT_FLAG_TRY0NULL) { db_key.data = (void *) name; db_key.size = strlen(name); if ((status = db->get(db, &db_key, &db_value, 0)) < 0) @@ -116,7 +117,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name) if (buf == 0) buf = vstring_alloc(10); vstring_strncpy(buf, db_value.data, db_value.size); - dict_db->flags &= ~DICT_DB_TRY1NULL; + dict_db->flags &= ~DICT_FLAG_TRY1NULL; return (vstring_str(buf)); } } @@ -142,19 +143,19 @@ static void dict_db_update(DICT *dict, const char *name, const char *value) * If undecided about appending a null byte to key and value, choose a * default depending on the platform. */ - if ((dict_db->flags & DICT_DB_TRY1NULL) - && (dict_db->flags & DICT_DB_TRY0NULL)) { + if ((dict_db->flags & DICT_FLAG_TRY1NULL) + && (dict_db->flags & DICT_FLAG_TRY0NULL)) { #ifdef DB_NO_TRAILING_NULL - dict_db->flags = DICT_DB_TRY0NULL; + dict_db->flags = DICT_FLAG_TRY0NULL; #else - dict_db->flags = DICT_DB_TRY1NULL; + dict_db->flags = DICT_FLAG_TRY1NULL; #endif } /* * Optionally append a null byte to key and value. */ - if (dict_db->flags & DICT_DB_TRY1NULL) { + if (dict_db->flags & DICT_FLAG_TRY1NULL) { db_key.size++; db_value.size++; } @@ -188,7 +189,8 @@ static void dict_db_close(DICT *dict) /* dict_db_open - open data base */ -static DICT *dict_db_open(const char *path, int flags, int type, void *tweak) +static DICT *dict_db_open(const char *path, int flags, int type, + void *tweak, int dict_flags) { DICT_DB *dict_db; DB *db; @@ -204,7 +206,9 @@ static DICT *dict_db_open(const char *path, int flags, int type, void *tweak) dict_db->dict.close = dict_db_close; dict_db->dict.fd = db->fd(db); close_on_exec(dict_db->dict.fd, CLOSE_ON_EXEC); - dict_db->flags = DICT_DB_TRY1NULL | DICT_DB_TRY0NULL; + dict_db->dict.flags = dict_flags; + if ((flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL); dict_db->db = db; dict_db->path = db_path; return (&dict_db->dict); @@ -212,26 +216,26 @@ static DICT *dict_db_open(const char *path, int flags, int type, void *tweak) /* dict_hash_open - create association with data base */ -DICT *dict_hash_open(const char *path, int flags) +DICT *dict_hash_open(const char *path, int open_flags, int dict_flags) { HASHINFO tweak; memset((char *) &tweak, 0, sizeof(tweak)); tweak.nelem = DICT_DB_NELM; tweak.cachesize = DICT_DB_CACHE_SIZE; - return (dict_db_open(path, flags, DB_HASH, (void *) &tweak)); + return (dict_db_open(path, open_flags, DB_HASH, (void *) &tweak, dict_flags)); } /* dict_btree_open - create association with data base */ -DICT *dict_btree_open(const char *path, int flags) +DICT *dict_btree_open(const char *path, int open_flags, int dict_flags) { BTREEINFO tweak; memset((char *) &tweak, 0, sizeof(tweak)); tweak.cachesize = DICT_DB_CACHE_SIZE; - return (dict_db_open(path, flags, DB_BTREE, (void *) &tweak)); + return (dict_db_open(path, open_flags, DB_BTREE, (void *) &tweak, dict_flags)); } #endif diff --git a/postfix/util/dict_db.h b/postfix/util/dict_db.h index d03e282f3..43d7e35ab 100644 --- a/postfix/util/dict_db.h +++ b/postfix/util/dict_db.h @@ -19,8 +19,8 @@ /* * External interface. */ -extern DICT *dict_hash_open(const char *, int); -extern DICT *dict_btree_open(const char *, int); +extern DICT *dict_hash_open(const char *, int, int); +extern DICT *dict_btree_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_dbm.c b/postfix/util/dict_dbm.c index a8adec777..87c6faad3 100644 --- a/postfix/util/dict_dbm.c +++ b/postfix/util/dict_dbm.c @@ -6,10 +6,11 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_dbm_open(path, flags) +/* DICT *dict_dbm_open(path, open_flags, dict_flags) /* const char *name; /* const char *path; -/* int flags; +/* int open_flags; +/* int dict_flags; /* DESCRIPTION /* dict_dbm_open() opens the named DBM database and makes it available /* via the generic interface described in dict_open(3). @@ -57,9 +58,6 @@ typedef struct { char *path; /* pathname */ } DICT_DBM; -#define DICT_DBM_TRY0NULL (1<<0) -#define DICT_DBM_TRY1NULL (1<<1) - /* dict_dbm_lookup - find database entry */ static const char *dict_dbm_lookup(DICT *dict, const char *name) @@ -73,12 +71,12 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name) * See if this DBM file was written with one null byte appended to key * and value. */ - if (dict_dbm->flags & DICT_DBM_TRY1NULL) { + if (dict_dbm->flags & DICT_FLAG_TRY1NULL) { dbm_key.dptr = (void *) name; dbm_key.dsize = strlen(name) + 1; dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key); if (dbm_value.dptr != 0) { - dict_dbm->flags &= ~DICT_DBM_TRY0NULL; + dict_dbm->flags &= ~DICT_FLAG_TRY0NULL; return (dbm_value.dptr); } } @@ -87,7 +85,7 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name) * See if this DBM file was written with no null byte appended to key and * value. */ - if (dict_dbm->flags & DICT_DBM_TRY0NULL) { + if (dict_dbm->flags & DICT_FLAG_TRY0NULL) { dbm_key.dptr = (void *) name; dbm_key.dsize = strlen(name); dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key); @@ -95,7 +93,7 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name) if (buf == 0) buf = vstring_alloc(10); vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize); - dict_dbm->flags &= ~DICT_DBM_TRY1NULL; + dict_dbm->flags &= ~DICT_FLAG_TRY1NULL; return (vstring_str(buf)); } } @@ -120,21 +118,19 @@ static void dict_dbm_update(DICT *dict, const char *name, const char *value) * If undecided about appending a null byte to key and value, choose a * default depending on the platform. */ - if ((dict_dbm->flags & DICT_DBM_TRY1NULL) - && (dict_dbm->flags & DICT_DBM_TRY0NULL)) { + if ((dict_dbm->flags & DICT_FLAG_TRY1NULL) + && (dict_dbm->flags & DICT_FLAG_TRY0NULL)) { #ifdef DBM_NO_TRAILING_NULL - dict_dbm->flags = DICT_DBM_TRY0NULL; + dict_dbm->flags = DICT_FLAG_TRY0NULL; #else - dict_dbm->flags = DICT_DBM_TRY1NULL; + dict_dbm->flags = DICT_FLAG_TRY1NULL; #endif } /* * Optionally append a null byte to key and value. */ - if ((dict_dbm->flags & DICT_DBM_TRY1NULL) - && strcmp(name, "YP_MASTER_NAME") != 0 - && strcmp(name, "YP_LAST_MODIFIED") != 0) { + if (dict_dbm->flags & DICT_FLAG_TRY1NULL) { dbm_key.dsize++; dbm_value.dsize++; } @@ -167,7 +163,7 @@ static void dict_dbm_close(DICT *dict) /* dict_dbm_open - open DBM data base */ -DICT *dict_dbm_open(const char *path, int flags) +DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) { DICT_DBM *dict_dbm; DBM *dbm; @@ -175,7 +171,7 @@ DICT *dict_dbm_open(const char *path, int flags) /* * XXX SunOS 5.x has no const in dbm_open() prototype. */ - if ((dbm = dbm_open((char *) path, flags, 0644)) == 0) + if ((dbm = dbm_open((char *) path, open_flags, 0644)) == 0) msg_fatal("open database %s.{dir,pag}: %m", path); dict_dbm = (DICT_DBM *) mymalloc(sizeof(*dict_dbm)); @@ -184,7 +180,9 @@ DICT *dict_dbm_open(const char *path, int flags) dict_dbm->dict.close = dict_dbm_close; dict_dbm->dict.fd = dbm_dirfno(dbm); close_on_exec(dict_dbm->dict.fd, CLOSE_ON_EXEC); - dict_dbm->flags = DICT_DBM_TRY0NULL | DICT_DBM_TRY1NULL; + dict_dbm->dict.flags = dict_flags; + if (dict_flagsflags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0) + dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL); dict_dbm->dbm = dbm; dict_dbm->path = mystrdup(path); diff --git a/postfix/util/dict_dbm.h b/postfix/util/dict_dbm.h index da8f5c031..e15e8fb72 100644 --- a/postfix/util/dict_dbm.h +++ b/postfix/util/dict_dbm.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_dbm_open(const char *, int); +extern DICT *dict_dbm_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_env.c b/postfix/util/dict_env.c index cbc8249e7..926a2b947 100644 --- a/postfix/util/dict_env.c +++ b/postfix/util/dict_env.c @@ -6,13 +6,14 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_env_open(name, flags) +/* DICT *dict_env_open(name, dummy, dict_flags) /* const char *name; -/* int flags; +/* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_env_open() opens the environment variable array and /* makes it accessible via the generic operations documented -/* in dict_open(3). The \fIname\fR and \fIflags\fR arguments +/* in dict_open(3). The \fIname\fR and \fIdummy\fR arguments /* are ignored. /* SEE ALSO /* dict(3) generic dictionary manager @@ -68,7 +69,7 @@ static void dict_env_close(DICT *dict) /* dict_env_open - make association with environment array */ -DICT *dict_env_open(const char *unused_name, int unused_flags) +DICT *dict_env_open(const char *unused_name, int unused_flags, int dict_flags) { DICT *dict; @@ -76,6 +77,7 @@ DICT *dict_env_open(const char *unused_name, int unused_flags) dict->lookup = dict_env_lookup; dict->update = dict_env_update; dict->close = dict_env_close; + dict->flags = dict_flags; dict->fd = -1; return (dict); } diff --git a/postfix/util/dict_env.h b/postfix/util/dict_env.h index 672c64a58..f49e10551 100644 --- a/postfix/util/dict_env.h +++ b/postfix/util/dict_env.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_env_open(const char *, int); +extern DICT *dict_env_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_ldap.c b/postfix/util/dict_ldap.c index d63150cbc..d22adae36 100644 --- a/postfix/util/dict_ldap.c +++ b/postfix/util/dict_ldap.c @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_ldap_open(attribute, dummy) +/* DICT *dict_ldap_open(attribute, dummy, dict_flags) /* const char *attribute; /* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_ldap_open() makes LDAP user information accessible via /* the generic dictionary operations described in dict_open(3). @@ -307,7 +308,7 @@ static void dict_ldap_close(DICT *dict) /* dict_ldap_open - create association with data base */ -DICT *dict_ldap_open(const char *ldapsource, int flags) +DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) { char *myname = "dict_ldap_open"; DICT_LDAP *dict_ldap; @@ -320,6 +321,7 @@ DICT *dict_ldap_open(const char *ldapsource, int flags) dict_ldap->dict.update = dict_ldap_update; dict_ldap->dict.close = dict_ldap_close; dict_ldap->dict.fd = -1; + dict_ldap->dict.flags = dict_flags; if (msg_verbose) msg_info("%s: using LDAP source %s", myname, ldapsource); diff --git a/postfix/util/dict_ldap.h b/postfix/util/dict_ldap.h index 8a88cdcef..818835df0 100644 --- a/postfix/util/dict_ldap.h +++ b/postfix/util/dict_ldap.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_ldap_open(const char *, int); +extern DICT *dict_ldap_open(const char *, int, int); /* AUTHOR(S) /* Wietse Venema diff --git a/postfix/util/dict_ni.c b/postfix/util/dict_ni.c index 06331d491..5f7aabd85 100644 --- a/postfix/util/dict_ni.c +++ b/postfix/util/dict_ni.c @@ -1,9 +1,193 @@ - /* - * The NetInfo software is not bundled with IBM's public release. It will be - * made available as contributed software from http://www.postfix.org/ - */ +/*++ +/* NAME +/* dict_ni 3 +/* SUMMARY +/* dictionary manager interface to NetInfo +/* SYNOPSIS +/* #include +/* +/* DICT *dict_ni_open(path, dummy, dict_flags) +/* char *path; +/* int dummy; +/* int dict_flags; +/* DESCRIPTION +/* dict_ni_open() `opens' the named NetInfo database. The result is +/* a pointer to a structure that can be used to access the dictionary +/* using the generic methods documented in dict_open(3). +/* DIAGNOSTICS +/* dict_ni_register() returns 0 in case of success, -1 in case +/* of problems. +/* Fatal errors: NetInfo errors, out of memory. +/* SEE ALSO +/* dict(3) generic dictionary manager +/* netinfo(3N) data base subroutines +/* AUTHOR(S) +/* Pieter Schoenmakers +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven +/* The Netherlands +/*--*/ + #include "sys_defs.h" #ifdef HAS_NETINFO -#error "This requires contributed software from http://www.postfix.org/" + +/* System library. */ + +#include +#include + +/* Utility library. */ + +#include "dict.h" +#include "dict_ni.h" +#include "msg.h" +#include "mymalloc.h" + +typedef struct { + DICT dict; /* my super */ + char *path; /* directory path */ +} DICT_NI; + + /* + * We'd like other possibilities, but that is not possible in the current + * dictionary setup... An example of a different setup: use `members' for + * multi-valued lookups (to be compatible with /aliases), and `value' for + * single-valued tables. + */ +#define NETINFO_PROP_KEY "name" +#define NETINFO_PROP_VALUE "members" +#define NETINFO_VALUE_SEP "," + +#define NETINFO_MAX_DOMAIN_DEPTH 100 + +/* Hard worker doing lookups. Returned value is statically allocated and + reused each call. */ +static const char *dict_ni_do_lookup(char *path, char *key_prop, + const char *key_value, char *val_prop) +{ + unsigned int result_cap = 0; + static char *result = 0; + + char *return_val = 0; + ni_namelist values; + int depth = 0; + void *domain; + void *next_domain; + char *query; + ni_status r; + ni_id dir; + + if (msg_verbose) + msg_info("ni_lookup %s %s=%s", path, key_prop, key_value); + + r = ni_open(NULL, ".", &domain); + if (r != NI_OK) { + msg_warn("ni_open `.': %d", r); + return NULL; + } + query = alloca(strlen(path) + strlen(key_prop) + 3 + strlen(key_value)); + sprintf(query, "%s/%s=%s", path, key_prop, key_value); + + for (;;) { + + /* + * What does it _mean_ if we find the directory but not the value? + */ + if (ni_pathsearch(domain, &dir, query) == NI_OK + && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK) + if (values.ni_namelist_len <= 0) + ni_namelist_free(&values); + else { + unsigned int i, + l, + n; + + for (i = l = 0; i < values.ni_namelist_len; i++) + l += 1 + strlen(values.ni_namelist_val[i]); + if (result_cap < l) { + if (result) + myfree(result); + result_cap = l + 100; + result = mymalloc(result_cap); + } + for (i = l = 0; i < values.ni_namelist_len; i++) { + n = strlen(values.ni_namelist_val[i]); + memcpy(result + l, values.ni_namelist_val[i], n); + l += n; + if (i < values.ni_namelist_len - 1) + result[l++] = ','; + } + result[l] = '\0'; + return_val = result; + break; + } + + if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) { + msg_warn("ni_open: domain depth limit"); + break; + } + r = ni_open(domain, "..", &next_domain); + if (r != NI_OK) { + if (r != NI_FAILED) + msg_warn("ni_open `..': %d", r); + break; + } + ni_free(domain); + domain = next_domain; + } + + ni_free(domain); + + return return_val; +} + +/* dict_ni_lookup - find table entry */ + +static const char *dict_ni_lookup(DICT *dict, const char *key) +{ + DICT_NI *d = (DICT_NI *) dict; + + return dict_ni_do_lookup(d->path, NETINFO_PROP_KEY, + key, NETINFO_PROP_VALUE); +} + +/* dict_ni_update - add or update table entry (not!) */ + +static void dict_ni_update(DICT *dict, const char *unused_name, + const char *unused_value) +{ + DICT_NI *d = (DICT_NI *) dict; + + msg_fatal("dict_ni_update: unimplemented: update NetInfo directory %s", + d->path); +} + +/* dict_ni_close - disassociate from NetInfo map */ + +static void dict_ni_close(DICT *dict) +{ + DICT_NI *d = (DICT_NI *) dict; + + myfree(d->path); + myfree((char *) d); +} + +/* dict_ni_open - create association with NetInfo map */ + +DICT *dict_ni_open(const char *path, int unused_flags, int dict_flags) +{ + DICT_NI *d = (void *) mymalloc(sizeof(*d)); + + d->dict.lookup = dict_ni_lookup; + d->dict.update = dict_ni_update; + d->dict.close = dict_ni_close; + d->dict.fd = -1; + d->dict.flags = dict_flags; + d->path = mystrdup(path); + + return &d->dict; +} + #endif diff --git a/postfix/util/dict_ni.h b/postfix/util/dict_ni.h index 2ce9c2db2..b0221a4b6 100644 --- a/postfix/util/dict_ni.h +++ b/postfix/util/dict_ni.h @@ -1,4 +1,32 @@ +#ifndef _DICT_NI_H_INCLUDED_ +#define _DICT_NI_H_INCLUDED_ + +/*++ +/* NAME +/* dict_ni 3h +/* SUMMARY +/* dictionary manager interface to NetInfo maps +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + /* - * The NetInfo software is not bundled with IBM's public release. It will be - * made available as contributed software from http://www.postfix.org/ + * Utility library. */ +#include + + /* + * External interface. + */ +extern DICT *dict_ni_open(const char *, int, int); + +/* AUTHOR(S) +/* Pieter Schoenmakers +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven +/* The Netherlands +/*--*/ + +#endif diff --git a/postfix/util/dict_nis.c b/postfix/util/dict_nis.c index 0441183d9..a042f3299 100644 --- a/postfix/util/dict_nis.c +++ b/postfix/util/dict_nis.c @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_nis_open(map, dummy) +/* DICT *dict_nis_open(map, dummy, dict_flags) /* const char *map; /* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_nis_open() makes the specified NIS map accessible via /* the generic dictionary operations described in dict_open(3). @@ -67,9 +68,6 @@ typedef struct { int flags; /* see below */ } DICT_NIS; -#define DICT_NIS_TRY0NULL (1<<0) -#define DICT_NIS_TRY1NULL (1<<1) - /* * Class variables, so that multiple maps can share this info. */ @@ -156,12 +154,12 @@ static const char *dict_nis_lookup(DICT *dict, const char *key) * See if this NIS map was written with one null byte appended to key and * value. */ - if (dict_nis->flags & DICT_NIS_TRY1NULL) { + if (dict_nis->flags & DICT_FLAG_TRY1NULL) { err = yp_match(dict_nis_domain, dict_nis->map, (void *) key, strlen(key) + 1, &result, &result_len); if (err == 0) { - dict_nis->flags &= ~DICT_NIS_TRY0NULL; + dict_nis->flags &= ~DICT_FLAG_TRY0NULL; return (result); } } @@ -170,12 +168,12 @@ static const char *dict_nis_lookup(DICT *dict, const char *key) * See if this NIS map was written with no null byte appended to key and * value. This should never be the case, but better play safe. */ - if (dict_nis->flags & DICT_NIS_TRY0NULL) { + if (dict_nis->flags & DICT_FLAG_TRY0NULL) { err = yp_match(dict_nis_domain, dict_nis->map, (void *) key, strlen(key), &result, &result_len); if (err == 0) { - dict_nis->flags &= ~DICT_NIS_TRY1NULL; + dict_nis->flags &= ~DICT_FLAG_TRY1NULL; if (buf == 0) buf = vstring_alloc(10); vstring_strncpy(buf, result, result_len); @@ -218,7 +216,7 @@ static void dict_nis_close(DICT *dict) /* dict_nis_open - open NIS map */ -DICT *dict_nis_open(const char *map, int unused_flags) +DICT *dict_nis_open(const char *map, int unused_flags, int dict_flags) { DICT_NIS *dict_nis; @@ -228,7 +226,9 @@ DICT *dict_nis_open(const char *map, int unused_flags) dict_nis->dict.close = dict_nis_close; dict_nis->dict.fd = -1; dict_nis->map = mystrdup(map); - dict_nis->flags = (DICT_NIS_TRY1NULL | DICT_NIS_TRY0NULL); + dict_nis->dict.flags = dict_flags; + if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL); if (dict_nis_domain == 0) dict_nis_init(); return (&dict_nis->dict); diff --git a/postfix/util/dict_nis.h b/postfix/util/dict_nis.h index 498715f9f..ff2759b7c 100644 --- a/postfix/util/dict_nis.h +++ b/postfix/util/dict_nis.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_nis_open(const char *, int); +extern DICT *dict_nis_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_nisplus.c b/postfix/util/dict_nisplus.c index 0949f540c..02a8790f1 100644 --- a/postfix/util/dict_nisplus.c +++ b/postfix/util/dict_nisplus.c @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_nisplus_open(map, dummy) +/* DICT *dict_nisplus_open(map, dummy, dict_flags) /* char *map; /* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_nisplus_open() makes the specified NIS+ map accessible via /* the generic dictionary operations described in dict_open(3). @@ -76,7 +77,7 @@ static void dict_nisplus_close(DICT *dict) /* dict_nisplus_open - open NISPLUS map */ -DICT *dict_nisplus_open(const char *map, int unused_flags) +DICT *dict_nisplus_open(const char *map, int unused_flags, int dict_flags) { DICT_NISPLUS *dict_nisplus; @@ -86,5 +87,6 @@ DICT *dict_nisplus_open(const char *map, int unused_flags) dict_nisplus->dict.close = dict_nisplus_close; dict_nisplus->dict.fd = -1; dict_nisplus->map = mystrdup(map); + dict_nisplus->dict.flags = dict_flags; return (&dict_nisplus->dict); } diff --git a/postfix/util/dict_nisplus.h b/postfix/util/dict_nisplus.h index 5c7a7c10b..f43b3141b 100644 --- a/postfix/util/dict_nisplus.h +++ b/postfix/util/dict_nisplus.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_nisplus_open(const char *, int); +extern DICT *dict_nisplus_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_open.c b/postfix/util/dict_open.c index b30defc86..3f91b647a 100644 --- a/postfix/util/dict_open.c +++ b/postfix/util/dict_open.c @@ -6,14 +6,16 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_open(dict_spec, flags) +/* DICT *dict_open(dict_spec, open_flags, dict_flags) /* const char *dict_spec; -/* int flags; +/* int open_flags; +/* int dict_flags; /* -/* DICT *dict_open3(dict_type, dict_name, flags) +/* DICT *dict_open3(dict_type, dict_name, open_flags, dict_flags) /* const char *dict_type; /* const char *dict_name; -/* int flags; +/* int open_flags; +/* int dict_flags; /* /* void dict_put(dict, key, value) /* DICT *dict; @@ -32,8 +34,18 @@ /* /* dict_open() takes a type:name pair that specifies a dictionary type /* and dictionary name, opens the dictionary, and returns a dictionary -/* handle. The \fIflags\fR arguments are as in open(2). The dictionary -/* types are as follows: +/* handle. The \fIopen_flags\fR arguments are as in open(2). The +/* \fIdict_flags\fR are the bit-wise OR of zero or more of the following: +/* .IP DICT_FLAG_DUP_WARN +/* Warn about duplicate keys, if the underlying database does not +/* support duplicate keys. The default is to terminate with a fatal +/* error. +/* .IP DICT_FLAG_DUP_IGNORE +/* Ignore duplicate keys if the underlying database does not +/* support duplicate keys. The default is to terminate with a fatal +/* error. +/* .PP +/* The dictionary types are as follows: /* .IP environ /* The process environment array. The \fIdict_name\fR argument is ignored. /* .IP dbm @@ -52,6 +64,8 @@ /* LDAP ("light-weight" directory access protocol) database access. /* .IP pcre /* PERL-compatible regular expressions. +/* .IP regexp +/* POSIX-compatible regular expressions. /* .PP /* dict_open3() takes separate arguments for dictionary type and /* name, but otherwise performs the same functions as dict_open(). @@ -103,6 +117,7 @@ #include #include #include +#include #include #include @@ -111,7 +126,7 @@ */ typedef struct { char *type; - struct DICT *(*open) (const char *, int); + struct DICT *(*open) (const char *, int, int); } DICT_OPEN_INFO; static DICT_OPEN_INFO dict_open_info[] = { @@ -138,13 +153,16 @@ static DICT_OPEN_INFO dict_open_info[] = { #endif #ifdef HAS_PCRE "pcre", dict_pcre_open, +#endif +#ifdef HAS_POSIX_REGEXP + "regexp", dict_regexp_open, #endif 0, }; /* dict_open - open dictionary */ -DICT *dict_open(const char *dict_spec, int flags) +DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags) { char *saved_dict_spec = mystrdup(dict_spec); char *dict_name; @@ -153,7 +171,7 @@ DICT *dict_open(const char *dict_spec, int flags) if ((dict_name = split_at(saved_dict_spec, ':')) == 0) msg_fatal("open dictionary: need \"type:name\" form: %s", dict_spec); - dict = dict_open3(saved_dict_spec, dict_name, flags); + dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags); myfree(saved_dict_spec); return (dict); } @@ -161,7 +179,8 @@ DICT *dict_open(const char *dict_spec, int flags) /* dict_open3 - open dictionary */ -DICT *dict_open3(const char *dict_type, const char *dict_name, int flags) +DICT *dict_open3(const char *dict_type, const char *dict_name, + int open_flags, int dict_flags) { char *myname = "dict_open"; DICT_OPEN_INFO *dp; @@ -169,7 +188,7 @@ DICT *dict_open3(const char *dict_type, const char *dict_name, int flags) for (dp = dict_open_info; dp->type; dp++) { if (strcasecmp(dp->type, dict_type) == 0) { - if ((dict = dp->open(dict_name, flags)) == 0) + if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0) msg_fatal("opening %s:%s %m", dict_type, dict_name); if (msg_verbose) msg_info("%s: %s:%s", myname, dict_type, dict_name); @@ -207,7 +226,7 @@ main(int argc, char **argv) VSTRING *keybuf = vstring_alloc(1); DICT *dict; char *dict_name; - int dict_flags; + int open_flags; char *key; const char *value; @@ -215,15 +234,15 @@ main(int argc, char **argv) if (argc != 3) msg_fatal("usage: %s type:file read|write|create", argv[0]); if (strcasecmp(argv[2], "create") == 0) - dict_flags = O_CREAT | O_RDWR | O_TRUNC; + open_flags = O_CREAT | O_RDWR | O_TRUNC; else if (strcasecmp(argv[2], "write") == 0) - dict_flags = O_RDWR; + open_flags = O_RDWR; else if (strcasecmp(argv[2], "read") == 0) - dict_flags = O_RDONLY; + open_flags = O_RDONLY; else msg_fatal("unknown access mode: %s", argv[2]); dict_name = argv[1]; - dict = dict_open(dict_name, dict_flags); + dict = dict_open(dict_name, open_flags, 0); while (vstring_fgets_nonl(keybuf, VSTREAM_IN)) { if ((key = strtok(vstring_str(keybuf), " =")) == 0) continue; diff --git a/postfix/util/dict_pcre.c b/postfix/util/dict_pcre.c index ebfc77036..d2e6121db 100644 --- a/postfix/util/dict_pcre.c +++ b/postfix/util/dict_pcre.c @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_pcre_open(name, flags) +/* DICT *dict_pcre_open(name, dummy, dict_flags) /* const char *name; -/* int flags; +/* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_pcre_open() opens the named file and compiles the contained /* regular expressions. @@ -16,10 +17,6 @@ /* The lookup interface will match only user@domain form addresses. /* SEE ALSO /* dict(3) generic dictionary manager -/* LICENSE -/* .ad -/* .fi -/* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Andrew McNamara /* andrewm@connect.com.au @@ -261,12 +258,12 @@ DICT *dict_pcre_open(const char *map, int unused_flags) dict_pcre->dict.close = dict_pcre_close; dict_pcre->dict.fd = -1; dict_pcre->map = mystrdup(map); - dict_pcre->flags = 0; + dict_pcre->dict.flags = dict_flags; dict_pcre->head = NULL; if (dict_pcre_init == 0) { - pcre_malloc = (void *(*)(size_t)) mymalloc; - pcre_free = (void (*)(void *)) myfree; + pcre_malloc = (void *(*) (size_t)) mymalloc; + pcre_free = (void (*) (void *)) myfree; dict_pcre_init = 1; } if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { @@ -374,12 +371,12 @@ DICT *dict_pcre_open(const char *map, int unused_flags) else pcre_list->next = pl; pcre_list = pl; -} + } -vstring_free(line_buffer); -vstream_fclose(map_fp); + vstring_free(line_buffer); + vstream_fclose(map_fp); -return (&dict_pcre->dict); + return (&dict_pcre->dict); } #endif /* HAS_PCRE */ diff --git a/postfix/util/dict_pcre.h b/postfix/util/dict_pcre.h index 2c6c118a6..253c69e78 100644 --- a/postfix/util/dict_pcre.h +++ b/postfix/util/dict_pcre.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_pcre_open(const char *, int); +extern DICT *dict_pcre_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/dict_regexp.c b/postfix/util/dict_regexp.c new file mode 100644 index 000000000..b3c402463 --- /dev/null +++ b/postfix/util/dict_regexp.c @@ -0,0 +1,408 @@ +/*++ +/* NAME +/* dict_regexp 3 +/* SUMMARY +/* dictionary manager interface to REGEXP regular expression library +/* SYNOPSIS +/* #include +/* +/* DICT *dict_regexp_open(name, dummy, dict_flags) +/* const char *name; +/* int dummy; +/* int dict_flags; +/* DESCRIPTION +/* dict_regexp_open() opens the named file and compiles the contained +/* regular expressions. +/* +/* The lookup interface will match only user@domain form addresses. +/* SEE ALSO +/* dict(3) generic dictionary manager +/* AUTHOR(S) +/* LaMont Jones +/* lamont@hp.com +/* +/* Based on PCRE dictionary contributed by Andrew McNamara +/* andrewm@connect.com.au +/* connect.com.au Pty. Ltd. +/* Level 3, 213 Miller St +/* North Sydney, NSW, Australia +/* +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include "sys_defs.h" + +#ifdef HAS_POSIX_REGEXP + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "mymalloc.h" +#include "msg.h" +#include "safe.h" +#include "vstream.h" +#include "vstring.h" +#include "stringops.h" +#include "readline.h" +#include "dict.h" +#include "dict_regexp.h" +#include "mac_parse.h" + +typedef struct dict_regexp_list { + struct dict_regexp_list *next; /* Next regexp in dict */ + regex_t *expr[2]; /* The compiled pattern(s) */ + char *replace; /* Replacement string */ + int lineno; /* Source file line number */ +} DICT_REGEXP_RULE; + +typedef struct { + DICT dict; /* generic members */ + char *map; /* map name */ + int flags; /* unused at the moment */ + regmatch_t *pmatch; /* Cut substrings */ + int nmatch; /* number of elements in pmatch */ + DICT_REGEXP_RULE *head; /* first rule */ +} DICT_REGEXP; + +/* + * Context for macro expansion callback. + */ +struct dict_regexp_context { + DICT_REGEXP *dict; /* the dictionary entry */ + DICT_REGEXP_RULE *rule; /* the rule we matched */ + VSTRING *buf; /* target string buffer */ + const char *subject; /* str against which we match */ +}; + +/* + * dict_regexp_update - not supported + */ +static void dict_regexp_update(DICT *dict, const char *unused_name, + const char *unused_value) +{ + DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict; + + msg_fatal("dict_regexp_update: attempt to update regexp map %s", + dict_regexp->map); +} + +/* + * Macro expansion callback - replace $0-${99} with strings cut from + * matched string. + */ +static void dict_regexp_action(int type, VSTRING *buf, char *ptr) +{ + struct dict_regexp_context *ctxt = (struct dict_regexp_context *) ptr; + DICT_REGEXP_RULE *rule = ctxt->rule; + DICT_REGEXP *dict = ctxt->dict; + int n; + + if (type == MAC_PARSE_VARNAME) { + n = atoi(vstring_str(buf)); + if (n >= dict->nmatch) { + msg_warn("regexp %s, line %d: replace index out of range", + dict->map, rule->lineno); + return; + } + if (dict->pmatch[n].rm_so < 0 || + dict->pmatch[n].rm_so == dict->pmatch[n].rm_eo) { + return; /* empty string or not + * matched */ + } + vstring_strncat(ctxt->buf, ctxt->subject + dict->pmatch[n].rm_so, + dict->pmatch[n].rm_eo - dict->pmatch[n].rm_so); + } else + /* Straight text - duplicate with no substitution */ + vstring_strcat(ctxt->buf, vstring_str(buf)); +} + +/* + * Look up regexp dict and perform string substitution on matched + * strings. + */ +static const char *dict_regexp_lookup(DICT *dict, const char *name) +{ + DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict; + DICT_REGEXP_RULE *rule; + struct dict_regexp_context ctxt; + static VSTRING *buf; + char *at; + int error; + + /* msg_info("dict_regexp_lookup: %s: %s", dict_regexp->map, name ); */ + + /* + * XXX Require user@domain, to defeat partial address matching for smtp + * access control, canonical and virtual mappings, and to prevent regexps + * from being used as alias databases because one might inadvertently + * copy "|command" or /file/name or :include: to the result. + */ + if (name[0] == '@' || (at = strrchr(name, '@')) == 0 || at[1] == 0) + return (0); + + /* Search for a matching expression */ + for (rule = dict_regexp->head; rule; rule = rule->next) { + error = regexec(rule->expr[0], name, rule->expr[0]->re_nsub + 1, + dict_regexp->pmatch, 0); + if (!error) { + if (rule->expr[1]) { + error = regexec(rule->expr[1], name, rule->expr[1]->re_nsub + 1, + dict_regexp->pmatch + rule->expr[0]->re_nsub + 1, 0); + if (!error) { + continue; + } else if (error != REG_NOMATCH) { + char errbuf[256]; + + (void) regerror(error, rule->expr[1], errbuf, sizeof(errbuf)); + msg_fatal("regexp map %s, line %d: %s.", + dict_regexp->map, rule->lineno, errbuf); + } + } + + /* + * We found a match. Do some final initialization on the + * subexpression fields, and perform substitution on replacement + * string + */ + if (!buf) + buf = vstring_alloc(10); + VSTRING_RESET(buf); + ctxt.buf = buf; + ctxt.subject = name; + ctxt.rule = rule; + ctxt.dict = dict_regexp; + + mac_parse(rule->replace, dict_regexp_action, (char *) &ctxt); + + VSTRING_TERMINATE(buf); + return (vstring_str(buf)); + } else if (error && error != REG_NOMATCH) { + char errbuf[256]; + + (void) regerror(error, rule->expr[0], errbuf, sizeof(errbuf)); + msg_fatal("regexp map %s, line %d: %s.", + dict_regexp->map, rule->lineno, errbuf); + return ((char *) 0); + } + } + return ((char *) 0); +} + +/* dict_regexp_close - close regexp dictionary */ + +static void dict_regexp_close(DICT *dict) +{ + DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict; + DICT_REGEXP_RULE *rule, + *next; + int i; + + for (rule = dict_regexp->head; rule; rule = next) { + next = rule->next; + for (i = 0; i < 2; i++) { + if (rule->expr[i]) { + regfree(rule->expr[i]); + myfree((char *) rule->expr[i]); + } + } + myfree((char *) rule->replace); + myfree((char *) rule); + } + myfree((char *) dict_regexp); +} + +static regex_t *dict_regexp_get_expr(int lineno, char **bufp, VSTREAM *map_fp) +{ + char *p = *bufp, + *regexp, + re_delim; + int re_options, + error; + regex_t *expr; + + re_delim = *p++; + regexp = p; + + /* Search for second delimiter, handling backslash escape */ + while (*p) { + if (*p == '\\') { + if (p[1]) + p++; + else + break; + } else if (*p == re_delim) { + break; + } + ++p; + } + if (!*p) { + msg_warn("%s, line %d: no closing regexp delimiter: %c", + VSTREAM_PATH(map_fp), lineno, re_delim); + return NULL; + } + *p++ = '\0'; /* Null term the regexp */ + + re_options = REG_EXTENDED | REG_ICASE; + while (*p) { + if (!*p || ISSPACE(*p) || (*p == '!' && p[1] == re_delim)) { + /* end of the regexp */ + expr = (regex_t *) mymalloc(sizeof(*expr)); + error = regcomp(expr, regexp, re_options); + if (error != 0) { + char errbuf[256]; + + (void) regerror(error, expr, errbuf, sizeof(errbuf)); + msg_warn("%s, line %d: error in regexp: %s.", + VSTREAM_PATH(map_fp), lineno, errbuf); + myfree((char *) expr); + return NULL; + } + *bufp = p; + return expr; + } else { + switch (*p) { + case 'i': + re_options ^= REG_ICASE; + break; + case 'm': + re_options ^= REG_NEWLINE; + break; + case 'x': + re_options ^= REG_EXTENDED; + break; + default: + msg_warn("%s, line %d: unknown regexp option '%c'", + VSTREAM_PATH(map_fp), lineno, *p); + } + ++p; + } + } + return NULL; +} + +static DICT_REGEXP_RULE *dict_regexp_parseline(int lineno, char *line, int *nsub, VSTREAM *map_fp) +{ + DICT_REGEXP_RULE *rule; + char *p, + re_delim; + regex_t *expr1, + *expr2; + int total_nsub; + + p = line; + re_delim = *p; + + expr1 = dict_regexp_get_expr(lineno, &p, map_fp); + if (!expr1) { + return NULL; + } else if (*p == '!' && p[1] == re_delim) { + p++; + expr2 = dict_regexp_get_expr(lineno, &p, map_fp); + if (!expr2) { + myfree((char *) expr1); + return NULL; + } + total_nsub = expr1->re_nsub + expr2->re_nsub + 2; + } else { + expr2 = NULL; + total_nsub = expr1->re_nsub + 1; + } + if (nsub) + *nsub = total_nsub; + + if (!ISSPACE(*p)) { + msg_warn("%s, line %d: Too many expressions.", + VSTREAM_PATH(map_fp), lineno); + myfree((char *) expr1); + if (expr2) + myfree((char *) expr2); + return NULL; + } + rule = (DICT_REGEXP_RULE *) mymalloc(sizeof(DICT_REGEXP_RULE)); + + while (*p && ISSPACE(*p)) + ++p; + + if (!*p) { + msg_warn("%s, line %d: no replacement text: using empty string", + VSTREAM_PATH(map_fp), lineno); + p = ""; + } + rule->expr[0] = expr1; + rule->expr[1] = expr2; + rule->replace = mystrdup(p); + rule->lineno = lineno; + return rule; +} + +/* + * dict_regexp_open - load and compile a file containing regular expressions + */ +DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags) +{ + DICT_REGEXP *dict_regexp; + VSTREAM *map_fp; + VSTRING *line_buffer; + DICT_REGEXP_RULE *rule, + *last_rule = NULL; + int lineno = 0; + int max_nsub = 0; + int nsub; + char *p; + + line_buffer = vstring_alloc(100); + + dict_regexp = (DICT_REGEXP *) mymalloc(sizeof(*dict_regexp)); + dict_regexp->dict.lookup = dict_regexp_lookup; + dict_regexp->dict.update = dict_regexp_update; + dict_regexp->dict.close = dict_regexp_close; + dict_regexp->dict.fd = -1; + dict_regexp->map = mystrdup(map); + dict_regexp->dict.flags = dict_flags; + + if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { + msg_fatal("open %s: %m", map); + } + while (readline(line_buffer, map_fp, &lineno)) { + p = vstring_str(line_buffer); + + if (*p == '#') /* Skip comments */ + continue; + + if (*p == 0) /* Skip blank lines */ + continue; + + rule = dict_regexp_parseline(lineno, p, &nsub, map_fp); + if (rule) { + if (nsub > max_nsub) + max_nsub = nsub; + + if (last_rule == NULL) + dict_regexp->head = rule; + else + last_rule->next = rule; + last_rule = rule; + } + } + last_rule->next = NULL; + + dict_regexp->pmatch = (regmatch_t *) mymalloc(sizeof(regmatch_t) * max_nsub); + dict_regexp->nmatch = max_nsub; + + vstring_free(line_buffer); + vstream_fclose(map_fp); + + return (&dict_regexp->dict); +} + +#endif /* NO_POSIX_REGEXP */ diff --git a/postfix/util/dict_regexp.h b/postfix/util/dict_regexp.h new file mode 100644 index 000000000..f487bedf6 --- /dev/null +++ b/postfix/util/dict_regexp.h @@ -0,0 +1,40 @@ +#ifndef _DICT_REGEXP_H_INCLUDED_ +#define _DICT_REGEXP_H_INCLUDED_ + +/*++ +/* NAME +/* dict_regexp 3h +/* SUMMARY +/* dictionary manager interface to REGEXP regular expression library +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +extern DICT *dict_regexp_open(const char *, int, int); + +/* AUTHOR(S) +/* LaMont Jones +/* lamont@hp.com +/* +/* Based on PCRE dictionary contributed by Andrew McNamara +/* andrewm@connect.com.au +/* connect.com.au Pty. Ltd. +/* Level 3, 213 Miller St +/* North Sydney, NSW, Australia +/* +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif diff --git a/postfix/util/dict_unix.c b/postfix/util/dict_unix.c index 82f36b805..efc945130 100644 --- a/postfix/util/dict_unix.c +++ b/postfix/util/dict_unix.c @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_unix_open(map, dummy) +/* DICT *dict_unix_open(map, dummy, dict_flags) /* const char *map; /* int dummy; +/* int dict_flags; /* DESCRIPTION /* dict_unix_open() makes the specified UNIX table accessible via /* the generic dictionary operations described in dict_open(3). @@ -96,7 +97,7 @@ static void dict_unix_close(DICT *dict) /* dict_unix_open - open UNIX map */ -DICT *dict_unix_open(const char *map, int unused_flags) +DICT *dict_unix_open(const char *map, int unused_flags, int dict_flags) { DICT_UNIX *dict_unix; struct dict_unix_lookup { @@ -121,5 +122,6 @@ DICT *dict_unix_open(const char *map, int unused_flags) dict_unix->dict.close = dict_unix_close; dict_unix->dict.fd = -1; dict_unix->map = mystrdup(map); + dict_unix->dict.flags = dict_flags; return (&dict_unix->dict); } diff --git a/postfix/util/dict_unix.h b/postfix/util/dict_unix.h index c0cce81a5..b82a1ec8f 100644 --- a/postfix/util/dict_unix.h +++ b/postfix/util/dict_unix.h @@ -19,7 +19,7 @@ /* * External interface. */ -extern DICT *dict_unix_open(const char *, int); +extern DICT *dict_unix_open(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/environ.c b/postfix/util/environ.c index f93f6d591..cec1a865c 100644 --- a/postfix/util/environ.c +++ b/postfix/util/environ.c @@ -1,10 +1,156 @@ /* - * The environ.c module from TCP Wrappers is not bundled with IBM's public - * release. It will be made available as contributed software from - * http://www.postfix.org/ + * From: TCP Wrapper. + * + * Many systems have putenv() but no setenv(). Other systems have setenv() but + * no putenv() (MIPS). Still other systems have neither (NeXT). This is a + * re-implementation that hopefully ends all problems. + * + * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #include "sys_defs.h" #ifdef MISSING_SETENV_PUTENV -#error "This requires contributed software from http://www.postfix.org/" + +#include +#include +#include + +extern char **environ; + +static int addenv(char *); /* append entry to environment */ +static int allocated = 0; /* environ is, or is not, allocated */ + +#define DO_CLOBBER 1 + +/* namelength - determine length of name in "name=whatever" */ + +static int namelength(const char *name) +{ + char *equal; + + equal = strchr(name, '='); + return ((equal == 0) ? strlen(name) : (equal - name)); +} + +/* findenv - given name, locate name=value */ + +static char **findenv(const char *name, int len) +{ + char **envp; + + for (envp = environ; envp && *envp; envp++) + if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=') + return (envp); + return (0); +} + +#if 0 + +/* getenv - given name, locate value */ + +char *getenv(const char *name) +{ + int len = namelength(name); + char **envp = findenv(name, len); + + return (envp ? *envp + len + 1 : 0); +} + +/* putenv - update or append environment (name,value) pair */ + +int putenv(const char *nameval) +{ + char *equal = strchr(nameval, '='); + char *value = (equal ? equal : ""); + + return (setenv(nameval, value, DO_CLOBBER)); +} + +/* unsetenv - remove variable from environment */ + +void unsetenv(const char *name) +{ + char **envp; + + while ((envp = findenv(name, namelength(name))) != 0) + while (envp[0] = envp[1]) + envp++; +} + +#endif + +/* setenv - update or append environment (name,value) pair */ + +int setenv(const char *name, const char *value, int clobber) +{ + char *destination; + char **envp; + int l_name; /* length of name part */ + unsigned int l_nameval; /* length of name=value */ + + /* Permit name= and =value. */ + + l_name = namelength(name); + envp = findenv(name, l_name); + if (envp != 0 && clobber == 0) + return (0); + if (*value == '=') + value++; + l_nameval = l_name + strlen(value) + 1; + + /* + * Use available memory if the old value is long enough. Never free an + * old name=value entry because it may not be allocated. + */ + + destination = (envp != 0 && strlen(*envp) >= l_nameval) ? + *envp : malloc(l_nameval + 1); + if (destination == 0) + return (-1); + strncpy(destination, name, l_name); + destination[l_name] = '='; + strcpy(destination + l_name + 1, value); + return ((envp == 0) ? addenv(destination) : (*envp = destination, 0)); +} + +/* cmalloc - malloc and copy block of memory */ + +static char *cmalloc(int new_len, char *old, int old_len) +{ + char *new = malloc(new_len); + + if (new != 0) + memcpy(new, old, old_len); + return (new); +} + +/* addenv - append environment entry */ + +static int addenv(char *nameval) +{ + char **envp; + int n_used; /* number of environment entries */ + int l_used; /* bytes used excl. terminator */ + int l_need; /* bytes needed incl. terminator */ + + for (envp = environ; envp && *envp; envp++) + /* void */ ; + n_used = envp - environ; + l_used = n_used * sizeof(*envp); + l_need = l_used + 2 * sizeof(*envp); + + envp = allocated ? + (char **) realloc((char *) environ, l_need) : + (char **) cmalloc(l_need, (char *) environ, l_used); + if (envp == 0) { + return (-1); + } else { + allocated = 1; + environ = envp; + environ[n_used++] = nameval; /* add new entry */ + environ[n_used] = 0; /* terminate list */ + return (0); + } +} + #endif diff --git a/postfix/util/match_list.c b/postfix/util/match_list.c index 1ced1d806..22f0a16ba 100644 --- a/postfix/util/match_list.c +++ b/postfix/util/match_list.c @@ -109,7 +109,7 @@ static ARGV *match_list_parse(ARGV *list, char *string) } else if (strchr(pattern, ':') != 0) { /* type:table */ for (cp = pattern; *cp == '!'; cp++) /* void */ ; - dict_register(pattern, dict_open(pattern, 0)); + dict_register(pattern, dict_open(pattern, 0, 0)); argv_add(list, pattern, (char *) 0); } else { /* other pattern */ argv_add(list, pattern, (char *) 0); diff --git a/postfix/util/posix_signals.c b/postfix/util/posix_signals.c index b7029ddb6..8ccddf0f7 100644 --- a/postfix/util/posix_signals.c +++ b/postfix/util/posix_signals.c @@ -1,15 +1,126 @@ - /* - * The NETXSTEP and OPENSTEP software is not bundled with IBM's public - * release. It will be made available as contributed software from - * http://www.postfix.org/ - */ +/*++ +/* NAME +/* posix_signals 3 +/* SUMMARY +/* POSIX signal handling compatibility +/* SYNOPSIS +/* #include +/* +/* int sigemptyset(m) +/* sigset_t *m; +/* +/* int sigaddset(set, signum) +/* sigset_t *set; +/* int signum; +/* +/* int sigprocmask(how, set, old) +/* int how; +/* sigset_t *set; +/* sigset_t *old; +/* +/* int sigaction(sig, act, oact) +/* int sig; +/* struct sigaction *act; +/* struct sigaction *oact; +/* DESCRIPTION +/* These routines emulate the POSIX signal handling interface. +/* AUTHOR(S) +/* Pieter Schoenmakers +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven +/* The Netherlands +/*--*/ + +/* System library. */ + #include "sys_defs.h" +#include +#include + +/* Utility library.*/ + +#include "posix_signals.h" #ifdef MISSING_SIGSET_T -#error "This requires contributed software from http://www.postfix.org/" + +int sigemptyset(sigset_t *m) +{ + return *m = 0; +} + +int sigaddset(sigset_t *set, int signum) +{ + *set |= sigmask(signum); + return 0; +} + +int sigprocmask(int how, sigset_t *set, sigset_t *old) +{ + int previous; + + if (how == SIG_BLOCK) + previous = sigblock(*set); + else if (how == SIG_SETMASK) + previous = sigsetmask(*set); + else if (how == SIG_UNBLOCK) { + int m = sigblock(0); + + previous = sigsetmask(m & ~*set); + } else { + errno = EINVAL; + return -1; + } + + if (old) + *old = previous; + return 0; +} + #endif #ifdef MISSING_SIGACTION -#error "This requires contributed software from http://www.postfix.org/" -#endif +static struct sigaction actions[NSIG] = {}; + +static int sighandle(int signum) +{ + if (signum == SIGCHLD) { + /* XXX If the child is just stopped, don't invoke the handler. */ + } + actions[signum].sa_handler(signum); +} + +int sigaction(int sig, struct sigaction *act, struct sigaction *oact) +{ + static int initialized = 0; + + if (!initialized) { + int i; + + for (i = 0; i < NSIG; i++) + actions[i].sa_handler = SIG_DFL; + initialized = 1; + } + if (sig <= 0 || sig >= NSIG) { + errno = EINVAL; + return -1; + } + if (oact) + *oact = actions[sig]; + + { + struct sigvec mine = { + sighandle, act->sa_mask, + act->sa_flags & SA_RESTART ? SV_INTERRUPT : 0 + }; + + if (sigvec(sig, &mine, NULL)) + return -1; + } + + actions[sig] = *act; + return 0; +} + +#endif diff --git a/postfix/util/posix_signals.h b/postfix/util/posix_signals.h index a2f6bbf6f..12c1664db 100644 --- a/postfix/util/posix_signals.h +++ b/postfix/util/posix_signals.h @@ -1,5 +1,59 @@ +#ifndef _POSIX_SIGNALS_H_INCLUDED_ +#define _POSIX_SIGNALS_H_INCLUDED_ +/*++ +/* NAME +/* posix_signals 3h +/* SUMMARY +/* POSIX signal handling compatibility +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + /* - * The NETXSTEP and OPENSTEP software is not bundled with IBM's public - * release. It will be made available as contributed software from - * http://www.postfix.org/ + * Compatibility interface. */ + +#ifdef MISSING_SIGSET_T + +typedef int sigset_t; + +enum { + SIG_BLOCK, + SIG_UNBLOCK, + SIG_SETMASK +}; + +extern int sigemptyset(sigset_t *); +extern int sigaddset(sigset_t *, int); +extern int sigprocmask(int, sigset_t *, sigset_t *); + +#endif + +#ifdef MISSING_SIGACTION + +struct sigaction { + void (*sa_handler) (); + sigset_t sa_mask; + int sa_flags; +}; + + /* Possible values for sa_flags. Or them to set multiple. */ +enum { + SA_RESTART, + SA_NOCLDSTOP = 4 /* drop the = 4. */ +}; + +extern int sigaction(int, struct sigaction *, struct sigaction *); + +#endif + +/* AUTHOR(S) +/* Pieter Schoenmakers +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven +/* The Netherlands +/*--*/ + +#endif diff --git a/postfix/util/sys_defs.h b/postfix/util/sys_defs.h index 3d5c4ad29..f0bbee356 100644 --- a/postfix/util/sys_defs.h +++ b/postfix/util/sys_defs.h @@ -36,6 +36,7 @@ #define ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" #define USE_STATFS #define STATFS_IN_SYS_MOUNT_H +#define HAS_POSIX_REGEXP #endif #if defined(OPENBSD2) @@ -285,6 +286,7 @@ extern int initgroups(const char *, int); #define STATFS_IN_SYS_VFS_H #define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT #define PREPEND_PLUS_TO_OPTSTRING +#define HAS_POSIX_REGEXP #endif /*