diff --git a/postfix/HISTORY b/postfix/HISTORY index 0f55b7bd1..1eb3a09c3 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23023,10 +23023,40 @@ Apologies for any names omitted. Security: Berkeley DB 2 and later try to read settings from a file DB_CONFIG in the current directory. This undocumented - feature may introduce undisclosed vulnerabilities resulting in - privilege escalation with Postfix set-gid programs (postdrop, - postqueue) before they chdir to the Postfix queue directory, - and with the postmap and postalias commands depending on whether - the user's current directory is writable by other users. This - fix does not change Postfix behavior for Berkeley DB < 3. - File: util/dict_db.c. + feature may introduce undisclosed vulnerabilities resulting + in privilege escalation with Postfix set-gid programs + (postdrop, postqueue) before they chdir to the Postfix queue + directory, and with the postmap and postalias commands + depending on whether the user's current directory is writable + by other users. This fix does not change Postfix behavior + for Berkeley DB < 3, but reduces file create performance + for Berkeley DB 3 .. 4.6. File: util/dict_db.c. + +20170617 + + Cleanup: the postconf command warns about unknown parameter + names in a database configuration file, specified as an + absolute pathname (for example, ldap:/path/to/file). This + code was mostly written in January 2017, and it still is a + partial implementation. Files: postconf/postconf_dbms.c, + postconf/Makefile.in, postconf/test66.ref. + +20170618 + + Cleanup: added missing "defined(__GLIBC__)" guards for + GLIBC version tests. File: util/sys_defs.h. + +20170620 + + Bugfix (introduced: Postfix 3.2) extension propagation was + broken with "recipient_delimiter = .", because of code that + was too clever by half. Files: global/mail_adr_crunch.c, + global/mail_addr_crunch.ref. + +20170704 + + Typos (introduced: Postfix 2.10): in comments about + IPv4-in-IPv6 addresses, replace :ffff::1.2.3.4 with the + correct form :ffff::1.2.3.4. Incorrect or misleading comments + are worse than no comments. Files: smtpd/smtpd_haproxy.c, + postscreen/postscreen_haproxy.c. diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 397e7833c..06e4907cd 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -6,6 +6,20 @@ Wish list: Disable -DSNAPSHOT and -DNONPROD in makedefs. + Add postwhite as a postscreen-related project. + https://github.com/stevejenkins/postwhite/blob/master/README.md + + Decide whether to deprecate database configuration pathnames + that start with ".", for example, ldap:./file/name. These forms + are documented for ldap:, memcache:, mysql:, pgsql:, and sqlite: + maps. Postfix daemon processes will look up files relative to the + queue directory, but with postmap command-line processes it would + be more natural to interpret relative pathnames relative to the + current directory of the calling process (it would be a surprise + if "postmap hash:./foo" would access "/var/spool/postfix/foo", + or if "postmap hash:foo" and or "postmap hash:./foo" would access + different files). + Convert postalias(1) to store external-form keys, and convert aliases(5) to perform external-first lookup with fallback to internal form, to make it consistent with the rest of Postfix. diff --git a/postfix/src/global/mail_addr_crunch.c b/postfix/src/global/mail_addr_crunch.c index 7ca7c0c9c..006d322b4 100644 --- a/postfix/src/global/mail_addr_crunch.c +++ b/postfix/src/global/mail_addr_crunch.c @@ -120,7 +120,7 @@ ARGV *mail_addr_crunch_opt(const char *string, const char *extension, tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL); canon_addr_external(canon_addr, STR(extern_addr)); unquote_822_local(intern_addr, STR(canon_addr)); - if (extension && strchr(STR(intern_addr), *extension) == 0) { + if (extension) { VSTRING_SPACE(intern_addr, extlen + 1); if ((ratsign = strrchr(STR(intern_addr), '@')) == 0) { vstring_strcat(intern_addr, extension); diff --git a/postfix/src/global/mail_addr_crunch.ref b/postfix/src/global/mail_addr_crunch.ref index ec95edfe6..fe5fb2e27 100644 --- a/postfix/src/global/mail_addr_crunch.ref +++ b/postfix/src/global/mail_addr_crunch.ref @@ -1,7 +1,7 @@ ==== external to internal, with extension |foo+extension@example.com| |foo bar+extension@example.com| -|foo+ext@example.com| +|foo+ext+extension@example.com| ==== external to internal, without extension |foo@example.com| |foo bar@example.com| @@ -9,14 +9,14 @@ ==== external to external, with extension |foo+extension@example.com| |"foo bar+extension"@example.com| -|foo+ext@example.com| +|foo+ext+extension@example.com| ==== external to external, without extension |foo@example.com| |"foo bar"@example.com| |foo+ext@example.com| ==== internal to internal, with extension |foo+extension@example.com| -|foo+ext@example.com| +|foo+ext+extension@example.com| ==== internal to internal, without extension |foo@example.com| |foo+ext@example.com| diff --git a/postfix/src/global/mail_addr_map.c b/postfix/src/global/mail_addr_map.c index de2ab09de..5e0959072 100644 --- a/postfix/src/global/mail_addr_map.c +++ b/postfix/src/global/mail_addr_map.c @@ -256,6 +256,7 @@ typedef struct { #define DO_PROPAGATE_UNMATCHED_EXTENSION 1 #define NO_RECIPIENT_DELIMITER "" #define PLUS_RECIPIENT_DELIMITER "+" +#define DOT_RECIPIENT_DELIMITER "." /* * All these tests must pass, so that we know that mail_addr_map_opt() works @@ -352,6 +353,14 @@ static MAIL_ADDR_MAP_TEST pass_tests[] = { "a@a@example.com", {"\"a@a\"@example.net"}, 1, }, + { + "12 external -external-> external, extension, propagation", + "inline:{ aa@example.com=bb@example.com }", + DO_PROPAGATE_UNMATCHED_EXTENSION, DOT_RECIPIENT_DELIMITER, + MA_FORM_EXTERNAL, MA_FORM_EXTERNAL, MA_FORM_EXTERNAL, + "aa.ext@example.com", + {"bb.ext@example.com"}, 1, + }, 0, }; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index bd7b1b29b..beb0abbd6 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 "20170612" +#define MAIL_RELEASE_DATE "20170716" #define MAIL_VERSION_NUMBER "3.3" #ifdef SNAPSHOT diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in index 05c6a3342..4a7d7ead1 100644 --- a/postfix/src/postconf/Makefile.in +++ b/postfix/src/postconf/Makefile.in @@ -52,7 +52,7 @@ tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \ test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \ test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \ test52 test53 test54 test55 test56 test57 test58 test59 test60 test61 \ - test62 test63 test64 test65 + test62 test63 test64 test65 test66 root_tests: @@ -870,6 +870,22 @@ test65: $(PROG) test65.ref diff test65.ref test65.tmp rm -f main.cf master.cf test65.tmp +# unknown parameters in database configuration file (absolute pathname). + +test66: $(PROG) test66.ref + rm -f main.cf master.cf + touch master.cf + echo alias_maps = ldap:`pwd`/test66.cf >> main.cf + echo " " mysql:`pwd`/test66.cf >> main.cf + echo " " pgsql:`pwd`/test66.cf >> main.cf + echo " " sqlite:`pwd`/test66.cf >> main.cf + echo " " memcache:`pwd`/test66.cf >> main.cf + echo junk = junk >> test66.cf + touch -t 197101010000 main.cf + $(SHLIB_ENV) ./$(PROG) -c. 2>test66.tmp >/dev/null + sed "s;PWD;`pwd`;" test66.ref | diff - test66.tmp + rm -f main.cf master.cf test66.tmp test66.cf + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -971,6 +987,7 @@ postconf_builtin.o: time_vars.h postconf_dbms.o: ../../include/argv.h postconf_dbms.o: ../../include/check_arg.h postconf_dbms.o: ../../include/dict.h +postconf_dbms.o: ../../include/dict_ht.h postconf_dbms.o: ../../include/dict_ldap.h postconf_dbms.o: ../../include/dict_memcache.h postconf_dbms.o: ../../include/dict_mysql.h diff --git a/postfix/src/postconf/postconf_dbms.c b/postfix/src/postconf/postconf_dbms.c index 5e3aca2e3..33542073a 100644 --- a/postfix/src/postconf/postconf_dbms.c +++ b/postfix/src/postconf/postconf_dbms.c @@ -22,7 +22,9 @@ /* When a database type is found that supports legacy-style /* configuration, the table name is combined with each of the /* database-defined suffixes to generate candidate parameter -/* names for that database type. +/* names for that database type; if the table name specifies +/* a client configuration file, that file is scanned for unused +/* parameter settings. /* .IP flag_parameter /* A function that takes as arguments a candidate parameter /* name, parameter flags, and a PCF_MASTER_ENT pointer. The @@ -46,6 +48,7 @@ /* System library. */ #include +#include #include /* Utility library. */ @@ -61,6 +64,7 @@ #include #include +#include #include #include #include @@ -145,6 +149,64 @@ static const PCF_DBMS_INFO pcf_dbms_info[] = { 0, }; +/* pcf_check_dbms_client - look for unused names in client configuration */ + +static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file) +{ + DICT *dict; + VSTREAM *fp; + const char **cpp; + const char *name; + const char *value; + char *dict_spec; + int dir; + + /* + * We read each database client configuration file into its own + * dictionary, and nag only the first time that a file is visited. + */ + dict_spec = concatenate(dp->db_type, ":", cf_file, (char *) 0); + if ((dict = dict_handle(dict_spec)) == 0) { + + /* + * Populate the dictionary with settings in this database client + * configuration file. Don't die if a file can't be opened - some + * files may contain passwords and should not be world-readable. + * Note: dict_load_fp() nags about duplicate pameter settings. + */ + dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0); + dict_register(dict_spec, dict); + if ((fp = vstream_fopen(cf_file, O_RDONLY, 0)) == 0 + && errno != EACCES) { + msg_warn("open \"%s\" configuration \"%s\": %m", + dp->db_type, cf_file); + myfree(dict_spec); + return; + } + dict_load_fp(dict_spec, fp); + if (vstream_fclose(fp)) { + msg_warn("read \"%s\" configuration \"%s\": %m", + dp->db_type, cf_file); + myfree(dict_spec); + return; + } + + /* + * Remove all known database client parameters from this dictionary, + * then report the remaining ones as "unused". We use ad-hoc logging + * code, because a database client parameter namespace is unlike the + * parameter namespaces in main.cf or master.cf. + */ + for (cpp = dp->db_suffixes; *cpp; cpp++) + (void) dict_del(dict, *cpp); + for (dir = DICT_SEQ_FUN_FIRST; + dict->sequence(dict, dir, &name, &value) == DICT_STAT_SUCCESS; + dir = DICT_SEQ_FUN_NEXT) + msg_warn("%s: unused parameter: %s=%s", dict_spec, name, value); + } + myfree(dict_spec); +} + /* pcf_register_dbms_helper - parse one possible database type:name */ static void pcf_register_dbms_helper(char *str_value, @@ -172,6 +234,28 @@ static void pcf_register_dbms_helper(char *str_value, && strcmp(db_type, DICT_TYPE_PROXY) == 0) db_type = prefix; + if (prefix == 0) + continue; + + /* + * Look for database:prefix where the prefix is an absolute pathname. + * Then, report unknown database client configuration parameters. + * + * XXX What about a pathname beginning with '.'? This supposedly is + * relative to the queue directory, which is the default directory + * for all Postfix daemon processes. This would also have to handle + * the case that the queue is not yet created. + */ + if (*prefix == '/') { + for (dp = pcf_dbms_info; dp->db_type != 0; dp++) { + if (strcmp(db_type, dp->db_type) == 0) { + pcf_check_dbms_client(dp, prefix); + break; + } + } + continue; + } + /* * Look for database:prefix where the prefix is not a pathname and * the database is a known type. Synthesize candidate parameter names @@ -179,7 +263,7 @@ static void pcf_register_dbms_helper(char *str_value, * list, and see if those parameters have a "name=value" entry in the * local or global namespace. */ - if (prefix != 0 && *prefix != '/' && *prefix != '.') { + if (*prefix != '.') { if (*prefix == CHARS_BRACE[0]) { if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) { /* XXX Encapsulate this in pcf_warn() function. */ diff --git a/postfix/src/postconf/test66.ref b/postfix/src/postconf/test66.ref new file mode 100644 index 000000000..bd35822e8 --- /dev/null +++ b/postfix/src/postconf/test66.ref @@ -0,0 +1,5 @@ +./postconf: warning: ldap:PWD/test66.cf: unused parameter: junk=junk +./postconf: warning: mysql:PWD/test66.cf: unused parameter: junk=junk +./postconf: warning: pgsql:PWD/test66.cf: unused parameter: junk=junk +./postconf: warning: sqlite:PWD/test66.cf: unused parameter: junk=junk +./postconf: warning: memcache:PWD/test66.cf: unused parameter: junk=junk diff --git a/postfix/src/postscreen/postscreen_haproxy.c b/postfix/src/postscreen/postscreen_haproxy.c index 664d76c04..b91cf1953 100644 --- a/postfix/src/postscreen/postscreen_haproxy.c +++ b/postfix/src/postscreen/postscreen_haproxy.c @@ -133,7 +133,7 @@ static void psc_endpt_haproxy_event(int event, void *context) /* * Parse the haproxy line. Note: the haproxy_srvr_parse() routine * performs address protocol checks, address and port syntax checks, and - * converts IPv4-in-IPv6 address string syntax (:ffff::1.2.3.4) to IPv4 + * converts IPv4-in-IPv6 address string syntax (::ffff:1.2.3.4) to IPv4 * syntax where permitted by the main.cf:inet_protocols setting. */ if (status == 0 && last_char == '\n') { diff --git a/postfix/src/smtpd/smtpd_haproxy.c b/postfix/src/smtpd/smtpd_haproxy.c index 300bce44a..3bcbffc6a 100644 --- a/postfix/src/smtpd/smtpd_haproxy.c +++ b/postfix/src/smtpd/smtpd_haproxy.c @@ -111,7 +111,7 @@ int smtpd_peer_from_haproxy(SMTPD_STATE *state) /* * Note: the haproxy_srvr_parse() routine performs address protocol * checks, address and port syntax checks, and converts IPv4-in-IPv6 - * address string syntax (:ffff::1.2.3.4) to IPv4 syntax where permitted + * address string syntax (::ffff:1.2.3.4) to IPv4 syntax where permitted * by the main.cf:inet_protocols setting, but logs no warnings. */ #define ENABLE_DEADLINE 1 diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index 3f570c46a..f4f53300f 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -782,7 +782,8 @@ extern int initgroups(const char *, int); #define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min) #else #define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \ - ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)) + (defined(__GLIBC__) && \ + ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))) #endif #if HAVE_GLIBC_API_VERSION_SUPPORT(2, 1) #define SOCKADDR_SIZE socklen_t @@ -805,7 +806,7 @@ extern int initgroups(const char *, int); #define KERNEL_VERSION(a,b,c) (LINUX_VERSION_CODE + 1) #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)) \ - || (__GLIBC__ < 2) + || (defined(__GLIBC__) && __GLIBC__ < 2) #define CANT_USE_SEND_RECV_MSG #define DEF_SMTP_CACHE_DEMAND 0 #else