]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
timesyncd: add RUNTIME servers
authorDaniel Mack <daniel@zonque.org>
Thu, 24 Feb 2022 14:47:35 +0000 (15:47 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 9 Apr 2022 01:23:14 +0000 (10:23 +0900)
This new server type can only be set at runtime through a D-Bus method
and is exposed for reading through a D-Bus property.

`CAP_NET_ADMIN` and a PolKit acknowledge is required for setting
runtime servers.

Entries submitted that way are used before system and link servers
are being looked at.

src/timesync/meson.build
src/timesync/org.freedesktop.timesync1.conf
src/timesync/org.freedesktop.timesync1.policy [new file with mode: 0644]
src/timesync/timesyncd-bus.c
src/timesync/timesyncd-manager.c
src/timesync/timesyncd-manager.h
src/timesync/timesyncd-server.c
src/timesync/timesyncd-server.h

index 35467026a84f7086748dfab883d7889e4adb2351..15ca7d2fd5a3d8b61b71110bd70102fafc1ed008 100644 (file)
@@ -50,6 +50,8 @@ if conf.get('ENABLE_TIMESYNCD') == 1
                      install_dir : dbussystemservicedir)
         install_data('80-systemd-timesync.list',
                      install_dir : ntpservicelistdir)
+        install_data('org.freedesktop.timesync1.policy',
+                     install_dir : polkitpolicydir)
 endif
 
 ############################################################
index eccdbec7189e4db4dfb1f8fefca4539be649ef18..8c74b36d6e16ae6930a2addbbefa923621bcee9b 100644 (file)
                        send_interface="org.freedesktop.DBus.Properties"
                        send_member="GetAll"/>
 
+                <allow send_destination="org.freedesktop.timesync1"
+                       send_interface="org.freedesktop.timesync1.Manager"
+                       send_member="SetRuntimeNTPServers"/>
+
                 <allow receive_sender="org.freedesktop.timesync1"/>
         </policy>
 
diff --git a/src/timesync/org.freedesktop.timesync1.policy b/src/timesync/org.freedesktop.timesync1.policy
new file mode 100644 (file)
index 0000000..e13e8df
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1-or-later
+
+  This file is part of systemd.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>https://systemd.io</vendor_url>
+
+        <action id="org.freedesktop.timesync1.set-runtime-servers">
+                <description gettext-domain="systemd">Set runtime NTP servers</description>
+                <message gettext-domain="systemd">Authentication is required to set runtime NTP servers.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-timesync</annotate>
+        </action>
+
+</policyconfig>
index b738dfd3cc2a38fc0ab2310143c9874a34879e40..7b929d9347a9dd35b54699baf135acc3ef4e9f66 100644 (file)
@@ -1,18 +1,24 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <sys/capability.h>
+
 #include "sd-bus.h"
 
 #include "alloc-util.h"
 #include "bus-get-properties.h"
 #include "bus-internal.h"
 #include "bus-log-control-api.h"
+#include "bus-polkit.h"
 #include "bus-protocol.h"
 #include "bus-util.h"
+#include "dns-domain.h"
 #include "in-addr-util.h"
 #include "log.h"
 #include "macro.h"
+#include "strv.h"
 #include "time-util.h"
 #include "timesyncd-bus.h"
