From 59eb33e0fec9b1502a9089561dcfda3f16a1816e Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 21 Nov 2016 23:15:41 +0100 Subject: networkd: move setting hostname and timezone to Manager Hostname and time zone are global settings, not link specific. Move these methods from Link into Manager. --- src/network/networkd-dhcp4.c | 6 +-- src/network/networkd-link.c | 103 ----------------------------------------- src/network/networkd-link.h | 2 - src/network/networkd-manager.c | 89 +++++++++++++++++++++++++++++++++++ src/network/networkd-manager.h | 3 ++ 5 files changed, 95 insertions(+), 108 deletions(-) (limited to 'src/network') diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ca23c1c2a7..c5c5b95c8f 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -255,7 +255,7 @@ static int dhcp_lease_lost(Link *link) { if (hostname) { /* If a hostname was set due to the lease, then unset it now. */ - r = link_set_hostname(link, NULL); + r = manager_set_hostname(link->manager, NULL); if (r < 0) log_link_warning_errno(link, r, "Failed to reset transient hostname: %m"); } @@ -439,7 +439,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { (void) sd_dhcp_lease_get_hostname(lease, &hostname); if (hostname) { - r = link_set_hostname(link, hostname); + r = manager_set_hostname(link->manager, hostname); if (r < 0) log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); } @@ -451,7 +451,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); if (tz) { - r = link_set_timezone(link, tz); + r = manager_set_timezone(link->manager, tz); if (r < 0) log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index b38eec1ba7..cb7df633b7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1175,109 +1175,6 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd return 0; } -static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { - _cleanup_link_unref_ Link *link = userdata; - const sd_bus_error *e; - - assert(m); - assert(link); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; - - e = sd_bus_message_get_error(m); - if (e) - log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message); - - return 1; -} - -int link_set_hostname(Link *link, const char *hostname) { - int r; - - assert(link); - assert(link->manager); - - log_link_debug(link, "Setting transient hostname: '%s'", strna(hostname)); - - if (!link->manager->bus) { - /* TODO: replace by assert when we can rely on kdbus */ - log_link_info(link, "Not connected to system bus, ignoring transient hostname."); - return 0; - } - - r = sd_bus_call_method_async( - link->manager->bus, - NULL, - "org.freedesktop.hostname1", - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - "SetHostname", - set_hostname_handler, - link, - "sb", - hostname, - false); - - if (r < 0) - return log_link_error_errno(link, r, "Could not set transient hostname: %m"); - - link_ref(link); - - return 0; -} - -static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { - _cleanup_link_unref_ Link *link = userdata; - const sd_bus_error *e; - - assert(m); - assert(link); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; - - e = sd_bus_message_get_error(m); - if (e) - log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message); - - return 1; -} - -int link_set_timezone(Link *link, const char *tz) { - int r; - - assert(link); - assert(link->manager); - assert(tz); - - log_link_debug(link, "Setting system timezone: '%s'", tz); - - if (!link->manager->bus) { - log_link_info(link, "Not connected to system bus, ignoring timezone."); - return 0; - } - - r = sd_bus_call_method_async( - link->manager->bus, - NULL, - "org.freedesktop.timedate1", - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "SetTimezone", - set_timezone_handler, - link, - "sb", - tz, - false); - if (r < 0) - return log_link_error_errno(link, r, "Could not set timezone: %m"); - - link_ref(link); - - return 0; -} - static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 77f72d070e..e6190fbe57 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -159,8 +159,6 @@ bool link_has_carrier(Link *link); int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu); -int link_set_hostname(Link *link, const char *hostname); -int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index c3d3f48a3f..a32d5648b6 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1365,3 +1365,92 @@ void manager_dirty(Manager *manager) { /* the serialized state in /run is no longer up-to-date */ manager->dirty = true; } + +static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + Manager *manager = userdata; + const sd_bus_error *e; + + assert(m); + assert(manager); + + e = sd_bus_message_get_error(m); + if (e) + log_warning_errno(sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message); + + return 1; +} + +int manager_set_hostname(Manager *m, const char *hostname) { + int r; + + log_debug("Setting transient hostname: '%s'", strna(hostname)); + + if (!m->bus) { + /* TODO: replace by assert when we can rely on kdbus */ + log_info("Not connected to system bus, ignoring transient hostname."); + return 0; + } + + r = sd_bus_call_method_async( + m->bus, + NULL, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "SetHostname", + set_hostname_handler, + m, + "sb", + hostname, + false); + + if (r < 0) + return log_error_errno(r, "Could not set transient hostname: %m"); + + return 0; +} + +static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + Manager *manager = userdata; + const sd_bus_error *e; + + assert(m); + assert(manager); + + e = sd_bus_message_get_error(m); + if (e) + log_warning_errno(sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message); + + return 1; +} + +int manager_set_timezone(Manager *m, const char *tz) { + int r; + + assert(m); + assert(tz); + + log_debug("Setting system timezone: '%s'", tz); + + if (!m->bus) { + log_info("Not connected to system bus, ignoring timezone."); + return 0; + } + + r = sd_bus_call_method_async( + m->bus, + NULL, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetTimezone", + set_timezone_handler, + m, + "sb", + tz, + false); + if (r < 0) + return log_error_errno(r, "Could not set timezone: %m"); + + return 0; +} diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index a90d9a933f..13363c70fa 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -97,5 +97,8 @@ int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, uni Link* manager_find_uplink(Manager *m, Link *exclude); +int manager_set_hostname(Manager *m, const char *hostname); +int manager_set_timezone(Manager *m, const char *timezone); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) -- cgit v1.2.3-54-g00ecf From 2c99aba7260a402e8f81d85aab12ce25d3d8786a Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 22 Nov 2016 08:05:18 +0100 Subject: networkd: allow networkd to set the timezone in timedated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit systemd-networkd runs as user "systemd-network" and thus is not privileged to set the timezone acquired from DHCP: systemd-networkd[4167]: test_eth42: Could not set timezone: Interactive authentication required. Similarly to commit e8c0de912, add a polkit rule to grant org.freedesktop.timedate1.set-timezone to the "systemd-network" system user. Move the polkit rules from src/hostname/ to src/network/ to avoid too many small distributed policy snippets (there might be more in the future), as it's easier to specify the privileges for a particular subject in this case. Add NetworkdClientTest.test_dhcp_timezone() test case to verify this (for all people except those in Pacific/Honolulu, there the test doesn't prove anything -- sorry ☺ ). --- Makefile.am | 18 ++++++++-------- src/hostname/systemd-networkd-hostname.pkla | 4 ---- src/hostname/systemd-networkd-hostname.rules | 5 ----- src/network/systemd-networkd.pkla | 4 ++++ src/network/systemd-networkd.rules | 8 +++++++ test/networkd-test.py | 32 ++++++++++++++++++++++++++-- 6 files changed, 51 insertions(+), 20 deletions(-) delete mode 100644 src/hostname/systemd-networkd-hostname.pkla delete mode 100644 src/hostname/systemd-networkd-hostname.rules create mode 100644 src/network/systemd-networkd.pkla create mode 100644 src/network/systemd-networkd.rules (limited to 'src/network') diff --git a/Makefile.am b/Makefile.am index 10ce363347..3aeb7b9ae2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4840,16 +4840,8 @@ endif polkitpolicy_in_files += \ src/hostname/org.freedesktop.hostname1.policy.in -polkitrules_files += \ - src/hostname/systemd-networkd-hostname.rules - -polkitpkla_files += \ - src/hostname/systemd-networkd-hostname.pkla - EXTRA_DIST += \ - units/systemd-hostnamed.service.in \ - src/hostname/systemd-networkd-hostname.rules \ - src/hostname/systemd-networkd-hostname.pkla + units/systemd-hostnamed.service.in # ------------------------------------------------------------------------------ dist_systemunit_DATA_busnames += \ @@ -5785,6 +5777,12 @@ SYSTEM_UNIT_ALIASES += \ BUSNAMES_TARGET_WANTS += \ org.freedesktop.network1.busname +polkitrules_files += \ + src/network/systemd-networkd.rules + +polkitpkla_files += \ + src/network/systemd-networkd.pkla + endif gperf_gperf_sources += \ @@ -5793,6 +5791,8 @@ gperf_gperf_sources += \ src/network/netdev/netdev-gperf.gperf EXTRA_DIST += \ + src/network/systemd-networkd.rules \ + src/network/systemd-networkd.pkla \ units/systemd-networkd.service.m4.in \ units/systemd-networkd-wait-online.service.in \ test/networkd-test.py diff --git a/src/hostname/systemd-networkd-hostname.pkla b/src/hostname/systemd-networkd-hostname.pkla deleted file mode 100644 index 345ce617c6..0000000000 --- a/src/hostname/systemd-networkd-hostname.pkla +++ /dev/null @@ -1,4 +0,0 @@ -[Allow systemd-networkd to set transient hostname] -Identity=unix-user:systemd-network -Action=org.freedesktop.hostname1.set-hostname -ResultAny=yes diff --git a/src/hostname/systemd-networkd-hostname.rules b/src/hostname/systemd-networkd-hostname.rules deleted file mode 100644 index b7b780da9e..0000000000 --- a/src/hostname/systemd-networkd-hostname.rules +++ /dev/null @@ -1,5 +0,0 @@ -polkit.addRule(function(action, subject) { - if (action.id == "org.freedesktop.hostname1.set-hostname" && subject.user == "systemd-network") { - return polkit.Result.YES; - } -}); diff --git a/src/network/systemd-networkd.pkla b/src/network/systemd-networkd.pkla new file mode 100644 index 0000000000..fb257d933b --- /dev/null +++ b/src/network/systemd-networkd.pkla @@ -0,0 +1,4 @@ +[Allow systemd-networkd to set timezone and transient hostname] +Identity=unix-user:systemd-network +Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.timedate1.set-timezone; +ResultAny=yes diff --git a/src/network/systemd-networkd.rules b/src/network/systemd-networkd.rules new file mode 100644 index 0000000000..2e4bc42bfb --- /dev/null +++ b/src/network/systemd-networkd.rules @@ -0,0 +1,8 @@ +// Allow systemd-networkd to set timezone and transient hostname +polkit.addRule(function(action, subject) { + if ((action.id == "org.freedesktop.hostname1.set-hostname" || + action.id == "org.freedesktop.timedate1.set-timezone") && + subject.user == "systemd-network") { + return polkit.Result.YES; + } +}); diff --git a/test/networkd-test.py b/test/networkd-test.py index a00941095b..84ab6c1b02 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -469,7 +469,7 @@ class NetworkdClientTest(ClientTestBase, unittest.TestCase): super().setUp() self.dnsmasq = None - def create_iface(self, ipv6=False): + def create_iface(self, ipv6=False, dhcpserver_opts=None): '''Create test interface with DHCP server behind it''' # run "router-side" networkd in own mount namespace to shield it from @@ -507,11 +507,13 @@ DHCPServer=yes PoolOffset=10 PoolSize=50 DNS=192.168.5.1 +%(dhopts)s EOF # run networkd as in systemd-networkd.service exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; p}') -''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or ''}) +''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or '', + 'dhopts': dhcpserver_opts or ''}) os.fchmod(fd, 0o755) @@ -642,6 +644,32 @@ DNS=127.0.0.1''') self.assertIn('nameserver 192.168.42.1\n', contents) self.assertIn('nameserver 127.0.0.1\n', contents) + def test_dhcp_timezone(self): + '''networkd sets time zone from DHCP''' + + def get_tz(): + out = subprocess.check_output(['busctl', 'get-property', 'org.freedesktop.timedate1', + '/org/freedesktop/timedate1', 'org.freedesktop.timedate1', 'Timezone']) + assert out.startswith(b's "') + out = out.strip() + assert out.endswith(b'"') + return out[3:-1].decode() + + orig_timezone = get_tz() + self.addCleanup(subprocess.call, ['timedatectl', 'set-timezone', orig_timezone]) + + self.create_iface(dhcpserver_opts='EmitTimezone=yes\nTimezone=Pacific/Honolulu') + self.do_test(coldplug=None, extra_opts='IPv6AcceptRA=false\n[DHCP]\nUseTimezone=true', dhcp_mode='ipv4') + + # should have applied the received timezone + try: + self.assertEqual(get_tz(), 'Pacific/Honolulu') + except AssertionError: + self.show_journal('systemd-networkd.service') + self.show_journal('systemd-hostnamed.service') + raise + + if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) -- cgit v1.2.3-54-g00ecf From 7901cea1997c3881f3da93ecc5ad03e6de1e87b7 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 22 Nov 2016 08:36:20 +0100 Subject: networkd: set DHCP-acquired timezone and hostname after connecting to D-Bus If setting the received timezone or transient hostname fails because D-Bus is not (yet) up, store the data in the Manager object and try again after connecting to D-Bus. --- src/network/networkd-manager.c | 19 +++++++++++++++++++ src/network/networkd-manager.h | 2 ++ 2 files changed, 21 insertions(+) (limited to 'src/network') diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a32d5648b6..4e3f9e35c6 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -192,6 +192,18 @@ int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); + /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ + if (m->dynamic_hostname) { + r = manager_set_hostname(m, m->dynamic_hostname); + if (r < 0) + return r; + } + if (m->dynamic_timezone) { + r = manager_set_timezone(m, m->dynamic_timezone); + if (r < 0) + return r; + } + return 0; } @@ -1119,6 +1131,9 @@ void manager_free(Manager *m) { sd_bus_slot_unref(m->prepare_for_sleep_slot); sd_event_source_unref(m->bus_retry_event_source); + free(m->dynamic_timezone); + free(m->dynamic_hostname); + free(m); } @@ -1384,6 +1399,8 @@ int manager_set_hostname(Manager *m, const char *hostname) { int r; log_debug("Setting transient hostname: '%s'", strna(hostname)); + if (free_and_strdup(&m->dynamic_hostname, hostname) < 0) + return log_oom(); if (!m->bus) { /* TODO: replace by assert when we can rely on kdbus */ @@ -1431,6 +1448,8 @@ int manager_set_timezone(Manager *m, const char *tz) { assert(tz); log_debug("Setting system timezone: '%s'", tz); + if (free_and_strdup(&m->dynamic_timezone, tz) < 0) + return log_oom(); if (!m->bus) { log_info("Not connected to system bus, ignoring timezone."); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 13363c70fa..c81f5057b7 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -63,6 +63,8 @@ struct Manager { usec_t network_dirs_ts_usec; DUID duid; + char* dynamic_hostname; + char* dynamic_timezone; }; static inline const DUID* link_duid(const Link *link) { -- cgit v1.2.3-54-g00ecf