Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sys/stat.h>
4 : : #include <sys/types.h>
5 : :
6 : : #include "sd-daemon.h"
7 : : #include "sd-event.h"
8 : :
9 : : #include "capability-util.h"
10 : : #include "clock-util.h"
11 : : #include "daemon-util.h"
12 : : #include "fd-util.h"
13 : : #include "fs-util.h"
14 : : #include "main-func.h"
15 : : #include "mkdir.h"
16 : : #include "network-util.h"
17 : : #include "process-util.h"
18 : : #include "signal-util.h"
19 : : #include "timesyncd-bus.h"
20 : : #include "timesyncd-conf.h"
21 : : #include "timesyncd-manager.h"
22 : : #include "user-util.h"
23 : :
24 : : #define STATE_DIR "/var/lib/systemd/timesync"
25 : : #define CLOCK_FILE STATE_DIR "/clock"
26 : :
27 : 0 : static int load_clock_timestamp(uid_t uid, gid_t gid) {
28 : 0 : _cleanup_close_ int fd = -1;
29 : 0 : usec_t min = TIME_EPOCH * USEC_PER_SEC;
30 : : usec_t ct;
31 : : int r;
32 : :
33 : : /* Let's try to make sure that the clock is always
34 : : * monotonically increasing, by saving the clock whenever we
35 : : * have a new NTP time, or when we shut down, and restoring it
36 : : * when we start again. This is particularly helpful on
37 : : * systems lacking a battery backed RTC. We also will adjust
38 : : * the time to at least the build time of systemd. */
39 : :
40 : 0 : fd = open(CLOCK_FILE, O_RDWR|O_CLOEXEC, 0644);
41 [ # # ]: 0 : if (fd >= 0) {
42 : : struct stat st;
43 : : usec_t stamp;
44 : :
45 : : /* check if the recorded time is later than the compiled-in one */
46 : 0 : r = fstat(fd, &st);
47 [ # # ]: 0 : if (r >= 0) {
48 : 0 : stamp = timespec_load(&st.st_mtim);
49 [ # # ]: 0 : if (stamp > min)
50 : 0 : min = stamp;
51 : : }
52 : :
53 [ # # ]: 0 : if (geteuid() == 0) {
54 : : /* Try to fix the access mode, so that we can still
55 : : touch the file after dropping privileges */
56 : 0 : r = fchmod_and_chown(fd, 0644, uid, gid);
57 [ # # ]: 0 : if (r < 0)
58 [ # # ]: 0 : log_warning_errno(r, "Failed to chmod or chown %s, ignoring: %m", CLOCK_FILE);
59 : : }
60 : :
61 : : } else {
62 : 0 : r = mkdir_safe_label(STATE_DIR, 0755, uid, gid,
63 : : MKDIR_FOLLOW_SYMLINK | MKDIR_WARN_MODE);
64 [ # # ]: 0 : if (r < 0) {
65 [ # # ]: 0 : log_debug_errno(r, "Failed to create state directory, ignoring: %m");
66 : 0 : goto settime;
67 : : }
68 : :
69 : : /* create stamp file with the compiled-in date */
70 : 0 : r = touch_file(CLOCK_FILE, false, min, uid, gid, 0644);
71 [ # # ]: 0 : if (r < 0)
72 [ # # ]: 0 : log_debug_errno(r, "Failed to create %s, ignoring: %m", CLOCK_FILE);
73 : : }
74 : :
75 : 0 : settime:
76 : 0 : ct = now(CLOCK_REALTIME);
77 [ # # ]: 0 : if (ct < min) {
78 : : struct timespec ts;
79 : : char date[FORMAT_TIMESTAMP_MAX];
80 : :
81 [ # # ]: 0 : log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s",
82 : : format_timestamp(date, sizeof(date), min));
83 : :
84 [ # # ]: 0 : if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
85 [ # # ]: 0 : log_error_errno(errno, "Failed to restore system clock, ignoring: %m");
86 : : }
87 : :
88 : 0 : return 0;
89 : : }
90 : :
91 : 0 : static int run(int argc, char *argv[]) {
92 : 0 : _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
93 : 0 : _cleanup_(manager_freep) Manager *m = NULL;
94 : 0 : const char *user = "systemd-timesync";
95 : : uid_t uid, uid_current;
96 : : gid_t gid;
97 : : int r;
98 : :
99 : 0 : log_set_facility(LOG_CRON);
100 : 0 : log_setup_service();
101 : :
102 : 0 : umask(0022);
103 : :
104 [ # # ]: 0 : if (argc != 1)
105 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program does not take arguments.");
106 : :
107 : 0 : uid = uid_current = geteuid();
108 : 0 : gid = getegid();
109 : :
110 [ # # ]: 0 : if (uid_current == 0) {
111 : 0 : r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
112 [ # # ]: 0 : if (r < 0)
113 [ # # ]: 0 : return log_error_errno(r, "Cannot resolve user name %s: %m", user);
114 : : }
115 : :
116 : 0 : r = load_clock_timestamp(uid, gid);
117 [ # # ]: 0 : if (r < 0)
118 : 0 : return r;
119 : :
120 : : /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
121 : : * privileges are already dropped. */
122 [ # # ]: 0 : if (uid_current == 0) {
123 : 0 : r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
124 [ # # ]: 0 : if (r < 0)
125 [ # # ]: 0 : return log_error_errno(r, "Failed to drop privileges: %m");
126 : : }
127 : :
128 [ # # ]: 0 : assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
129 : :
130 : 0 : r = manager_new(&m);
131 [ # # ]: 0 : if (r < 0)
132 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate manager: %m");
133 : :
134 : 0 : r = manager_connect_bus(m);
135 [ # # ]: 0 : if (r < 0)
136 [ # # ]: 0 : return log_error_errno(r, "Could not connect to bus: %m");
137 : :
138 [ # # ]: 0 : if (clock_is_localtime(NULL) > 0) {
139 [ # # ]: 0 : log_info("The system is configured to read the RTC time in the local time zone. "
140 : : "This mode cannot be fully supported. All system time to RTC updates are disabled.");
141 : 0 : m->rtc_local_time = true;
142 : : }
143 : :
144 : 0 : r = manager_parse_config_file(m);
145 [ # # ]: 0 : if (r < 0)
146 [ # # ]: 0 : log_warning_errno(r, "Failed to parse configuration file: %m");
147 : :
148 : 0 : r = manager_parse_fallback_string(m, NTP_SERVERS);
149 [ # # ]: 0 : if (r < 0)
150 [ # # ]: 0 : return log_error_errno(r, "Failed to parse fallback server strings: %m");
151 : :
152 [ # # ]: 0 : log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
153 : :
154 : 0 : notify_message = notify_start("READY=1\n"
155 : : "STATUS=Daemon is running",
156 : : NOTIFY_STOPPING);
157 : :
158 [ # # ]: 0 : if (network_is_online()) {
159 : 0 : r = manager_connect(m);
160 [ # # ]: 0 : if (r < 0)
161 : 0 : return r;
162 : : }
163 : :
164 : 0 : r = sd_event_loop(m->event);
165 [ # # ]: 0 : if (r < 0)
166 [ # # ]: 0 : return log_error_errno(r, "Failed to run event loop: %m");
167 : :
168 : : /* if we got an authoritative time, store it in the file system */
169 [ # # ]: 0 : if (m->sync) {
170 : 0 : r = touch(CLOCK_FILE);
171 [ # # ]: 0 : if (r < 0)
172 [ # # ]: 0 : log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE);
173 : : }
174 : :
175 : 0 : return 0;
176 : : }
177 : :
178 : 0 : DEFINE_MAIN_FUNCTION(run);
|