networkd: allow networkd to set the timezone in timedated
authorMartin Pitt <martin.pitt@ubuntu.com>
Tue, 22 Nov 2016 07:05:18 +0000 (08:05 +0100)
committerMartin Pitt <martin.pitt@ubuntu.com>
Wed, 23 Nov 2016 15:32:06 +0000 (16:32 +0100)
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
src/hostname/systemd-networkd-hostname.pkla [deleted file]
src/hostname/systemd-networkd-hostname.rules [deleted file]
src/network/systemd-networkd.pkla [new file with mode: 0644]
src/network/systemd-networkd.rules [new file with mode: 0644]
test/networkd-test.py

index 10ce363..3aeb7b9 100644 (file)
@@ -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 (file)
index 345ce61..0000000
+++ /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 (file)
index b7b780d..0000000
+++ /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 (file)
index 0000000..fb257d9
--- /dev/null
@@ -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 (file)
index 0000000..2e4bc42
--- /dev/null
@@ -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;
+    }
+});
index a009410..84ab6c1 100755 (executable)
@@ -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))