]> git.ipfire.org Git - thirdparty/chrony.git/blame - main.c
ntp: fix exp1 EF search in process_response()
[thirdparty/chrony.git] / main.c
CommitLineData
88840341 1/*
88840341
RC
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
6672f045 5 * Copyright (C) Richard P. Curnow 1997-2003
f7e08d0c 6 * Copyright (C) John G. Hasler 2009
3916c336 7 * Copyright (C) Miroslav Lichvar 2012-2020
88840341
RC
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
8e23110a 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
88840341
RC
21 *
22 **********************************************************************
23
24 =======================================================================
25
26 The main program
27 */
28
da2c8d90
ML
29#include "config.h"
30
88840341
RC
31#include "sysincl.h"
32
33#include "main.h"
34#include "sched.h"
35#include "local.h"
36#include "sys.h"
37#include "ntp_io.h"
577aed48 38#include "ntp_signd.h"
88840341
RC
39#include "ntp_sources.h"
40#include "ntp_core.h"
a420ed57 41#include "nts_ke_server.h"
6043632f 42#include "nts_ntp_server.h"
2de24cfd 43#include "socket.h"
88840341
RC
44#include "sources.h"
45#include "sourcestats.h"
46#include "reference.h"
47#include "logging.h"
48#include "conf.h"
49#include "cmdmon.h"
50#include "keys.h"
88840341 51#include "manual.h"
88840341 52#include "rtc.h"
ac30bb06 53#include "refclock.h"
88840341 54#include "clientlog.h"
fbd20c42 55#include "nameserv.h"
610f2340 56#include "privops.h"
7f45eb79 57#include "smooth.h"
c386d117 58#include "tempcomp.h"
ceef8ad2 59#include "util.h"
88840341
RC
60
61/* ================================================== */
62
63/* Set when the initialisation chain has been completed. Prevents finalisation
64 * chain being run if a fatal error happened early. */
65
66static int initialised = 0;
67
93b66ac1 68static int exit_status = 0;
88840341
RC
69
70static int reload = 0;
71
e176587e 72static REF_Mode ref_mode = REF_ModeNormal;
7fda9c67 73
88840341
RC
74/* ================================================== */
75
bafb434f
ML
76static void
77do_platform_checks(void)
78{
79 /* Require at least 32-bit integers, two's complement representation and
80 the usual implementation of conversion of unsigned integers */
81 assert(sizeof (int) >= 4);
82 assert(-1 == ~0);
fe502128 83 assert((int32_t)4294967295U == (int32_t)-1);
bafb434f
ML
84}
85
86/* ================================================== */
87
88840341
RC
88static void
89delete_pidfile(void)
90{
91 const char *pidfile = CNF_GetPidFile();
778fce40 92
60049f15 93 if (!pidfile)
778fce40
ML
94 return;
95
e18903a6
ML
96 if (!UTI_RemoveFile(NULL, pidfile, NULL))
97 ;
88840341
RC
98}
99
100/* ================================================== */
101
1e7e7d32 102void
88840341
RC
103MAI_CleanupAndExit(void)
104{
93b66ac1 105 if (!initialised) exit(exit_status);
88840341 106
3cef7f97 107 LCL_CancelOffsetCorrection();
60049f15 108 SRC_DumpSources();
88840341 109
f6ed7844
ML
110 /* Don't update clock when removing sources */
111 REF_SetMode(REF_ModeIgnore);
112
7f45eb79 113 SMT_Finalise();
c386d117 114 TMC_Finalise();
88840341 115 MNL_Finalise();
88840341 116 CLG_Finalise();
a420ed57 117 NKS_Finalise();
6043632f 118 NNS_Finalise();
577aed48 119 NSD_Finalise();
88840341 120 NSR_Finalise();
8854c00d 121 SST_Finalise();
88840341 122 NCR_Finalise();
4e54770f 123 NIO_Finalise();
8854c00d 124 CAM_Finalise();
66e097e3 125
1c901b82 126 KEY_Finalise();
ac30bb06 127 RCL_Finalise();
3a222336 128 SRC_Finalise();
f6ed7844 129 REF_Finalise();
be42b4ee 130 RTC_Finalise();
88840341 131 SYS_Finalise();
66e097e3
ML
132
133 SCK_Finalise();
88840341
RC
134 SCH_Finalise();
135 LCL_Finalise();
334ac061 136 PRV_Finalise();
88840341
RC
137
138 delete_pidfile();
139
f6ed7844 140 CNF_Finalise();
f6ed7844 141 HSH_Finalise();
b712c100 142 LOG_Finalise();
f6ed7844 143
93b66ac1 144 exit(exit_status);
88840341
RC
145}
146
147/* ================================================== */
148
149static void
150signal_cleanup(int x)
151{
9416a24f 152 SCH_QuitProgram();
88840341
RC
153}
154
155/* ================================================== */
156
35134848
ML
157static void
158quit_timeout(void *arg)
159{
160 /* Return with non-zero status if the clock is not synchronised */
161 exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
162 SCH_QuitProgram();
163}
164
165/* ================================================== */
166
88840341 167static void
6ee357d2 168ntp_source_resolving_end(void)
88840341 169{
6ee357d2 170 NSR_SetSourceResolvingEndHandler(NULL);
88840341 171
88840341
RC
172 if (reload) {
173 /* Note, we want reload to come well after the initialisation from
174 the real time clock - this gives us a fighting chance that the
175 system-clock scale for the reloaded samples still has a
176 semblence of validity about it. */
177 SRC_ReloadSources();
178 }
88840341 179
a06a5f1b 180 SRC_RemoveDumpFiles();
88840341 181 RTC_StartMeasurements();
ac30bb06 182 RCL_StartRefclocks();
779e40ed
ML
183 NSR_StartSources();
184 NSR_AutoStartSources();
70feea48
ML
185
186 /* Special modes can end only when sources update their reachability.
144fcdde 187 Give up immediately if there are no active sources. */
7fa22d4c 188 if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
70feea48
ML
189 REF_SetUnsynchronised();
190 }
88840341
RC
191}
192
193/* ================================================== */
194
6ee357d2
ML
195static void
196post_init_ntp_hook(void *anything)
197{
198 if (ref_mode == REF_ModeInitStepSlew) {
199 /* Remove the initstepslew sources and set normal mode */
200 NSR_RemoveAllSources();
201 ref_mode = REF_ModeNormal;
202 REF_SetMode(ref_mode);
203 }
204
205 /* Close the pipe to the foreground process so it can exit */
206 LOG_CloseParentFd();
207
208 CNF_AddSources();
209 CNF_AddBroadcasts();
210
211 NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end);
212 NSR_ResolveSources();
213}
214
215/* ================================================== */
216
7fda9c67
ML
217static void
218reference_mode_end(int result)
219{
220 switch (ref_mode) {
221 case REF_ModeNormal:
70feea48
ML
222 case REF_ModeUpdateOnce:
223 case REF_ModePrintOnce:
93b66ac1
ML
224 exit_status = !result;
225 SCH_QuitProgram();
7fda9c67
ML
226 break;
227 case REF_ModeInitStepSlew:
ead3ca14
ML
228 /* Switch to the normal mode, the delay is used to prevent polling
229 interval shorter than the burst interval if some configured servers
230 were used also for initstepslew */
231 SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL);
7fda9c67
ML
232 break;
233 default:
234 assert(0);
235 }
236}
237
238/* ================================================== */
239
88840341
RC
240static void
241post_init_rtc_hook(void *anything)
242{
7fda9c67
ML
243 if (CNF_GetInitSources() > 0) {
244 CNF_AddInitSources();
779e40ed 245 NSR_StartSources();
7fda9c67
ML
246 assert(REF_GetMode() != REF_ModeNormal);
247 /* Wait for mode end notification */
248 } else {
249 (post_init_ntp_hook)(NULL);
250 }
88840341
RC
251}
252
253/* ================================================== */
88840341 254
7bd1c027
ML
255static void
256check_pidfile(void)
88840341
RC
257{
258 const char *pidfile = CNF_GetPidFile();
259 FILE *in;
260 int pid, count;
261
60049f15 262 if (!pidfile)
077dbd56
ML
263 return;
264
e18903a6 265 in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0);
7bd1c027
ML
266 if (!in)
267 return;
88840341
RC
268
269 count = fscanf(in, "%d", &pid);
270 fclose(in);
271
7bd1c027
ML
272 if (count != 1)
273 return;
88840341 274
7bd1c027
ML
275 if (getsid(pid) < 0)
276 return;
277
278 LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
279 pid, pidfile);
88840341
RC
280}
281
282/* ================================================== */
283
284static void
7bd1c027 285write_pidfile(void)
88840341
RC
286{
287 const char *pidfile = CNF_GetPidFile();
288 FILE *out;
289
60049f15 290 if (!pidfile)
778fce40
ML
291 return;
292
e18903a6
ML
293 out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
294 fprintf(out, "%d\n", (int)getpid());
295 fclose(out);
88840341
RC
296}
297
298/* ================================================== */
299
da862158
ML
300#define DEV_NULL "/dev/null"
301
fe4b661f
ML
302static void
303go_daemon(void)
304{
1d2a0856
ML
305 int pid, fd, pipefd[2];
306
307 /* Create pipe which will the daemon use to notify the grandparent
308 when it's initialised or send an error message */
309 if (pipe(pipefd)) {
539ef3f7 310 LOG_FATAL("pipe() failed : %s", strerror(errno));
1d2a0856 311 }
fe4b661f
ML
312
313 /* Does this preserve existing signal handlers? */
314 pid = fork();
315
316 if (pid < 0) {
539ef3f7 317 LOG_FATAL("fork() failed : %s", strerror(errno));
fe4b661f 318 } else if (pid > 0) {
1d2a0856
ML
319 /* In the 'grandparent' */
320 char message[1024];
321 int r;
322
323 close(pipefd[1]);
324 r = read(pipefd[0], message, sizeof (message));
325 if (r) {
326 if (r > 0) {
327 /* Print the error message from the child */
a7802e9a
ML
328 message[sizeof (message) - 1] = '\0';
329 fprintf(stderr, "%s\n", message);
1d2a0856
ML
330 }
331 exit(1);
332 } else
333 exit(0);
fe4b661f 334 } else {
1d2a0856 335 close(pipefd[0]);
fe4b661f
ML
336
337 setsid();
338
339 /* Do 2nd fork, as-per recommended practice for launching daemons. */
340 pid = fork();
341
342 if (pid < 0) {
539ef3f7 343 LOG_FATAL("fork() failed : %s", strerror(errno));
fe4b661f
ML
344 } else if (pid > 0) {
345 exit(0); /* In the 'parent' */
346 } else {
347 /* In the child we want to leave running as the daemon */
348
2a305d8e
ML
349 /* Change current directory to / */
350 if (chdir("/") < 0) {
539ef3f7 351 LOG_FATAL("chdir() failed : %s", strerror(errno));
2a305d8e
ML
352 }
353
1d2a0856
ML
354 /* Don't keep stdin/out/err from before. But don't close
355 the parent pipe yet. */
fe4b661f 356 for (fd=0; fd<1024; fd++) {
1d2a0856
ML
357 if (fd != pipefd[1])
358 close(fd);
fe4b661f 359 }
919b5b5a 360
1d2a0856 361 LOG_SetParentFd(pipefd[1]);
da862158
ML
362
363 /* Open /dev/null as new stdin/out/err */
364 errno = 0;
365 if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
366 open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
367 open(DEV_NULL, O_RDWR) != STDERR_FILENO)
368 LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
fe4b661f
ML
369 }
370 }
fe4b661f
ML
371}
372
373/* ================================================== */
374
ae0c3bbb
ML
375static void
376print_help(const char *progname)
377{
0e08ca7c
ML
378 printf("Usage: %s [OPTION]... [DIRECTIVE]...\n\n"
379 "Options:\n"
380 " -4\t\tUse IPv4 addresses only\n"
381 " -6\t\tUse IPv6 addresses only\n"
382 " -f FILE\tSpecify configuration file (%s)\n"
383 " -n\t\tDon't run as daemon\n"
384 " -d\t\tDon't run as daemon and log to stderr\n"
385#if DEBUG > 0
386 " -d -d\t\tEnable debug messages\n"
387#endif
388 " -l FILE\tLog to file\n"
389 " -L LEVEL\tSet logging threshold (0)\n"
390 " -p\t\tPrint configuration and exit\n"
391 " -q\t\tSet clock and exit\n"
392 " -Q\t\tLog offset and exit\n"
393 " -r\t\tReload dump files\n"
394 " -R\t\tAdapt configuration for restart\n"
395 " -s\t\tSet clock from RTC\n"
396 " -t SECONDS\tExit after elapsed time\n"
397 " -u USER\tSpecify user (%s)\n"
398 " -U\t\tDon't check for root\n"
399 " -F LEVEL\tSet system call filter level (0)\n"
400 " -P PRIORITY\tSet process priority (0)\n"
401 " -m\t\tLock memory\n"
402 " -x\t\tDon't control clock\n"
403 " -v, --version\tPrint version and exit\n"
404 " -h, --help\tPrint usage and exit\n",
405 progname, DEFAULT_CONF_FILE, DEFAULT_USER);
ae0c3bbb
ML
406}
407
408/* ================================================== */
409
410static void
411print_version(void)
412{
413 printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
414}
415
416/* ================================================== */
417
418static int
419parse_int_arg(const char *arg)
420{
421 int i;
422
423 if (sscanf(arg, "%d", &i) != 1)
424 LOG_FATAL("Invalid argument %s", arg);
425 return i;
426}
427
428/* ================================================== */
429
88840341
RC
430int main
431(int argc, char **argv)
432{
0f8def4c 433 const char *conf_file = DEFAULT_CONF_FILE;
1cda2db4 434 const char *progname = argv[0];
a1cbd4eb 435 char *user = NULL, *log_file = NULL;
6402350c 436 struct passwd *pw;
ae0c3bbb 437 int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
552d3b53 438 int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1;
434faeec 439 int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
70fa3a69 440 int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
02c38934 441 int user_check = 1, config_args = 0, print_config = 0;
35e662d8 442
bafb434f
ML
443 do_platform_checks();
444
88840341
RC
445 LOG_Initialise();
446
068cd3c3 447 /* Parse long command-line options */
ae0c3bbb
ML
448 for (optind = 1; optind < argc; optind++) {
449 if (!strcmp("--help", argv[optind])) {
450 print_help(progname);
1769b8ea 451 return 0;
ae0c3bbb
ML
452 } else if (!strcmp("--version", argv[optind])) {
453 print_version();
1769b8ea 454 return 0;
ae0c3bbb
ML
455 }
456 }
457
458 optind = 1;
459
460 /* Parse short command-line options */
02c38934 461 while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -1) {
ae0c3bbb
ML
462 switch (opt) {
463 case '4':
464 case '6':
465 address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
466 break;
467 case 'd':
468 debug++;
469 nofork = 1;
470 system_log = 0;
471 break;
472 case 'f':
473 conf_file = optarg;
474 break;
475 case 'F':
476 scfilter_level = parse_int_arg(optarg);
477 break;
478 case 'l':
479 log_file = optarg;
480 break;
70fa3a69
ML
481 case 'L':
482 log_severity = parse_int_arg(optarg);
483 break;
ae0c3bbb
ML
484 case 'm':
485 lock_memory = 1;
486 break;
487 case 'n':
488 nofork = 1;
489 break;
1b82604f
ML
490 case 'p':
491 print_config = 1;
02c38934 492 user_check = 0;
1b82604f
ML
493 nofork = 1;
494 system_log = 0;
517b1ae2 495 log_severity = LOGS_WARN;
1b82604f 496 break;
ae0c3bbb
ML
497 case 'P':
498 sched_priority = parse_int_arg(optarg);
499 break;
500 case 'q':
4f1fc1ee
BC
501 ref_mode = REF_ModeUpdateOnce;
502 nofork = 1;
503 client_only = 0;
504 system_log = 0;
505 break;
ae0c3bbb 506 case 'Q':
4f1fc1ee 507 ref_mode = REF_ModePrintOnce;
ae0c3bbb 508 nofork = 1;
778fce40 509 client_only = 1;
02c38934 510 user_check = 0;
778fce40 511 clock_control = 0;
ae0c3bbb
ML
512 system_log = 0;
513 break;
514 case 'r':
515 reload = 1;
516 break;
517 case 'R':
518 restarted = 1;
519 break;
520 case 's':
521 do_init_rtc = 1;
522 break;
523 case 't':
524 timeout = parse_int_arg(optarg);
525 break;
526 case 'u':
527 user = optarg;
528 break;
02c38934
ML
529 case 'U':
530 user_check = 0;
531 break;
ae0c3bbb
ML
532 case 'v':
533 print_version();
534 return 0;
535 case 'x':
536 clock_control = 0;
537 break;
538 default:
539 print_help(progname);
540 return opt != 'h';
88840341
RC
541 }
542 }
543
02c38934 544 if (user_check && getuid() != 0)
3a5566c6 545 LOG_FATAL("Not superuser");
88840341 546
88840341 547 /* Turn into a daemon */
fe4b661f
ML
548 if (!nofork) {
549 go_daemon();
550 }
551
a1cbd4eb
ML
552 if (log_file) {
553 LOG_OpenFileLog(log_file);
554 } else if (system_log) {
fe4b661f 555 LOG_OpenSystemLog();
88840341
RC
556 }
557
70fa3a69 558 LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity);
4bbc5520 559
f282856c 560 LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
cb905507 561
72d0b3c9
ML
562 DNS_SetAddressFamily(address_family);
563
778fce40 564 CNF_Initialise(restarted, client_only);
1b82604f
ML
565 if (print_config)
566 CNF_EnablePrint();
3edd3fe5
ML
567
568 /* Parse the config file or the remaining command line arguments */
ae0c3bbb 569 config_args = argc - optind;
3edd3fe5
ML
570 if (!config_args) {
571 CNF_ReadFile(conf_file);
572 } else {
ae0c3bbb
ML
573 for (; optind < argc; optind++)
574 CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
3edd3fe5 575 }
1e35b268 576
1b82604f
ML
577 if (print_config)
578 return 0;
579
7bd1c027
ML
580 /* Check whether another chronyd may already be running */
581 check_pidfile();
88840341 582
c5d8af02
ML
583 if (!user)
584 user = CNF_GetUser();
585
586 pw = getpwnam(user);
587 if (!pw)
588 LOG_FATAL("Could not get user/group ID of %s", user);
589
590 /* Create directories for sockets, log files, and dump files */
591 CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
592
26e08abe
ML
593 /* Write our pidfile to prevent other instances from running */
594 write_pidfile();
595
334ac061 596 PRV_Initialise();
88840341
RC
597 LCL_Initialise();
598 SCH_Initialise();
66e097e3
ML
599 SCK_Initialise(address_family);
600
601 /* Start helper processes if needed */
602 NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level);
603
c4434609 604 SYS_Initialise(clock_control);
c6e06420 605 RTC_Initialise(do_init_rtc);
3a222336 606 SRC_Initialise();
ac30bb06 607 RCL_Initialise();
1c901b82 608 KEY_Initialise();
be42b4ee 609
8854c00d 610 /* Open privileged ports before dropping root */
27e20a56
ML
611 CAM_Initialise();
612 NIO_Initialise();
8854c00d
ML
613 NCR_Initialise();
614 CNF_SetupAccessRestrictions();
615
e3234465
ML
616 /* Command-line switch must have priority */
617 if (!sched_priority) {
618 sched_priority = CNF_GetSchedPriority();
619 }
620 if (sched_priority) {
621 SYS_SetScheduler(sched_priority);
96759116
ML
622 }
623
e3234465
ML
624 if (lock_memory || CNF_GetLockMemory()) {
625 SYS_LockMemory();
96759116
ML
626 }
627
778fce40
ML
628 /* Drop root privileges if the specified user has a non-zero UID */
629 if (!geteuid() && (pw->pw_uid || pw->pw_gid))
a96d2880 630 SYS_DropRoot(pw->pw_uid, pw->pw_gid, SYS_MAIN_PROCESS);
be42b4ee 631
4f878ba1
ML
632 if (!geteuid())
633 LOG(LOGS_WARN, "Running with root privileges");
634
88840341
RC
635 REF_Initialise();
636 SST_Initialise();
88840341 637 NSR_Initialise();
577aed48 638 NSD_Initialise();
6043632f 639 NNS_Initialise();
66e097e3 640 NKS_Initialise();
88840341 641 CLG_Initialise();
88840341 642 MNL_Initialise();
c386d117 643 TMC_Initialise();
7f45eb79 644 SMT_Initialise();
88840341
RC
645
646 /* From now on, it is safe to do finalisation on exit */
647 initialised = 1;
648
879d9362 649 UTI_SetQuitSignalsHandler(signal_cleanup, 1);
ea2858b3 650
8854c00d 651 CAM_OpenUnixSocket();
46951b85 652
434faeec 653 if (scfilter_level)
e6848b1e 654 SYS_EnableSystemCallFilter(scfilter_level, SYS_MAIN_PROCESS);
434faeec 655
70feea48 656 if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
7fda9c67
ML
657 ref_mode = REF_ModeInitStepSlew;
658 }
659
660 REF_SetModeEndHandler(reference_mode_end);
661 REF_SetMode(ref_mode);
662
552d3b53 663 if (timeout >= 0)
35134848
ML
664 SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);
665
88840341
RC
666 if (do_init_rtc) {
667 RTC_TimeInit(post_init_rtc_hook, NULL);
668 } else {
669 post_init_rtc_hook(NULL);
670 }
671
88840341
RC
672 /* The program normally runs under control of the main loop in
673 the scheduler. */
674 SCH_MainLoop();
675
f282856c 676 LOG(LOGS_INFO, "chronyd exiting");
0fc9b555 677
88840341
RC
678 MAI_CleanupAndExit();
679
680 return 0;
681}
682
683/* ================================================== */