diff --git a/postfix/HISTORY b/postfix/HISTORY index baaf4922a..d535f378f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -27078,3 +27078,29 @@ Apologies for any names omitted. Cleanup: in the PostgreSQL client, cosmetic changes to make the code easier to maintain (in preparation for adding new functionality). File: global/dict_pgsql.c. + +20230428 + + Bugfix (defect introduced: Postfix 1.0): the command 'postconf + .. name=v1 .. name=v2 ..' (multiple instances of the same + parameter name) created multiple name=value entries with + the same parameter name. It now logs a warning and skips + the earlier update. Found during code maintenance. File: + postconf/postconf_edit.c + + Bugfix (defect introduced: Postfix 3.3): the command 'postconf + -M name1/type1='name2 type2 ..." died with a segmentation + violation when the request matched multiple master.cf + entries. The master.cf file was not damaged. Problem reported + by SATOH Fumiyasu. File: postconf/postconf_master.c. + +20230502 + + Bugfix (defect introduced: Postfix 2.11): the command + 'postconf -M name1/type1="name2 type2 ...'" could add a + service definition to master.cf that conflicted with an + already existing service definition. It now replaces all + existing service definitions that match the service pattern + 'name1/type1' or the service name and type in 'name2 type2 + ...' with a single service definition 'name2 type2 ...'. + Problem reported by SATOH Fumiyasu. File: postconf/postconf_edit.c. diff --git a/postfix/proto/stop.spell-history b/postfix/proto/stop.spell-history index 096da091a..ccaef1f1f 100644 --- a/postfix/proto/stop.spell-history +++ b/postfix/proto/stop.spell-history @@ -56,3 +56,5 @@ Valgrind Florian Piekert refactored +Fumiyasu +SATOH diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 775fa2a8c..202583f12 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 "20230419" +#define MAIL_RELEASE_DATE "20230502" #define MAIL_VERSION_NUMBER "3.9" #ifdef SNAPSHOT diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in index 6aff794aa..f872b8aae 100644 --- a/postfix/src/postconf/Makefile.in +++ b/postfix/src/postconf/Makefile.in @@ -55,7 +55,8 @@ 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 test66 test67 test68 test69 test70 test71 + test62 test63 test64 test65 test66 test67 test68 test69 test70 test71 \ + test72 test73 test74 test75 root_tests: @@ -989,6 +990,54 @@ test71: $(PROG) test71.ref diff test71.ref test71.tmp rm -f main.cf master.cf test71.tmp +# Different requests to add lines to master.cf. +test72: $(PROG) test72.ref + rm -f main.cf master.cf + touch main.cf master.cf + ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other' + touch -t 197201010000 main.cf + $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test72.tmp 2>&1 + diff test72.ref test72.tmp + rm -f main.cf master.cf test72.tmp + +# Replace one entry based on the name+type in the request's service entry. +test73: $(PROG) test73.ref + rm -f main.cf master.cf + touch main.cf master.cf + ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp unix - n n - 0 otherx' + touch -t 197301010000 main.cf + $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test73.tmp 2>&1 + diff test73.ref test73.tmp + rm -f main.cf master.cf test73.tmp + +# Replace one entry based on the name+type in the request's service pattern. +test74: $(PROG) test74.ref + rm -f main.cf master.cf + touch main.cf master.cf + ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other' + ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other' + ./postconf -Mc. smtp/fifo='lmtp unix - n n - 0 otherx' + touch -t 197401010000 main.cf + $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test74.tmp 2>&1 + diff test74.ref test74.tmp + rm -f main.cf master.cf test74.tmp + +# Warn about skipping redundant name=value update. +test75: $(PROG) test75.ref + rm -f main.cf master.cf + touch main.cf master.cf + ./postconf -c. mail_version=x mail_version=y >test75.tmp 2>&1 + touch -t 197501010000 main.cf + $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc. >>test75.tmp 2>&1 + diff test75.ref test75.tmp + rm -f main.cf master.cf test75.tmp + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -1184,6 +1233,7 @@ postconf_main.o: postconf_main.c postconf_master.o: ../../include/argv.h postconf_master.o: ../../include/check_arg.h postconf_master.o: ../../include/dict.h +postconf_master.o: ../../include/dict_ht.h postconf_master.o: ../../include/htable.h postconf_master.o: ../../include/mail_params.h postconf_master.o: ../../include/master_proto.h diff --git a/postfix/src/postconf/postconf_edit.c b/postfix/src/postconf/postconf_edit.c index eb57cc8b5..7085acd72 100644 --- a/postfix/src/postconf/postconf_edit.c +++ b/postfix/src/postconf/postconf_edit.c @@ -192,6 +192,11 @@ void pcf_edit_main(int mode, int argc, char **argv) } else { msg_panic("pcf_edit_main: unknown mode %d", mode); } + if ((cvalue = htable_find(table, pattern)) != 0) { + msg_warn("ignoring earlier request: '%s = %s'", + pattern, cvalue->value); + htable_delete(table, pattern, myfree); + } cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); cvalue->value = edit_value; cvalue->found = 0; @@ -456,8 +461,38 @@ void pcf_edit_master(int mode, int argc, char **argv) /* * Match each service pattern. + * + * Additional care is needed when a request adds or replaces an + * entire service definition, instead of a specific field or + * parameter. Given a command "postconf -M name1/type1='name2 + * type2 ...'", where name1 and name2 may differ, and likewise + * for type1 and type2: + * + * - First, if an existing service definition a) matches the service + * pattern 'name1/type1', or b) matches the name and type in the + * new service definition 'name2 type2 ...', remove the service + * definition. + * + * - Then, after an a) or b) type match, add a new service + * definition for 'name2 type2 ...', but only after the first + * match. + * + * - Finally, if a request had no a) or b) type match for any + * master.cf service definition, add a new service definition for + * 'name2 type2 ...'. */ for (req = edit_reqs; req < edit_reqs + num_reqs; req++) { + PCF_MASTER_ENT *tentative_entry = 0; + int use_tentative_entry = 0; + + /* Additional care for whole service definition requests. */ + if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) { + tentative_entry = (PCF_MASTER_ENT *) + mymalloc(sizeof(*tentative_entry)); + if ((err = pcf_parse_master_entry(tentative_entry, + req->edit_value)) != 0) + msg_fatal("%s: \"%s\"", err, req->raw_text); + } if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern, service_name, service_type)) { @@ -503,18 +538,30 @@ void pcf_edit_master(int mode, int argc, char **argv) * Replace entire master.cf entry. */ case PCF_MASTER_ENTRY: - if (new_entry != 0) - pcf_free_master_entry(new_entry); - new_entry = (PCF_MASTER_ENT *) - mymalloc(sizeof(*new_entry)); - if ((err = pcf_parse_master_entry(new_entry, - req->edit_value)) != 0) - msg_fatal("%s: \"%s\"", err, req->raw_text); + if (req->match_count == 1) + use_tentative_entry = 1; break; default: msg_panic("%s: unknown edit mode %d", myname, mode); } } + } else if (tentative_entry != 0 + && PCF_MATCH_SERVICE_PATTERN(tentative_entry->argv, + service_name, + service_type)) { + service_name_type_matched = 1; /* Sticky flag */ + req->match_count += 1; + if (req->match_count == 1) + use_tentative_entry = 1; + } + if (tentative_entry != 0) { + if (use_tentative_entry) { + if (new_entry != 0) + pcf_free_master_entry(new_entry); + new_entry = tentative_entry; + } else { + pcf_free_master_entry(tentative_entry); + } } } diff --git a/postfix/src/postconf/postconf_master.c b/postfix/src/postconf/postconf_master.c index 3606ac70c..bddb1af25 100644 --- a/postfix/src/postconf/postconf_master.c +++ b/postfix/src/postconf/postconf_master.c @@ -156,6 +156,7 @@ #include #include #include +#include /* Global library. */ @@ -395,12 +396,12 @@ const char *pcf_parse_master_entry(PCF_MASTER_ENT *masterp, const char *buf) concatenate("ro", PCF_NAMESP_SEP_STR, masterp->name_space, (char *) 0); masterp->argv = argv; masterp->valid_names = 0; + masterp->ro_params = dict_ht_open(ro_name_space, O_CREAT | O_RDWR, 0); process_name = basename(argv->argv[PCF_MASTER_FLD_CMD]); - dict_update(ro_name_space, VAR_PROCNAME, process_name); - dict_update(ro_name_space, VAR_SERVNAME, - strcmp(process_name, argv->argv[0]) != 0 ? - argv->argv[0] : process_name); - masterp->ro_params = dict_handle(ro_name_space); + dict_put(masterp->ro_params, VAR_PROCNAME, process_name); + dict_put(masterp->ro_params, VAR_SERVNAME, + strcmp(process_name, argv->argv[0]) != 0 ? + argv->argv[0] : process_name); myfree(ro_name_space); masterp->all_params = 0; return (0); diff --git a/postfix/src/postconf/test72.ref b/postfix/src/postconf/test72.ref new file mode 100644 index 000000000..6b13cdcbd --- /dev/null +++ b/postfix/src/postconf/test72.ref @@ -0,0 +1,3 @@ +smtp unix - n n - 0 other +smtp fifo - n n - 0 other +smtp inet - n n - 0 other diff --git a/postfix/src/postconf/test73.ref b/postfix/src/postconf/test73.ref new file mode 100644 index 000000000..9554cc074 --- /dev/null +++ b/postfix/src/postconf/test73.ref @@ -0,0 +1,3 @@ +smtp unix - n n - 0 otherx +smtp fifo - n n - 0 other +smtp inet - n n - 0 other diff --git a/postfix/src/postconf/test74.ref b/postfix/src/postconf/test74.ref new file mode 100644 index 000000000..288633496 --- /dev/null +++ b/postfix/src/postconf/test74.ref @@ -0,0 +1,3 @@ +smtp unix - n n - 0 other +lmtp unix - n n - 0 otherx +smtp inet - n n - 0 other diff --git a/postfix/src/postconf/test75.ref b/postfix/src/postconf/test75.ref new file mode 100644 index 000000000..b8c54abe0 --- /dev/null +++ b/postfix/src/postconf/test75.ref @@ -0,0 +1,3 @@ +./postconf: warning: ignoring earlier request: 'mail_version = x' +config_directory = . +mail_version = y