From: Wietse Venema Date: Tue, 16 Nov 1999 05:00:00 +0000 (-0500) Subject: snapshot-19991116 X-Git-Tag: v20010228~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=406e23a161533e160ea54c7bf3915de0479240e0;p=thirdparty%2Fpostfix.git snapshot-19991116 --- diff --git a/postfix/DEBUG_README b/postfix/DEBUG_README index c309f4263..89ca99136 100644 --- a/postfix/DEBUG_README +++ b/postfix/DEBUG_README @@ -43,6 +43,9 @@ a process is attempting to do. This is as much information as you can get without running an interactive debugger program, as described in the next section. +See the next section on how to automatically attach a program to +a Postfix daemon. + 5 - Running daemon programs under an interactive debugger ========================================================= @@ -68,3 +71,48 @@ Stop and start the Postfix system. Whenever the suspect daemon process is started, a debugger window pops up and you can watch in detail what happens. + +6 - Unreasonable behavior +========================= + +Sometimes the behavior exhibit by Postfix just does not match the +source code. Why can a program deviate from the instructions given +by its author? There are two possibilities. + +1 - The compiler has messed up. + +2 - The hardware has messed up. + +In both cases, the program being executed is not the program that +was supposed to be executed, so anything can happen. + +Hardware-related failures happen erratically, and they usually do +not reproduce after power cycling and rebooting the system. There's +little I can do about bad hardware. Be sure to use hardware that +at the very least can detect memory errors. Otherwise, Postfix will +just be a sitting duck waiting to be hit by a bit error. Critical +systems deserve real hardware. + +When a compiler messes up, the problem can be reproduced whenever +the resulting program is run. Compiler errors are most likely to +happen in the code optimizer. If a problem is reproducible across +power cycles and system reboots, it can be worthwhile to rebuild +Postfix with optimization disabled, and to see if optimization +makes a difference. + +In order to compile Postfix with optimizations turned off: + + % make tidy + % make makefiles OPT= + +This produces a set of Makefiles that do not request compiler +optomization. + +Once the makefiles are set up, build the software: + + % make + % su + # make install + +And see if the problem reproduces. If the problem goes away, talk +to your vendor. diff --git a/postfix/HISTORY b/postfix/HISTORY index 9996bd434..561854489 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -3220,6 +3220,23 @@ Apologies for any names omitted. Feature: permit_auth_destination restriction based on code by Jesper Skriver @ skriver.dk. - Code cleanup: the transport table now can override local - deliveries. Postfix no longer uses the "empty next-hop - hostname hack" to remember that a destination is local. + Code cleanup: the transport table now can override all + deliveries, including local ones. + +19991116 + + Code cleanup: a new "local_transports" configuration + parameter explicitly lists all transports that deliver + mail locally. The first name listed there is the default + local transport. This is the end of the "empty next-hop + hostname" hack to indicate that a destination is local. + Files: trivial-rewrite/resolve.c, global/local_transport.[hc] + + Feature: "postconf -m" shows what lookup table types are + available. Code by Scott Cotton, Internet Consultants + Group, Inc. + + Feature: "postconf -e" edits any number of main.cf parameters. + The edit is done on a copy, and the copy is renamed into + the place of the original. File: postconf/postconf.c, + util/readlline.[hc]. diff --git a/postfix/dns/Makefile.in b/postfix/dns/Makefile.in index 5deff368a..be767bef2 100644 --- a/postfix/dns/Makefile.in +++ b/postfix/dns/Makefile.in @@ -75,6 +75,7 @@ dns_lookup.o: ../include/vstring.h dns_lookup.o: ../include/vbuf.h dns_lookup.o: ../include/msg.h dns_lookup.o: ../include/valid_hostname.h +dns_lookup.o: ../include/stringops.h dns_lookup.o: dns.h dns_rr.o: dns_rr.c dns_rr.o: ../include/sys_defs.h diff --git a/postfix/dns/dns_lookup.c b/postfix/dns/dns_lookup.c index e548f2c0f..19e809dd2 100644 --- a/postfix/dns/dns_lookup.c +++ b/postfix/dns/dns_lookup.c @@ -247,7 +247,7 @@ static int dns_get_fixed(unsigned char *pos, DNS_FIXED *fixed) static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos, char *rr_name, DNS_FIXED *fixed) { - char temp[DNS_NAME_LEN]; + unsigned char temp[DNS_NAME_LEN]; int data_len; unsigned pref = 0; unsigned char *src; diff --git a/postfix/global/Makefile.in b/postfix/global/Makefile.in index 25c29af3b..e4c6889ce 100644 --- a/postfix/global/Makefile.in +++ b/postfix/global/Makefile.in @@ -2,7 +2,8 @@ SHELL = /bin/sh SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \ debug_peer.c debug_process.c defer.c deliver_completed.c \ deliver_flock.c deliver_pass.c deliver_request.c domain_list.c \ - dot_lockfile.c file_id.c header_opts.c is_header.c mail_addr.c \ + dot_lockfile.c dot_lockfile_as.c ext_prop.c file_id.c \ + header_opts.c is_header.c local_transport.c mail_addr.c \ mail_addr_crunch.c mail_addr_find.c mail_addr_map.c \ mail_command_read.c mail_command_write.c mail_conf.c \ mail_conf_bool.c mail_conf_int.c mail_conf_raw.c mail_conf_str.c \ @@ -16,12 +17,12 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \ recipient_list.c record.c remove.c resolve_clnt.c resolve_local.c \ rewrite_clnt.c sent.c smtp_stream.c split_addr.c string_list.c \ sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \ - tok822_resolve.c tok822_rewrite.c tok822_tree.c ext_prop.c \ - dot_lockfile_as.c + tok822_resolve.c tok822_rewrite.c tok822_tree.c OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ debug_peer.o debug_process.o defer.o deliver_completed.o \ deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \ - dot_lockfile.o file_id.o header_opts.o is_header.o mail_addr.o \ + dot_lockfile.o dot_lockfile_as.o ext_prop.o file_id.o \ + header_opts.o is_header.o local_transport.o mail_addr.o \ mail_addr_crunch.o mail_addr_find.o mail_addr_map.o \ mail_command_read.o mail_command_write.o mail_conf.o \ mail_conf_bool.o mail_conf_int.o mail_conf_raw.o mail_conf_str.o \ @@ -35,12 +36,12 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ recipient_list.o record.o remove.o resolve_clnt.o resolve_local.o \ rewrite_clnt.o sent.o smtp_stream.o split_addr.o string_list.o \ sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \ - tok822_resolve.o tok822_rewrite.o tok822_tree.o ext_prop.o \ - dot_lockfile_as.o + tok822_resolve.o tok822_rewrite.o tok822_tree.o HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ config.h debug_peer.h debug_process.h defer.h deliver_completed.h \ deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \ - dot_lockfile.h file_id.h header_opts.h is_header.h mail_addr.h \ + dot_lockfile.h dot_lockfile_as.h ext_prop.h file_id.h \ + header_opts.h is_header.h local_transport.h mail_addr.h \ mail_addr_crunch.h mail_addr_find.h mail_addr_map.h mail_conf.h \ mail_copy.h mail_date.h mail_error.h mail_flush.h mail_open_ok.h \ mail_params.h mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h \ @@ -50,7 +51,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ quote_822_local.h rec_streamlf.h rec_type.h recipient_list.h \ record.h resolve_clnt.h resolve_local.h rewrite_clnt.h sent.h \ smtp_stream.h split_addr.h string_list.h sys_exits.h timed_ipc.h \ - tok822.h ext_prop.h dot_lockfile_as.h + tok822.h TESTSRC = rec2stream.c stream2rec.c recdump.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ @@ -62,7 +63,8 @@ LIB = libglobal.a TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \ mail_addr_map mail_date maps mynetworks mypwd namadr_list \ off_cvt quote_822_local rec2stream recdump resolve_clnt \ - resolve_local rewrite_clnt stream2rec string_list tok822_parse + resolve_local rewrite_clnt stream2rec string_list tok822_parse \ + local_transport LIBS = ../lib/libutil.a LIB_DIR = ../lib @@ -187,6 +189,11 @@ string_list: $(LIB) $(LIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) mv junk $@.o +local_transport: $(LIB) $(LIBS) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) + mv junk $@.o + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -361,6 +368,13 @@ header_opts.o: header_opts.h is_header.o: is_header.c is_header.o: ../include/sys_defs.h is_header.o: is_header.h +local_transport.o: local_transport.c +local_transport.o: ../include/sys_defs.h +local_transport.o: ../include/msg.h +local_transport.o: ../include/mymalloc.h +local_transport.o: string_list.h +local_transport.o: mail_params.h +local_transport.o: local_transport.h mail_addr.o: mail_addr.c mail_addr.o: ../include/sys_defs.h mail_addr.o: ../include/stringops.h diff --git a/postfix/global/local_transport.c b/postfix/global/local_transport.c new file mode 100644 index 000000000..97f3f623f --- /dev/null +++ b/postfix/global/local_transport.c @@ -0,0 +1,134 @@ +/*++ +/* NAME +/* local_transport 3 +/* SUMMARY +/* determine if transport delivers locally +/* SYNOPSIS +/* #include +/* +/* const char *def_local_transport() +/* +/* int local_transport(transport) +/* const char *transport; +/* DESCRIPTION +/* This module uses the information kept in the "local_transports" +/* configuration parameter, which lists the names of the default +/* local transport followed by zero or more other transports that +/* deliver locally. +/* +/* def_local_transport() returns the name of the default local +/* transport, that is, the first transport name specified with +/* the "local_transports" configuration parameter. +/* +/* local_transport() determines if the named transport is listed +/* in the "local_transports" configuration parameter. +/* SEE ALSO +/* resolve_local(3), see if address resolves locally. +/* 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 + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific */ + +static STRING_LIST *local_transport_list; +static char *local_transport_name; + +/* local_transport_init - initialize lookup table */ + +static void local_transport_init(void) +{ + char *myname = "local_transport_init"; + + /* + * Sanity check. + */ + if (local_transport_list || local_transport_name) + msg_panic("local_transport_init: duplicate initialization"); + + /* + * Initialize. + */ + local_transport_list = string_list_init(var_local_transports); + local_transport_name = mystrndup(var_local_transports, + strcspn(var_local_transports, ", \t\r\n")); + + /* + * Sanity check. + */ + if (!local_transport(local_transport_name)) + msg_panic("%s: unable to intialize", myname); +} + +/* def_local_transport - determine default local transport */ + +const char *def_local_transport(void) +{ + + /* + * Initialize on the fly. + */ + if (local_transport_list == 0) + local_transport_init(); + + /* + * Return the first transport listed. + */ + return (local_transport_name); +} + +/* local_transport - match address against list of local destinations */ + +int local_transport(const char *transport) +{ + + /* + * Initialize on the fly. + */ + if (local_transport_list == 0) + local_transport_init(); + + /* + * Compare the transport against the list of transports that are listed + * as delivering locally. + */ + return (string_list_match(local_transport_list, transport)); +} + +#ifdef TEST + +#include +#include + +int main(int argc, char **argv) +{ + if (argc != 2) + msg_fatal("usage: %s transport", argv[0]); + mail_conf_read(); + vstream_printf("%s\n", local_transport(argv[1]) ? "yes" : "no"); + vstream_fflush(VSTREAM_OUT); +} + +#endif diff --git a/postfix/global/local_transport.h b/postfix/global/local_transport.h new file mode 100644 index 000000000..d3defdaa3 --- /dev/null +++ b/postfix/global/local_transport.h @@ -0,0 +1,31 @@ +#ifndef _LOCAL_TRANSPORT_H_INCLUDED_ +#define _LOCAL_TRANSPORT_H_INCLUDED_ + +/*++ +/* NAME +/* local_transport 3h +/* SUMMARY +/* determine if transport delivers locally +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * External interface. + */ +extern const char *def_local_transport(void); +extern int local_transport(const char *); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif diff --git a/postfix/global/mail_params.c b/postfix/global/mail_params.c index 00d15ef8f..7f65ef3dd 100644 --- a/postfix/global/mail_params.c +++ b/postfix/global/mail_params.c @@ -57,6 +57,7 @@ /* time_t var_starttime; /* int var_ownreq_special; /* int var_daemon_timeout; +/* char *var_local_transports; /* /* void mail_params_init() /* DESCRIPTION @@ -161,6 +162,7 @@ int var_soft_bounce; time_t var_starttime; int var_ownreq_special; int var_daemon_timeout; +char *var_local_transports; /* check_myhostname - lookup hostname and validate */ @@ -261,6 +263,7 @@ void mail_params_init() VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1, + VAR_LOCAL_TRANSP, DEF_LOCAL_TRANSP, &var_local_transports, 1, 0, 0, }; static CONFIG_STR_FN_TABLE function_str_defaults_2[] = { diff --git a/postfix/global/mail_params.h b/postfix/global/mail_params.h index 53c2f1800..4ac0d40ee 100644 --- a/postfix/global/mail_params.h +++ b/postfix/global/mail_params.h @@ -80,6 +80,13 @@ extern char *var_myhostname; #define VAR_MYDOMAIN "mydomain" /* my domain name */ extern char *var_mydomain; + /* + * Transports that deliver locally. Order matters. + */ +#define VAR_LOCAL_TRANSP "local_transports" +#define DEF_LOCAL_TRANSP "local" +extern char *var_local_transports; + /* * Where to send postmaster copies of bounced mail, and other notices. */ diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index 070732ad2..d2a5741a2 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-19991115" +#define DEF_MAIL_VERSION "Snapshot-19991116" extern char *var_mail_version; /* LICENSE diff --git a/postfix/local/Makefile.in b/postfix/local/Makefile.in index 738d12e57..47c074ee5 100644 --- a/postfix/local/Makefile.in +++ b/postfix/local/Makefile.in @@ -375,6 +375,7 @@ resolve.o: ../include/resolve_clnt.h resolve.o: ../include/rewrite_clnt.h resolve.o: ../include/tok822.h resolve.o: ../include/mail_params.h +resolve.o: ../include/local_transport.h resolve.o: local.h resolve.o: ../include/been_here.h resolve.o: ../include/deliver_request.h diff --git a/postfix/local/resolve.c b/postfix/local/resolve.c index b6b1837b6..2aa44a1eb 100644 --- a/postfix/local/resolve.c +++ b/postfix/local/resolve.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include /* Application-specific. */ @@ -139,7 +139,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr * ugly code to force local recursive alias expansions on a host with no * authority over the local domain, but that code was just too unclean. */ - if (resolve_local(STR(reply.nexthop))) { + if (local_transport(STR(reply.transport))) { status = deliver_recipient(state, usr_attr); } else { status = deliver_indirect(state); diff --git a/postfix/master/master_ent.c b/postfix/master/master_ent.c index ae77491ca..7f6b79748 100644 --- a/postfix/master/master_ent.c +++ b/postfix/master/master_ent.c @@ -237,7 +237,7 @@ MASTER_SERV *get_master_ent() * Skip blank lines and comment lines. */ do { - if (readlline(buf, master_fp, &master_line) == 0) { + if (readlline(buf, master_fp, &master_line, READLL_STRIPNL) == 0) { vstring_free(buf); vstring_free(junk); return (0); diff --git a/postfix/postalias/postalias.c b/postfix/postalias/postalias.c index 93b8d5fe9..79f7f40ea 100644 --- a/postfix/postalias/postalias.c +++ b/postfix/postalias/postalias.c @@ -164,7 +164,7 @@ static void postalias(char *map_type, char *path_name, * Add records to the database. */ lineno = 0; - while (readlline(line_buffer, source_fp, &lineno)) { + while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) { /* * Skip comments. diff --git a/postfix/postconf/postconf.c b/postfix/postconf/postconf.c index d7d44c871..dbc99f307 100644 --- a/postfix/postconf/postconf.c +++ b/postfix/postconf/postconf.c @@ -5,21 +5,32 @@ /* Postfix configuration utility /* SYNOPSIS /* .fi -/* \fBpostconf\fR [\fB-c \fIconfig_dir\fR] [\fB-d\fR] [\fB-h\fR] -/* [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR] +/* \fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR] +/* [\fIparameter ...\fR] +/* +/* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR] +/* [\fIparameter=value ...\fR] /* DESCRIPTION /* The \fBpostconf\fR command prints the actual value of /* \fIparameter\fR (all known parameters by default), one -/* parameter per line. +/* parameter per line, changes its value, or prints other +/* information about the Postfix mail system. /* /* Options: /* .IP "\fB-c \fIconfig_dir\fR" /* The \fBmain.cf\fR configuration file is in the named directory. /* .IP \fB-d\fR /* Print default parameter settings instead of actual settings. +/* .IP \fB-e\fR +/* Edit the \fBmain.cf\fR configuration file. The file is copied +/* to a temporary file then renamed into place. Parameters and +/* values are specified on the command line. Use quotes in order +/* to protect shell metacharacters and whitespace. /* .IP \fB-h\fR /* Show parameter values only, not the ``name = '' label /* that normally precedes the value. +/* .IP \fB-m\fR +/* List the names of all supported lookup table types. /* .IP \fB-n\fR /* Print non-default parameter settings only. /* .IP \fB-v\fR @@ -42,10 +53,12 @@ #include #include +#include /* rename() */ #include #include #include #include +#include #ifdef STRCASECMP_IN_STRINGS_H #include @@ -66,7 +79,10 @@ #include #include #include -#include +#include +#include +#include +#include /* Global library. */ @@ -78,11 +94,13 @@ #include /* - * What output we should generate. + * What we're supposed to be doing. */ #define SHOW_NONDEF (1<<0) /* show non-default settings */ #define SHOW_DEFS (1<<1) /* show default setting */ #define SHOW_NAME (1<<2) /* show parameter name */ +#define SHOW_MAPS (1<<3) /* show map types */ +#define EDIT_MAIN (1<<4) /* edit main.cf */ /* * Lookup table for in-core parameter info. @@ -214,6 +232,131 @@ static const char *check_mynetworks(void) return (mynetworks()); } +/* edit_parameters - edit parameter file */ + +static void edit_parameters(int argc, char **argv) +{ + char *config_dir; + char *path; + char *temp; + VSTREAM *src; + VSTREAM *dst; + VSTRING *buf = vstring_alloc(100); + VSTRING *key = vstring_alloc(10); + char *cp; + char *value; + HTABLE *table; + int first = 1; + struct cvalue { + char *value; + int found; + }; + struct cvalue *cvalue; + HTABLE_INFO **ht_info; + HTABLE_INFO **ht; + + /* + * Store command-line parameters for quick lookup. + */ + table = htable_create(argc); + while ((cp = *argv++) != 0) { + if ((value = split_at(cp, '=')) == 0 + || *(cp += strspn(cp, " \t\r\n")) == 0) + msg_fatal("edit requires \"key = value\" arguments"); + cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); + cvalue->value = value; + cvalue->found = 0; + htable_enter(table, mystrtok(&cp, " \t\r\n"), (char *) cvalue); + } + + /* + * XXX Avoid code duplication by better code decomposition. + */ + if (var_config_dir) + myfree(var_config_dir); + var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ? + config_dir : DEF_CONFIG_DIR); /* XXX */ + set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir); + + /* + * Open the original file for input. + */ + path = concatenate(var_config_dir, "/", "main.cf", (char *) 0); + if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) + msg_fatal("open %s for reading: %m", path); + + /* + * Open a temp file for the result. We use a fixed name so we don't leave + * behind thrash with random names. Lock the temp file to avoid + * accidents. Truncate the file only after we have an exclusive lock. + */ + temp = concatenate(path, ".tmp", (char *) 0); + if ((dst = vstream_fopen(temp, O_CREAT | O_WRONLY, 0644)) == 0) + msg_fatal("open %s: %m", temp); + if (myflock(vstream_fileno(dst), MYFLOCK_EXCLUSIVE) < 0) + msg_fatal("lock %s: %m", temp); + if (ftruncate(vstream_fileno(dst), 0) < 0) + msg_fatal("truncate %s: %m", temp); + + /* + * Copy original file to temp file, while replacing parameters on the + * fly. Issue warnings for names found multiple times. + */ +#define STR(x) vstring_str(x) + + while (readlline(buf, src, (int *) 0, READLL_KEEPNL)) { + cp = STR(buf); + if (first) { + first = 0; + if (ISSPACE(*cp)) + msg_fatal("%s: file starts with whitespace", path); + } + if (*cp == '#') { + vstream_fputs(STR(buf), dst); + continue; + } + cp += strspn(cp, " \t\r\n"); + vstring_strncpy(key, cp, strcspn(cp, " \t\r\n=")); + cvalue = (struct cvalue *) htable_find(table, STR(key)); + if (cvalue == 0) { + vstream_fputs(STR(buf), dst); + } else { + if (cvalue->found++ == 1) + msg_warn("%s: multiple entries for key %s", path, STR(key)); + vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value); + } + } + + /* + * Generate new entries for parameters that were not found. + */ + for (ht_info = ht = htable_list(table); *ht; ht++) { + cvalue = (struct cvalue *) ht[0]->value; + if (cvalue->found == 0) + vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value); + } + myfree((char *) ht_info); + + /* + * When all is well, rename the temp file to the original one. + */ + if (vstream_fclose(src)) + msg_fatal("read %s: %m", path); + if (vstream_fclose(dst)) + msg_fatal("write %s: %m", temp); + if (rename(temp, path) < 0) + msg_fatal("rename %s to %s: %m", temp, path); + + /* + * Cleanup. + */ + myfree(path); + myfree(temp); + vstring_free(buf); + vstring_free(key); + htable_free(table, myfree); +} + /* read_parameters - read parameter info from file */ static void read_parameters(void) @@ -430,6 +573,19 @@ static int comp_names(const void *a, const void *b) return (strcmp(ap[0]->key, bp[0]->key)); } +/* show_maps - show available maps */ + +static void show_maps(void) +{ + ARGV *maps_argv; + int i; + + maps_argv = dict_mapnames(); + for (i = 0; i < maps_argv->argc; i++) + vstream_printf("%s\n", maps_argv->argv[i]); + argv_free(maps_argv); +} + /* show_parameters - show parameter info */ static void show_parameters(int mode, char **names) @@ -470,6 +626,7 @@ int main(int argc, char **argv) int ch; int fd; struct stat st; + int junk; /* * To minimize confusion, make sure that the standard file descriptors @@ -489,44 +646,70 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "c:dhnv")) > 0) { + while ((ch = GETOPT(argc, argv, "c:dehnmv")) > 0) { switch (ch) { case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'd': - if (mode & SHOW_NONDEF) - msg_fatal("specify one of -d and -n"); mode |= SHOW_DEFS; break; + case 'e': + mode |= EDIT_MAIN; + break; case 'h': mode &= ~SHOW_NAME; break; + case 'm': + mode |= SHOW_MAPS; + break; case 'n': - if (mode & SHOW_DEFS) - msg_fatal("specify one of -d and -n"); mode |= SHOW_NONDEF; break; case 'v': msg_verbose++; break; default: - msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]); + msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-m (map types) [-n (non-defaults)] [-v] [name...]", argv[0]); } } /* - * If showing non-default values, read main.cf. + * Sanity check. + */ + junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | EDIT_MAIN)); + if (junk != 0 && junk != SHOW_DEFS && junk != SHOW_NONDEF + && junk != SHOW_MAPS && junk != EDIT_MAIN) + msg_fatal("specify one of -d, -e, -n and -m"); + + /* + * If showing map types, show them and exit + */ + if (mode & SHOW_MAPS) { + show_maps(); + } + + /* + * Edit main.cf. */ - if ((mode & SHOW_DEFS) == 0) - read_parameters(); + if (mode & EDIT_MAIN) { + edit_parameters(argc - optind, argv + optind); + } /* - * Throw together all parameters and show the asked values. + * If showing non-default values, read main.cf. */ - hash_parameters(); - show_parameters(mode, argv + optind); + else { + if ((mode & SHOW_DEFS) == 0) + read_parameters(); + + /* + * Throw together all parameters and show the asked values. + */ + hash_parameters(); + show_parameters(mode, argv + optind); + } vstream_fflush(VSTREAM_OUT); exit(0); } diff --git a/postfix/postmap/postmap.c b/postfix/postmap/postmap.c index af6a2b7c6..702119aee 100644 --- a/postfix/postmap/postmap.c +++ b/postfix/postmap/postmap.c @@ -168,7 +168,7 @@ static void postmap(char *map_type, char *path_name, * Add records to the database. */ lineno = 0; - while (readlline(line_buffer, source_fp, &lineno)) { + while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) { /* * Skip comments. diff --git a/postfix/qmgr/qmgr_message.c b/postfix/qmgr/qmgr_message.c index 522a0dcd9..c3ba5e8e9 100644 --- a/postfix/qmgr/qmgr_message.c +++ b/postfix/qmgr/qmgr_message.c @@ -110,7 +110,7 @@ #include #include #include -#include +#include /* Client stubs. */ @@ -477,7 +477,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) /* * Bounce mail to non-existent users in virtual domains. */ - if (!resolve_local(STR(reply.nexthop)) + if (!local_transport(STR(reply.transport)) && qmgr_virtual != 0 && (at = strrchr(recipient->address, '@')) != 0) { domain = lowercase(mystrdup(at + 1)); @@ -516,7 +516,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) * job requires knowledge of local aliases. Yuck! I don't want to * duplicate delivery-agent specific knowledge in the queue manager. */ - if (resolve_local(STR(reply.nexthop))) { + if (local_transport(STR(reply.transport))) { vstring_strcpy(reply.nexthop, STR(reply.recipient)); (void) split_at_right(STR(reply.nexthop), '@'); #if 0 diff --git a/postfix/smtpd/Makefile.in b/postfix/smtpd/Makefile.in index 2fa6b677a..1b8c0cac8 100644 --- a/postfix/smtpd/Makefile.in +++ b/postfix/smtpd/Makefile.in @@ -172,6 +172,7 @@ smtpd_check.o: ../include/own_inet_addr.h smtpd_check.o: ../include/mail_conf.h smtpd_check.o: ../include/maps.h smtpd_check.o: ../include/mail_addr_find.h +smtpd_check.o: ../include/local_transport.h smtpd_check.o: smtpd.h smtpd_check.o: ../include/mail_stream.h smtpd_check.o: smtpd_check.h diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index 8febad8c2..a31fcc3ce 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -275,6 +275,7 @@ #include #include #include +#include /* Application-specific. */ @@ -712,7 +713,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient, * Permit if destination is local. XXX This must be generalized for * per-domain user tables and for non-UNIX local delivery agents. */ - if (resolve_local(STR(reply.nexthop)) + if (local_transport(STR(reply.transport)) || (domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; @@ -751,7 +752,7 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient) * Permit if destination is local. XXX This must be generalized for * per-domain user tables and for non-UNIX local delivery agents. */ - if (resolve_local(STR(reply.nexthop)) + if (local_transport(STR(reply.transport)) || (domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; @@ -788,7 +789,7 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient) * Pass if destination is local. XXX This must be generalized for * per-domain user tables and for non-UNIX local delivery agents. */ - if (resolve_local(STR(reply.nexthop)) + if (local_transport(STR(reply.transport)) || (domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_DUNNO); domain += 1; @@ -890,7 +891,7 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient) * If the destination is local, it is acceptable, because we are * supposedly MX for our own address. */ - if (resolve_local(STR(reply.nexthop)) + if (local_transport(STR(reply.transport)) || (domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_OK); domain += 1; @@ -1024,7 +1025,7 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr, /* * Skip local destinations and non-DNS forms. */ - if (resolve_local(STR(reply.nexthop)) + if (local_transport(STR(reply.transport)) || (domain = strrchr(STR(reply.recipient), '@')) == 0) return (SMTPD_CHECK_DUNNO); domain += 1; @@ -1064,7 +1065,7 @@ static int permit_rcpt_map(char *table, char *reply_name) return (SMTPD_CHECK_DUNNO); domain += 1; if (domain[0] == '#' || domain[0] == '[') - if (!resolve_local(STR(reply.nexthop))) + if (!local_transport(STR(reply.transport))) return (SMTPD_CHECK_DUNNO); /* diff --git a/postfix/trivial-rewrite/resolve.c b/postfix/trivial-rewrite/resolve.c index f298da479..6e8c2f74a 100644 --- a/postfix/trivial-rewrite/resolve.c +++ b/postfix/trivial-rewrite/resolve.c @@ -72,6 +72,7 @@ #include #include #include +#include /* Application-specific. */ @@ -151,44 +152,55 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop, } /* - * The transport map, if specified, overrides default routing. + * Make sure the resolved envelope recipient has the user@domain form. If + * no domain was specified in the address, assume the local machine. See + * above for what happens with an empty localpart. */ - if (*var_transport_maps == 0 - || (tok822_internalize(addr_buf, domain->next, TOK822_STR_DEFL), - transport_lookup(STR(addr_buf), channel, nexthop)) == 0) { - - /* - * Non-local delivery. Use the default transport specified in - * var_def_transport. If no default mail relay is specified in - * var_relayhost, forward to the domain's mail exchanger. - */ - if (domain != 0) { - vstring_strcpy(channel, var_def_transport); - if (*var_relayhost) - vstring_strcpy(nexthop, var_relayhost); - else - tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL); - } - - /* - * Local delivery. Use the default transport and next-hop hostname. - * If no domain was specified, assume the local machine. See above - * for what happens with an empty localpart. - */ - else { - vstring_strcpy(channel, MAIL_SERVICE_LOCAL); - vstring_strcpy(nexthop, var_myhostname); - if (saved_domain) { - tok822_sub_append(tree, saved_domain); - saved_domain = 0; - } else { - tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); - tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0)); - } + if (domain == 0) { + if (saved_domain) { + tok822_sub_append(tree, saved_domain); + saved_domain = 0; + } else { + tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); + tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0)); } } tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL); + /* + * The transport map overrides the default transport and next-hop host + * info that was set up just moments ago. For a long time, it was not + * possible to override routing of mail that resolves locally, because + * Postfix used a zero-length next-hop hostname result to indicate local + * delivery, and transport maps cannot return zero-length hostnames. + */ + if (*var_transport_maps + && transport_lookup(strrchr(STR(nextrcpt), '@') + 1, channel, nexthop)) { + /* void */ ; + } + + /* + * Non-local delivery, presumably. Set up the default remote transport + * specified with var_local_transports. Use the destination's mail + * exchanger unless a default mail relay is specified with var_relayhost. + */ + else if (domain != 0) { + vstring_strcpy(channel, var_def_transport); + if (*var_relayhost) + vstring_strcpy(nexthop, var_relayhost); + else + tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL); + } + + /* + * Local delivery. Set up the default local transport and the default + * next-hop hostname. + */ + else { + vstring_strcpy(channel, def_local_transport()); + vstring_strcpy(nexthop, var_myhostname); + } + /* * Clean up. */ diff --git a/postfix/util/dict.c b/postfix/util/dict.c index d14a5fb6f..6467441ab 100644 --- a/postfix/util/dict.c +++ b/postfix/util/dict.c @@ -394,7 +394,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp) buf = vstring_alloc(100); lineno = 0; - while (readlline(buf, fp, &lineno)) { + while (readlline(buf, fp, &lineno, READLL_STRIPNL)) { start = STR(buf); SKIP(start, member, ISSPACE(*member)); /* find member begin */ if (*member == 0 || *member == '#') diff --git a/postfix/util/dict.h b/postfix/util/dict.h index 3ec4e93fe..88b4a6982 100644 --- a/postfix/util/dict.h +++ b/postfix/util/dict.h @@ -20,6 +20,7 @@ * Utility library. */ #include +#include /* * Generic dictionary interface - in reality, a dictionary extends this @@ -56,6 +57,11 @@ extern int dict_errno; #define DICT_SEQ_FUN_FIRST 0 /* set cursor to first record */ #define DICT_SEQ_FUN_NEXT 1 /* set cursor to next record */ + /* + * Interface for dictionary types. + */ +extern ARGV *dict_mapnames(void); + /* * High-level interface, with logical dictionary names. */ @@ -96,5 +102,6 @@ extern int dict_changed(void); /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ +/**INDENT** Error@47: Unmatched #endif */ #endif diff --git a/postfix/util/dict_open.c b/postfix/util/dict_open.c index 56696ee1d..37b560212 100644 --- a/postfix/util/dict_open.c +++ b/postfix/util/dict_open.c @@ -280,6 +280,27 @@ void dict_open_register(const char *type, htable_enter(dict_open_hash, dp->type, (char *) dp); } +/* dict_mapnames - return an ARGV of available map_names */ + +ARGV *dict_mapnames() +{ + HTABLE_INFO **ht_info; + HTABLE_INFO **ht; + DICT_OPEN_INFO *dp; + ARGV *mapnames; + + if (dict_open_hash == 0) + dict_open_init(); + mapnames = argv_alloc(dict_open_hash->used + 1); + for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) { + dp = (DICT_OPEN_INFO *) ht[0]->value; + argv_add(mapnames, dp->type, ARGV_END); + } + myfree((char *) ht_info); + argv_terminate(mapnames); + return mapnames; +} + #ifdef TEST /* diff --git a/postfix/util/dict_pcre.c b/postfix/util/dict_pcre.c index c19c8c5ff..ddaf39bdd 100644 --- a/postfix/util/dict_pcre.c +++ b/postfix/util/dict_pcre.c @@ -273,7 +273,7 @@ DICT *dict_pcre_open(const char *map, int unused_flags, int dict_flags) if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { msg_fatal("open %s: %m", map); } - while (readlline(line_buffer, map_fp, &lineno)) { + while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) { if (*vstring_str(line_buffer) == '#') /* Skip comments */ continue; diff --git a/postfix/util/dict_regexp.c b/postfix/util/dict_regexp.c index d42deef0f..85ae9a49c 100644 --- a/postfix/util/dict_regexp.c +++ b/postfix/util/dict_regexp.c @@ -373,7 +373,7 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags) if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { msg_fatal("open %s: %m", map); } - while (readlline(line_buffer, map_fp, &lineno)) { + while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) { p = vstring_str(line_buffer); if (*p == '#') /* Skip comments */ diff --git a/postfix/util/readlline.c b/postfix/util/readlline.c index 8d71b85c6..314d6962b 100644 --- a/postfix/util/readlline.c +++ b/postfix/util/readlline.c @@ -6,14 +6,16 @@ /* SYNOPSIS /* #include /* -/* VSTRING *readlline(buf, fp, lineno) +/* VSTRING *readlline(buf, fp, lineno, stripnl) /* VSTRING *buf; /* VSTREAM *fp; /* int *lineno; +/* int stripnl; /* DESCRIPTION /* readlline() reads one logical line from the named stream. /* A line that starts with whitespace is a continuation of -/* the previous line. The newline between continued lines +/* the previous line. When the stripnl argument is non-zero, +/* the newline between continued lines /* is deleted from the input. The result value is the input /* buffer argument or a null pointer when no input is found. /* @@ -25,6 +27,9 @@ /* .IP lineno /* A null pointer, or a pointer to an integer that is incremented /* after reading a newline. +/* .IP stripnl +/* Non-zero to strip newlines. readlline.h provides the symbolic +/* constants READLL_STRIPNL and READLL_KEEPNL for convenience. /* LICENSE /* .ad /* .fi @@ -48,7 +53,7 @@ /* readlline - read one logical line */ -VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno) +VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno, int stripnl) { int ch; int next; @@ -59,6 +64,8 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno) VSTRING_RESET(buf); while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) { if (ch == '\n') { + if (stripnl == 0) + VSTRING_ADDCH(buf, ch); if (lineno) *lineno += 1; if ((next = VSTREAM_GETC(fp)) == ' ' || next == '\t') { diff --git a/postfix/util/readlline.h b/postfix/util/readlline.h index 8a8bd5487..00658433c 100644 --- a/postfix/util/readlline.h +++ b/postfix/util/readlline.h @@ -20,7 +20,10 @@ /* * External interface. */ -extern VSTRING *readlline(VSTRING *, VSTREAM *, int *); +extern VSTRING *readlline(VSTRING *, VSTREAM *, int *, int); + +#define READLL_STRIPNL 1 +#define READLL_KEEPNL 0 /* LICENSE /* .ad