From 22ed4a6d9aa67998eaa917ab6e9fd19b35bd4fd0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 2 Jun 2020 16:44:34 +0200 Subject: [PATCH 1/3] fs-util: add stat_warn_permissions() that operates on struct stat instead of fd --- src/basic/fs-util.c | 38 ++++++++++++++++++++++++-------------- src/basic/fs-util.h | 1 + 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 7bbcb6051e..943bc56319 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -353,26 +353,36 @@ int fchmod_opath(int fd, mode_t m) { return 0; } +int stat_warn_permissions(const char *path, const struct stat *st) { + assert(path); + assert(st); + + /* Don't complain if we are reading something that is not a file, for example /dev/null */ + if (!S_ISREG(st->st_mode)) + return 0; + + if (st->st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st->st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid_cached() == 1 && (st->st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + int fd_warn_permissions(const char *path, int fd) { struct stat st; + assert(path); + assert(fd >= 0); + if (fstat(fd, &st) < 0) return -errno; - /* Don't complain if we are reading something that is not a file, for example /dev/null */ - if (!S_ISREG(st.st_mode)) - return 0; - - if (st.st_mode & 0111) - log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); - - if (st.st_mode & 0002) - log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); - - if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044) - log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); - - return 0; + return stat_warn_permissions(path, &st); } int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index dd101c61cc..b184570f9f 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -40,6 +40,7 @@ int fchmod_umask(int fd, mode_t mode); int fchmod_opath(int fd, mode_t m); int fd_warn_permissions(const char *path, int fd); +int stat_warn_permissions(const char *path, const struct stat *st); #define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) From 5aca2e6733d35534f82359e5720b3dea1d1332e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 2 Jun 2020 16:49:50 +0200 Subject: [PATCH 2/3] conf-parse: fix pretty bad typo --- src/shared/conf-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index b04eb3912c..2eda6ae03a 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -331,7 +331,7 @@ int config_parse(const char *unit, return r; } if (r < 0) { - if (CONFIG_PARSE_WARN) + if (FLAGS_SET(flags, CONFIG_PARSE_WARN)) log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); return r; From 4f9ff96a55187927a4164a19df580329f4c6522b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 2 Jun 2020 14:55:12 +0200 Subject: [PATCH 3/3] conf-parser: return mtime in config_parse() and friends This is a follow-up for 9f83091e3cceb646a66fa9df89de6d9a77c21d86. Instead of reading the mtime off the configuration files after reading, let's do so before reading, but with the fd we read the data from. This is not only cleaner (as it allows us to save one stat()), but also has the benefit that we'll detect changes that happen while we read the files. This also reworks unit file drop-ins to use the common code for determining drop-in mtime, instead of reading system clock for that. --- src/core/load-dropin.c | 13 +- src/core/load-fragment.c | 4 +- src/core/main.c | 8 +- src/coredump/coredump.c | 13 +- src/fuzz/fuzz-unit-file.c | 11 +- src/home/homed-conf.c | 13 +- src/journal-remote/journal-remote-main.c | 12 +- src/journal-remote/journal-upload.c | 15 ++- src/journal/journald-server.c | 23 ++-- src/login/logind-core.c | 12 +- src/network/netdev/netdev.c | 21 ++-- src/network/networkd-conf.c | 14 ++- src/network/networkd-network.c | 118 ++++++++---------- src/nspawn/nspawn-settings.c | 2 +- src/partition/repart.c | 7 +- src/pstore/pstore.c | 13 +- src/resolve/resolved-conf.c | 13 +- src/resolve/resolved-dnssd.c | 11 +- src/shared/conf-parser.c | 52 +++++--- src/shared/conf-parser.h | 11 +- src/shared/install.c | 3 +- src/shared/sleep-config.c | 12 +- src/test/test-conf-parser.c | 10 +- src/timesync/timesyncd-conf.c | 13 +- .../tty-ask-password-agent.c | 4 +- src/udev/net/link-config.c | 3 +- .../xdg-autostart-service.c | 3 +- 27 files changed, 253 insertions(+), 181 deletions(-) diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index f61e9da6f2..0da3eafb12 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -114,12 +114,13 @@ int unit_load_dropin(Unit *u) { } STRV_FOREACH(f, u->dropin_paths) - (void) config_parse(u->id, *f, NULL, - UNIT_VTABLE(u)->sections, - config_item_perf_lookup, load_fragment_gperf_lookup, - 0, u); - - u->dropin_mtime = now(CLOCK_REALTIME); + (void) config_parse( + u->id, *f, NULL, + UNIT_VTABLE(u)->sections, + config_item_perf_lookup, load_fragment_gperf_lookup, + 0, + u, + &u->dropin_mtime); return 0; } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a967627946..780692ce0e 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -4864,7 +4864,9 @@ int unit_load_fragment(Unit *u) { r = config_parse(u->id, fragment, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, load_fragment_gperf_lookup, - CONFIG_PARSE_ALLOW_INCLUDE, u); + CONFIG_PARSE_ALLOW_INCLUDE, + u, + NULL); if (r == -ENOEXEC) log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started."); if (r < 0) diff --git a/src/core/main.c b/src/core/main.c index 32b963d4a4..e1de821e66 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -657,7 +657,13 @@ static int parse_config_file(void) { CONF_PATHS_NULSTR("systemd/system.conf.d") : CONF_PATHS_NULSTR("systemd/user.conf.d"); - (void) config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL); + (void) config_parse_many_nulstr( + fn, conf_dirs_nulstr, + "Manager\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY * like everywhere else. */ diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 42231dbd6b..d156d98efc 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -155,11 +155,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf", - CONF_PATHS_NULSTR("systemd/coredump.conf.d"), - "Coredump\0", - config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/coredump.conf", + CONF_PATHS_NULSTR("systemd/coredump.conf.d"), + "Coredump\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static uint64_t storage_size_max(void) { diff --git a/src/fuzz/fuzz-unit-file.c b/src/fuzz/fuzz-unit-file.c index d3993cf123..34f59a4437 100644 --- a/src/fuzz/fuzz-unit-file.c +++ b/src/fuzz/fuzz-unit-file.c @@ -70,10 +70,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { name = strjoina("a.", unit_type_to_string(t)); assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0); - (void) config_parse(name, name, f, - UNIT_VTABLE(u)->sections, - config_item_perf_lookup, load_fragment_gperf_lookup, - CONFIG_PARSE_ALLOW_INCLUDE, u); + (void) config_parse( + name, name, f, + UNIT_VTABLE(u)->sections, + config_item_perf_lookup, load_fragment_gperf_lookup, + CONFIG_PARSE_ALLOW_INCLUDE, + u, + NULL); g = open_memstream_unlocked(&out, &out_size); assert_se(g); diff --git a/src/home/homed-conf.c b/src/home/homed-conf.c index 14ec8b336d..df3a17358b 100644 --- a/src/home/homed-conf.c +++ b/src/home/homed-conf.c @@ -10,11 +10,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf", - CONF_PATHS_NULSTR("systemd/homed.conf.d"), - "Home\0", - config_item_perf_lookup, homed_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/homed.conf", + CONF_PATHS_NULSTR("systemd/homed.conf.d"), + "Home\0", + config_item_perf_lookup, homed_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index 551b84130d..948b2d2fce 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -762,10 +762,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf", - CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), - "Remote\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journal-remote.conf", + CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), + "Remote\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static int help(void) { diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index bf656ac670..bd58fdbcdf 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -562,12 +562,17 @@ static int parse_config(void) { { "Upload", "ServerKeyFile", config_parse_path_or_ignore, 0, &arg_key }, { "Upload", "ServerCertificateFile", config_parse_path_or_ignore, 0, &arg_cert }, { "Upload", "TrustedCertificateFile", config_parse_path_or_ignore, 0, &arg_trust }, - {}}; + {} + }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf", - CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), - "Upload\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journal-upload.conf", + CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), + "Upload\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static int help(void) { diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 9efa65a294..5865bf9809 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1633,23 +1633,24 @@ static int server_parse_config_file(Server *s) { /* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */ namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf"); - r = config_parse( - NULL, - namespaced, NULL, - "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s); + r = config_parse(NULL, + namespaced, NULL, + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, s, + NULL); if (r < 0) return r; return 0; } - return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf", - CONF_PATHS_NULSTR("systemd/journald.conf.d"), - "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journald.conf", + CONF_PATHS_NULSTR("systemd/journald.conf.d"), + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, s, NULL); } static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) { diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 1375f438e4..4289461df6 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -69,11 +69,13 @@ void manager_reset_config(Manager *m) { int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf", - CONF_PATHS_NULSTR("systemd/logind.conf.d"), - "Login\0", - config_item_perf_lookup, logind_gperf_lookup, - CONFIG_PARSE_WARN, m); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/logind.conf", + CONF_PATHS_NULSTR("systemd/logind.conf.d"), + "Login\0", + config_item_perf_lookup, logind_gperf_lookup, + CONFIG_PARSE_WARN, m, + NULL); } int manager_add_device(Manager *m, const char *sysfs, bool master, Device **ret_device) { diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index a990c64b55..1889f6f13c 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -686,10 +686,13 @@ int netdev_load_one(Manager *manager, const char *filename) { }; dropin_dirname = strjoina(basename(filename), ".d"); - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, - config_item_perf_lookup, network_netdev_gperf_lookup, - CONFIG_PARSE_WARN, netdev_raw, NULL); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, + config_item_perf_lookup, network_netdev_gperf_lookup, + CONFIG_PARSE_WARN, + netdev_raw, + NULL); if (r < 0) return r; @@ -726,10 +729,12 @@ int netdev_load_one(Manager *manager, const char *filename) { if (NETDEV_VTABLE(netdev)->init) NETDEV_VTABLE(netdev)->init(netdev); - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - NETDEV_VTABLE(netdev)->sections, - config_item_perf_lookup, network_netdev_gperf_lookup, - CONFIG_PARSE_WARN, netdev, NULL); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + NETDEV_VTABLE(netdev)->sections, + config_item_perf_lookup, network_netdev_gperf_lookup, + CONFIG_PARSE_WARN, + netdev, NULL); if (r < 0) return r; diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 350fea634c..30625117e4 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -23,11 +23,15 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/networkd.conf", - CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "Network\0DHCP\0", - config_item_perf_lookup, networkd_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "Network\0" + "DHCP\0", + config_item_perf_lookup, networkd_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index b928f7585c..50e50fd945 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -335,7 +335,6 @@ int network_verify(Network *network) { int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) { _cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_(network_unrefp) Network *network = NULL; - _cleanup_strv_free_ char **dropins = NULL; _cleanup_fclose_ FILE *file = NULL; const char *dropin_dirname; char *d; @@ -477,54 +476,57 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ip_service_type = -1, }; - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - "Match\0" - "Link\0" - "Network\0" - "Address\0" - "Neighbor\0" - "IPv6AddressLabel\0" - "RoutingPolicyRule\0" - "Route\0" - "NextHop\0" - "DHCP\0" /* compat */ - "DHCPv4\0" - "DHCPv6\0" - "DHCPServer\0" - "IPv6AcceptRA\0" - "IPv6NDPProxyAddress\0" - "Bridge\0" - "BridgeFDB\0" - "BridgeVLAN\0" - "IPv6PrefixDelegation\0" - "IPv6Prefix\0" - "IPv6RoutePrefix\0" - "LLDP\0" - "TrafficControlQueueingDiscipline\0" - "CAN\0" - "QDisc\0" - "BFIFO\0" - "CAKE\0" - "ControlledDelay\0" - "DeficitRoundRobinScheduler\0" - "DeficitRoundRobinSchedulerClass\0" - "PFIFO\0" - "PFIFOFast\0" - "PFIFOHeadDrop\0" - "FairQueueing\0" - "FairQueueingControlledDelay\0" - "GenericRandomEarlyDetection\0" - "HeavyHitterFilter\0" - "HierarchyTokenBucket\0" - "HierarchyTokenBucketClass\0" - "NetworkEmulator\0" - "PIE\0" - "StochasticFairBlue\0" - "StochasticFairnessQueueing\0" - "TokenBucketFilter\0" - "TrivialLinkEqualizer\0", - config_item_perf_lookup, network_network_gperf_lookup, - CONFIG_PARSE_WARN, network, &dropins); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + "Match\0" + "Link\0" + "Network\0" + "Address\0" + "Neighbor\0" + "IPv6AddressLabel\0" + "RoutingPolicyRule\0" + "Route\0" + "NextHop\0" + "DHCP\0" /* compat */ + "DHCPv4\0" + "DHCPv6\0" + "DHCPServer\0" + "IPv6AcceptRA\0" + "IPv6NDPProxyAddress\0" + "Bridge\0" + "BridgeFDB\0" + "BridgeVLAN\0" + "IPv6PrefixDelegation\0" + "IPv6Prefix\0" + "IPv6RoutePrefix\0" + "LLDP\0" + "TrafficControlQueueingDiscipline\0" + "CAN\0" + "QDisc\0" + "BFIFO\0" + "CAKE\0" + "ControlledDelay\0" + "DeficitRoundRobinScheduler\0" + "DeficitRoundRobinSchedulerClass\0" + "PFIFO\0" + "PFIFOFast\0" + "PFIFOHeadDrop\0" + "FairQueueing\0" + "FairQueueingControlledDelay\0" + "GenericRandomEarlyDetection\0" + "HeavyHitterFilter\0" + "HierarchyTokenBucket\0" + "HierarchyTokenBucketClass\0" + "NetworkEmulator\0" + "PIE\0" + "StochasticFairBlue\0" + "StochasticFairnessQueueing\0" + "TokenBucketFilter\0" + "TrivialLinkEqualizer\0", + config_item_perf_lookup, network_network_gperf_lookup, + CONFIG_PARSE_WARN, + network, + &network->timestamp); if (r < 0) return r; @@ -539,24 +541,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m", network->filename); - struct stat stats; - if (stat(filename, &stats) >= 0) - network->timestamp = timespec_load(&stats.st_mtim); - - char **f; - STRV_FOREACH(f, dropins) { - usec_t t; - - if (stat(*f, &stats) < 0) { - network->timestamp = 0; - break; - } - - t = timespec_load(&stats.st_mtim); - if (t > network->timestamp) - network->timestamp = t; - } - if (network_verify(network) < 0) /* Ignore .network files that do not match the conditions. */ return 0; diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 4e1cb3835c..996c0027c3 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -78,7 +78,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) { "Files\0", config_item_perf_lookup, nspawn_gperf_lookup, CONFIG_PARSE_WARN, - s); + s, NULL); if (r < 0) return r; diff --git a/src/partition/repart.c b/src/partition/repart.c index 16cb5e45c4..4c6e459529 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -976,7 +976,12 @@ static int partition_read_definition(Partition *p, const char *path) { }; int r; - r = config_parse(NULL, path, NULL, "Partition\0", config_item_table_lookup, table, CONFIG_PARSE_WARN, p); + r = config_parse(NULL, path, NULL, + "Partition\0", + config_item_table_lookup, table, + CONFIG_PARSE_WARN, + p, + NULL); if (r < 0) return r; diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c index 5c812b5d5b..59d0b5b74e 100644 --- a/src/pstore/pstore.c +++ b/src/pstore/pstore.c @@ -78,11 +78,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf", - CONF_PATHS_NULSTR("systemd/pstore.conf.d"), - "PStore\0", - config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/pstore.conf", + CONF_PATHS_NULSTR("systemd/pstore.conf.d"), + "PStore\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } /* File list handling - PStoreEntry is the struct and diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index e915343c01..9a6b1e88e1 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -381,11 +381,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/resolved.conf", - CONF_PATHS_NULSTR("systemd/resolved.conf.d"), - "Resolve\0", - config_item_perf_lookup, resolved_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), + "Resolve\0", + config_item_perf_lookup, resolved_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index c331b2d94c..4458ad1d2d 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -86,10 +86,13 @@ static int dnssd_service_load(Manager *manager, const char *filename) { dropin_dirname = strjoina(service->name, ".dnssd.d"); - r = config_parse_many(filename, DNSSD_SERVICE_DIRS, dropin_dirname, - "Service\0", - config_item_perf_lookup, resolved_dnssd_gperf_lookup, - false, service, NULL); + r = config_parse_many( + filename, DNSSD_SERVICE_DIRS, dropin_dirname, + "Service\0", + config_item_perf_lookup, resolved_dnssd_gperf_lookup, + CONFIG_PARSE_WARN, + service, + NULL); if (r < 0) return r; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 2eda6ae03a..2122657342 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -199,7 +199,7 @@ static int parse_line( if (!fn) return -ENOMEM; - return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata); + return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata, NULL); } if (!utf8_is_valid(l)) @@ -289,13 +289,15 @@ int config_parse(const char *unit, ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false, bom_seen = false; int r, fd; + usec_t mtime; assert(filename); assert(lookup); @@ -313,8 +315,16 @@ int config_parse(const char *unit, } fd = fileno(f); - if (fd >= 0) /* stream might not have an fd, let's be careful hence */ - fd_warn_permissions(filename, fd); + if (fd >= 0) { /* stream might not have an fd, let's be careful hence */ + struct stat st; + + if (fstat(fd, &st) < 0) + return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno, + "Failed to fstat(%s): %m", filename); + + (void) stat_warn_permissions(filename, &st); + mtime = timespec_load(&st.st_mtim); + } for (;;) { _cleanup_free_ char *buf = NULL; @@ -434,6 +444,9 @@ int config_parse(const char *unit, } } + if (ret_mtime) + *ret_mtime = mtime; + return 0; } @@ -444,23 +457,32 @@ static int config_parse_many_files( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { + usec_t mtime = 0; char **fn; int r; if (conf_file) { - r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata); + r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime); if (r < 0) return r; } STRV_FOREACH(fn, files) { - r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata); + usec_t t; + + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t); if (r < 0) return r; + if (t > mtime) /* Find the newest */ + mtime = t; } + if (ret_mtime) + *ret_mtime = mtime; + return 0; } @@ -472,7 +494,8 @@ int config_parse_many_nulstr( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { _cleanup_strv_free_ char **files = NULL; int r; @@ -481,7 +504,7 @@ int config_parse_many_nulstr( if (r < 0) return r; - return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); } /* Parse each config file in the directories specified as strv. */ @@ -494,7 +517,7 @@ int config_parse_many( const void *table, ConfigParseFlags flags, void *userdata, - char ***ret_dropins) { + usec_t *ret_mtime) { _cleanup_strv_free_ char **dropin_dirs = NULL; _cleanup_strv_free_ char **files = NULL; @@ -510,14 +533,7 @@ int config_parse_many( if (r < 0) return r; - r = config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); - if (r < 0) - return r; - - if (ret_dropins) - *ret_dropins = TAKE_PTR(files); - - return 0; + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); } #define DEFINE_PARSER(type, vartype, conv_func) \ diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 480988f392..6c8c1092ea 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -10,6 +10,7 @@ #include "alloc-util.h" #include "log.h" #include "macro.h" +#include "time-util.h" /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */ @@ -84,11 +85,12 @@ int config_parse( const char *unit, const char *filename, FILE *f, - const char *sections, /* nulstr */ + const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata); + void *userdata, + usec_t *ret_mtime); /* possibly NULL */ int config_parse_many_nulstr( const char *conf_file, /* possibly NULL */ @@ -97,7 +99,8 @@ int config_parse_many_nulstr( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata); + void *userdata, + usec_t *ret_mtime); /* possibly NULL */ int config_parse_many( const char *conf_file, /* possibly NULL */ @@ -108,7 +111,7 @@ int config_parse_many( const void *table, ConfigParseFlags flags, void *userdata, - char ***ret_dropins); /* possibly NULL */ + usec_t *ret_mtime); /* possibly NULL */ CONFIG_PARSER_PROTOTYPE(config_parse_int); CONFIG_PARSER_PROTOTYPE(config_parse_unsigned); diff --git a/src/shared/install.c b/src/shared/install.c index 60005967e7..5dd5d2aa9a 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1304,7 +1304,8 @@ static int unit_file_load( "-Target\0" "-Timer\0", config_item_table_lookup, items, - CONFIG_PARSE_ALLOW_INCLUDE, info); + CONFIG_PARSE_ALLOW_INCLUDE, info, + NULL); if (r < 0) return log_debug_errno(r, "Failed to parse %s: %m", info->name); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 5cee1ce1aa..81862c776d 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -59,10 +59,14 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) { {} }; - (void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf", - CONF_PATHS_NULSTR("systemd/sleep.conf.d"), - "Sleep\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + (void) config_parse_many_nulstr( + PKGSYSCONFDIR "/sleep.conf", + CONF_PATHS_NULSTR("systemd/sleep.conf.d"), + "Sleep\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); /* use default values unless set */ sc->allow_suspend = allow_suspend != 0; diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 510b1de72d..07edc17f92 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -335,13 +335,17 @@ static void test_config_parse(unsigned i, const char *s) { ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) + void *userdata, + usec_t *ret_mtime) */ r = config_parse(NULL, name, f, - "Section\0-NoWarnSection\0", + "Section\0" + "-NoWarnSection\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + CONFIG_PARSE_WARN, + NULL, + NULL); switch (i) { case 0 ... 4: diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index a26c2dad7f..532d6ea7ec 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -102,11 +102,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/timesyncd.conf", - CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), - "Time\0", - config_item_perf_lookup, timesyncd_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/timesyncd.conf", + CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), + "Time\0", + config_item_perf_lookup, timesyncd_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 0e33c0b48f..eb84719111 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -192,7 +192,9 @@ static int process_one_password_file(const char *filename) { r = config_parse(NULL, filename, NULL, NULL, config_item_table_lookup, items, - CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL); + CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, + NULL, + NULL); if (r < 0) return r; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 806f457458..abe1276dfa 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -161,7 +161,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename) { r = config_parse(NULL, filename, file, "Match\0Link\0", config_item_perf_lookup, link_config_gperf_lookup, - CONFIG_PARSE_WARN, link); + CONFIG_PARSE_WARN, link, + NULL); if (r < 0) return r; diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c index c99b6cc883..6d10d7052b 100644 --- a/src/xdg-autostart-generator/xdg-autostart-service.c +++ b/src/xdg-autostart-generator/xdg-autostart-service.c @@ -319,7 +319,8 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) { r = config_parse(NULL, service->path, NULL, "Desktop Entry\0", xdg_config_item_table_lookup, items, - CONFIG_PARSE_WARN, service); + CONFIG_PARSE_WARN, service, + NULL); /* If parsing failed, only hide the file so it will still mask others. */ if (r < 0) { log_warning_errno(r, "Failed to parse %s, ignoring it", service->path);