double-free() attempt. Reported by Florian Piekert. File:
dns/dns_rr.c.
- Usability: Postfix does not support #comments after other
- text, but people add them anyway, with unexpected results.
- The postconf command now warns for trailing comments in
- main.cf files. Similar warnings are planned for database
- client configuration files. Files: util/mystrtok.c,
+ Usability: The postconf command now warns for trailing
+ comments in Postfix parameter values. Also refactored comment
+ warnings in match lists. Files: util/mystrtok.c,
util/mystrtok.ref, util/match_list.c, global/namadr_list.ref,
postconf/postconf_dbms.c, postconf/test71.ref.
- TODO: #comment after text in DB client configuration files.
+ Cleanup: some postconf warnings did not include the full
+ main.cf or master.cf pathname, complicating the analysis
+ of multi-instance configurations. Also refactored ad-hoc
+ code that computed full main.cf or master.cf pathnames.
+ Files: postconf/postconf.h, postconf/postconf_dbms.c,
+ postconf/postconf_edit.c, postconf/postconf_main.c,
+ postconf/postconf_master.c, postconf/postconf_misc.c.
+
+ Cleanup: eliminated unused libdns dependencies. Files:
+ postlogd/Makefile.in.
- TOIDO: test for dns_rr_copy() + dns_rr_free().
+ Cleanup: added inet_prefix_top() tests. File:
+ util/inet_prefix_top.c.
Multi-recipient support in sender/recipient_bcc_maps and
always_bcc.
+ Test for dns_rr_copy() + dns_rr_free().
+
+
mail_conf_xxx supprt for non-negative numbers (i.e.
numbers with a lower bound of zero).
util inet_prefix_top hc smtpd smtpd c smtpd smtpd_peer c
File smtp smtp h
manpage File postscreen postscreen c
+ Files postconf postconf h postconf postconf_dbms c
Stankevic
Gallagher
Valgrind
+Florian
+Piekert
+refactored
* Note: struct copy, because dns_rr_create() would not copy all fields.
*/
dst = (DNS_RR *) mymalloc(sizeof(*dst));
- memcpy((void *) dst, (void *) src, sizeof(*dst));
+ *dst = *src;
dst->qname = mystrdup(src->qname);
dst->rname = mystrdup(src->rname);
if (dst->data)
- dst->data = mymemdup(dst->data, dst->data_len);
+ dst->data = mymemdup(src->data, src->data_len);
dst->next = 0;
return (dst);
}
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20230406"
+#define MAIL_RELEASE_DATE "20230409"
#define MAIL_VERSION_NUMBER "3.8"
#ifdef SNAPSHOT
rm -f main.cf master.cf
touch main.cf master.cf
echo "smtpd_client_restrictions = inline:{" >>main.cf
- echo " { aaa0 = #aaa1 } #aaa2" >>main.cf
+ echo " {" >>main.cf
+ echo " aaa0 = #aaa1" >>main.cf
+ echo " } #aaa2" >>main.cf
echo " }" >>main.cf
echo "smtpd_helo_restrictions = pcre:{" >>main.cf
- echo " { /bbb0 #bbb1/ } #bbb2" >>main.cf
+ echo " {" >>main.cf
+ echo " /bbb0 #bbb1/" >>main.cf
+ echo " } #bbb2" >>main.cf
echo " }" >>main.cf
echo "smtpd_sender_restrictions = regexp:{" >>main.cf
- echo " { /ccc0 #ccc1/ } #ccc2" >>main.cf
+ echo " {" >>main.cf
+ echo " /ccc0 #ccc1/" >>main.cf
+ echo " } #ccc2" >>main.cf
echo " }" >>main.cf
touch -t 197101010000 main.cf
$(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test71.tmp 2>&1
* postconf_misc.c.
*/
extern void pcf_set_config_dir(void);
+extern const char *pcf_get_main_path(void);
+extern const char *pcf_get_master_path(void);
/*
* postconf_main.c
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
/*--*/
* database or some other text.
*/
while ((db_type = mystrtokq_cw(&str_value, CHARS_COMMA_SP, CHARS_BRACE,
- local_scope ? MASTER_CONF_FILE : MAIN_CONF_FILE)) != 0) {
+ local_scope ? pcf_get_master_path() : pcf_get_main_path())) != 0) {
if (*db_type == CHARS_BRACE[0]) {
if ((err = extpar(&db_type, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
/* XXX Encapsulate this in pcf_warn() function. */
if (local_scope)
- msg_warn("%s:%s: %s",
- MASTER_CONF_FILE, local_scope->name_space, err);
+ msg_warn("%s:%s: %s", pcf_get_master_path(),
+ local_scope->name_space, err);
else
- msg_warn("%s: %s", MAIN_CONF_FILE, err);
+ msg_warn("%s: %s", pcf_get_main_path(), err);
myfree(err);
}
if (recurse)
if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
/* XXX Encapsulate this in pcf_warn() function. */
if (local_scope)
- msg_warn("%s:%s: %s",
- MASTER_CONF_FILE, local_scope->name_space,
- err);
+ msg_warn("%s:%s: %s", pcf_get_master_path(),
+ local_scope->name_space, err);
else
- msg_warn("%s: %s", MAIN_CONF_FILE, err);
+ msg_warn("%s: %s", pcf_get_main_path(), err);
myfree(err);
}
for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
/*--*/
/* System library. */
void pcf_edit_main(int mode, int argc, char **argv)
{
- char *path;
+ const char *path;
EDIT_FILE *ep;
VSTREAM *src;
VSTREAM *dst;
* don't leave behind thrash with random names.
*/
pcf_set_config_dir();
- path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
+ path = pcf_get_main_path();
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;
/*
* Cleanup.
*/
- myfree(path);
vstring_free(buf);
vstring_free(key);
htable_free(table, myfree);
void pcf_edit_master(int mode, int argc, char **argv)
{
const char *myname = "pcf_edit_master";
- char *path;
+ const char *path;
EDIT_FILE *ep;
VSTREAM *src;
VSTREAM *dst;
* don't leave behind thrash with random names.
*/
pcf_set_config_dir();
- path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
+ path = pcf_get_master_path();
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;
/*
* Cleanup.
*/
- myfree(path);
vstring_free(line_buf);
vstring_free(parse_buf);
vstring_free(full_entry_buf);
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
/*--*/
/* System library. */
void pcf_read_parameters(void)
{
- char *path;
+ const char *path;
/*
* A direct rip-off of mail_conf_read(). XXX Avoid code duplication by
* better code decomposition.
*/
pcf_set_config_dir();
- path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
+ path = pcf_get_main_path();
if (dict_load_file_xt(CONFIG_DICT, path) == 0)
msg_fatal("open %s: %m", path);
- myfree(path);
}
/* pcf_set_parameters - add or override name=value pairs */
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
/*--*/
/* System library. */
void pcf_read_master(int fail_on_open_error)
{
const char *myname = "pcf_read_master";
- char *path;
+ const char *path;
VSTRING *buf;
VSTREAM *fp;
const char *err;
*/
if (var_config_dir == 0)
pcf_set_config_dir();
- path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
+ path = pcf_get_master_path();
/*
* Initialize the in-memory master table.
* Null-terminate the master table and clean up.
*/
pcf_master_table[entry_count].argv = 0;
- myfree(path);
}
/* pcf_print_master_entry - print one master line */
/* #include <postconf.h>
/*
/* void pcf_set_config_dir()
+/*
+/* const char *pcf_get_main_path()
+/*
+/* const char *pcf_get_master_path()
/* DESCRIPTION
/* pcf_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.
+/*
+/* pcf_get_main_path() and pcf_get_master_path() return a
+/* pointer to a cached main.cf or master.cf full pathname,
+/* based on the current var_config_dir setting. The functions
+/* call pcf_set_config_dir() when no full pathname is cached.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* LICENSE
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
/*--*/
/* System library. */
#include <mymalloc.h>
#include <safe.h>
+#include <stringops.h>
/* Global library. */
#include <postconf.h>
+ /*
+ * Pathname cache, based on current var_config_dir.
+ */
+static char *pcf_main_path = 0;
+static char *pcf_master_path = 0;
+
/* pcf_set_config_dir - forcibly override var_config_dir */
void pcf_set_config_dir(void)
} else {
var_config_dir = mystrdup(DEF_CONFIG_DIR);
}
+
+ /*
+ * Populate the full pathname cache.
+ */
+ if (pcf_main_path)
+ myfree(pcf_main_path);
+ pcf_main_path =
+ concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
+ if (pcf_master_path)
+ myfree(pcf_master_path);
+ pcf_master_path =
+ concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
+}
+
+/* pcf_get_main_path - generate and return full main.cf pathname */
+
+const char *pcf_get_main_path(void)
+{
+ if (pcf_main_path == 0)
+ pcf_set_config_dir();
+ return (pcf_main_path);
+}
+
+/* pcf_get_master_path - generate and return full master.cf pathname */
+
+const char *pcf_get_master_path(void)
+{
+ if (pcf_master_path == 0)
+ pcf_set_config_dir();
+ return (pcf_master_path);
}
-./postconf: warning: main.cf: syntax error after '}' in "{ldap:xxx, memcache:yy}x"
-./postconf: warning: main.cf: missing '}' in "{xx"
+./postconf: warning: ./main.cf: syntax error after '}' in "{ldap:xxx, memcache:yy}x"
+./postconf: warning: ./main.cf: missing '}' in "{xx"
config_directory = .
mydestination = foo bar pipemap:{ldap:xxx, memcache:yy}x randmap:{xx
xxx_domain = foo
-./postconf: warning: main.cf: #comment after other text is not allowed: #aaa1 ...
-./postconf: warning: main.cf: #comment after other text is not allowed: #aaa2 ...
-./postconf: warning: main.cf: #comment after other text is not allowed: #ccc2 ...
-./postconf: warning: main.cf: #comment after other text is not allowed: #bbb2 ...
+./postconf: warning: ./main.cf: #comment after other text is not allowed: #aaa1 ...
+./postconf: warning: ./main.cf: #comment after other text is not allowed: #aaa2 ...
+./postconf: warning: ./main.cf: #comment after other text is not allowed: #ccc2 ...
+./postconf: warning: ./main.cf: #comment after other text is not allowed: #bbb2 ...
config_directory = .
smtpd_client_restrictions = inline:{ { aaa0 = #aaa1 } #aaa2 }
smtpd_helo_restrictions = pcre:{ { /bbb0 #bbb1/ } #bbb2 }
TESTPROG=
PROG = postlogd
INC_DIR = ../../include
-LIBS = ../../lib/lib$(LIB_PREFIX)dns$(LIB_SUFFIX) \
- ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \
+LIBS = ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \
vbuf_print split_qnameval vstream msg_logger byte_mask \
known_tcp_ports dict_stream find_inet binhash hash_fnv argv \
- clean_env
+ clean_env inet_prefix_top
PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \
$(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
HTABLE_FIX = NORANDOMIZE=1
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+inet_prefix_top: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test host_port_test dict_tests \
strcasecmp_utf8_test vbuf_print_test miss_endif_cidr_test \
miss_endif_regexp_test split_qnameval_test vstring_test \
vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \
- binhash_test argv_test
+ binhash_test argv_test inet_prefix_top_test
dict_tests: all dict_test \
dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
argv_test: argv
$(SHLIB_ENV) ${VALGRIND} ./argv
+inet_prefix_top_test: inet_prefix_top
+ $(SHLIB_ENV) ${VALGRIND} ./inet_prefix_top
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
vstring_sprintf_append(buf, "/%d", prefix_len);
return (vstring_export(buf));
}
+
+#ifdef TEST
+
+#include <stdlib.h>
+#include <msg_vstream.h>
+
+ /*
+ * TODO: add test cases for fatal and panic errors, intercept msg_fatal()
+ * and msg_panic(), and verify the expected error messages.
+ */
+typedef struct TEST_CASE {
+ int in_af;
+ const char *in_address;
+ int in_prefix_len;
+ const char *exp_prefix;
+} TEST_CASE;
+
+static TEST_CASE test_cases[] = {
+ AF_INET, "255.255.255.255", 32, "255.255.255.255",
+ AF_INET, "255.255.255.255", 28, "255.255.255.240/28",
+ AF_INET, "255.255.255.255", 4, "240.0.0.0/4",
+ AF_INET, "255.255.255.255", 0, "0.0.0.0/0",
+ AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 124, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124",
+ AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 4, "f000::/4",
+ AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, "::/0",
+};
+
+#define TEST_CASE_COUNT (sizeof(test_cases) / sizeof(test_cases[0]))
+
+int main(int argc, char **argv)
+{
+ TEST_CASE *tp;
+ union {
+ struct in_addr in_addr;
+ struct in6_addr in6_addr;
+ } u;
+ char *act_prefix;
+ int pass = 0;
+ int fail = 0;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ for (tp = test_cases; tp < test_cases + TEST_CASE_COUNT; tp++) {
+ msg_info("RUN %s/%d -> %s", tp->in_address, tp->in_prefix_len,
+ tp->exp_prefix);
+ switch (inet_pton(tp->in_af, tp->in_address, &u)) {
+ case -1:
+ msg_warn("inet_pton(af = %d, src = \"%s\", &u) failed: %m",
+ tp->in_af, tp->in_address);
+ fail += 1;
+ msg_info("FAIL %s/%d -> %s", tp->in_address, tp->in_prefix_len,
+ tp->exp_prefix);
+ break;
+ default:
+ msg_warn("inet_pton(af = %d, src = \"%s\", &u) failed",
+ tp->in_af, tp->in_address);
+ fail += 1;
+ msg_info("FAIL %s/%d -> %s", tp->in_address, tp->in_prefix_len,
+ tp->exp_prefix);
+ break;
+ case 1:
+ act_prefix = inet_prefix_top(tp->in_af, &u, tp->in_prefix_len);
+ if (strcmp(act_prefix, tp->exp_prefix) != 0) {
+ msg_warn("got \"%s\", want \"%s\"", act_prefix, tp->exp_prefix);
+ fail += 1;
+ msg_info("FAIL %s/%d -> %s", tp->in_address, tp->in_prefix_len,
+ tp->exp_prefix);
+ } else {
+ pass += 1;
+ msg_info("PASS %s/%d -> %s", tp->in_address, tp->in_prefix_len,
+ tp->exp_prefix);
+ }
+ break;
+ }
+ }
+ msg_info("PASS=%d FAIL=%d", pass, fail);
+ return (fail > 0);
+}
+
+#endif /* TEST */