1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <sys/capability.h>
7 #include "alloc-util.h"
8 #include "bus-get-properties.h"
9 #include "bus-internal.h"
10 #include "bus-log-control-api.h"
11 #include "bus-polkit.h"
12 #include "bus-protocol.h"
14 #include "dns-domain.h"
15 #include "in-addr-util.h"
19 #include "time-util.h"
20 #include "timesyncd-bus.h"
21 #include "user-util.h"
23 static int property_get_servers(
26 const char *interface
,
28 sd_bus_message
*reply
,
30 sd_bus_error
*error
) {
32 ServerName
**s
= ASSERT_PTR(userdata
);
38 r
= sd_bus_message_open_container(reply
, 'a', "s");
42 LIST_FOREACH(names
, p
, *s
) {
43 r
= sd_bus_message_append(reply
, "s", p
->string
);
48 return sd_bus_message_close_container(reply
);
51 static int method_set_runtime_servers(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
52 _cleanup_strv_free_
char **msg_names
= NULL
;
53 Manager
*m
= ASSERT_PTR(userdata
);
58 r
= sd_bus_message_read_strv(message
, &msg_names
);
62 STRV_FOREACH(name
, msg_names
) {
63 r
= dns_name_is_valid_or_address(*name
);
65 return log_error_errno(r
, "Failed to check validity of NTP server name or address '%s': %m", *name
);
67 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid NTP server name or address, refusing: %s", *name
);
70 r
= bus_verify_polkit_async(message
, CAP_NET_ADMIN
,
71 "org.freedesktop.timesync1.set-runtime-servers",
72 NULL
, true, UID_INVALID
,
73 &m
->polkit_registry
, error
);
77 /* Polkit will call us back */
80 manager_flush_runtime_servers(m
);
82 STRV_FOREACH(name
, msg_names
) {
83 r
= server_name_new(m
, NULL
, SERVER_RUNTIME
, *name
);
85 manager_flush_runtime_servers(m
);
87 return log_error_errno(r
, "Failed to add runtime server '%s': %m", *name
);
91 m
->exhausted_servers
= true;
92 manager_set_server_name(m
, NULL
);
93 (void) manager_connect(m
);
95 return sd_bus_reply_method_return(message
, NULL
);
98 static int property_get_current_server_name(
101 const char *interface
,
102 const char *property
,
103 sd_bus_message
*reply
,
105 sd_bus_error
*error
) {
107 ServerName
**s
= ASSERT_PTR(userdata
);
112 return sd_bus_message_append(reply
, "s", *s
? (*s
)->string
: NULL
);
115 static int property_get_current_server_address(
118 const char *interface
,
119 const char *property
,
120 sd_bus_message
*reply
,
122 sd_bus_error
*error
) {
131 a
= *(ServerAddress
**) userdata
;
134 return sd_bus_message_append(reply
, "(iay)", AF_UNSPEC
, 0);
136 assert(IN_SET(a
->sockaddr
.sa
.sa_family
, AF_INET
, AF_INET6
));
138 r
= sd_bus_message_open_container(reply
, 'r', "iay");
142 r
= sd_bus_message_append(reply
, "i", a
->sockaddr
.sa
.sa_family
);
146 r
= sd_bus_message_append_array(reply
, 'y',
147 a
->sockaddr
.sa
.sa_family
== AF_INET
? (void*) &a
->sockaddr
.in
.sin_addr
: (void*) &a
->sockaddr
.in6
.sin6_addr
,
148 FAMILY_ADDRESS_SIZE(a
->sockaddr
.sa
.sa_family
));
152 return sd_bus_message_close_container(reply
);
155 static usec_t
ntp_ts_short_to_usec(const struct ntp_ts_short
*ts
) {
156 return be16toh(ts
->sec
) * USEC_PER_SEC
+ (be16toh(ts
->frac
) * USEC_PER_SEC
) / (usec_t
) 0x10000ULL
;
159 static usec_t
ntp_ts_to_usec(const struct ntp_ts
*ts
) {
160 return (be32toh(ts
->sec
) - OFFSET_1900_1970
) * USEC_PER_SEC
+ (be32toh(ts
->frac
) * USEC_PER_SEC
) / (usec_t
) 0x100000000ULL
;
163 static int property_get_ntp_message(
166 const char *interface
,
167 const char *property
,
168 sd_bus_message
*reply
,
170 sd_bus_error
*error
) {
172 Manager
*m
= ASSERT_PTR(userdata
);
177 r
= sd_bus_message_open_container(reply
, 'r', "uuuuittayttttbtt");
181 r
= sd_bus_message_append(reply
, "uuuuitt",
182 NTP_FIELD_LEAP(m
->ntpmsg
.field
),
183 NTP_FIELD_VERSION(m
->ntpmsg
.field
),
184 NTP_FIELD_MODE(m
->ntpmsg
.field
),
187 ntp_ts_short_to_usec(&m
->ntpmsg
.root_delay
),
188 ntp_ts_short_to_usec(&m
->ntpmsg
.root_dispersion
));
192 r
= sd_bus_message_append_array(reply
, 'y', m
->ntpmsg
.refid
, 4);
196 r
= sd_bus_message_append(reply
, "ttttbtt",
197 timespec_load(&m
->origin_time
),
198 ntp_ts_to_usec(&m
->ntpmsg
.recv_time
),
199 ntp_ts_to_usec(&m
->ntpmsg
.trans_time
),
200 timespec_load(&m
->dest_time
),
203 (usec_t
) (m
->samples_jitter
* USEC_PER_SEC
));
207 return sd_bus_message_close_container(reply
);
210 static const sd_bus_vtable manager_vtable
[] = {
211 SD_BUS_VTABLE_START(0),
213 SD_BUS_PROPERTY("LinkNTPServers", "as", property_get_servers
, offsetof(Manager
, link_servers
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
214 SD_BUS_PROPERTY("SystemNTPServers", "as", property_get_servers
, offsetof(Manager
, system_servers
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
215 SD_BUS_PROPERTY("RuntimeNTPServers", "as", property_get_servers
, offsetof(Manager
, runtime_servers
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
216 SD_BUS_PROPERTY("FallbackNTPServers", "as", property_get_servers
, offsetof(Manager
, fallback_servers
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
217 SD_BUS_PROPERTY("ServerName", "s", property_get_current_server_name
, offsetof(Manager
, current_server_name
), 0),
218 SD_BUS_PROPERTY("ServerAddress", "(iay)", property_get_current_server_address
, offsetof(Manager
, current_server_address
), 0),
219 SD_BUS_PROPERTY("RootDistanceMaxUSec", "t", bus_property_get_usec
, offsetof(Manager
, root_distance_max_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
220 SD_BUS_PROPERTY("PollIntervalMinUSec", "t", bus_property_get_usec
, offsetof(Manager
, poll_interval_min_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
221 SD_BUS_PROPERTY("PollIntervalMaxUSec", "t", bus_property_get_usec
, offsetof(Manager
, poll_interval_max_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
222 SD_BUS_PROPERTY("PollIntervalUSec", "t", bus_property_get_usec
, offsetof(Manager
, poll_interval_usec
), 0),
223 SD_BUS_PROPERTY("NTPMessage", "(uuuuittayttttbtt)", property_get_ntp_message
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
224 SD_BUS_PROPERTY("Frequency", "x", NULL
, offsetof(Manager
, drift_freq
), 0),
226 SD_BUS_METHOD_WITH_ARGS("SetRuntimeNTPServers",
227 SD_BUS_ARGS("as", runtime_servers
),
229 method_set_runtime_servers
,
230 SD_BUS_VTABLE_UNPRIVILEGED
),
235 int manager_connect_bus(Manager
*m
) {
243 r
= bus_open_system_watch_bind_with_description(&m
->bus
, "bus-api-timesync");
245 return log_error_errno(r
, "Failed to connect to bus: %m");
247 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/timesync1", "org.freedesktop.timesync1.Manager", manager_vtable
, m
);
249 return log_error_errno(r
, "Failed to add manager object vtable: %m");
251 r
= bus_log_control_api_register(m
->bus
);
255 r
= sd_bus_request_name_async(m
->bus
, NULL
, "org.freedesktop.timesync1", 0, NULL
, NULL
);
257 return log_error_errno(r
, "Failed to request name: %m");
259 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
261 return log_error_errno(r
, "Failed to attach bus to event loop: %m");