+#include "user-util.h"
 
 static int property_get_servers(
                 sd_bus *bus,
@@ -43,6 +49,54 @@ static int property_get_servers(
         return sd_bus_message_close_container(reply);
 }
 
+static int method_set_runtime_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **msg_names = NULL;
+        Manager *m = userdata;
+        int r;
+
+        assert(m);
+        assert(message);
+
+        r = sd_bus_message_read_strv(message, &msg_names);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(name, msg_names) {
+                r = dns_name_is_valid_or_address(*name);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to check validity of NTP server name or address '%s': %m", *name);
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server name or address, refusing: %s", *name);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.timesync1.set-runtime-servers",
+                                    NULL, true, UID_INVALID,
+                                    &m->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                /* Polkit will call us back */
+                return 1;
+
+        manager_flush_runtime_servers(m);
+
+        STRV_FOREACH(name, msg_names) {
+                r = server_name_new(m, NULL, SERVER_RUNTIME, *name);
+                if (r < 0) {
+                        manager_flush_runtime_servers(m);
+
+                        return log_error_errno(r, "Failed to add runtime server '%s': %m", *name);
+                }
+        }
+
+        m->exhausted_servers = true;
+        manager_set_server_name(m, NULL);
+        (void) manager_connect(m);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 static int property_get_current_server_name(
                 sd_bus *bus,
                 const char *path,
@@ -162,6 +216,7 @@ static const sd_bus_vtable manager_vtable[] = {
 
         SD_BUS_PROPERTY("LinkNTPServers", "as", property_get_servers, offsetof(Manager, link_servers), 0),
         SD_BUS_PROPERTY("SystemNTPServers", "as", property_get_servers, offsetof(Manager, system_servers), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RuntimeNTPServers", "as", property_get_servers, offsetof(Manager, runtime_servers), 0),
         SD_BUS_PROPERTY("FallbackNTPServers", "as", property_get_servers, offsetof(Manager, fallback_servers), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ServerName", "s", property_get_current_server_name, offsetof(Manager, current_server_name), 0),
         SD_BUS_PROPERTY("ServerAddress", "(iay)", property_get_current_server_address, offsetof(Manager, current_server_address), 0),
@@ -172,6 +227,13 @@ static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("NTPMessage", "(uuuuittayttttbtt)", property_get_ntp_message, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Frequency", "x", NULL, offsetof(Manager, drift_freq), 0),
 
+        SD_BUS_METHOD_WITH_NAMES("SetRuntimeNTPServers",
+                                 "as",
+                                 SD_BUS_PARAM(runtime_servers),
+                                 NULL,,
+                                 method_set_runtime_servers,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
         SD_BUS_VTABLE_END
 };
 
index ee2b24e2b16f784e0c28a412ca000d3cfd599902..40fd4d3464fe2a24b4997baaee5c24ae8f5d2dcc 100644 (file)
@@ -14,6 +14,7 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "bus-polkit.h"
 #include "dns-domain.h"
 #include "event-util.h"
 #include "fd-util.h"
@@ -825,22 +826,25 @@ int manager_connect(Manager *m) {
                         bool restart = true;
 
                         /* Our current server name list is exhausted,
-                         * let's find the next one to iterate. First
-                         * we try the system list, then the link list.
-                         * After having processed the link list we
-                         * jump back to the system list. However, if
-                         * both lists are empty, we change to the
-                         * fallback list. */
+                         * let's find the next one to iterate. First we try the runtime list, then the system list,
+                         * then the link list. After having processed the link list we jump back to the system list
+                         * if no runtime server list.
+                         * However, if all lists are empty, we change to the fallback list. */
                         if (!m->current_server_name || m->current_server_name->type == SERVER_LINK) {
-                                f = m->system_servers;
+                                f = m->runtime_servers;
+                                if (!f)
+                                        f = m->system_servers;
                                 if (!f)
                                         f = m->link_servers;
                         } else {
                                 f = m->link_servers;
-                                if (!f)
-                                        f = m->system_servers;
-                                else
+                                if (f)
                                         restart = false;
+                                else {
+                                        f = m->runtime_servers;
+                                        if (!f)
+                                                f = m->system_servers;
+                                }
                         }
 
                         if (!f)
@@ -925,6 +929,16 @@ void manager_flush_server_names(Manager  *m, ServerType t) {
         if (t == SERVER_FALLBACK)
                 while (m->fallback_servers)
                         server_name_free(m->fallback_servers);
+
+        if (t == SERVER_RUNTIME)
+                manager_flush_runtime_servers(m);
+}
+
+void manager_flush_runtime_servers(Manager *m) {
+        assert(m);
+
+        while (m->runtime_servers)
+                server_name_free(m->runtime_servers);
 }
 
 Manager* manager_free(Manager *m) {
@@ -934,6 +948,7 @@ Manager* manager_free(Manager *m) {
         manager_disconnect(m);
         manager_flush_server_names(m, SERVER_SYSTEM);
         manager_flush_server_names(m, SERVER_LINK);
+        manager_flush_server_names(m, SERVER_RUNTIME);
         manager_flush_server_names(m, SERVER_FALLBACK);
 
         sd_event_source_unref(m->event_retry);
@@ -948,6 +963,8 @@ Manager* manager_free(Manager *m) {
 
         sd_bus_flush_close_unref(m->bus);
 
+        bus_verify_polkit_async_registry_free(m->polkit_registry);
+
         return mfree(m);
 }
 
index f9d6567bdb162c450607373725e719418f1121ff..e595c7ddfc1f04579104b77f68e514c2e3879c38 100644 (file)
@@ -8,6 +8,7 @@
 #include "sd-network.h"
 #include "sd-resolve.h"
 
+#include "hashmap.h"
 #include "list.h"
 #include "ratelimit.h"
 #include "time-util.h"
@@ -41,6 +42,7 @@ struct Manager {
 
         LIST_HEAD(ServerName, system_servers);
         LIST_HEAD(ServerName, link_servers);
+        LIST_HEAD(ServerName, runtime_servers);
         LIST_HEAD(ServerName, fallback_servers);
 
         bool have_fallbacks:1;
@@ -63,6 +65,9 @@ struct Manager {
         sd_event_source *event_timeout;
         bool talking;
 
+        /* PolicyKit */
+        Hashmap *polkit_registry;
+
         /* last sent packet */
         struct timespec trans_time_mon;
         struct timespec trans_time;
@@ -121,6 +126,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 void manager_set_server_name(Manager *m, ServerName *n);
 void manager_set_server_address(Manager *m, ServerAddress *a);
 void manager_flush_server_names(Manager *m, ServerType t);
+void manager_flush_runtime_servers(Manager *m);
 
 int manager_connect(Manager *m);
 void manager_disconnect(Manager *m);
index dd168917341ef43399221831c848304bed660f66..002a6117cc2bb81cc36780a88e83281f96907a89 100644 (file)
@@ -85,6 +85,9 @@ int server_name_new(
         } else if (type == SERVER_FALLBACK) {
                 LIST_FIND_TAIL(names, m->fallback_servers, tail);
                 LIST_INSERT_AFTER(names, m->fallback_servers, tail, n);
+        } else if (type == SERVER_RUNTIME) {
+                LIST_FIND_TAIL(names, m->runtime_servers, tail);
+                LIST_INSERT_AFTER(names, m->runtime_servers, tail, n);
         } else
                 assert_not_reached();
 
@@ -114,6 +117,8 @@ ServerName *server_name_free(ServerName *n) {
                         LIST_REMOVE(names, n->manager->link_servers, n);
                 else if (n->type == SERVER_FALLBACK)
                         LIST_REMOVE(names, n->manager->fallback_servers, n);
+                else if (n->type == SERVER_RUNTIME)
+                        LIST_REMOVE(names, n->manager->runtime_servers, n);
                 else
                         assert_not_reached();
 
index 8e9e408eccb09781f09f5df42af1a596a8907507..ca994bf6ae3648b6919bf435cf82aec3bd8e7ca3 100644 (file)
@@ -11,6 +11,7 @@ typedef enum ServerType {
         SERVER_SYSTEM,
         SERVER_FALLBACK,
         SERVER_LINK,
+        SERVER_RUNTIME,
 } ServerType;
 
 #include "timesyncd-manager.h"