From bd2d30312351a79fee2ad7a39367dfac8cf5d8ab Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Fri, 25 Nov 2011 00:00:00 -0500 Subject: [PATCH] postfix-2.9-20111125 --- postfix/.indent.pro | 1 + postfix/HISTORY | 27 +- postfix/README_FILES/INSTALL | 78 +- postfix/html/INSTALL.html | 86 +- postfix/html/postconf.1.html | 6 +- postfix/makedefs | 3 +- postfix/man/man1/postconf.1 | 6 +- postfix/proto/INSTALL.html | 86 +- postfix/src/global/mail_version.h | 2 +- postfix/src/postconf/Makefile.in | 241 ++- postfix/src/postconf/postconf.c | 1658 +-------------------- postfix/src/postconf/postconf.h | 179 +++ postfix/src/postconf/postconf_builtin.c | 368 +++++ postfix/src/postconf/postconf_edit.c | 202 +++ postfix/src/postconf/postconf_main.c | 258 ++++ postfix/src/postconf/postconf_master.c | 270 ++++ postfix/src/postconf/postconf_misc.c | 57 + postfix/src/postconf/postconf_node.c | 185 +++ postfix/src/postconf/postconf_other.c | 100 ++ postfix/src/postconf/postconf_service.c | 184 +++ postfix/src/postconf/postconf_unused.c | 129 ++ postfix/src/postconf/postconf_user.c | 304 ++++ postfix/src/postconf/test18.ref | 3 + postfix/src/postconf/test19.ref | 3 + postfix/src/postscreen/postscreen_smtpd.c | 4 +- 25 files changed, 2741 insertions(+), 1699 deletions(-) create mode 100644 postfix/src/postconf/postconf.h create mode 100644 postfix/src/postconf/postconf_builtin.c create mode 100644 postfix/src/postconf/postconf_edit.c create mode 100644 postfix/src/postconf/postconf_main.c create mode 100644 postfix/src/postconf/postconf_master.c create mode 100644 postfix/src/postconf/postconf_misc.c create mode 100644 postfix/src/postconf/postconf_node.c create mode 100644 postfix/src/postconf/postconf_other.c create mode 100644 postfix/src/postconf/postconf_service.c create mode 100644 postfix/src/postconf/postconf_unused.c create mode 100644 postfix/src/postconf/postconf_user.c create mode 100644 postfix/src/postconf/test18.ref create mode 100644 postfix/src/postconf/test19.ref diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 32e60db68..4756b0266 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -187,6 +187,7 @@ -TNAME_MASK -TNBBIO -TPC_MASTER_ENT +-TPC_PARAM_NODE -TPC_SERVICE_DEF -TPC_STRING_NV -TPEER_NAME diff --git a/postfix/HISTORY b/postfix/HISTORY index f3057480b..f8523f346 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -17133,6 +17133,27 @@ Apologies for any names omitted. 20111122 - Cleanup: documentation examples to request VERP-style - delivery at SMTP time with the smtpd_command_filter feature. - Files: proto/VERP_README.html, proto/postconf.proto. + Documentation: examples to request VERP-style delivery at + SMTP time with the smtpd_command_filter feature. Files: + proto/VERP_README.html, proto/postconf.proto. + + Documentation: complete list of "make makefiles" overrides. + File: proto/INSTALL.html. + + Cleanup: postscreen now logs more than the first word of + non-SMTP commands. File: postscreen/postscreen_smtpd.c. + +20111124 + + Cleanup: eliminated false postconf "unused parameter" + warnings with legacy parameters such as $virtual_maps, and + with non-default parameter values for smtpd_expansion_filter + that can contain legitimate "$" without a macro name. + + Cleanup: split postconf source into separate modules. + Files: postconf/postconf.c, postconf/postconf_builtin.c, + postconf/postconf_edit.c, postconf/postconf_main.c, + postconf/postconf_master.c, postconf/postconf_misc.c, + postconf/postconf_node.c, postconf/postconf_other.c, + postconf/postconf_service.c postconf/postconf_unused.c, + postconf/postconf_user.c, postconf/postconf.h. diff --git a/postfix/README_FILES/INSTALL b/postfix/README_FILES/INSTALL index fde109409..ae74b3145 100644 --- a/postfix/README_FILES/INSTALL +++ b/postfix/README_FILES/INSTALL @@ -223,7 +223,81 @@ Parameters whose defaults can be specified in this way are: Note: the data_directory parameter (for caches and pseudo-random numbers) was introduced with Postfix version 2.5. -44..55 -- SSuuppppoorrtt ffoorr tthhoouussaannddss ooff pprroocceesssseess +44..55 -- OOvveerrrriiddiinngg ootthheerr ccoommppiillee--ttiimmee ffeeaattuurreess + +The general method to override Postfix compile-time features is as follows: + + % make makefiles name=value name=value... + % make + +The following is an extensive list of names and values. + + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +|NNaammee//VVaalluuee |DDeessccrriippttiioonn | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|AUXLIBS="object_library..." |Specifies one or more non-default object | +| |libraries. | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|CC=compiler_command |Specifies a non-default compiler. On many | +| |systems, the default is gcc. | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +| |Specifies non-default compiler arguments, for | +|CCARGS="compiler_arguments..."|example, a non-default include directory. The | +| |following directives turn off Postfix features| +| |at compile time: | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with Solaris /dev/poll support. | +||-DNO_DEVPOLL |By default, /dev/poll support is compiled in | +|| |on Solaris versions that are known to support | +|| |this feature. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with Linux EPOLL support. By | +||-DNO_EPOLL |default, EPOLL support is compiled in on | +|| |platforms that are known to support this | +|| |feature. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with IPv6 support. By default, | +|| |IPv6 support is compiled in on platforms that | +||-DNO_IPV6 |are known to have IPv6 support. Note: this | +|| |directive is for debugging and testing only. | +|| |It is not guaranteed to work on all platforms.| +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with FreeBSD / NetBSD / OpenBSD /| +||-DNO_KQUEUE |MacOSX KQUEUE support. By default, KQUEUE | +|| |support is compiled in on platforms that are | +|| |known to support it. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with NIS or NISPLUS support. NIS | +||-DNO_NIS |is not available on some recent Linux or | +|| |Solaris distributions. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Do not build with PCRE support. By default, | +||-DNO_PCRE |PCRE support is compiled in when the pcre- | +|| |config utility is installed. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Disable support for POSIX getpwnam_r/ | +||-DNO_POSIX_GETPW_R |getpwuid_r. By default Postfix uses these | +|| |where they are known to be available. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +|| |Use setjmp()/longjmp() instead of sigsetjmp()/| +||-DNO_SIGSETJMP |siglongjmp(). By default, Postfix uses | +|| |sigsetjmp()/siglongjmp() when they are known | +|| |to be available. | +|_|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +| |Specifies a non-default compiler debugging | +|DEBUG=debug_level |level. The default is -g. Specify DEBUG= to | +| |turn off debugging. | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +| |Specifies a non-default optimization level. | +|OPT=optimization_level |The default is -O. Specify OPT= to turn off | +| |optimization. | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | +| |Specifies non-default gcc compiler warning | +|WARN="warning_flags..." |options for use when "make" is invoked in a | +| |source subdirectory only. | +|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + +44..66 -- SSuuppppoorrtt ffoorr tthhoouussaannddss ooff pprroocceesssseess The number of connections that Postfix can manage simultaneously is limited by the number of processes that it can run. This number in turn is limited by the @@ -255,7 +329,7 @@ But wait, there is more: none of this will work unless the operating system is configured to handle thousands of connections. See the TUNING_README guide for examples of how to increase the number of open sockets or files. -44..66 -- CCoommppiilliinngg PPoossttffiixx,, aatt llaasstt +44..77 -- CCoommppiilliinngg PPoossttffiixx,, aatt llaasstt If the command diff --git a/postfix/html/INSTALL.html b/postfix/html/INSTALL.html index c51abab17..8df125974 100644 --- a/postfix/html/INSTALL.html +++ b/postfix/html/INSTALL.html @@ -342,7 +342,89 @@ default

Note: the data_directory parameter (for caches and pseudo-random numbers) was introduced with Postfix version 2.5.

-

4.5 - Support for thousands of processes

+

4.5 - Overriding other compile-time features

+ +

The general method to override Postfix compile-time features +is as follows:

+ +
+
+% make makefiles name=value name=value...
+% make
+
+
+ +

The following is an extensive list of names and values.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name/Value Description
AUXLIBS="object_library..." Specifies +one or more non-default object libraries.
CC=compiler_command Specifies a +non-default compiler. On many systems, the default is gcc. +
CCARGS="compiler_arguments..." +Specifies non-default compiler arguments, for example, a non-default +include directory. The following directives turn +off Postfix features at compile time:
-DNO_DEVPOLL Do not build with +Solaris /dev/poll support. By default, /dev/poll +support is compiled in on Solaris versions that are known to support +this feature.
-DNO_EPOLL Do not build with Linux +EPOLL support. By default, EPOLL support is compiled in on platforms +that are known to support this feature.
-DNO_IPV6 Do not build with IPv6 +support. By default, IPv6 support is compiled in on platforms that +are known to have IPv6 support. Note: this directive is for debugging +and testing only. It is not guaranteed to work on all platforms. +
-DNO_KQUEUE Do not build with FreeBSD +/ NetBSD / OpenBSD / MacOSX KQUEUE support. By default, KQUEUE +support is compiled in on platforms that are known to support it. +
-DNO_NIS Do not build with NIS or +NISPLUS support. NIS is not available on some recent Linux or Solaris +distributions.
-DNO_PCRE Do not build with PCRE +support. By default, PCRE support is compiled in when the +pcre-config utility is installed.
-DNO_POSIX_GETPW_R Disable support +for POSIX getpwnam_r/getpwuid_r. By default Postfix uses +these where they are known to be available.
-DNO_SIGSETJMP Use +setjmp()/longjmp() instead of sigsetjmp()/siglongjmp(). +By default, Postfix uses sigsetjmp()/siglongjmp() when +they are known to be available.
DEBUG=debug_level Specifies a +non-default compiler debugging level. The default is -g. +Specify DEBUG= to turn off debugging.
OPT=optimization_level Specifies +a non-default optimization level. The default is -O. Specify OPT= +to turn off optimization.
WARN="warning_flags..." Specifies +non-default gcc compiler warning options for use when +"make" is invoked in a source subdirectory only.
+ +

4.6 - Support for thousands of processes

The number of connections that Postfix can manage simultaneously is limited by the number of processes that it can run. This number @@ -390,7 +472,7 @@ operating system is configured to handle thousands of connections. See the TUNING_README guide for examples of how to increase the number of open sockets or files.

-

4.6 - Compiling Postfix, at last

+

4.7 - Compiling Postfix, at last

If the command

diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html index bbbb551d2..dcbd5e177 100644 --- a/postfix/html/postconf.1.html +++ b/postfix/html/postconf.1.html @@ -71,8 +71,8 @@ POSTCONF(1) POSTCONF(1) -b [template_file] Display the message text that appears at the begin- ning of delivery status notification (DSN) mes- - sages, with $name expressions replaced by actual - values as described in bounce(5). + sages, replacing $name expressions with actual val- + ues as described in bounce(5). To override the built-in templates, specify a tem- plate file name at the end of the postconf(1) com- @@ -100,7 +100,7 @@ POSTCONF(1) POSTCONF(1) the postconf(1) command line. The file is copied to a temporary file then renamed into place. Specify quotes to protect special characters and whitespace - on the fBpostconf(1) command line. + on the postconf(1) command line. The -e is no longer needed with Postfix version 2.8 and later. diff --git a/postfix/makedefs b/postfix/makedefs index 02fd05dff..329485f9d 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -45,7 +45,8 @@ # By default, KQUEUE support is compiled in on platforms that # are known to support it. # .IP \fB-DNO_NIS\fR -# Do not build with NIS or NISPLUS support. +# Do not build with NIS or NISPLUS support. Support for NIS +# is unavailable on some recent Linux and Solaris distributions. # .IP \fB-DNO_PCRE\fR # Do not build with PCRE support. # By default, PCRE support is compiled in when the \fBpcre-config\fR diff --git a/postfix/man/man1/postconf.1 b/postfix/man/man1/postconf.1 index 13ced579f..57d2d061b 100644 --- a/postfix/man/man1/postconf.1 +++ b/postfix/man/man1/postconf.1 @@ -73,8 +73,8 @@ Cyrus SASL support. This feature is available with Postfix 2.3 and later. .IP "\fB-b\fR [\fItemplate_file\fR]" Display the message text that appears at the beginning of -delivery status notification (DSN) messages, with $\fBname\fR -expressions replaced by actual values as described in +delivery status notification (DSN) messages, replacing +$\fBname\fR expressions with actual values as described in \fBbounce\fR(5). To override the built-in templates, specify a template file @@ -101,7 +101,7 @@ parameter settings with the "\fIname\fR=\fIvalue\fR" pairs on the \fBpostconf\fR(1) command line. The file is copied to a temporary file then renamed into place. Specify quotes to protect special characters and whitespace -on the fBpostconf\fR(1) command line. +on the \fBpostconf\fR(1) command line. The \fB-e\fR is no longer needed with Postfix version 2.8 and later. diff --git a/postfix/proto/INSTALL.html b/postfix/proto/INSTALL.html index 17b188bab..bb436a3ae 100644 --- a/postfix/proto/INSTALL.html +++ b/postfix/proto/INSTALL.html @@ -342,7 +342,89 @@ default

Note: the data_directory parameter (for caches and pseudo-random numbers) was introduced with Postfix version 2.5.

-

4.5 - Support for thousands of processes

+

4.5 - Overriding other compile-time features

+ +

The general method to override Postfix compile-time features +is as follows:

+ +
+
+% make makefiles name=value name=value...
+% make
+
+
+ +

The following is an extensive list of names and values.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name/Value Description
AUXLIBS="object_library..." Specifies +one or more non-default object libraries.
CC=compiler_command Specifies a +non-default compiler. On many systems, the default is gcc. +
CCARGS="compiler_arguments..." +Specifies non-default compiler arguments, for example, a non-default +include directory. The following directives turn +off Postfix features at compile time:
-DNO_DEVPOLL Do not build with +Solaris /dev/poll support. By default, /dev/poll +support is compiled in on Solaris versions that are known to support +this feature.
-DNO_EPOLL Do not build with Linux +EPOLL support. By default, EPOLL support is compiled in on platforms +that are known to support this feature.
-DNO_IPV6 Do not build with IPv6 +support. By default, IPv6 support is compiled in on platforms that +are known to have IPv6 support. Note: this directive is for debugging +and testing only. It is not guaranteed to work on all platforms. +
-DNO_KQUEUE Do not build with FreeBSD +/ NetBSD / OpenBSD / MacOSX KQUEUE support. By default, KQUEUE +support is compiled in on platforms that are known to support it. +
-DNO_NIS Do not build with NIS or +NISPLUS support. NIS is not available on some recent Linux or Solaris +distributions.
-DNO_PCRE Do not build with PCRE +support. By default, PCRE support is compiled in when the +pcre-config utility is installed.
-DNO_POSIX_GETPW_R Disable support +for POSIX getpwnam_r/getpwuid_r. By default Postfix uses +these where they are known to be available.
-DNO_SIGSETJMP Use +setjmp()/longjmp() instead of sigsetjmp()/siglongjmp(). +By default, Postfix uses sigsetjmp()/siglongjmp() when +they are known to be available.
DEBUG=debug_level Specifies a +non-default compiler debugging level. The default is -g. +Specify DEBUG= to turn off debugging.
OPT=optimization_level Specifies +a non-default optimization level. The default is -O. Specify OPT= +to turn off optimization.
WARN="warning_flags..." Specifies +non-default gcc compiler warning options for use when +"make" is invoked in a source subdirectory only.
+ +

4.6 - Support for thousands of processes

The number of connections that Postfix can manage simultaneously is limited by the number of processes that it can run. This number @@ -390,7 +472,7 @@ operating system is configured to handle thousands of connections. See the TUNING_README guide for examples of how to increase the number of open sockets or files.

-

4.6 - Compiling Postfix, at last

+

4.7 - Compiling Postfix, at last

If the command

diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 3c38cc398..caa41ebfa 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20111122" +#define MAIL_RELEASE_DATE "20111125" #define MAIL_VERSION_NUMBER "2.9" #ifdef SNAPSHOT diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in index 748d2e32b..a6a1b8249 100644 --- a/postfix/src/postconf/Makefile.in +++ b/postfix/src/postconf/Makefile.in @@ -1,11 +1,15 @@ SHELL = /bin/sh -SRCS = postconf.c -OBJS = postconf.o -HDRS = -TESTSRC = +SRCS = postconf.c postconf_builtin.c postconf_edit.c postconf_main.c \ + postconf_master.c postconf_misc.c postconf_node.c postconf_other.c \ + postconf_service.c postconf_unused.c postconf_user.c +OBJS = postconf.o postconf_builtin.o postconf_edit.o postconf_main.o \ + postconf_master.o postconf_misc.o postconf_node.o postconf_other.o \ + postconf_service.o postconf_unused.o postconf_user.o +HDRS = postconf.h +TESTSRC = DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) -TESTPROG= +TESTPROG= MAKES = bool_table.h bool_vars.h int_table.h int_vars.h str_table.h \ str_vars.h time_table.h time_vars.h raw_table.h raw_vars.h \ nint_table.h nint_vars.h nbool_table.h nbool_vars.h long_table.h \ @@ -37,7 +41,7 @@ Makefile: Makefile.in test: $(TESTPROG) tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \ - test12 test13 test14 test15 test16 test17 + test12 test13 test14 test15 test16 test17 test18 test19 root_tests: @@ -168,7 +172,7 @@ test11: $(PROG) test11.ref diff test11.ref test11.tmp rm -f main.cf master.cf test11.tmp -# Duplicate service entry. +# Duplicate service entry. test12: $(PROG) test12.ref rm -f main.cf master.cf @@ -236,6 +240,28 @@ test17: $(PROG) test17.ref diff test17.ref test17.tmp rm -f main.cf master.cf test17.tmp +# Test legacy $name in built-in defaults. + +test18: $(PROG) test18.ref + rm -f main.cf master.cf + touch main.cf master.cf + echo virtual_maps=xxx >> main.cf + echo smtpd_client_connection_limit_exceptions=yyy >> main.cf + ./$(PROG) -nc . >test18.tmp 2>&1 + diff test18.ref test18.tmp + rm -f main.cf master.cf test18.tmp + +# Test $name in "raw" parameters. + +test19: $(PROG) test19.ref + rm -f main.cf master.cf + touch main.cf master.cf + echo forward_path='$$'aaaa >> main.cf + echo default_rbl_reply='$$'bbbb >> main.cf + ./$(PROG) -nc . >test19.tmp 2>&1 + diff test19.ref test19.tmp + rm -f main.cf master.cf test19.tmp + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -265,56 +291,181 @@ depend: $(MAKES) # do not edit below this line - it is generated by 'make depend' postconf.o: ../../include/argv.h -postconf.o: ../../include/attr.h postconf.o: ../../include/dict.h -postconf.o: ../../include/edit_file.h -postconf.o: ../../include/get_hostname.h postconf.o: ../../include/htable.h -postconf.o: ../../include/inet_proto.h -postconf.o: ../../include/iostuff.h -postconf.o: ../../include/mac_expand.h -postconf.o: ../../include/mac_parse.h -postconf.o: ../../include/mail_addr.h postconf.o: ../../include/mail_conf.h postconf.o: ../../include/mail_dict.h postconf.o: ../../include/mail_params.h -postconf.o: ../../include/mail_proto.h postconf.o: ../../include/mail_run.h postconf.o: ../../include/mail_version.h -postconf.o: ../../include/master_proto.h -postconf.o: ../../include/match_service.h -postconf.o: ../../include/mbox_conf.h postconf.o: ../../include/msg.h postconf.o: ../../include/msg_vstream.h -postconf.o: ../../include/myflock.h -postconf.o: ../../include/mymalloc.h -postconf.o: ../../include/mynetworks.h -postconf.o: ../../include/readlline.h -postconf.o: ../../include/safe.h -postconf.o: ../../include/split_at.h postconf.o: ../../include/stringops.h postconf.o: ../../include/sys_defs.h postconf.o: ../../include/vbuf.h postconf.o: ../../include/vstream.h postconf.o: ../../include/vstring.h -postconf.o: ../../include/vstring_vstream.h -postconf.o: ../../include/xsasl.h -postconf.o: bool_table.h -postconf.o: bool_vars.h -postconf.o: install_table.h -postconf.o: install_vars.h -postconf.o: int_table.h -postconf.o: int_vars.h -postconf.o: long_table.h -postconf.o: long_vars.h -postconf.o: nbool_table.h -postconf.o: nbool_vars.h -postconf.o: nint_table.h -postconf.o: nint_vars.h postconf.o: postconf.c -postconf.o: raw_table.h -postconf.o: raw_vars.h -postconf.o: str_table.h -postconf.o: str_vars.h -postconf.o: time_table.h -postconf.o: time_vars.h +postconf.o: postconf.h +postconf_builtin.o: ../../include/argv.h +postconf_builtin.o: ../../include/attr.h +postconf_builtin.o: ../../include/dict.h +postconf_builtin.o: ../../include/get_hostname.h +postconf_builtin.o: ../../include/htable.h +postconf_builtin.o: ../../include/inet_proto.h +postconf_builtin.o: ../../include/iostuff.h +postconf_builtin.o: ../../include/mail_addr.h +postconf_builtin.o: ../../include/mail_conf.h +postconf_builtin.o: ../../include/mail_params.h +postconf_builtin.o: ../../include/mail_proto.h +postconf_builtin.o: ../../include/mail_version.h +postconf_builtin.o: ../../include/msg.h +postconf_builtin.o: ../../include/mymalloc.h +postconf_builtin.o: ../../include/mynetworks.h +postconf_builtin.o: ../../include/stringops.h +postconf_builtin.o: ../../include/sys_defs.h +postconf_builtin.o: ../../include/vbuf.h +postconf_builtin.o: ../../include/vstream.h +postconf_builtin.o: ../../include/vstring.h +postconf_builtin.o: bool_table.h +postconf_builtin.o: bool_vars.h +postconf_builtin.o: install_table.h +postconf_builtin.o: install_vars.h +postconf_builtin.o: int_table.h +postconf_builtin.o: int_vars.h +postconf_builtin.o: long_table.h +postconf_builtin.o: long_vars.h +postconf_builtin.o: nbool_table.h +postconf_builtin.o: nbool_vars.h +postconf_builtin.o: nint_table.h +postconf_builtin.o: nint_vars.h +postconf_builtin.o: postconf.h +postconf_builtin.o: postconf_builtin.c +postconf_builtin.o: raw_table.h +postconf_builtin.o: raw_vars.h +postconf_builtin.o: str_table.h +postconf_builtin.o: str_vars.h +postconf_builtin.o: time_table.h +postconf_builtin.o: time_vars.h +postconf_edit.o: ../../include/argv.h +postconf_edit.o: ../../include/dict.h +postconf_edit.o: ../../include/edit_file.h +postconf_edit.o: ../../include/htable.h +postconf_edit.o: ../../include/mail_params.h +postconf_edit.o: ../../include/msg.h +postconf_edit.o: ../../include/mymalloc.h +postconf_edit.o: ../../include/readlline.h +postconf_edit.o: ../../include/stringops.h +postconf_edit.o: ../../include/sys_defs.h +postconf_edit.o: ../../include/vbuf.h +postconf_edit.o: ../../include/vstream.h +postconf_edit.o: ../../include/vstring.h +postconf_edit.o: ../../include/vstring_vstream.h +postconf_edit.o: postconf.h +postconf_edit.o: postconf_edit.c +postconf_main.o: ../../include/argv.h +postconf_main.o: ../../include/dict.h +postconf_main.o: ../../include/htable.h +postconf_main.o: ../../include/mail_conf.h +postconf_main.o: ../../include/mail_params.h +postconf_main.o: ../../include/msg.h +postconf_main.o: ../../include/mymalloc.h +postconf_main.o: ../../include/readlline.h +postconf_main.o: ../../include/stringops.h +postconf_main.o: ../../include/sys_defs.h +postconf_main.o: ../../include/vbuf.h +postconf_main.o: ../../include/vstream.h +postconf_main.o: ../../include/vstring.h +postconf_main.o: postconf.h +postconf_main.o: postconf_main.c +postconf_master.o: ../../include/argv.h +postconf_master.o: ../../include/dict.h +postconf_master.o: ../../include/htable.h +postconf_master.o: ../../include/mail_params.h +postconf_master.o: ../../include/match_service.h +postconf_master.o: ../../include/msg.h +postconf_master.o: ../../include/mymalloc.h +postconf_master.o: ../../include/readlline.h +postconf_master.o: ../../include/stringops.h +postconf_master.o: ../../include/sys_defs.h +postconf_master.o: ../../include/vbuf.h +postconf_master.o: ../../include/vstream.h +postconf_master.o: ../../include/vstring.h +postconf_master.o: postconf.h +postconf_master.o: postconf_master.c +postconf_misc.o: ../../include/argv.h +postconf_misc.o: ../../include/dict.h +postconf_misc.o: ../../include/htable.h +postconf_misc.o: ../../include/mail_conf.h +postconf_misc.o: ../../include/mail_params.h +postconf_misc.o: ../../include/mymalloc.h +postconf_misc.o: ../../include/safe.h +postconf_misc.o: ../../include/sys_defs.h +postconf_misc.o: ../../include/vbuf.h +postconf_misc.o: ../../include/vstream.h +postconf_misc.o: ../../include/vstring.h +postconf_misc.o: postconf.h +postconf_misc.o: postconf_misc.c +postconf_node.o: ../../include/argv.h +postconf_node.o: ../../include/dict.h +postconf_node.o: ../../include/htable.h +postconf_node.o: ../../include/msg.h +postconf_node.o: ../../include/mymalloc.h +postconf_node.o: ../../include/sys_defs.h +postconf_node.o: ../../include/vbuf.h +postconf_node.o: ../../include/vstream.h +postconf_node.o: ../../include/vstring.h +postconf_node.o: postconf.h +postconf_node.o: postconf_node.c +postconf_other.o: ../../include/argv.h +postconf_other.o: ../../include/dict.h +postconf_other.o: ../../include/htable.h +postconf_other.o: ../../include/mbox_conf.h +postconf_other.o: ../../include/sys_defs.h +postconf_other.o: ../../include/vbuf.h +postconf_other.o: ../../include/vstream.h +postconf_other.o: ../../include/vstring.h +postconf_other.o: ../../include/xsasl.h +postconf_other.o: postconf.h +postconf_other.o: postconf_other.c +postconf_service.o: ../../include/argv.h +postconf_service.o: ../../include/dict.h +postconf_service.o: ../../include/htable.h +postconf_service.o: ../../include/mail_params.h +postconf_service.o: ../../include/msg.h +postconf_service.o: ../../include/mymalloc.h +postconf_service.o: ../../include/stringops.h +postconf_service.o: ../../include/sys_defs.h +postconf_service.o: ../../include/vbuf.h +postconf_service.o: ../../include/vstream.h +postconf_service.o: ../../include/vstring.h +postconf_service.o: postconf.h +postconf_service.o: postconf_service.c +postconf_unused.o: ../../include/argv.h +postconf_unused.o: ../../include/dict.h +postconf_unused.o: ../../include/htable.h +postconf_unused.o: ../../include/mail_conf.h +postconf_unused.o: ../../include/mail_params.h +postconf_unused.o: ../../include/msg.h +postconf_unused.o: ../../include/sys_defs.h +postconf_unused.o: ../../include/vbuf.h +postconf_unused.o: ../../include/vstream.h +postconf_unused.o: ../../include/vstring.h +postconf_unused.o: postconf.h +postconf_unused.o: postconf_unused.c +postconf_user.o: ../../include/argv.h +postconf_user.o: ../../include/dict.h +postconf_user.o: ../../include/htable.h +postconf_user.o: ../../include/mac_expand.h +postconf_user.o: ../../include/mac_parse.h +postconf_user.o: ../../include/mail_conf.h +postconf_user.o: ../../include/mail_params.h +postconf_user.o: ../../include/msg.h +postconf_user.o: ../../include/mymalloc.h +postconf_user.o: ../../include/stringops.h +postconf_user.o: ../../include/sys_defs.h +postconf_user.o: ../../include/vbuf.h +postconf_user.o: ../../include/vstream.h +postconf_user.o: ../../include/vstring.h +postconf_user.o: postconf.h +postconf_user.o: postconf_user.c diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index 0af9d13fd..10a273c15 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -67,8 +67,8 @@ /* This feature is available with Postfix 2.3 and later. /* .IP "\fB-b\fR [\fItemplate_file\fR]" /* Display the message text that appears at the beginning of -/* delivery status notification (DSN) messages, with $\fBname\fR -/* expressions replaced by actual values as described in +/* delivery status notification (DSN) messages, replacing +/* $\fBname\fR expressions with actual values as described in /* \fBbounce\fR(5). /* /* To override the built-in templates, specify a template file @@ -93,9 +93,9 @@ /* Edit the \fBmain.cf\fR configuration file, and update /* parameter settings with the "\fIname\fR=\fIvalue\fR" pairs /* on the \fBpostconf\fR(1) command line. The file is copied -/* to a temporary file then renamed into place. +/* to a temporary file then renamed into place. /* Specify quotes to protect special characters and whitespace -/* on the fBpostconf\fR(1) command line. +/* on the \fBpostconf\fR(1) command line. /* /* The \fB-e\fR is no longer needed with Postfix version 2.8 /* and later. @@ -304,1653 +304,40 @@ #include #include -#include /* rename() */ -#include -#include #include -#include -#include - -#ifdef USE_PATHS_H -#include -#endif /* Utility library. */ #include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include /* Global library. */ -#include -#include -#include -#include -#include #include -#include -#include +#include +#include #include -#include +#include -/* XSASL library. */ +/* Application-specific. */ -#include - -/* master library. */ - -#include +#include /* - * What we're supposed to be doing. + * Global storage. See postconf.h for description. */ -#define SHOW_NONDEF (1<<0) /* show main.cf non-default settings */ -#define SHOW_DEFS (1<<1) /* show main.cf default setting */ -#define SHOW_NAME (1<<2) /* show main.cf parameter name */ -#define SHOW_MAPS (1<<3) /* show map types */ -#define EDIT_MAIN (1<<4) /* edit main.cf */ -#define SHOW_LOCKS (1<<5) /* show mailbox lock methods */ -#define SHOW_EVAL (1<<6) /* expand main.cf right-hand sides */ -#define SHOW_SASL_SERV (1<<7) /* show server auth plugin types */ -#define SHOW_SASL_CLNT (1<<8) /* show client auth plugin types */ -#define COMMENT_OUT (1<<9) /* #-out selected main.cf entries */ -#define SHOW_MASTER (1<<10) /* show master.cf entries */ -#define FOLD_LINE (1<<11) /* fold long *.cf entries */ +PC_PARAM_TABLE *param_table; +PC_MASTER_ENT *master_table; +int cmd_mode = DEF_MODE; /* - * Lookup table for global "valid" parameter information. - * - * XXX Change the hash-table values from table indices to parameter object - * pointers, where each object supplies its own print etc. method. + * Application fingerprinting. */ -HTABLE *param_table; - - /* - * Global hash with all names in the global smtpd_restriction_classes value. - * This is used when validating "-o user-defined-name=value" in master.cf. - */ -HTABLE *rest_class_table; - - /* - * In-core information for one master.cf entry. - */ -typedef struct { - char *name_space; /* service.type, parameter name space */ - ARGV *argv; /* null, or master.cf fields */ - DICT *all_params; /* null, or all name=value entries */ - HTABLE *valid_names; /* null, or "valid" parameter names */ -} PC_MASTER_ENT; - - /* - * Lookup table for master.cf entries. The table is terminated with an entry - * that has a null argv member. - */ -static PC_MASTER_ENT *master_table; - - /* - * Support for built-in parameters: declarations generated by scanning - * actual C source files. - */ -#include "time_vars.h" -#include "bool_vars.h" -#include "int_vars.h" -#include "str_vars.h" -#include "raw_vars.h" -#include "nint_vars.h" -#include "nbool_vars.h" -#include "long_vars.h" - - /* - * Support for built-in parameters: manually extracted. - */ -#include "install_vars.h" - - /* - * Support for built-in parameters: lookup tables generated by scanning - * actual C source files. - */ -static const CONFIG_TIME_TABLE time_table[] = { -#include "time_table.h" - 0, -}; - -static const CONFIG_BOOL_TABLE bool_table[] = { -#include "bool_table.h" - 0, -}; - -static const CONFIG_INT_TABLE int_table[] = { -#include "int_table.h" - 0, -}; - -static const CONFIG_STR_TABLE str_table[] = { -#include "str_table.h" -#include "install_table.h" - 0, -}; - -static const CONFIG_RAW_TABLE raw_table[] = { -#include "raw_table.h" - 0, -}; - -static const CONFIG_NINT_TABLE nint_table[] = { -#include "nint_table.h" - 0, -}; - -static const CONFIG_NBOOL_TABLE nbool_table[] = { -#include "nbool_table.h" - 0, -}; - -static const CONFIG_LONG_TABLE long_table[] = { -#include "long_table.h" - 0, -}; - - /* - * Ad-hoc name-value string pair. - */ -typedef struct { - const char *name; - const char *value; -} PC_STRING_NV; - - /* - * Service-defined parameter names are created by appending postfix-defined - * suffixes to master.cf service names. All service-defined parameters have - * default values that are defined by built-in parameters. We represent - * service-defined parameters as (service-defined name, built-in default - * parameter name) tuples. - */ -static PC_STRING_NV *serv_param_table; -static ssize_t serv_param_tablen; - - /* - * Support for user-defined parameters. - * - * There are multiple parameter name spaces: the global main.cf parameter name - * space, and the local parameter name space of each master.cf entry. Local - * name spaces take precedence over the global one. - * - * There are three categories of known parameters: built-in, service-defined - * (see previous comment), and valid user-defined. - * - * There are two categories of valid user-defined parameters: - * - * - Parameters whose user-defined-name appears in the value of - * smtpd_restriction_classes in main.cf or master.cf. - * - * - Parameters whose $user-defined-name appear in the value of "name=value" - * entries in main.cf or master.cf. - * - * - In both cases the parameters must have a "user-defined-name=value" entry - * in main.cf or master.cf. - * - * Other user-defined parameters are flagged as "unused". - */ - - /* - * Global-scope valid user-defined parameter names. The local-scope valid - * user-defined names are kept in the table with master.cf entries. - */ -static char **user_param_table; -static ssize_t user_param_tablen; - - /* - * Parameters with default values obtained via function calls. - */ -char *var_myhostname; -char *var_mydomain; -char *var_mynetworks; - -static const char *check_myhostname(void); -static const char *check_mydomainname(void); -static const char *check_mynetworks(void); - -static const CONFIG_STR_FN_TABLE str_fn_table[] = { - VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0, - VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0, - 0, -}; -static const CONFIG_STR_FN_TABLE str_fn_table_2[] = { - VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0, - 0, -}; - - /* - * Line-wrapping support. - */ -#define LINE_LIMIT 80 /* try to fold longer lines */ -#define SEPARATORS " \t\r\n" -#define INDENT_LEN 4 /* indent long text by 4 */ -#define INDENT_TEXT " " - - /* - * XXX Global so that call-backs can see it. - */ -#define DEF_MODE SHOW_NAME -static int cmd_mode = DEF_MODE; - -/* set_config_dir - forcibly override var_config_dir */ - -static void set_config_dir(void) -{ - char *config_dir; - - 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); -} - -/* check_myhostname - lookup hostname and validate */ - -static const char *check_myhostname(void) -{ - static const char *name; - const char *dot; - const char *domain; - - /* - * Use cached result. - */ - if (name) - return (name); - - /* - * If the local machine name is not in FQDN form, try to append the - * contents of $mydomain. - */ - name = get_hostname(); - if ((dot = strchr(name, '.')) == 0) { - if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) - domain = DEF_MYDOMAIN; - name = concatenate(name, ".", domain, (char *) 0); - } - return (name); -} - -/* get_myhostname - look up and store my hostname */ - -static void get_myhostname(void) -{ - const char *name; - - if ((name = mail_conf_lookup_eval(VAR_MYHOSTNAME)) == 0) - name = check_myhostname(); - var_myhostname = mystrdup(name); -} - -/* check_mydomainname - lookup domain name and validate */ - -static const char *check_mydomainname(void) -{ - char *dot; - - /* - * Use the hostname when it is not a FQDN ("foo"), or when the hostname - * actually is a domain name ("foo.com"). - */ - if (var_myhostname == 0) - get_myhostname(); - if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0) - return (DEF_MYDOMAIN); - return (dot + 1); -} - -/* check_mynetworks - lookup network address list */ - -static const char *check_mynetworks(void) -{ - INET_PROTO_INFO *proto_info; - const char *junk; - - if (var_inet_interfaces == 0) { - if ((cmd_mode & SHOW_DEFS) - || (junk = mail_conf_lookup_eval(VAR_INET_INTERFACES)) == 0) - junk = DEF_INET_INTERFACES; - var_inet_interfaces = mystrdup(junk); - } - if (var_mynetworks_style == 0) { - if ((cmd_mode & SHOW_DEFS) - || (junk = mail_conf_lookup_eval(VAR_MYNETWORKS_STYLE)) == 0) - junk = DEF_MYNETWORKS_STYLE; - var_mynetworks_style = mystrdup(junk); - } - if (var_inet_protocols == 0) { - if ((cmd_mode & SHOW_DEFS) - || (junk = mail_conf_lookup_eval(VAR_INET_PROTOCOLS)) == 0) - junk = DEF_INET_PROTOCOLS; - var_inet_protocols = mystrdup(junk); - proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols); - } - return (mynetworks()); -} - -/* edit_parameters - edit parameter file */ - -static void edit_parameters(int cmd_mode, int argc, char **argv) -{ - char *path; - EDIT_FILE *ep; - VSTREAM *src; - VSTREAM *dst; - VSTRING *buf = vstring_alloc(100); - VSTRING *key = vstring_alloc(10); - char *cp; - char *edit_key; - char *edit_val; - HTABLE *table; - struct cvalue { - char *value; - int found; - }; - struct cvalue *cvalue; - HTABLE_INFO **ht_info; - HTABLE_INFO **ht; - int interesting; - const char *err; - - /* - * Store command-line parameters for quick lookup. - */ - table = htable_create(argc); - while ((cp = *argv++) != 0) { - if (strchr(cp, '\n') != 0) - msg_fatal("-e or -# accepts no multi-line input"); - while (ISSPACE(*cp)) - cp++; - if (*cp == '#') - msg_fatal("-e or -# accepts no comment input"); - if (cmd_mode & EDIT_MAIN) { - if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0) - msg_fatal("%s: \"%s\"", err, cp); - } else if (cmd_mode & COMMENT_OUT) { - if (*cp == 0) - msg_fatal("-# requires non-blank parameter names"); - if (strchr(cp, '=') != 0) - msg_fatal("-# requires parameter names only"); - edit_key = mystrdup(cp); - trimblanks(edit_key, 0); - edit_val = 0; - } else { - msg_panic("edit_parameters: unknown mode %d", cmd_mode); - } - cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); - cvalue->value = edit_val; - cvalue->found = 0; - htable_enter(table, edit_key, (char *) cvalue); - } - - /* - * Open a temp file for the result. This uses a deterministic name so we - * don't leave behind thrash with random names. - */ - set_config_dir(); - path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0); - if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0) - msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX); - dst = ep->tmp_fp; - - /* - * Open the original file for input. - */ - if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) { - /* OK to delete, since we control the temp file name exclusively. */ - (void) unlink(ep->tmp_path); - msg_fatal("open %s for reading: %m", path); - } - - /* - * 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) - - interesting = 0; - while (vstring_get(buf, src) != VSTREAM_EOF) { - for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++) - /* void */ ; - /* Copy comment, all-whitespace, or empty line. */ - if (*cp == '#' || *cp == 0) { - vstream_fputs(STR(buf), dst); - } - /* Copy, skip or replace continued text. */ - else if (cp > STR(buf)) { - if (interesting == 0) - vstream_fputs(STR(buf), dst); - else if (cmd_mode & COMMENT_OUT) - vstream_fprintf(dst, "#%s", STR(buf)); - } - /* Copy or replace start of logical line. */ - else { - vstring_strncpy(key, cp, strcspn(cp, " \t\r\n=")); - cvalue = (struct cvalue *) htable_find(table, STR(key)); - if ((interesting = !!cvalue) != 0) { - if (cvalue->found++ == 1) - msg_warn("%s: multiple entries for \"%s\"", path, STR(key)); - if (cmd_mode & EDIT_MAIN) - vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value); - else if (cmd_mode & COMMENT_OUT) - vstream_fprintf(dst, "#%s", cp); - else - msg_panic("edit_parameters: unknown mode %d", cmd_mode); - } else { - vstream_fputs(STR(buf), dst); - } - } - } - - /* - * Generate new entries for parameters that were not found. - */ - if (cmd_mode & EDIT_MAIN) { - 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 (edit_file_close(ep) != 0) - msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX); - - /* - * Cleanup. - */ - myfree(path); - vstring_free(buf); - vstring_free(key); - htable_free(table, myfree); -} - -/* read_parameters - read parameter info from file */ - -static void read_parameters(void) -{ - char *path; - - /* - * A direct rip-off of mail_conf_read(). XXX Avoid code duplication by - * better code decomposition. - */ - dict_unknown_allowed = 1; - set_config_dir(); - path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0); - dict_load_file(CONFIG_DICT, path); - myfree(path); -} - -/* set_parameters - set parameter values from default or explicit setting */ - -static void set_parameters(void) -{ - - /* - * The proposal below describes some of the steps needed to expand - * parameter values. It has a problem: it updates the configuration - * parameter dictionary, and in doing so breaks the "postconf -d" - * implementation. This makes "-d" and "-e" mutually exclusive. - * - * Populate the configuration parameter dictionary with default settings or - * with actual settings. - * - * Iterate over each entry in str_fn_table, str_fn_table_2, time_table, - * bool_table, int_table, str_table, and raw_table. Look up each - * parameter name in the configuration parameter dictionary. If the - * parameter is not set, take the default value, or take the value from - * main.cf, without doing $name expansions. This includes converting - * default values from numeric/boolean internal forms to external string - * form. - * - * Once the configuration parameter dictionary is populated, printing a - * parameter setting is a matter of querying the configuration parameter - * dictionary, optionally expanding of $name values, and printing the - * result. - */ -} - -/* read_master - read and digest the master.cf file */ - -static void read_master(int fail_on_open_error) -{ - char *path; - VSTRING *buf; - ARGV *argv; - VSTREAM *fp; - int entry_count = 0; - int line_count = 0; - - /* - * Get the location of master.cf. - */ - if (var_config_dir == 0) - set_config_dir(); - path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0); - - /* - * We can't use the master daemon's master_ent routines in their current - * form. They convert everything to internal form, and they skip disabled - * services. - * - * The postconf command needs to show default fields as "-", and needs to - * know about all service names so that it can generate service-dependent - * parameter names (transport-dependent etc.). - */ -#define MASTER_BLANKS " \t\r\n" /* XXX */ -#define MASTER_FIELD_COUNT 8 /* XXX */ - - /* - * Initialize the in-memory master table. - */ - master_table = (PC_MASTER_ENT *) mymalloc(sizeof(*master_table)); - - /* - * Skip blank lines and comment lines. Degrade gracefully if master.cf is - * not available, and master.cf is not the primary target. - */ -#define WARN_ON_OPEN_ERROR 0 -#define FAIL_ON_OPEN_ERROR 1 - - if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) { - if (fail_on_open_error) - msg_fatal("open %s: %m", path); - msg_warn("open %s: %m", path); - } else { - buf = vstring_alloc(100); - while (readlline(buf, fp, &line_count) != 0) { - master_table = (PC_MASTER_ENT *) myrealloc((char *) master_table, - (entry_count + 2) * sizeof(*master_table)); - argv = argv_split(STR(buf), MASTER_BLANKS); - if (argv->argc < MASTER_FIELD_COUNT) - msg_fatal("file %s: line %d: bad field count", - path, line_count); - master_table[entry_count].name_space = - concatenate(argv->argv[0], ".", argv->argv[1], (char *) 0); - master_table[entry_count].argv = argv; - master_table[entry_count].valid_names = 0; - master_table[entry_count].all_params = 0; - entry_count += 1; - } - vstream_fclose(fp); - vstring_free(buf); - } - - /* - * Null-terminate the master table and clean up. - */ - master_table[entry_count].argv = 0; - myfree(path); -} - - /* - * Basename of programs in $daemon_directory. XXX These belong in a header - * file, or they should be made configurable. - */ -#ifndef MAIL_PROGRAM_LOCAL -#define MAIL_PROGRAM_LOCAL "local" -#define MAIL_PROGRAM_ERROR "error" -#define MAIL_PROGRAM_VIRTUAL "virtual" -#define MAIL_PROGRAM_SMTP "smtp" -#define MAIL_PROGRAM_LMTP "lmtp" -#define MAIL_PROGRAM_PIPE "pipe" -#define MAIL_PROGRAM_SPAWN "spawn" -#endif - -/* add_service_parameter - add one service parameter name and default */ - -static void add_service_parameter(const char *service, const char *suffix, - const char *defparam) -{ - PC_STRING_NV *sp; - char *name = concatenate(service, suffix, (char *) 0); - - /* - * Skip service parameter names that have built-in definitions. This - * happens with message delivery transports that have a non-default - * per-destination concurrency or recipient limit, such as local(8). - */ - if (htable_locate(param_table, name) != 0) { - myfree(name); - } else { - serv_param_table = (PC_STRING_NV *) - myrealloc((char *) serv_param_table, - (serv_param_tablen + 1) * sizeof(*serv_param_table)); - sp = serv_param_table + serv_param_tablen; - sp->name = name; - sp->value = defparam; - serv_param_tablen += 1; - } -} - -/* add_service_parameters - add all service parameters with defaults */ - -static void add_service_parameters(void) -{ - static const PC_STRING_NV service_params[] = { - /* suffix, default parameter name */ - _XPORT_RCPT_LIMIT, VAR_XPORT_RCPT_LIMIT, - _STACK_RCPT_LIMIT, VAR_STACK_RCPT_LIMIT, - _XPORT_REFILL_LIMIT, VAR_XPORT_REFILL_LIMIT, - _XPORT_REFILL_DELAY, VAR_XPORT_REFILL_DELAY, - _DELIVERY_SLOT_COST, VAR_DELIVERY_SLOT_COST, - _DELIVERY_SLOT_LOAN, VAR_DELIVERY_SLOT_LOAN, - _DELIVERY_SLOT_DISCOUNT, VAR_DELIVERY_SLOT_DISCOUNT, - _MIN_DELIVERY_SLOTS, VAR_MIN_DELIVERY_SLOTS, - _INIT_DEST_CON, VAR_INIT_DEST_CON, - _DEST_CON_LIMIT, VAR_DEST_CON_LIMIT, - _DEST_RCPT_LIMIT, VAR_DEST_RCPT_LIMIT, - _CONC_POS_FDBACK, VAR_CONC_POS_FDBACK, - _CONC_NEG_FDBACK, VAR_CONC_NEG_FDBACK, - _CONC_COHORT_LIM, VAR_CONC_COHORT_LIM, - _DEST_RATE_DELAY, VAR_DEST_RATE_DELAY, - 0, - }; - static const PC_STRING_NV spawn_params[] = { - /* suffix, default parameter name */ - _MAXTIME, VAR_COMMAND_MAXTIME, - 0, - }; - typedef struct { - const char *progname; - const PC_STRING_NV *params; - } PC_SERVICE_DEF; - static const PC_SERVICE_DEF service_defs[] = { - MAIL_PROGRAM_LOCAL, service_params, - MAIL_PROGRAM_ERROR, service_params, - MAIL_PROGRAM_VIRTUAL, service_params, - MAIL_PROGRAM_SMTP, service_params, - MAIL_PROGRAM_LMTP, service_params, - MAIL_PROGRAM_PIPE, service_params, - MAIL_PROGRAM_SPAWN, spawn_params, - 0, - }; - const PC_STRING_NV *sp; - const char *progname; - const char *service; - PC_MASTER_ENT *masterp; - ARGV *argv; - const PC_SERVICE_DEF *sd; - - /* - * Initialize the table with service parameter names and defaults. - */ - serv_param_table = (PC_STRING_NV *) mymalloc(1); - serv_param_tablen = 0; - - /* - * Extract service names from master.cf and generate service parameter - * information. - */ - for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) { - - /* - * Add service parameters for message delivery transports or spawn - * programs. - */ - progname = argv->argv[7]; - for (sd = service_defs; sd->progname; sd++) { - if (strcmp(sd->progname, progname) == 0) { - service = argv->argv[0]; - for (sp = sd->params; sp->name; sp++) - add_service_parameter(service, sp->name, sp->value); - break; - } - } - } - - /* - * Now that the service parameter table size is frozen, enter the - * parameters into the hash so that we can find and print them. - */ - for (sp = serv_param_table; sp < serv_param_table + serv_param_tablen; sp++) - if (htable_locate(param_table, sp->name) == 0) - htable_enter(param_table, sp->name, (char *) sp); -} - -#define NO_SCAN_RESULT ((VSTRING *) 0) -#define NO_SCAN_FILTER ((char *) 0) -#define NO_SCAN_MODE (0) - -/* SCAN_USER_PARAMETER_VALUE - examine macro names in parameter value */ - -#define SCAN_USER_PARAMETER_VALUE(value, scope) do { \ - (void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \ - NO_SCAN_FILTER, flag_user_parameter, ((char *) (scope))); \ -} while (0) - -/* FLAG_USER_PARAMETER - flag user-defined name "valid" if it has name=value */ - -#define FLAG_USER_PARAMETER(name, scope) do { \ - flag_user_parameter((name), NO_SCAN_MODE, ((char *) (scope))); \ -} while (0) - -/* flag_user_parameter - flag user-defined name "valid" if it has name=value */ - -static const char *flag_user_parameter(const char *mac_name, - int unused_mode, - char *context) -{ - PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context; - - /* - * If the name=value exists in the local (or global) name space, update - * the local (or global) "valid" parameter name table. - * - * Do not "validate" user-defined parameters whose name appears only as - * macro expansion; this is how Postfix historically implements backwards - * compatibility after a feature name change. - */ - if (local_scope && dict_get(local_scope->all_params, mac_name)) { - if (htable_locate(local_scope->valid_names, mac_name) == 0) - htable_enter(local_scope->valid_names, mac_name, ""); - } else if (mail_conf_lookup(mac_name) != 0) { - if (htable_locate(param_table, mac_name) == 0) { - user_param_table = (char **) - myrealloc((char *) user_param_table, - (user_param_tablen + 1) * sizeof(*user_param_table)); - user_param_table[user_param_tablen] = mystrdup(mac_name); - user_param_tablen += 1; - } - } - return (0); -} - -/* pc_lookup_eval - generalized mail_conf_lookup_eval */ - -static const char *pc_lookup_eval(const char *dict_name, const char *name) -{ - const char *value; - -#define RECURSIVE 1 - - if ((value = dict_lookup(dict_name, name)) != 0) - value = dict_eval(dict_name, value, RECURSIVE); - return (value); -} - -/* scan_user_parameter_namespace - scan parameters in name space */ - -static void scan_user_parameter_namespace(const char *dict_name, - PC_MASTER_ENT *local_scope) -{ - const char *myname = "scan_user_parameter_namespace"; - const char *class_list; - char *saved_class_list; - char *cp; - DICT *dict; - char *param_name; - int how; - const char *cparam_name; - const char *cparam_value; - - /* - * Flag parameter names in smtpd_restriction_classes as "valid", but only - * if they have a "name=value" entry. If we are in not in a local name - * space, update the global restriction class name table, so that we can - * query the global table from within a local master.cf name space. - */ - if ((class_list = pc_lookup_eval(dict_name, VAR_REST_CLASSES)) != 0) { - cp = saved_class_list = mystrdup(class_list); - while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0) { - if (local_scope == 0 - && htable_locate(rest_class_table, param_name) == 0) - htable_enter(rest_class_table, param_name, ""); - FLAG_USER_PARAMETER(param_name, local_scope); - } - myfree(saved_class_list); - } - - /* - * For all "name=value" instances: a) if the name space is local and the - * name appears in the global restriction class table, flag the name as - * "valid" in the local name space; b) scan the value for macro - * expansions of unknown parameter names, and flag those parameter names - * as "valid" if they have a "name=value" entry. - */ - if ((dict = dict_handle(dict_name)) == 0) - msg_panic("%s: parameter dictionary %s not found", - myname, dict_name); - if (dict->sequence == 0) - msg_panic("%s: parameter dictionary %s has no iterator", - myname, dict_name); - for (how = DICT_SEQ_FUN_FIRST; - dict->sequence(dict, how, &cparam_name, &cparam_value) == 0; - how = DICT_SEQ_FUN_NEXT) { - if (local_scope != 0 - && htable_locate(local_scope->valid_names, cparam_name) == 0 - && htable_locate(rest_class_table, cparam_name) != 0) - htable_enter(local_scope->valid_names, cparam_name, ""); - SCAN_USER_PARAMETER_VALUE(cparam_value, local_scope); - } -} - -/* add_user_parameters - add parameters with user-defined names */ - -static void add_user_parameters(void) -{ - PC_MASTER_ENT *masterp; - ARGV *argv; - char *arg; - int field; - char *saved_arg; - char *param_name; - char *param_value; - DICT *dict; - char **up; - - /* - * Initialize the global table with user-defined parameter names, and the - * table with global restriction class names. - */ - user_param_table = (char **) mymalloc(1); - user_param_tablen = 0; - rest_class_table = htable_create(1); - - /* - * Scan the explicit name=value entries in the global name space. - */ - scan_user_parameter_namespace(CONFIG_DICT, (PC_MASTER_ENT *) 0); - - /* - * Scan the "-o parameter=value" instances in each master.cf name space. - */ - for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) { - for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) { - arg = argv->argv[field]; - if (arg[0] != '-') - break; - if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) { - saved_arg = mystrdup(arg); - if (split_nameval(saved_arg, ¶m_name, ¶m_value) == 0) - dict_update(masterp->name_space, param_name, param_value); - myfree(saved_arg); - field += 1; - } - } - if ((dict = dict_handle(masterp->name_space)) != 0) { - masterp->all_params = dict; - masterp->valid_names = htable_create(1); - scan_user_parameter_namespace(masterp->name_space, masterp); - } - } - - /* - * Now that the user-defined parameter table size is frozen, enter the - * parameters into the hash so that we can find and print them. - */ - for (up = user_param_table; up < user_param_table + user_param_tablen; up++) - if (htable_locate(param_table, *up) == 0) - htable_enter(param_table, *up, (char *) up); -} - -/* hash_parameters - hash all parameter names so we can find and sort them */ - -static void hash_parameters(void) -{ - const CONFIG_TIME_TABLE *ctt; - const CONFIG_BOOL_TABLE *cbt; - const CONFIG_INT_TABLE *cit; - const CONFIG_STR_TABLE *cst; - const CONFIG_STR_FN_TABLE *csft; - const CONFIG_RAW_TABLE *rst; - const CONFIG_NINT_TABLE *nst; - const CONFIG_NBOOL_TABLE *bst; - const CONFIG_LONG_TABLE *lst; - - param_table = htable_create(100); - - for (ctt = time_table; ctt->name; ctt++) - htable_enter(param_table, ctt->name, (char *) ctt); - for (cbt = bool_table; cbt->name; cbt++) - htable_enter(param_table, cbt->name, (char *) cbt); - for (cit = int_table; cit->name; cit++) - htable_enter(param_table, cit->name, (char *) cit); - for (cst = str_table; cst->name; cst++) - htable_enter(param_table, cst->name, (char *) cst); - for (csft = str_fn_table; csft->name; csft++) - htable_enter(param_table, csft->name, (char *) csft); - for (csft = str_fn_table_2; csft->name; csft++) - htable_enter(param_table, csft->name, (char *) csft); - for (rst = raw_table; rst->name; rst++) - htable_enter(param_table, rst->name, (char *) rst); - for (nst = nint_table; nst->name; nst++) - htable_enter(param_table, nst->name, (char *) nst); - for (bst = nbool_table; bst->name; bst++) - htable_enter(param_table, bst->name, (char *) bst); - for (lst = long_table; lst->name; lst++) - htable_enter(param_table, lst->name, (char *) lst); -} - -/* print_line - show line possibly folded, and with normalized whitespace */ - -static void print_line(int mode, const char *fmt,...) -{ - va_list ap; - static VSTRING *buf = 0; - char *start; - char *next; - int line_len = 0; - int word_len; - - /* - * One-off initialization. - */ - if (buf == 0) - buf = vstring_alloc(100); - - /* - * Format the text. - */ - va_start(ap, fmt); - vstring_vsprintf(buf, fmt, ap); - va_end(ap); - - /* - * Normalize the whitespace. We don't use the line_wrap() routine because - * 1) that function does not normalize whitespace between words and 2) we - * want to normalize whitespace even when not wrapping lines. - * - * XXX Some parameters preserve whitespace: for example, smtpd_banner and - * smtpd_reject_footer. If we have to preserve whitespace between words, - * then perhaps readlline() can be changed to canonicalize whitespace - * that follows a newline. - */ - for (start = STR(buf); *(start += strspn(start, SEPARATORS)) != 0; start = next) { - word_len = strcspn(start, SEPARATORS); - if (*(next = start + word_len) != 0) - *next++ = 0; - if (word_len > 0 && line_len > 0) { - if ((mode & FOLD_LINE) == 0 || line_len + word_len < LINE_LIMIT) { - vstream_fputs(" ", VSTREAM_OUT); - line_len += 1; - } else { - vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); - line_len = INDENT_LEN; - } - } - vstream_fputs(start, VSTREAM_OUT); - line_len += word_len; - } - vstream_fputs("\n", VSTREAM_OUT); -} - -/* show_strval - show string-valued parameter */ - -static void show_strval(int mode, const char *name, const char *value) -{ - if (mode & SHOW_EVAL) - value = mail_conf_eval(value); - - if (mode & SHOW_NAME) { - print_line(mode, "%s = %s\n", name, value); - } else { - print_line(mode, "%s\n", value); - } -} - -/* show_intval - show integer-valued parameter */ - -static void show_intval(int mode, const char *name, int value) -{ - if (mode & SHOW_NAME) { - print_line(mode, "%s = %d\n", name, value); - } else { - print_line(mode, "%d\n", value); - } -} - -/* show_longval - show long-valued parameter */ - -static void show_longval(int mode, const char *name, long value) -{ - if (mode & SHOW_NAME) { - print_line(mode, "%s = %ld\n", name, value); - } else { - print_line(mode, "%ld\n", value); - } -} - -/* print_bool - print boolean parameter */ - -static void print_bool(int mode, const char *name, CONFIG_BOOL_TABLE *cbt) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, cbt->defval ? "yes" : "no"); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, cbt->defval ? "yes" : "no"); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_time - print relative time parameter */ - -static void print_time(int mode, const char *name, CONFIG_TIME_TABLE *ctt) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, ctt->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, ctt->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_int - print integer parameter */ - -static void print_int(int mode, const char *name, CONFIG_INT_TABLE *cit) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_intval(mode, name, cit->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_intval(mode, name, cit->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_str - print string parameter */ - -static void print_str(int mode, const char *name, CONFIG_STR_TABLE *cst) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, cst->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, cst->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_str_fn - print string-function parameter */ - -static void print_str_fn(int mode, const char *name, CONFIG_STR_FN_TABLE *csft) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, csft->defval()); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, csft->defval()); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_str_fn_2 - print string-function parameter */ - -static void print_str_fn_2(int mode, const char *name, CONFIG_STR_FN_TABLE *csft) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, csft->defval()); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, csft->defval()); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_raw - print raw string parameter */ - -static void print_raw(int mode, const char *name, CONFIG_RAW_TABLE *rst) -{ - const char *value; - - if (mode & SHOW_EVAL) - msg_warn("parameter %s expands at run-time", rst->name); - mode &= ~SHOW_EVAL; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, rst->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, rst->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_nint - print new integer parameter */ - -static void print_nint(int mode, const char *name, CONFIG_NINT_TABLE *rst) -{ - const char *value; - - if (mode & SHOW_EVAL) - msg_warn("parameter %s expands at run-time", name); - mode &= ~SHOW_EVAL; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, rst->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, rst->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_nbool - print new boolean parameter */ - -static void print_nbool(int mode, const char *name, CONFIG_NBOOL_TABLE *bst) -{ - const char *value; - - if (mode & SHOW_EVAL) - msg_warn("parameter %s expands at run-time", name); - mode &= ~SHOW_EVAL; - - if (mode & SHOW_DEFS) { - show_strval(mode, name, bst->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_strval(mode, name, bst->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_long - print long parameter */ - -static void print_long(int mode, const char *name, CONFIG_LONG_TABLE *clt) -{ - const char *value; - - if (mode & SHOW_DEFS) { - show_longval(mode, name, clt->defval); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - show_longval(mode, name, clt->defval); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -static void print_parameter(int, const char *, char *); - -/* print_service_param_default show service parameter default value */ - -static void print_service_param_default(int mode, const char *name, - const char *defparam) -{ - const char *myname = "print_service_param_default"; - char *ptr; - - if ((ptr = htable_find(param_table, defparam)) == 0) - msg_panic("%s: service parameter %s has unknown default value $%s", - myname, name, defparam); - if (mode & SHOW_EVAL) - print_parameter(mode, name, ptr); - else - print_line(mode, "%s = $%s\n", name, defparam); -} - -/* print_service_param - show service parameter */ - -static void print_service_param(int mode, const char *name, - const PC_STRING_NV *dst) -{ - const char *value; - - if (mode & SHOW_DEFS) { - print_service_param_default(mode, name, dst->value); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { - print_service_param_default(mode, name, dst->value); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_user_param - show user-defined parameter */ - -static void print_user_param(int mode, const char *name) -{ - const char *value; - - if (mode & SHOW_DEFS) { /* can't happen */ - show_strval(mode, name, ""); - } else { - value = dict_lookup(CONFIG_DICT, name); - if ((mode & SHOW_NONDEF) == 0) { - if (value == 0) { /* can't happen */ - show_strval(mode, name, ""); - } else { - show_strval(mode, name, value); - } - } else { - if (value != 0) - show_strval(mode, name, value); - } - } -} - -/* print_parameter - show specific parameter */ - -static void print_parameter(int mode, const char *name, char *ptr) -{ - -#define INSIDE(p,t) (ptr >= (char *) t && ptr < ((char *) t) + sizeof(t)) -#define INSIDE3(p,t,l) (ptr >= (char *) t && ptr < (char *) ((t) + (l))) - - /* - * This is gross, but the best we can do on short notice. - */ - if (INSIDE(ptr, time_table)) - print_time(mode, name, (CONFIG_TIME_TABLE *) ptr); - if (INSIDE(ptr, bool_table)) - print_bool(mode, name, (CONFIG_BOOL_TABLE *) ptr); - if (INSIDE(ptr, int_table)) - print_int(mode, name, (CONFIG_INT_TABLE *) ptr); - if (INSIDE(ptr, str_table)) - print_str(mode, name, (CONFIG_STR_TABLE *) ptr); - if (INSIDE(ptr, str_fn_table)) - print_str_fn(mode, name, (CONFIG_STR_FN_TABLE *) ptr); - if (INSIDE(ptr, str_fn_table_2)) - print_str_fn_2(mode, name, (CONFIG_STR_FN_TABLE *) ptr); - if (INSIDE(ptr, raw_table)) - print_raw(mode, name, (CONFIG_RAW_TABLE *) ptr); - if (INSIDE(ptr, nint_table)) - print_nint(mode, name, (CONFIG_NINT_TABLE *) ptr); - if (INSIDE(ptr, nbool_table)) - print_nbool(mode, name, (CONFIG_NBOOL_TABLE *) ptr); - if (INSIDE(ptr, long_table)) - print_long(mode, name, (CONFIG_LONG_TABLE *) ptr); - if (INSIDE3(ptr, serv_param_table, serv_param_tablen)) - print_service_param(mode, name, (PC_STRING_NV *) ptr); - if (INSIDE3(ptr, user_param_table, user_param_tablen)) - print_user_param(mode, name); - if (msg_verbose) - vstream_fflush(VSTREAM_OUT); -} - -/* comp_names - qsort helper */ - -static int comp_names(const void *a, const void *b) -{ - HTABLE_INFO **ap = (HTABLE_INFO **) a; - HTABLE_INFO **bp = (HTABLE_INFO **) b; - - return (strcmp(ap[0]->key, bp[0]->key)); -} - -/* show_parameters - show parameter info */ - -static void show_parameters(int mode, char **names) -{ - HTABLE_INFO **list; - HTABLE_INFO **ht; - char **namep; - char *value; - - /* - * Show all parameters. - */ - if (*names == 0) { - list = htable_list(param_table); - qsort((char *) list, param_table->used, sizeof(*list), comp_names); - for (ht = list; *ht; ht++) - print_parameter(mode, ht[0]->key, ht[0]->value); - myfree((char *) list); - return; - } - - /* - * Show named parameters. - */ - for (namep = names; *namep; namep++) { - if ((value = htable_find(param_table, *namep)) == 0) { - msg_warn("%s: unknown parameter", *namep); - } else { - print_parameter(mode, *namep, value); - } - } -} - -/* 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_locks - show available mailbox locking methods */ - -static void show_locks(void) -{ - ARGV *locks_argv; - int i; - - locks_argv = mbox_lock_names(); - for (i = 0; i < locks_argv->argc; i++) - vstream_printf("%s\n", locks_argv->argv[i]); - argv_free(locks_argv); -} - -/* print_master_line - print one master line */ - -static void print_master_line(int mode, ARGV *argv) -{ - char *arg; - char *aval; - int line_len; - int field; - int in_daemon_options; - static int column_goal[] = { - 0, /* service */ - 11, /* type */ - 17, /* private */ - 25, /* unpriv */ - 33, /* chroot */ - 41, /* wakeup */ - 49, /* maxproc */ - 57, /* command */ - }; - -#define ADD_TEXT(text, len) do { \ - vstream_fputs(text, VSTREAM_OUT); line_len += len; } \ - while (0) -#define ADD_SPACE ADD_TEXT(" ", 1) - - /* - * Show the standard fields at their preferred column position. Use - * single-space separation when some field does not fit. - */ - for (line_len = 0, field = 0; field < MASTER_FIELD_COUNT; field++) { - arg = argv->argv[field]; - if (line_len > 0) { - while (line_len < column_goal[field] - 1) - ADD_SPACE; - ADD_SPACE; - } - ADD_TEXT(arg, strlen(arg)); - } - - /* - * Format the daemon command-line options and non-option arguments. Here, - * we have no data-dependent preference for column positions, but we do - * have argument grouping preferences. - */ - in_daemon_options = 1; - for ( /* void */ ; argv->argv[field] != 0; field++) { - arg = argv->argv[field]; - if (in_daemon_options) { - - /* - * Try to show the generic options (-v -D) on the first line, and - * non-options on a later line. - */ - if (arg[0] != '-') { - in_daemon_options = 0; - if ((mode & FOLD_LINE) - && line_len > column_goal[MASTER_FIELD_COUNT - 1]) { - vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); - line_len = INDENT_LEN; - } - } - - /* - * Try to avoid breaking "-o name=value" over multiple lines if - * it would fit on one line. - */ - else if ((mode & FOLD_LINE) - && line_len > INDENT_LEN && strcmp(arg, "-o") == 0 - && (aval = argv->argv[field + 1]) != 0 - && INDENT_LEN + 3 + strlen(aval) < LINE_LIMIT) { - vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); - line_len = INDENT_LEN; - ADD_TEXT(arg, strlen(arg)); - arg = aval; - field += 1; - } - } - - /* - * Insert a line break when the next argument won't fit (unless, of - * course, we just inserted a line break). - */ - if (line_len > INDENT_LEN) { - if ((mode & FOLD_LINE) == 0 - || line_len + 1 + strlen(arg) < LINE_LIMIT) { - ADD_SPACE; - } else { - vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); - line_len = INDENT_LEN; - } - } - ADD_TEXT(arg, strlen(arg)); - } - vstream_fputs("\n", VSTREAM_OUT); -} - -/* show_master - show master.cf entries */ - -static void show_master(int mode, char **filters) -{ - PC_MASTER_ENT *masterp; - ARGV *argv; - ARGV *service_filter = 0; - - /* - * Initialize the service filter. - */ - if (filters[0]) - service_filter = match_service_init_argv(filters); - - /* - * Iterate over the master table. - */ - for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) - if (service_filter == 0 - || match_service_match(service_filter, masterp->name_space) != 0) - print_master_line(mode, argv); - if (service_filter != 0) - argv_free(service_filter); -} - -/* show_sasl - show SASL plug-in types */ - -static void show_sasl(int what) -{ - ARGV *sasl_argv; - int i; - - sasl_argv = (what & SHOW_SASL_SERV) ? xsasl_server_types() : - xsasl_client_types(); - for (i = 0; i < sasl_argv->argc; i++) - vstream_printf("%s\n", sasl_argv->argv[i]); - argv_free(sasl_argv); -} - -/* flag_unused_parameters - warn about unused parameters */ - -static void flag_unused_parameters(DICT *dict, const char *conf_name, - PC_MASTER_ENT *local_scope) -{ - const char *myname = "flag_unused_parameters"; - const char *param_name; - const char *param_value; - int how; - - /* - * Iterate over all entries, and flag parameter names that aren't used - * anywhere. Show the warning message at the end of the output. - */ - if (dict->sequence == 0) - msg_panic("%s: parameter dictionary %s has no iterator", - myname, conf_name); - for (how = DICT_SEQ_FUN_FIRST; - dict->sequence(dict, how, ¶m_name, ¶m_value) == 0; - how = DICT_SEQ_FUN_NEXT) { - if (htable_locate(param_table, param_name) == 0 - && (local_scope == 0 - || htable_locate(local_scope->valid_names, param_name) == 0)) { - vstream_fflush(VSTREAM_OUT); - msg_warn("%s/%s: unused parameter: %s=%s", - var_config_dir, conf_name, param_name, param_value); - } - } -} - -/* flag_unused_main_parameters - warn about unused parameters */ - -static void flag_unused_main_parameters(void) -{ - const char *myname = "flag_unused_main_parameters"; - DICT *dict; - - /* - * Iterate over all main.cf entries, and flag parameter names that aren't - * used anywhere. - */ - if ((dict = dict_handle(CONFIG_DICT)) == 0) - msg_panic("%s: parameter dictionary %s not found", - myname, CONFIG_DICT); - flag_unused_parameters(dict, MAIN_CONF_FILE, (PC_MASTER_ENT *) 0); -} - -/* flag_unused_master_parameters - warn about unused parameters */ - -static void flag_unused_master_parameters(void) -{ - PC_MASTER_ENT *masterp; - DICT *dict; - - /* - * Iterate over all master.cf entries, and flag parameter names that - * aren't used anywhere. - */ - for (masterp = master_table; masterp->argv != 0; masterp++) - if ((dict = masterp->all_params) != 0) - flag_unused_parameters(dict, MASTER_CONF_FILE, masterp); -} - MAIL_VERSION_STAMP_DECLARE; /* main */ @@ -2145,17 +532,18 @@ int main(int argc, char **argv) read_parameters(); set_parameters(); } - hash_parameters(); + register_builtin_parameters(); /* * Add service-dependent parameters (service names from master.cf) * and user-defined parameters ($name macros in parameter values in - * main.cf and master.cf). + * main.cf and master.cf, but only if those names have a name=value + * in main.cf or master.cf). */ read_master(WARN_ON_OPEN_ERROR); - add_service_parameters(); + register_service_parameters(); if ((cmd_mode & SHOW_DEFS) == 0) - add_user_parameters(); + register_user_parameters(); /* * Show the requested values. diff --git a/postfix/src/postconf/postconf.h b/postfix/src/postconf/postconf.h new file mode 100644 index 000000000..b5ec355dc --- /dev/null +++ b/postfix/src/postconf/postconf.h @@ -0,0 +1,179 @@ +/*++ +/* NAME +/* postconf 3h +/* SUMMARY +/* module interfaces +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include +#include +#include + + /* + * What we're supposed to be doing. + */ +#define SHOW_NONDEF (1<<0) /* show main.cf non-default settings */ +#define SHOW_DEFS (1<<1) /* show main.cf default setting */ +#define SHOW_NAME (1<<2) /* show main.cf parameter name */ +#define SHOW_MAPS (1<<3) /* show map types */ +#define EDIT_MAIN (1<<4) /* edit main.cf */ +#define SHOW_LOCKS (1<<5) /* show mailbox lock methods */ +#define SHOW_EVAL (1<<6) /* expand main.cf right-hand sides */ +#define SHOW_SASL_SERV (1<<7) /* show server auth plugin types */ +#define SHOW_SASL_CLNT (1<<8) /* show client auth plugin types */ +#define COMMENT_OUT (1<<9) /* #-out selected main.cf entries */ +#define SHOW_MASTER (1<<10) /* show master.cf entries */ +#define FOLD_LINE (1<<11) /* fold long *.cf entries */ + +#define DEF_MODE SHOW_NAME /* default mode */ + + /* + * Structure for one "valid parameter" (built-in, service-defined or valid + * user-defined). See the postconf_builtin, postconf_service and + * postconf_user modules for narrative text. + */ +typedef struct { + int flags; /* see below */ + char *param_data; /* mostly, the default value */ + const char *(*convert_fn) (char *); /* value to string */ +} PC_PARAM_NODE; + + /* Values for flags. See the postconf_node module for narrative text. */ +#define PC_PARAM_FLAG_NONE (0) +#define PC_PARAM_FLAG_RAW (1<<0) + +#define PC_RAW_PARAMETER(node) ((node)->flags & PC_PARAM_FLAG_RAW) + + /* Values for param_data. See postconf_node module for narrative text. */ +#define PC_PARAM_NO_DATA ((char *) 0) + + /* + * Lookup table for global "valid parameter" information. + */ +#define PC_PARAM_TABLE HTABLE +#define PC_PARAM_INFO HTABLE_INFO + +extern PC_PARAM_TABLE *param_table; + + /* + * postconf_node.c. + */ +#define PC_PARAM_TABLE_CREATE(size) htable_create(size); +#define PC_PARAM_NODE_CAST(ptr) ((PC_PARAM_NODE *) (ptr)) + +#define PC_PARAM_TABLE_LIST(table) htable_list(table) +#define PC_PARAM_INFO_NAME(ht) ((const char *) (ht)->key) +#define PC_PARAM_INFO_NODE(ht) PC_PARAM_NODE_CAST((ht)->value) + +#define PC_PARAM_TABLE_FIND(table, name) \ + PC_PARAM_NODE_CAST(htable_find((table), (name))) +#define PC_PARAM_TABLE_LOCATE(table, name) htable_locate((table), (name)) +#define PC_PARAM_TABLE_ENTER(table, name, flags, data, func) \ + htable_enter((table), (name), (char *) make_param_node((flags), \ + (data), (func))) + +PC_PARAM_NODE *make_param_node(int, char *, const char *(*) (char *)); +const char *convert_param_node(int, const char *, PC_PARAM_NODE *); +extern VSTRING *param_string_buf; + + /* + * Structure of one master.cf entry. + */ +typedef struct { + char *name_space; /* service.type, parameter name space */ + ARGV *argv; /* null, or master.cf fields */ + DICT *all_params; /* null, or all name=value entries */ + HTABLE *valid_names; /* null, or "valid" parameter names */ +} PC_MASTER_ENT; + +#define PC_MASTER_MIN_FIELDS 8 /* mandatory field count */ + + /* + * Lookup table for master.cf entries. The table is terminated with an entry + * that has a null argv member. + */ +PC_MASTER_ENT *master_table; + + /* + * Line-wrapping support. + */ +#define LINE_LIMIT 80 /* try to fold longer lines */ +#define SEPARATORS " \t\r\n" +#define INDENT_LEN 4 /* indent long text by 4 */ +#define INDENT_TEXT " " + + /* + * XXX Global so that postconf_builtin.c call-backs can see it. + */ +extern int cmd_mode; + + /* + * postconf_misc.c. + */ +extern void set_config_dir(void); + + /* + * postconf_main.c + */ +extern void read_parameters(void); +extern void set_parameters(void); +extern void show_parameters(int, char **); + + /* + * postconf_edit.c + */ +extern void edit_parameters(int, int, char **); + + /* + * postconf_master.c. + */ +extern void read_master(int); +extern void show_master(int, char **); + +#define WARN_ON_OPEN_ERROR 0 +#define FAIL_ON_OPEN_ERROR 1 + + /* + * postconf_builtin.c. + */ +extern void register_builtin_parameters(void); + + /* + * postconf_service.c. + */ +extern void register_service_parameters(void); + + /* + * postconf_user.c. + */ +extern void register_user_parameters(void); + + /* + * postconf_unused.c. + */ +extern void flag_unused_main_parameters(void); +extern void flag_unused_master_parameters(void); + + /* + * postconf_other.c. + */ +extern void show_maps(void); +extern void show_locks(void); +extern void show_sasl(int); + +/* 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 +/*--*/ diff --git a/postfix/src/postconf/postconf_builtin.c b/postfix/src/postconf/postconf_builtin.c new file mode 100644 index 000000000..09893e50d --- /dev/null +++ b/postfix/src/postconf/postconf_builtin.c @@ -0,0 +1,368 @@ +/*++ +/* NAME +/* postconf_builtin 3 +/* SUMMARY +/* built-in parameter support +/* SYNOPSIS +/* #include +/* +/* void register_builtin_parameters() +/* DESCRIPTION +/* register_builtin_parameters() initializes the global parameter +/* name space and adds all built-in parameter information. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 + +#ifdef USE_PATHS_H +#include +#endif + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include +#include +#include + +/* Application-specific. */ + +#include + + /* + * Support for built-in parameters: declarations generated by scanning + * actual C source files. + */ +#include "time_vars.h" +#include "bool_vars.h" +#include "int_vars.h" +#include "str_vars.h" +#include "raw_vars.h" +#include "nint_vars.h" +#include "nbool_vars.h" +#include "long_vars.h" + + /* + * Support for built-in parameters: manually extracted. + */ +#include "install_vars.h" + + /* + * Support for built-in parameters: lookup tables generated by scanning + * actual C source files. + */ +static const CONFIG_TIME_TABLE time_table[] = { +#include "time_table.h" + 0, +}; + +static const CONFIG_BOOL_TABLE bool_table[] = { +#include "bool_table.h" + 0, +}; + +static const CONFIG_INT_TABLE int_table[] = { +#include "int_table.h" + 0, +}; + +static const CONFIG_STR_TABLE str_table[] = { +#include "str_table.h" +#include "install_table.h" + 0, +}; + +static const CONFIG_RAW_TABLE raw_table[] = { +#include "raw_table.h" + 0, +}; + +static const CONFIG_NINT_TABLE nint_table[] = { +#include "nint_table.h" + 0, +}; + +static const CONFIG_NBOOL_TABLE nbool_table[] = { +#include "nbool_table.h" + 0, +}; + +static const CONFIG_LONG_TABLE long_table[] = { +#include "long_table.h" + 0, +}; + + /* + * Parameters with default values obtained via function calls. + */ +char *var_myhostname; +char *var_mydomain; +char *var_mynetworks; + +static const char *check_myhostname(void); +static const char *check_mydomainname(void); +static const char *check_mynetworks(void); + +static const CONFIG_STR_FN_TABLE str_fn_table[] = { + VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0, + VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0, + 0, +}; +static const CONFIG_STR_FN_TABLE str_fn_table_2[] = { + VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0, + 0, +}; + +#define STR(x) vstring_str(x) + +/* check_myhostname - lookup hostname and validate */ + +static const char *check_myhostname(void) +{ + static const char *name; + const char *dot; + const char *domain; + + /* + * Use cached result. + */ + if (name) + return (name); + + /* + * If the local machine name is not in FQDN form, try to append the + * contents of $mydomain. + */ + name = get_hostname(); + if ((dot = strchr(name, '.')) == 0) { + if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) + domain = DEF_MYDOMAIN; + name = concatenate(name, ".", domain, (char *) 0); + } + return (name); +} + +/* get_myhostname - look up and store my hostname */ + +static void get_myhostname(void) +{ + const char *name; + + if ((name = mail_conf_lookup_eval(VAR_MYHOSTNAME)) == 0) + name = check_myhostname(); + var_myhostname = mystrdup(name); +} + +/* check_mydomainname - lookup domain name and validate */ + +static const char *check_mydomainname(void) +{ + char *dot; + + /* + * Use the hostname when it is not a FQDN ("foo"), or when the hostname + * actually is a domain name ("foo.com"). + */ + if (var_myhostname == 0) + get_myhostname(); + if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0) + return (DEF_MYDOMAIN); + return (dot + 1); +} + +/* check_mynetworks - lookup network address list */ + +static const char *check_mynetworks(void) +{ + INET_PROTO_INFO *proto_info; + const char *junk; + + if (var_inet_interfaces == 0) { + if ((cmd_mode & SHOW_DEFS) + || (junk = mail_conf_lookup_eval(VAR_INET_INTERFACES)) == 0) + junk = DEF_INET_INTERFACES; + var_inet_interfaces = mystrdup(junk); + } + if (var_mynetworks_style == 0) { + if ((cmd_mode & SHOW_DEFS) + || (junk = mail_conf_lookup_eval(VAR_MYNETWORKS_STYLE)) == 0) + junk = DEF_MYNETWORKS_STYLE; + var_mynetworks_style = mystrdup(junk); + } + if (var_inet_protocols == 0) { + if ((cmd_mode & SHOW_DEFS) + || (junk = mail_conf_lookup_eval(VAR_INET_PROTOCOLS)) == 0) + junk = DEF_INET_PROTOCOLS; + var_inet_protocols = mystrdup(junk); + proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols); + } + return (mynetworks()); +} + +/* convert_bool_parameter - get boolean parameter string value */ + +static const char *convert_bool_parameter(char *ptr) +{ + CONFIG_BOOL_TABLE *cbt = (CONFIG_BOOL_TABLE *) ptr; + + return (cbt->defval ? "yes" : "no"); +} + +/* convert_time_parameter - get relative time parameter string value */ + +static const char *convert_time_parameter(char *ptr) +{ + CONFIG_TIME_TABLE *ctt = (CONFIG_TIME_TABLE *) ptr; + + return (ctt->defval); +} + +/* convert_int_parameter - get integer parameter string value */ + +static const char *convert_int_parameter(char *ptr) +{ + CONFIG_INT_TABLE *cit = (CONFIG_INT_TABLE *) ptr; + + return (STR(vstring_sprintf(param_string_buf, "%d", cit->defval))); +} + +/* convert_str_parameter - get string parameter string value */ + +static const char *convert_str_parameter(char *ptr) +{ + CONFIG_STR_TABLE *cst = (CONFIG_STR_TABLE *) ptr; + + return (cst->defval); +} + +/* convert_str_fn_parameter - get string-function parameter string value */ + +static const char *convert_str_fn_parameter(char *ptr) +{ + CONFIG_STR_FN_TABLE *cft = (CONFIG_STR_FN_TABLE *) ptr; + + return (cft->defval()); +} + +/* convert_raw_parameter - get raw string parameter string value */ + +static const char *convert_raw_parameter(char *ptr) +{ + CONFIG_RAW_TABLE *rst = (CONFIG_RAW_TABLE *) ptr; + + return (rst->defval); +} + +/* convert_nint_parameter - get new integer parameter string value */ + +static const char *convert_nint_parameter(char *ptr) +{ + CONFIG_NINT_TABLE *rst = (CONFIG_NINT_TABLE *) ptr; + + return (rst->defval); +} + +/* convert_nbool_parameter - get new boolean parameter string value */ + +static const char *convert_nbool_parameter(char *ptr) +{ + CONFIG_NBOOL_TABLE *bst = (CONFIG_NBOOL_TABLE *) ptr; + + return (bst->defval); +} + +/* convert_long_parameter - get long parameter string value */ + +static const char *convert_long_parameter(char *ptr) +{ + CONFIG_LONG_TABLE *clt = (CONFIG_LONG_TABLE *) ptr; + + return (STR(vstring_sprintf(param_string_buf, "%ld", clt->defval))); +} + +/* register_builtin_parameters - add built-ins to the global name space */ + +void register_builtin_parameters(void) +{ + const char *myname = "register_builtin_parameters"; + const CONFIG_TIME_TABLE *ctt; + const CONFIG_BOOL_TABLE *cbt; + const CONFIG_INT_TABLE *cit; + const CONFIG_STR_TABLE *cst; + const CONFIG_STR_FN_TABLE *cft; + const CONFIG_RAW_TABLE *rst; + const CONFIG_NINT_TABLE *nst; + const CONFIG_NBOOL_TABLE *bst; + const CONFIG_LONG_TABLE *lst; + + /* + * Sanity checks. + */ + if (param_table != 0) + msg_panic("%s: global parameter table is already initialized", myname); + + /* + * Initialize the global parameter table. + */ + param_table = PC_PARAM_TABLE_CREATE(100); + + /* + * Add the built-in parameters to the global name space. + */ + for (ctt = time_table; ctt->name; ctt++) + PC_PARAM_TABLE_ENTER(param_table, ctt->name, PC_PARAM_FLAG_NONE, + (char *) ctt, convert_time_parameter); + for (cbt = bool_table; cbt->name; cbt++) + PC_PARAM_TABLE_ENTER(param_table, cbt->name, PC_PARAM_FLAG_NONE, + (char *) cbt, convert_bool_parameter); + for (cit = int_table; cit->name; cit++) + PC_PARAM_TABLE_ENTER(param_table, cit->name, PC_PARAM_FLAG_NONE, + (char *) cit, convert_int_parameter); + for (cst = str_table; cst->name; cst++) + PC_PARAM_TABLE_ENTER(param_table, cst->name, PC_PARAM_FLAG_NONE, + (char *) cst, convert_str_parameter); + for (cft = str_fn_table; cft->name; cft++) + PC_PARAM_TABLE_ENTER(param_table, cft->name, PC_PARAM_FLAG_NONE, + (char *) cft, convert_str_fn_parameter); + for (cft = str_fn_table_2; cft->name; cft++) + PC_PARAM_TABLE_ENTER(param_table, cft->name, PC_PARAM_FLAG_NONE, + (char *) cft, convert_str_fn_parameter); + for (rst = raw_table; rst->name; rst++) + PC_PARAM_TABLE_ENTER(param_table, rst->name, PC_PARAM_FLAG_RAW, + (char *) rst, convert_raw_parameter); + for (nst = nint_table; nst->name; nst++) + PC_PARAM_TABLE_ENTER(param_table, nst->name, PC_PARAM_FLAG_NONE, + (char *) nst, convert_nint_parameter); + for (bst = nbool_table; bst->name; bst++) + PC_PARAM_TABLE_ENTER(param_table, bst->name, PC_PARAM_FLAG_NONE, + (char *) bst, convert_nbool_parameter); + for (lst = long_table; lst->name; lst++) + PC_PARAM_TABLE_ENTER(param_table, lst->name, PC_PARAM_FLAG_NONE, + (char *) lst, convert_long_parameter); +} diff --git a/postfix/src/postconf/postconf_edit.c b/postfix/src/postconf/postconf_edit.c new file mode 100644 index 000000000..660e7e9c3 --- /dev/null +++ b/postfix/src/postconf/postconf_edit.c @@ -0,0 +1,202 @@ +/*++ +/* NAME +/* postconf_edit 3 +/* SUMMARY +/* edit main.cf +/* SYNOPSIS +/* #include +/* +/* void edit_parameters(mode, argc, argv) +/* int mode; +/* int argc; +/* char **argv; +/* DESCRIPTION +/* Edit the \fBmain.cf\fR configuration file, and update +/* parameter settings with the "\fIname\fR=\fIvalue\fR" pairs +/* given on the command line. The file is copied to a temporary +/* file then renamed into place. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* FILES +/* /etc/postfix/main.cf, Postfix configuration parameters +/* /etc/postfix/main.cf.tmp, temporary name +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include + +/* Application-specific. */ + +#include + +#define STR(x) vstring_str(x) + +/* edit_parameters - edit parameter file */ + +void edit_parameters(int mode, int argc, char **argv) +{ + char *path; + EDIT_FILE *ep; + VSTREAM *src; + VSTREAM *dst; + VSTRING *buf = vstring_alloc(100); + VSTRING *key = vstring_alloc(10); + char *cp; + char *edit_key; + char *edit_val; + HTABLE *table; + struct cvalue { + char *value; + int found; + }; + struct cvalue *cvalue; + HTABLE_INFO **ht_info; + HTABLE_INFO **ht; + int interesting; + const char *err; + + /* + * Store command-line parameters for quick lookup. + */ + table = htable_create(argc); + while ((cp = *argv++) != 0) { + if (strchr(cp, '\n') != 0) + msg_fatal("-e or -# accepts no multi-line input"); + while (ISSPACE(*cp)) + cp++; + if (*cp == '#') + msg_fatal("-e or -# accepts no comment input"); + if (mode & EDIT_MAIN) { + if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0) + msg_fatal("%s: \"%s\"", err, cp); + } else if (mode & COMMENT_OUT) { + if (*cp == 0) + msg_fatal("-# requires non-blank parameter names"); + if (strchr(cp, '=') != 0) + msg_fatal("-# requires parameter names only"); + edit_key = mystrdup(cp); + trimblanks(edit_key, 0); + edit_val = 0; + } else { + msg_panic("edit_parameters: unknown mode %d", mode); + } + cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); + cvalue->value = edit_val; + cvalue->found = 0; + htable_enter(table, edit_key, (char *) cvalue); + } + + /* + * Open a temp file for the result. This uses a deterministic name so we + * don't leave behind thrash with random names. + */ + set_config_dir(); + path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0); + if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0) + msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX); + dst = ep->tmp_fp; + + /* + * Open the original file for input. + */ + if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) { + /* OK to delete, since we control the temp file name exclusively. */ + (void) unlink(ep->tmp_path); + msg_fatal("open %s for reading: %m", path); + } + + /* + * 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) + + interesting = 0; + while (vstring_get(buf, src) != VSTREAM_EOF) { + for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++) + /* void */ ; + /* Copy comment, all-whitespace, or empty line. */ + if (*cp == '#' || *cp == 0) { + vstream_fputs(STR(buf), dst); + } + /* Copy, skip or replace continued text. */ + else if (cp > STR(buf)) { + if (interesting == 0) + vstream_fputs(STR(buf), dst); + else if (mode & COMMENT_OUT) + vstream_fprintf(dst, "#%s", STR(buf)); + } + /* Copy or replace start of logical line. */ + else { + vstring_strncpy(key, cp, strcspn(cp, " \t\r\n=")); + cvalue = (struct cvalue *) htable_find(table, STR(key)); + if ((interesting = !!cvalue) != 0) { + if (cvalue->found++ == 1) + msg_warn("%s: multiple entries for \"%s\"", path, STR(key)); + if (mode & EDIT_MAIN) + vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value); + else if (mode & COMMENT_OUT) + vstream_fprintf(dst, "#%s", cp); + else + msg_panic("edit_parameters: unknown mode %d", mode); + } else { + vstream_fputs(STR(buf), dst); + } + } + } + + /* + * Generate new entries for parameters that were not found. + */ + if (mode & EDIT_MAIN) { + 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 (edit_file_close(ep) != 0) + msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX); + + /* + * Cleanup. + */ + myfree(path); + vstring_free(buf); + vstring_free(key); + htable_free(table, myfree); +} diff --git a/postfix/src/postconf/postconf_main.c b/postfix/src/postconf/postconf_main.c new file mode 100644 index 000000000..e7b0f72ab --- /dev/null +++ b/postfix/src/postconf/postconf_main.c @@ -0,0 +1,258 @@ +/*++ +/* NAME +/* postconf_main 3 +/* SUMMARY +/* basic support for main.cf +/* SYNOPSIS +/* #include +/* +/* void read_parameters() +/* +/* void set_parameters() +/* +/* void show_parameters(mode, names) +/* int mode; +/* char **names; +/* DESCRIPTION +/* read_parameters() reads parameters from main.cf. +/* +/* set_parameters() does nothing. It is a place holder for +/* code that assigns actual or default parameter values, which +/* could be needed to implement "postconf -e" parameter value +/* expansion. +/* +/* show_parameters() writes main.cf parameters to the standard +/* output stream. +/* +/* Arguments: +/* .IP mode +/* Bit-wise OR of zero or more of the following: +/* .RS +/* .IP FOLD_LINE +/* Fold long lines. +/* .IP SHOW_DEFS +/* Output default parameter values. +/* .IP SHOW_NONDEF +/* Output explicit settings only. +/* .IP SHOW_NAME +/* Output the parameter as "name = value". +/* .IP SHOW_EVAL +/* Expand parameter values (not implemented). +/* .RE +/* .IP names +/* List of zero or more parameter names. If the list is empty, +/* output all parameters. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + +#define STR(x) vstring_str(x) + +/* read_parameters - read parameter info from file */ + +void read_parameters(void) +{ + char *path; + + /* + * A direct rip-off of mail_conf_read(). XXX Avoid code duplication by + * better code decomposition. + */ + dict_unknown_allowed = 1; + set_config_dir(); + path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0); + dict_load_file(CONFIG_DICT, path); + myfree(path); +} + +/* set_parameters - set parameter values from default or explicit setting */ + +void set_parameters(void) +{ + + /* + * The proposal below describes some of the steps needed to expand + * parameter values. It has a problem: it updates the configuration + * parameter dictionary, and in doing so breaks the "postconf -d" + * implementation. This makes "-d" and "-e" mutually exclusive. + * + * Populate the configuration parameter dictionary with default settings or + * with actual settings. + * + * Iterate over each entry in str_fn_table, str_fn_table_2, time_table, + * bool_table, int_table, str_table, and raw_table. Look up each + * parameter name in the configuration parameter dictionary. If the + * parameter is not set, take the default value, or take the value from + * main.cf, without doing $name expansions. This includes converting + * default values from numeric/boolean internal forms to external string + * form. + * + * Once the configuration parameter dictionary is populated, printing a + * parameter setting is a matter of querying the configuration parameter + * dictionary, optionally expanding of $name values, and printing the + * result. + */ +} + +/* print_line - show line possibly folded, and with normalized whitespace */ + +static void print_line(int mode, const char *fmt,...) +{ + va_list ap; + static VSTRING *buf = 0; + char *start; + char *next; + int line_len = 0; + int word_len; + + /* + * One-off initialization. + */ + if (buf == 0) + buf = vstring_alloc(100); + + /* + * Format the text. + */ + va_start(ap, fmt); + vstring_vsprintf(buf, fmt, ap); + va_end(ap); + + /* + * Normalize the whitespace. We don't use the line_wrap() routine because + * 1) that function does not normalize whitespace between words and 2) we + * want to normalize whitespace even when not wrapping lines. + * + * XXX Some parameters preserve whitespace: for example, smtpd_banner and + * smtpd_reject_footer. If we have to preserve whitespace between words, + * then perhaps readlline() can be changed to canonicalize whitespace + * that follows a newline. + */ + for (start = STR(buf); *(start += strspn(start, SEPARATORS)) != 0; start = next) { + word_len = strcspn(start, SEPARATORS); + if (*(next = start + word_len) != 0) + *next++ = 0; + if (word_len > 0 && line_len > 0) { + if ((mode & FOLD_LINE) == 0 || line_len + word_len < LINE_LIMIT) { + vstream_fputs(" ", VSTREAM_OUT); + line_len += 1; + } else { + vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); + line_len = INDENT_LEN; + } + } + vstream_fputs(start, VSTREAM_OUT); + line_len += word_len; + } + vstream_fputs("\n", VSTREAM_OUT); +} + +/* print_parameter - show specific parameter */ + +static void print_parameter(int mode, const char *name, + PC_PARAM_NODE *node) +{ + const char *value; + + /* + * Use the default or actual value. + */ + if ((mode & SHOW_DEFS) != 0 + || ((value = dict_lookup(CONFIG_DICT, name)) == 0 + && (mode & SHOW_NONDEF) == 0)) + value = convert_param_node(SHOW_DEFS, name, node); + + /* + * Print with or without the name= prefix. + */ + if (value != 0) { + if (mode & SHOW_NAME) { + print_line(mode, "%s = %s\n", name, value); + } else { + print_line(mode, "%s\n", value); + } + if (msg_verbose) + vstream_fflush(VSTREAM_OUT); + } +} + +/* comp_names - qsort helper */ + +static int comp_names(const void *a, const void *b) +{ + PC_PARAM_INFO **ap = (PC_PARAM_INFO **) a; + PC_PARAM_INFO **bp = (PC_PARAM_INFO **) b; + + return (strcmp(PC_PARAM_INFO_NAME(ap[0]), + PC_PARAM_INFO_NAME(bp[0]))); +} + +/* show_parameters - show parameter info */ + +void show_parameters(int mode, char **names) +{ + PC_PARAM_INFO **list; + PC_PARAM_INFO **ht; + char **namep; + PC_PARAM_NODE *node; + + /* + * Show all parameters. + */ + if (*names == 0) { + list = PC_PARAM_TABLE_LIST(param_table); + qsort((char *) list, param_table->used, sizeof(*list), comp_names); + for (ht = list; *ht; ht++) + print_parameter(mode, PC_PARAM_INFO_NAME(*ht), + PC_PARAM_INFO_NODE(*ht)); + myfree((char *) list); + return; + } + + /* + * Show named parameters. + */ + for (namep = names; *namep; namep++) { + if ((node = PC_PARAM_TABLE_FIND(param_table, *namep)) == 0) { + msg_warn("%s: unknown parameter", *namep); + } else { + print_parameter(mode, *namep, node); + } + } +} diff --git a/postfix/src/postconf/postconf_master.c b/postfix/src/postconf/postconf_master.c new file mode 100644 index 000000000..ab20cc659 --- /dev/null +++ b/postfix/src/postconf/postconf_master.c @@ -0,0 +1,270 @@ +/*++ +/* NAME +/* postconf_master 3 +/* SUMMARY +/* support for master.cf +/* SYNOPSIS +/* #include +/* +/* void read_master(fail_on_open) +/* int fail_on_open; +/* +/* void show_master(mode, filters) +/* int mode; +/* char **filters; +/* DESCRIPTION +/* read_master() reads entries from master.cf into memory. +/* +/* show_master() writes the entries in the master.cf file +/* to standard output. +/* +/* Arguments +/* .IP fail_on_open +/* Specify FAIL_ON_OPEN if open failure is a fatal error, +/* WARN_ON_OPEN if a warning should be logged instead. +/* .IP mode +/* If the FOLD_LINE flag is set, show_master() wraps long +/* output lines. +/* .IP filters +/* A list of zero or more expressions in master_service(3) +/* format. If no list is specified, show_master() outputs +/* all master.cf entries in the specified order. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + +#define STR(x) vstring_str(x) + +/* read_master - read and digest the master.cf file */ + +void read_master(int fail_on_open_error) +{ + const char *myname = "read_master"; + char *path; + VSTRING *buf; + ARGV *argv; + VSTREAM *fp; + int entry_count = 0; + int line_count = 0; + + /* + * Sanity check. + */ + if (master_table != 0) + msg_panic("%s: master table is already initialized", myname); + + /* + * Get the location of master.cf. + */ + if (var_config_dir == 0) + set_config_dir(); + path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0); + + /* + * We can't use the master daemon's master_ent routines in their current + * form. They convert everything to internal form, and they skip disabled + * services. + * + * The postconf command needs to show default fields as "-", and needs to + * know about all service names so that it can generate service-dependent + * parameter names (transport-dependent etc.). + */ +#define MASTER_BLANKS " \t\r\n" /* XXX */ + + /* + * Initialize the in-memory master table. + */ + master_table = (PC_MASTER_ENT *) mymalloc(sizeof(*master_table)); + + /* + * Skip blank lines and comment lines. Degrade gracefully if master.cf is + * not available, and master.cf is not the primary target. + */ + if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) { + if (fail_on_open_error) + msg_fatal("open %s: %m", path); + msg_warn("open %s: %m", path); + } else { + buf = vstring_alloc(100); + while (readlline(buf, fp, &line_count) != 0) { + master_table = (PC_MASTER_ENT *) myrealloc((char *) master_table, + (entry_count + 2) * sizeof(*master_table)); + argv = argv_split(STR(buf), MASTER_BLANKS); + if (argv->argc < PC_MASTER_MIN_FIELDS) + msg_fatal("file %s: line %d: bad field count", + path, line_count); + master_table[entry_count].name_space = + concatenate(argv->argv[0], ".", argv->argv[1], (char *) 0); + master_table[entry_count].argv = argv; + master_table[entry_count].valid_names = 0; + master_table[entry_count].all_params = 0; + entry_count += 1; + } + vstream_fclose(fp); + vstring_free(buf); + } + + /* + * Null-terminate the master table and clean up. + */ + master_table[entry_count].argv = 0; + myfree(path); +} + +/* print_master_line - print one master line */ + +static void print_master_line(int mode, ARGV *argv) +{ + char *arg; + char *aval; + int line_len; + int field; + int in_daemon_options; + static int column_goal[] = { + 0, /* service */ + 11, /* type */ + 17, /* private */ + 25, /* unpriv */ + 33, /* chroot */ + 41, /* wakeup */ + 49, /* maxproc */ + 57, /* command */ + }; + +#define ADD_TEXT(text, len) do { \ + vstream_fputs(text, VSTREAM_OUT); line_len += len; } \ + while (0) +#define ADD_SPACE ADD_TEXT(" ", 1) + + /* + * Show the standard fields at their preferred column position. Use at + * least one-space column separation. + */ + for (line_len = 0, field = 0; field < PC_MASTER_MIN_FIELDS; field++) { + arg = argv->argv[field]; + if (line_len > 0) { + do { + ADD_SPACE; + } while (line_len < column_goal[field]); + } + ADD_TEXT(arg, strlen(arg)); + } + + /* + * Format the daemon command-line options and non-option arguments. Here, + * we have no data-dependent preference for column positions, but we do + * have argument grouping preferences. + */ + in_daemon_options = 1; + for ( /* void */ ; argv->argv[field] != 0; field++) { + arg = argv->argv[field]; + if (in_daemon_options) { + + /* + * Try to show the generic options (-v -D) on the first line, and + * non-options on a later line. + */ + if (arg[0] != '-') { + in_daemon_options = 0; + if ((mode & FOLD_LINE) + && line_len > column_goal[PC_MASTER_MIN_FIELDS - 1]) { + vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); + line_len = INDENT_LEN; + } + } + + /* + * Try to avoid breaking "-o name=value" over multiple lines if + * it would fit on one line. + */ + else if ((mode & FOLD_LINE) + && line_len > INDENT_LEN && strcmp(arg, "-o") == 0 + && (aval = argv->argv[field + 1]) != 0 + && INDENT_LEN + 3 + strlen(aval) < LINE_LIMIT) { + vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); + line_len = INDENT_LEN; + ADD_TEXT(arg, strlen(arg)); + arg = aval; + field += 1; + } + } + + /* + * Insert a line break when the next argument won't fit (unless, of + * course, we just inserted a line break). + */ + if (line_len > INDENT_LEN) { + if ((mode & FOLD_LINE) == 0 + || line_len + 1 + strlen(arg) < LINE_LIMIT) { + ADD_SPACE; + } else { + vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT); + line_len = INDENT_LEN; + } + } + ADD_TEXT(arg, strlen(arg)); + } + vstream_fputs("\n", VSTREAM_OUT); +} + +/* show_master - show master.cf entries */ + +void show_master(int mode, char **filters) +{ + PC_MASTER_ENT *masterp; + ARGV *argv; + ARGV *service_filter = 0; + + /* + * Initialize the service filter. + */ + if (filters[0]) + service_filter = match_service_init_argv(filters); + + /* + * Iterate over the master table. + */ + for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) + if (service_filter == 0 + || match_service_match(service_filter, masterp->name_space) != 0) + print_master_line(mode, argv); + + /* + * Cleanup. + */ + if (service_filter != 0) + argv_free(service_filter); +} diff --git a/postfix/src/postconf/postconf_misc.c b/postfix/src/postconf/postconf_misc.c new file mode 100644 index 000000000..179614deb --- /dev/null +++ b/postfix/src/postconf/postconf_misc.c @@ -0,0 +1,57 @@ +/*++ +/* NAME +/* postconf_misc 3 +/* SUMMARY +/* miscellaneous low-level code +/* SYNOPSIS +/* #include +/* +/* void set_config_dir() +/* DESCRIPTION +/* set_config_dir() forcibly overrides the var_config_dir +/* parameter setting with the value from the environment or +/* with the default pathname, and updates the mail parameter +/* dictionary. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + +/* set_config_dir - forcibly override var_config_dir */ + +void set_config_dir(void) +{ + char *config_dir; + + 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); +} diff --git a/postfix/src/postconf/postconf_node.c b/postfix/src/postconf/postconf_node.c new file mode 100644 index 000000000..b7d2bbfd3 --- /dev/null +++ b/postfix/src/postconf/postconf_node.c @@ -0,0 +1,185 @@ +/*++ +/* NAME +/* postconf_node 3 +/* SUMMARY +/* low-level parameter node support +/* SYNOPSIS +/* #include +/* +/* PC_PARAM_TABLE *PC_PARAM_TABLE_CREATE(size) +/* ssize_t size; +/* +/* PC_PARAM_INFO **PC_PARAM_TABLE_LIST(table) +/* PC_PARAM_TABLE *table; +/* +/* const char *PC_PARAM_INFO_NAME(info) +/* PC_PARAM_INFO *info; +/* +/* PC_PARAM_NODE *PC_PARAM_INFO_NODE(info) +/* PC_PARAM_INFO *info; +/* +/* PC_PARAM_NODE *PC_PARAM_TABLE_FIND(table, name) +/* PC_PARAM_TABLE *table; +/* const char *name; +/* +/* PC_PARAM_INFO *PC_PARAM_TABLE_LOCATE(table, name) +/* PC_PARAM_TABLE *table; +/* const char *name; +/* +/* PC_PARAM_INFO *PC_PARAM_TABLE_ENTER(table, name, flags, +/* param_data, convert_fn) +/* PC_PARAM_TABLE *table; +/* const char *name; +/* int flags; +/* char *param_data; +/* const char *(*convert_fn)(char *); +/* +/* PC_PARAM_NODE *make_param_node(flags, param_data, convert_fn) +/* int flags; +/* char *param_data; +/* const char *(*convert_fn) (char *); +/* +/* const char *convert_param_node(mode, name, node) +/* int mode; +/* const char *name; +/* PC_PARAM_NODE *node; +/* +/* VSTRING *param_string_buf; +/* +/* PC_RAW_PARAMETER(node) +/* const PC_PARAM_NODE *node; +/* DESCRIPTION +/* This module maintains data structures (PC_PARAM_NODE) with +/* information about known-legitimate parameters. These data +/* structures are stored in a hash table. +/* +/* The PC_PARAM_MUMBLE() macros are wrappers around the htable(3) +/* module. Their sole purpose is to encapsulate all the pointer +/* casting from and to (PC_PARAM_NODE *). Apart from that, the +/* macros have no features worth discussing. +/* +/* make_param_node() creates a node for the global parameter +/* table. This node provides a parameter default value, and a +/* function that converts the default value to string. +/* +/* convert_param_node() produces a string representation for +/* a global parameter default value. +/* +/* PC_RAW_PARAMETER() returns non-zero is the specified parameter +/* node represents a "raw parameter". The value of such +/* parameters must not be scanned for macro names. Some "raw +/* parameter" values contain "$" without macros, such as the +/* smtpd_expansion_filter "safe character" set; and some contain +/* $name from a private name space, such as forward_path. Some +/* "raw parameter" values in postscreen(8) are safe to expand +/* by one level. Support for that may be added later. +/* +/* param_string_buf is a buffer that is initialized on the fly +/* and that parameter-to-string conversion functions may use for +/* temporary result storage. +/* +/* Arguments: +/* .IP size +/* The initial size of the hash table. +/* .IP table +/* A hash table for storage of "valid parameter" information. +/* .IP info +/* A data structure with a name component and a PC_PARAM_NODE +/* component. Use PC_PARAM_INFO_NAME() and PC_PARAM_INFO_NODE() +/* to access these components. +/* .IP name +/* The name of a "valid parameter". +/* .IP flags +/* PC_PARAM_FLAG_RAW for a "raw parameter", PC_PARAM_FLAG_NONE +/* otherwise. See the PC_RAW_PARAMETER() discussion above for +/* discussion of "raw parameter" values. +/* .IP param_data +/* Information about the parameter value. Specify PC_PARAM_NO_DATA +/* if this is not applicable. +/* .IP convert_fn +/* The function that will be invoked to produce a string +/* representation of the information in param_data. The function +/* receives the param_data value as argument. +/* .IP mode +/* For now, the SHOW_DEFS flag is required. +/* .IP name +/* The name of the parameter whose value is requested. This +/* is used for diagnostics. +/* .IP node +/* The (flags, param_data, convert_fn) information that needs +/* to be converted to a string representation of the default +/* value. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 + +/* Utility library. */ + +#include +#include +#include + +/* Application-specific. */ + +#include + +VSTRING *param_string_buf; + +/* make_param_node - make node for global parameter table */ + +PC_PARAM_NODE *make_param_node(int flags, char *param_data, + const char *(*convert_fn) (char *)) +{ + PC_PARAM_NODE *node; + + node = (PC_PARAM_NODE *) mymalloc(sizeof(*node)); + node->flags = flags; + node->param_data = param_data; + node->convert_fn = convert_fn; + return (node); +} + +/* convert_param_node - get actual or default parameter value */ + +const char *convert_param_node(int mode, const char *name, PC_PARAM_NODE *node) +{ + const char *myname = "convert_param_node"; + const char *value; + + /* + * One-off initialization. + */ + if (param_string_buf == 0) + param_string_buf = vstring_alloc(100); + + /* + * Sanity check. A null value indicates that a parameter does not have + * the requested value. At this time, the only requested value can be the + * default value, and a null pointer value makes no sense here. + */ + if ((mode & SHOW_DEFS) == 0) + msg_panic("%s: request for non-default value of parameter %s", + myname, name); + if ((value = node->convert_fn(node->param_data)) == 0) + msg_panic("%s: parameter %s has null pointer default value", + myname, name); + + /* + * Return the parameter default value. + */ + return (value); +} diff --git a/postfix/src/postconf/postconf_other.c b/postfix/src/postconf/postconf_other.c new file mode 100644 index 000000000..04f9404ac --- /dev/null +++ b/postfix/src/postconf/postconf_other.c @@ -0,0 +1,100 @@ +/*++ +/* NAME +/* postconf_other 3 +/* SUMMARY +/* support for miscellaneous information categories +/* SYNOPSIS +/* #include +/* +/* void show_maps() +/* +/* void show_locks() +/* +/* void show_sasl(mode) +/* int mode; +/* DESCRIPTION +/* show_maps() lists the available map (lookup table) types. +/* +/* show_locks() lists the available mailbox lock types. +/* +/* show_sasl() shows the available SASL authentication +/* plugin types. +/* +/* Arguments: +/* .IP mode +/* Show server information if the SHOW_SASL_SERV flag is set, +/* otherwise show client information. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include + +/* XSASL library. */ + +#include + +/* Application-specific. */ + +#include + +/* show_maps - show available maps */ + +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_locks - show available mailbox locking methods */ + +void show_locks(void) +{ + ARGV *locks_argv; + int i; + + locks_argv = mbox_lock_names(); + for (i = 0; i < locks_argv->argc; i++) + vstream_printf("%s\n", locks_argv->argv[i]); + argv_free(locks_argv); +} + +/* show_sasl - show SASL plug-in types */ + +void show_sasl(int what) +{ + ARGV *sasl_argv; + int i; + + sasl_argv = (what & SHOW_SASL_SERV) ? xsasl_server_types() : + xsasl_client_types(); + for (i = 0; i < sasl_argv->argc; i++) + vstream_printf("%s\n", sasl_argv->argv[i]); + argv_free(sasl_argv); +} diff --git a/postfix/src/postconf/postconf_service.c b/postfix/src/postconf/postconf_service.c new file mode 100644 index 000000000..b3f792020 --- /dev/null +++ b/postfix/src/postconf/postconf_service.c @@ -0,0 +1,184 @@ +/*++ +/* NAME +/* postconf_service 3 +/* SUMMARY +/* service-defined parameter support +/* SYNOPSIS +/* #include +/* +/* void register_service_parameters() +/* DESCRIPTION +/* Service-defined parameter names are created by appending +/* postfix-defined suffixes to master.cf service names. All +/* service-defined parameters have default values that are +/* defined by a built-in parameter. +/* +/* register_service_parameters() adds the service-defined parameters +/* to the global name space. This function must be called after +/* the built-in parameters are added to the global name space, +/* and after the master.cf file is read. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 +#include +#include +#include + +/* Global library. */ + +#include + +/* Application-specific. */ + +#include + + /* + * Basename of programs in $daemon_directory. XXX These belong in a header + * file, or they should be made configurable. + */ +#ifndef MAIL_PROGRAM_LOCAL +#define MAIL_PROGRAM_LOCAL "local" +#define MAIL_PROGRAM_ERROR "error" +#define MAIL_PROGRAM_VIRTUAL "virtual" +#define MAIL_PROGRAM_SMTP "smtp" +#define MAIL_PROGRAM_LMTP "lmtp" +#define MAIL_PROGRAM_PIPE "pipe" +#define MAIL_PROGRAM_SPAWN "spawn" +#endif + + /* + * Ad-hoc name-value string pair. + */ +typedef struct { + const char *name; + const char *value; +} PC_STRING_NV; + +#define STR(x) vstring_str(x) + +/* convert_service_parameter - get service parameter string value */ + +static const char *convert_service_parameter(char *ptr) +{ + return (STR(vstring_sprintf(param_string_buf, "$%s", ptr))); +} + +/* register_service_parameter - add one service parameter name and default */ + +static void register_service_parameter(const char *service, const char *suffix, + const char *defparam) +{ + char *name = concatenate(service, suffix, (char *) 0); + + /* + * Skip service parameter names that have built-in definitions. This + * happens with message delivery transports that have a non-default + * per-destination concurrency or recipient limit, such as local(8). + */ + if (PC_PARAM_TABLE_LOCATE(param_table, name) != 0) { + myfree(name); + } else { + PC_PARAM_TABLE_ENTER(param_table, name, PC_PARAM_FLAG_NONE, + (char *) defparam, convert_service_parameter); + } +} + +/* register_service_parameters - add all service parameters with defaults */ + +void register_service_parameters(void) +{ + const char *myname = "register_service_parameters"; + static const PC_STRING_NV service_params[] = { + /* suffix, default parameter name */ + _XPORT_RCPT_LIMIT, VAR_XPORT_RCPT_LIMIT, + _STACK_RCPT_LIMIT, VAR_STACK_RCPT_LIMIT, + _XPORT_REFILL_LIMIT, VAR_XPORT_REFILL_LIMIT, + _XPORT_REFILL_DELAY, VAR_XPORT_REFILL_DELAY, + _DELIVERY_SLOT_COST, VAR_DELIVERY_SLOT_COST, + _DELIVERY_SLOT_LOAN, VAR_DELIVERY_SLOT_LOAN, + _DELIVERY_SLOT_DISCOUNT, VAR_DELIVERY_SLOT_DISCOUNT, + _MIN_DELIVERY_SLOTS, VAR_MIN_DELIVERY_SLOTS, + _INIT_DEST_CON, VAR_INIT_DEST_CON, + _DEST_CON_LIMIT, VAR_DEST_CON_LIMIT, + _DEST_RCPT_LIMIT, VAR_DEST_RCPT_LIMIT, + _CONC_POS_FDBACK, VAR_CONC_POS_FDBACK, + _CONC_NEG_FDBACK, VAR_CONC_NEG_FDBACK, + _CONC_COHORT_LIM, VAR_CONC_COHORT_LIM, + _DEST_RATE_DELAY, VAR_DEST_RATE_DELAY, + 0, + }; + static const PC_STRING_NV spawn_params[] = { + /* suffix, default parameter name */ + _MAXTIME, VAR_COMMAND_MAXTIME, + 0, + }; + typedef struct { + const char *progname; + const PC_STRING_NV *params; + } PC_SERVICE_DEF; + static const PC_SERVICE_DEF service_defs[] = { + MAIL_PROGRAM_LOCAL, service_params, + MAIL_PROGRAM_ERROR, service_params, + MAIL_PROGRAM_VIRTUAL, service_params, + MAIL_PROGRAM_SMTP, service_params, + MAIL_PROGRAM_LMTP, service_params, + MAIL_PROGRAM_PIPE, service_params, + MAIL_PROGRAM_SPAWN, spawn_params, + 0, + }; + const PC_STRING_NV *sp; + const char *progname; + const char *service; + PC_MASTER_ENT *masterp; + ARGV *argv; + const PC_SERVICE_DEF *sd; + + /* + * Sanity checks. + */ + if (param_table == 0) + msg_panic("%s: global parameter table is not initialized", myname); + if (master_table == 0) + msg_panic("%s: master table is not initialized", myname); + + /* + * Extract service names from master.cf and generate service parameter + * information. + */ + for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) { + + /* + * Add service parameters for message delivery transports or spawn + * programs. + */ + progname = argv->argv[7]; + for (sd = service_defs; sd->progname; sd++) { + if (strcmp(sd->progname, progname) == 0) { + service = argv->argv[0]; + for (sp = sd->params; sp->name; sp++) + register_service_parameter(service, sp->name, sp->value); + break; + } + } + } +} diff --git a/postfix/src/postconf/postconf_unused.c b/postfix/src/postconf/postconf_unused.c new file mode 100644 index 000000000..ca79d0da9 --- /dev/null +++ b/postfix/src/postconf/postconf_unused.c @@ -0,0 +1,129 @@ +/*++ +/* NAME +/* postconf_unused 3 +/* SUMMARY +/* report unused parameters +/* SYNOPSIS +/* #include +/* +/* void flag_unused_main_parameters() +/* +/* void flag_unused_master_parameters() +/* DESCRIPTION +/* These functions must be called after all parameter information +/* is initialized: built-ins, service-defined and user-defined. +/* In other words, don't call these functions with "postconf -d" +/* which ignores user-defined main.cf settings. +/* +/* flag_unused_main_parameters() reports unused "name=value" +/* entries in main.cf. +/* +/* flag_unused_master_parameters() reports unused "-o name=value" +/* entries in master.cf. +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + +/* flag_unused_parameters - warn about unused parameters */ + +static void flag_unused_parameters(DICT *dict, const char *conf_name, + PC_MASTER_ENT *local_scope) +{ + const char *myname = "flag_unused_parameters"; + const char *param_name; + const char *param_value; + int how; + + /* + * Sanity checks. + */ + if (param_table == 0) + msg_panic("%s: global parameter table is not initialized", myname); + + /* + * Iterate over all entries, and flag parameter names that aren't used + * anywhere. Show the warning message at the end of the output. + */ + if (dict->sequence == 0) + msg_panic("%s: parameter dictionary %s has no iterator", + myname, conf_name); + for (how = DICT_SEQ_FUN_FIRST; + dict->sequence(dict, how, ¶m_name, ¶m_value) == 0; + how = DICT_SEQ_FUN_NEXT) { + if (PC_PARAM_TABLE_LOCATE(param_table, param_name) == 0 + && (local_scope == 0 + || PC_PARAM_TABLE_LOCATE(local_scope->valid_names, param_name) == 0)) { + vstream_fflush(VSTREAM_OUT); + msg_warn("%s/%s: unused parameter: %s=%s", + var_config_dir, conf_name, param_name, param_value); + } + } +} + +/* flag_unused_main_parameters - warn about unused parameters */ + +void flag_unused_main_parameters(void) +{ + const char *myname = "flag_unused_main_parameters"; + DICT *dict; + + /* + * Iterate over all main.cf entries, and flag parameter names that aren't + * used anywhere. + */ + if ((dict = dict_handle(CONFIG_DICT)) == 0) + msg_panic("%s: parameter dictionary %s not found", + myname, CONFIG_DICT); + flag_unused_parameters(dict, MAIN_CONF_FILE, (PC_MASTER_ENT *) 0); +} + +/* flag_unused_master_parameters - warn about unused parameters */ + +void flag_unused_master_parameters(void) +{ + const char *myname = "flag_unused_master_parameters"; + PC_MASTER_ENT *masterp; + DICT *dict; + + /* + * Sanity checks. + */ + if (master_table == 0) + msg_panic("%s: master table is not initialized", myname); + + /* + * Iterate over all master.cf entries, and flag parameter names that + * aren't used anywhere. + */ + for (masterp = master_table; masterp->argv != 0; masterp++) + if ((dict = masterp->all_params) != 0) + flag_unused_parameters(dict, MASTER_CONF_FILE, masterp); +} diff --git a/postfix/src/postconf/postconf_user.c b/postfix/src/postconf/postconf_user.c new file mode 100644 index 000000000..28362bf90 --- /dev/null +++ b/postfix/src/postconf/postconf_user.c @@ -0,0 +1,304 @@ +/*++ +/* NAME +/* postconf_user 3 +/* SUMMARY +/* support for user-defined parameters +/* SYNOPSIS +/* #include +/* +/* void register_user_parameters() +/* DESCRIPTION +/* Postfix has multiple parameter name spaces: the global +/* main.cf parameter name space, and the local parameter name +/* space of each master.cf entry. Parameters in local name +/* spaces take precedence over global parameters. +/* +/* There are three categories of known parameters: built-in, +/* service-defined (see postconf_service.c), and valid +/* user-defined. +/* +/* There are two categories of valid user-defined parameters: +/* +/* - Parameters whose user-defined-name appears in the value +/* of smtpd_restriction_classes in main.cf or master.cf. +/* +/* - Parameters whose $user-defined-name appear in the value +/* of "name=value" entries in main.cf or master.cf. +/* +/* - In both cases the parameters must have a +/* "user-defined-name=value" entry in main.cf or master.cf. +/* +/* Other user-defined parameters are flagged as "unused". +/* +/* register_user_parameters() scans the global and per-service +/* name spaces for user-defined parameters and flags +/* parameters as "valid" in the global name space (param_table) +/* or in the per-service name space (valid_params). +/* DIAGNOSTICS +/* Problems are reported to the standard error stream. +/* 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 +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + + /* + * Hash with all user-defined names in the global smtpd_restriction_classes + * value. This is used when validating "-o user-defined-name=value" entries + * in master.cf. + */ +static HTABLE *rest_class_table; + + /* + * Macros to make code with obscure constants more readable. + */ +#define NO_SCAN_RESULT ((VSTRING *) 0) +#define NO_SCAN_FILTER ((char *) 0) +#define NO_SCAN_MODE (0) + +/* SCAN_USER_PARAMETER_VALUE - examine macro names in parameter value */ + +#define SCAN_USER_PARAMETER_VALUE(value, local_scope) do { \ + (void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \ + NO_SCAN_FILTER, flag_user_parameter, ((char *) (local_scope))); \ +} while (0) + +/* FLAG_USER_PARAMETER - flag user-defined name "valid" if it has name=value */ + +#define FLAG_USER_PARAMETER(name, local_scope) do { \ + flag_user_parameter((name), NO_SCAN_MODE, ((char *) (local_scope))); \ +} while (0) + +/* convert_user_parameter - get user-defined parameter string value */ + +static const char *convert_user_parameter(char *unused_ptr) +{ + return (""); /* can't happen */ +} + +/* flag_user_parameter - flag user-defined name "valid" if it has name=value */ + +static const char *flag_user_parameter(const char *mac_name, + int unused_mode, + char *context) +{ + PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context; + + /* + * If the name=value exists in the local (or global) name space, update + * the local (or global) "valid" parameter name table. + * + * Do not "validate" user-defined parameters whose name appears only as + * macro expansion; this is how Postfix historically implements backwards + * compatibility after a feature name change. + */ + if (local_scope && dict_get(local_scope->all_params, mac_name)) { + if (PC_PARAM_TABLE_LOCATE(local_scope->valid_names, mac_name) == 0) + PC_PARAM_TABLE_ENTER(local_scope->valid_names, mac_name, + PC_PARAM_FLAG_NONE, PC_PARAM_NO_DATA, + convert_user_parameter); + } else if (mail_conf_lookup(mac_name) != 0) { + if (PC_PARAM_TABLE_LOCATE(param_table, mac_name) == 0) + PC_PARAM_TABLE_ENTER(param_table, mac_name, PC_PARAM_FLAG_NONE, + PC_PARAM_NO_DATA, convert_user_parameter); + } + return (0); +} + +/* pc_lookup_eval - generalized mail_conf_lookup_eval */ + +static const char *pc_lookup_eval(const char *dict_name, const char *name) +{ + const char *value; + +#define RECURSIVE 1 + + if ((value = dict_lookup(dict_name, name)) != 0) + value = dict_eval(dict_name, value, RECURSIVE); + return (value); +} + +/* scan_user_parameter_namespace - scan parameters in name space */ + +static void scan_user_parameter_namespace(const char *dict_name, + PC_MASTER_ENT *local_scope) +{ + const char *myname = "scan_user_parameter_namespace"; + const char *class_list; + char *saved_class_list; + char *cp; + DICT *dict; + char *param_name; + int how; + const char *cparam_name; + const char *cparam_value; + PC_PARAM_NODE *node; + + /* + * Flag parameter names in smtpd_restriction_classes as "valid", but only + * if they have a "name=value" entry. If we are in not in a local name + * space, update the global restriction class name table, so that we can + * query the global table from within a local master.cf name space. + */ + if ((class_list = pc_lookup_eval(dict_name, VAR_REST_CLASSES)) != 0) { + cp = saved_class_list = mystrdup(class_list); + while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0) { + if (local_scope == 0 + && htable_locate(rest_class_table, param_name) == 0) + htable_enter(rest_class_table, param_name, ""); + FLAG_USER_PARAMETER(param_name, local_scope); + } + myfree(saved_class_list); + } + + /* + * For all "name=value" instances: a) if the name space is local and the + * name appears in the global restriction class table, flag the name as + * "valid" in the local name space; b) scan the value for macro + * expansions of unknown parameter names, and flag those parameter names + * as "valid" if they have a "name=value" entry. + */ + if ((dict = dict_handle(dict_name)) == 0) + msg_panic("%s: parameter dictionary %s not found", + myname, dict_name); + if (dict->sequence == 0) + msg_panic("%s: parameter dictionary %s has no iterator", + myname, dict_name); + for (how = DICT_SEQ_FUN_FIRST; + dict->sequence(dict, how, &cparam_name, &cparam_value) == 0; + how = DICT_SEQ_FUN_NEXT) { + if (local_scope != 0 + && PC_PARAM_TABLE_LOCATE(local_scope->valid_names, cparam_name) == 0 + && htable_locate(rest_class_table, cparam_name) != 0) + PC_PARAM_TABLE_ENTER(local_scope->valid_names, cparam_name, + PC_PARAM_FLAG_NONE, PC_PARAM_NO_DATA, + convert_user_parameter); + /* Skip "do not expand" parameters. */ + if ((node = PC_PARAM_TABLE_FIND(param_table, cparam_name)) != 0 + && PC_RAW_PARAMETER(node)) + continue; + SCAN_USER_PARAMETER_VALUE(cparam_value, local_scope); + } +} + +/* scan_default_parameter_values - scan parameters at implicit defaults */ + +static void scan_default_parameter_values(HTABLE *valid_params, + const char *dict_name, + PC_MASTER_ENT *local_scope) +{ + const char *myname = "scan_default_parameter_values"; + PC_PARAM_INFO **list; + PC_PARAM_INFO **ht; + const char *param_value; + + list = PC_PARAM_TABLE_LIST(valid_params); + for (ht = list; *ht; ht++) { + /* Skip "do not expand" parameters. */ + if (PC_RAW_PARAMETER(PC_PARAM_INFO_NODE(*ht))) + continue; + /* Skip parameters with a non-default value. */ + if (dict_lookup(dict_name, PC_PARAM_INFO_NAME(*ht))) + continue; + if ((param_value = convert_param_node(SHOW_DEFS, PC_PARAM_INFO_NAME(*ht), + PC_PARAM_INFO_NODE(*ht))) == 0) + msg_panic("%s: parameter %s has no default value", + myname, PC_PARAM_INFO_NAME(*ht)); + SCAN_USER_PARAMETER_VALUE(param_value, local_scope); + } + myfree((char *) list); +} + +/* register_user_parameters - add parameters with user-defined names */ + +void register_user_parameters(void) +{ + const char *myname = "register_user_parameters"; + PC_MASTER_ENT *masterp; + ARGV *argv; + char *arg; + int field; + char *saved_arg; + char *param_name; + char *param_value; + DICT *dict; + + /* + * Sanity checks. + */ + if (param_table == 0) + msg_panic("%s: global parameter table is not initialized", myname); + if (master_table == 0) + msg_panic("%s: master table is not initialized", myname); + if (rest_class_table != 0) + msg_panic("%s: restriction class table is already initialized", myname); + + /* + * Initialize the table with global restriction class names. + */ + rest_class_table = htable_create(1); + + /* + * Scan parameter values that are left at their defaults in the global + * name space. Some defaults contain the $name of an obsolete parameter + * for backwards compatilility purposes. We might warn that an explicit + * name=value is obsolete, but we must not warn that the parameter is + * unused. + */ + scan_default_parameter_values(param_table, CONFIG_DICT, (PC_MASTER_ENT *) 0); + + /* + * Scan the explicit name=value entries in the global name space. + */ + scan_user_parameter_namespace(CONFIG_DICT, (PC_MASTER_ENT *) 0); + + /* + * Scan the "-o parameter=value" instances in each master.cf name space. + */ + for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) { + for (field = PC_MASTER_MIN_FIELDS; argv->argv[field] != 0; field++) { + arg = argv->argv[field]; + if (arg[0] != '-') + break; + if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) { + saved_arg = mystrdup(arg); + if (split_nameval(saved_arg, ¶m_name, ¶m_value) == 0) + dict_update(masterp->name_space, param_name, param_value); + myfree(saved_arg); + field += 1; + } + } + if ((dict = dict_handle(masterp->name_space)) != 0) { + masterp->all_params = dict; + masterp->valid_names = htable_create(1); + scan_user_parameter_namespace(masterp->name_space, masterp); + } + } +} diff --git a/postfix/src/postconf/test18.ref b/postfix/src/postconf/test18.ref new file mode 100644 index 000000000..09224a638 --- /dev/null +++ b/postfix/src/postconf/test18.ref @@ -0,0 +1,3 @@ +config_directory = . +smtpd_client_connection_limit_exceptions = yyy +virtual_maps = xxx diff --git a/postfix/src/postconf/test19.ref b/postfix/src/postconf/test19.ref new file mode 100644 index 000000000..5a286c68c --- /dev/null +++ b/postfix/src/postconf/test19.ref @@ -0,0 +1,3 @@ +config_directory = . +default_rbl_reply = $bbbb +forward_path = $aaaa diff --git a/postfix/src/postscreen/postscreen_smtpd.c b/postfix/src/postscreen/postscreen_smtpd.c index 3eae5a585..5c7c5cd07 100644 --- a/postfix/src/postscreen/postscreen_smtpd.c +++ b/postfix/src/postscreen/postscreen_smtpd.c @@ -925,8 +925,8 @@ static void psc_smtpd_read_event(int event, char *context) || (*var_psc_forbid_cmds && string_list_match(psc_forbid_cmds, command)))) { printable(command, '?'); - msg_info("NON-SMTP COMMAND from [%s]:%s %.100s", - PSC_CLIENT_ADDR_PORT(state), command); + msg_info("NON-SMTP COMMAND from [%s]:%s %.100s %.100s", + PSC_CLIENT_ADDR_PORT(state), command, cmd_buffer_ptr); PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL); PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS); state->nsmtp_stamp = PSC_TIME_STAMP_DISABLED; /* XXX */