If the reload sources command was received in the chronyd start-up
sequence with initstepslew and/or RTC init (-s option), the sources
loaded from sourcedirs caused a crash due to failed assertion after
adding sources specified in the config.
Ignore the reload sources command until chronyd enters the normal
operation mode.
Fixes: 519796de37
("conf: add sourcedirs directive")
2673 lines
66 KiB
C
2673 lines
66 KiB
C
/*
|
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
|
|
**********************************************************************
|
|
* Copyright (C) Richard P. Curnow 1997-2003
|
|
* Copyright (C) Miroslav Lichvar 2009-2017, 2020
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
**********************************************************************
|
|
|
|
=======================================================================
|
|
|
|
Module that reads and processes the configuration file.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "sysincl.h"
|
|
|
|
#include "array.h"
|
|
#include "conf.h"
|
|
#include "ntp_sources.h"
|
|
#include "ntp_core.h"
|
|
#include "nts_ke.h"
|
|
#include "refclock.h"
|
|
#include "cmdmon.h"
|
|
#include "socket.h"
|
|
#include "srcparams.h"
|
|
#include "logging.h"
|
|
#include "nameserv.h"
|
|
#include "memory.h"
|
|
#include "cmdparse.h"
|
|
#include "util.h"
|
|
|
|
/* ================================================== */
|
|
|
|
#define MAX_LINE_LENGTH 2048
|
|
#define MAX_CONF_DIRS 10
|
|
#define MAX_INCLUDE_LEVEL 10
|
|
|
|
/* ================================================== */
|
|
/* Forward prototypes */
|
|
|
|
static int parse_string(char *line, char **result);
|
|
static int parse_int(char *line, int *result);
|
|
static int parse_double(char *line, double *result);
|
|
static int parse_null(char *line);
|
|
|
|
static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow);
|
|
static void parse_authselectmode(char *);
|
|
static void parse_bindacqaddress(char *);
|
|
static void parse_bindaddress(char *);
|
|
static void parse_bindcmdaddress(char *);
|
|
static void parse_broadcast(char *);
|
|
static void parse_clientloglimit(char *);
|
|
static void parse_confdir(char *);
|
|
static void parse_fallbackdrift(char *);
|
|
static void parse_hwtimestamp(char *);
|
|
static void parse_include(char *);
|
|
static void parse_initstepslew(char *);
|
|
static void parse_leapsecmode(char *);
|
|
static void parse_local(char *);
|
|
static void parse_log(char *);
|
|
static void parse_mailonchange(char *);
|
|
static void parse_makestep(char *);
|
|
static void parse_maxchange(char *);
|
|
static void parse_ntsserver(char *, ARR_Instance files);
|
|
static void parse_ntstrustedcerts(char *);
|
|
static void parse_ratelimit(char *line, int *enabled, int *interval,
|
|
int *burst, int *leak);
|
|
static void parse_refclock(char *);
|
|
static void parse_smoothtime(char *);
|
|
static void parse_source(char *line, char *type, int fatal);
|
|
static void parse_sourcedir(char *);
|
|
static void parse_tempcomp(char *);
|
|
|
|
/* ================================================== */
|
|
/* Configuration variables */
|
|
|
|
static int print_config = 0;
|
|
static int restarted = 0;
|
|
static char *rtc_device;
|
|
static int acquisition_port = -1;
|
|
static int ntp_port = NTP_PORT;
|
|
static char *keys_file = NULL;
|
|
static char *drift_file = NULL;
|
|
static char *rtc_file = NULL;
|
|
static double max_update_skew = 1000.0;
|
|
static double correction_time_ratio = 3.0;
|
|
static double max_clock_error = 1.0; /* in ppm */
|
|
static double max_drift = 500000.0; /* in ppm */
|
|
static double max_slew_rate = 1e6 / 12.0; /* in ppm */
|
|
static double clock_precision = 0.0; /* in seconds */
|
|
|
|
static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX;
|
|
static double max_distance = 3.0;
|
|
static double max_jitter = 1.0;
|
|
static double reselect_distance = 1e-4;
|
|
static double stratum_weight = 1e-3;
|
|
static double combine_limit = 3.0;
|
|
|
|
static int cmd_port = DEFAULT_CANDM_PORT;
|
|
|
|
static int raw_measurements = 0;
|
|
static int do_log_measurements = 0;
|
|
static int do_log_selection = 0;
|
|
static int do_log_statistics = 0;
|
|
static int do_log_tracking = 0;
|
|
static int do_log_rtc = 0;
|
|
static int do_log_refclocks = 0;
|
|
static int do_log_tempcomp = 0;
|
|
static int log_banner = 32;
|
|
static char *logdir = NULL;
|
|
static char *dumpdir = NULL;
|
|
|
|
static int enable_local=0;
|
|
static int local_stratum;
|
|
static int local_orphan;
|
|
static double local_distance;
|
|
|
|
/* Threshold (in seconds) - if absolute value of initial error is less
|
|
than this, slew instead of stepping */
|
|
static double init_slew_threshold;
|
|
/* Array of IPAddr */
|
|
static ARR_Instance init_sources;
|
|
|
|
static int enable_manual=0;
|
|
|
|
/* Flag set if the RTC runs UTC (default is it runs local time
|
|
incl. daylight saving). */
|
|
static int rtc_on_utc = 0;
|
|
|
|
/* Filename used to read the hwclock(8) LOCAL/UTC setting */
|
|
static char *hwclock_file;
|
|
|
|
/* Flag set if the RTC should be automatically synchronised by kernel */
|
|
static int rtc_sync = 0;
|
|
|
|
/* Limit and threshold for clock stepping */
|
|
static int make_step_limit = 0;
|
|
static double make_step_threshold = 0.0;
|
|
|
|
/* Threshold for automatic RTC trimming */
|
|
static double rtc_autotrim_threshold = 0.0;
|
|
|
|
/* Minimum number of selectables sources required to update the clock */
|
|
static int min_sources = 1;
|
|
|
|
/* Number of updates before offset checking, number of ignored updates
|
|
before exiting and the maximum allowed offset */
|
|
static int max_offset_delay = -1;
|
|
static int max_offset_ignore;
|
|
static double max_offset;
|
|
|
|
/* Maximum and minimum number of samples per source */
|
|
static int max_samples = 0; /* no limit */
|
|
static int min_samples = 6;
|
|
|
|
/* Threshold for a time adjustment to be logged to syslog */
|
|
static double log_change_threshold = 1.0;
|
|
|
|
static char *mail_user_on_change = NULL;
|
|
static double mail_change_threshold = 0.0;
|
|
|
|
/* Flag indicating that we don't want to log clients, e.g. to save
|
|
memory */
|
|
static int no_client_log = 0;
|
|
|
|
/* Limit memory allocated for the clients log */
|
|
static unsigned long client_log_limit = 524288;
|
|
|
|
/* Minimum and maximum fallback drift intervals */
|
|
static int fb_drift_min = 0;
|
|
static int fb_drift_max = 0;
|
|
|
|
/* IP addresses for binding the NTP server sockets to. UNSPEC family means
|
|
INADDR_ANY will be used */
|
|
static IPAddr bind_address4, bind_address6;
|
|
|
|
/* IP addresses for binding the NTP client sockets to. UNSPEC family means
|
|
INADDR_ANY will be used */
|
|
static IPAddr bind_acq_address4, bind_acq_address6;
|
|
|
|
/* IP addresses for binding the command socket to. UNSPEC family means
|
|
the loopback address will be used */
|
|
static IPAddr bind_cmd_address4, bind_cmd_address6;
|
|
|
|
/* Interface names to bind the NTP server, NTP client, and command socket */
|
|
static char *bind_ntp_iface = NULL;
|
|
static char *bind_acq_iface = NULL;
|
|
static char *bind_cmd_iface = NULL;
|
|
|
|
/* Path to the Unix domain command socket. */
|
|
static char *bind_cmd_path = NULL;
|
|
|
|
/* Differentiated Services Code Point (DSCP) in transmitted NTP packets */
|
|
static int ntp_dscp = 0;
|
|
|
|
/* Path to Samba (ntp_signd) socket. */
|
|
static char *ntp_signd_socket = NULL;
|
|
|
|
/* Filename to use for storing pid of running chronyd, to prevent multiple
|
|
* chronyds being started. */
|
|
static char *pidfile = NULL;
|
|
|
|
/* Rate limiting parameters */
|
|
static int ntp_ratelimit_enabled = 0;
|
|
static int ntp_ratelimit_interval = 3;
|
|
static int ntp_ratelimit_burst = 8;
|
|
static int ntp_ratelimit_leak = 2;
|
|
static int nts_ratelimit_enabled = 0;
|
|
static int nts_ratelimit_interval = 6;
|
|
static int nts_ratelimit_burst = 8;
|
|
static int nts_ratelimit_leak = 2;
|
|
static int cmd_ratelimit_enabled = 0;
|
|
static int cmd_ratelimit_interval = -4;
|
|
static int cmd_ratelimit_burst = 8;
|
|
static int cmd_ratelimit_leak = 2;
|
|
|
|
/* Smoothing constants */
|
|
static double smooth_max_freq = 0.0; /* in ppm */
|
|
static double smooth_max_wander = 0.0; /* in ppm/s */
|
|
static int smooth_leap_only = 0;
|
|
|
|
/* Temperature sensor, update interval and compensation coefficients */
|
|
static char *tempcomp_sensor_file = NULL;
|
|
static char *tempcomp_point_file = NULL;
|
|
static double tempcomp_interval;
|
|
static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
|
|
|
|
static int sched_priority = 0;
|
|
static int lock_memory = 0;
|
|
|
|
/* Leap second handling mode */
|
|
static REF_LeapMode leapsec_mode = REF_LeapModeSystem;
|
|
|
|
/* Name of a system timezone containing leap seconds occuring at midnight */
|
|
static char *leapsec_tz = NULL;
|
|
|
|
/* File name of leap seconds list, usually /usr/share/zoneinfo/leap-seconds.list */
|
|
static char *leapsec_list = NULL;
|
|
|
|
/* Name of the user to which will be dropped root privileges. */
|
|
static char *user;
|
|
|
|
/* Address refresh interval */
|
|
static int refresh = 1209600; /* 2 weeks */
|
|
|
|
/* NTS server and client configuration */
|
|
static char *nts_dump_dir = NULL;
|
|
static char *nts_ntp_server = NULL;
|
|
static ARR_Instance nts_server_cert_files; /* array of (char *) */
|
|
static ARR_Instance nts_server_key_files; /* array of (char *) */
|
|
static int nts_server_port = NKE_PORT;
|
|
static int nts_server_processes = 1;
|
|
static int nts_server_connections = 100;
|
|
static int nts_refresh = 2419200; /* 4 weeks */
|
|
static int nts_rotate = 604800; /* 1 week */
|
|
static ARR_Instance nts_trusted_certs_paths; /* array of (char *) */
|
|
static ARR_Instance nts_trusted_certs_ids; /* array of uint32_t */
|
|
|
|
/* Number of clock updates needed to enable certificate time checks */
|
|
static int no_cert_time_check = 0;
|
|
|
|
/* Flag disabling use of system trusted certificates */
|
|
static int no_system_cert = 0;
|
|
|
|
/* Array of CNF_HwTsInterface */
|
|
static ARR_Instance hwts_interfaces;
|
|
|
|
/* Timeout for resuming reading from sockets waiting for HW TX timestamp */
|
|
static double hwts_timeout = 0.001;
|
|
|
|
/* PTP event port (disabled by default) */
|
|
static int ptp_port = 0;
|
|
|
|
typedef struct {
|
|
NTP_Source_Type type;
|
|
int pool;
|
|
CPS_NTP_Source params;
|
|
} NTP_Source;
|
|
|
|
/* Array of NTP_Source */
|
|
static ARR_Instance ntp_sources;
|
|
/* Array of (char *) */
|
|
static ARR_Instance ntp_source_dirs;
|
|
/* Array of uint32_t corresponding to ntp_sources (for sourcedirs reload) */
|
|
static ARR_Instance ntp_source_ids;
|
|
/* Flag indicating ntp_sources and ntp_source_ids are used for sourcedirs */
|
|
static int conf_ntp_sources_added = 0;
|
|
|
|
/* Array of RefclockParameters */
|
|
static ARR_Instance refclock_sources;
|
|
|
|
typedef struct _AllowDeny {
|
|
IPAddr ip;
|
|
int subnet_bits;
|
|
int all; /* 1 to override existing more specific defns */
|
|
int allow; /* 0 for deny, 1 for allow */
|
|
} AllowDeny;
|
|
|
|
/* Arrays of AllowDeny */
|
|
static ARR_Instance ntp_restrictions;
|
|
static ARR_Instance cmd_restrictions;
|
|
|
|
typedef struct {
|
|
NTP_Remote_Address addr;
|
|
int interval;
|
|
} NTP_Broadcast_Destination;
|
|
|
|
/* Array of NTP_Broadcast_Destination */
|
|
static ARR_Instance broadcasts;
|
|
|
|
/* ================================================== */
|
|
|
|
/* The line number in the configuration file being processed */
|
|
static int line_number;
|
|
static const char *processed_file;
|
|
static const char *processed_command;
|
|
|
|
static int include_level = 0;
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
command_parse_error(void)
|
|
{
|
|
LOG_FATAL("Could not parse %s directive at line %d%s%s",
|
|
processed_command, line_number, processed_file ? " in file " : "",
|
|
processed_file ? processed_file : "");
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
other_parse_error(const char *message)
|
|
{
|
|
LOG_FATAL("%s at line %d%s%s",
|
|
message, line_number, processed_file ? " in file " : "",
|
|
processed_file ? processed_file : "");
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
get_number_of_args(char *line)
|
|
{
|
|
int num = 0;
|
|
|
|
/* The line is normalized, between arguments is just one space */
|
|
if (*line == ' ')
|
|
line++;
|
|
if (*line)
|
|
num++;
|
|
for (; *line; line++) {
|
|
if (*line == ' ')
|
|
num++;
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
check_number_of_args(char *line, int num)
|
|
{
|
|
num -= get_number_of_args(line);
|
|
|
|
if (num) {
|
|
LOG_FATAL("%s arguments for %s directive at line %d%s%s",
|
|
num > 0 ? "Missing" : "Too many",
|
|
processed_command, line_number, processed_file ? " in file " : "",
|
|
processed_file ? processed_file : "");
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_Initialise(int r, int client_only)
|
|
{
|
|
restarted = r;
|
|
|
|
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
|
|
|
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
|
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
|
ntp_source_dirs = ARR_CreateInstance(sizeof (char *));
|
|
ntp_source_ids = ARR_CreateInstance(sizeof (uint32_t));
|
|
refclock_sources = ARR_CreateInstance(sizeof (RefclockParameters));
|
|
broadcasts = ARR_CreateInstance(sizeof (NTP_Broadcast_Destination));
|
|
|
|
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
|
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
|
|
|
nts_server_cert_files = ARR_CreateInstance(sizeof (char *));
|
|
nts_server_key_files = ARR_CreateInstance(sizeof (char *));
|
|
nts_trusted_certs_paths = ARR_CreateInstance(sizeof (char *));
|
|
nts_trusted_certs_ids = ARR_CreateInstance(sizeof (uint32_t));
|
|
|
|
rtc_device = Strdup(DEFAULT_RTC_DEVICE);
|
|
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
|
|
user = Strdup(DEFAULT_USER);
|
|
|
|
if (client_only) {
|
|
cmd_port = ntp_port = 0;
|
|
} else {
|
|
bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
|
|
pidfile = Strdup(DEFAULT_PID_FILE);
|
|
}
|
|
|
|
SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_address4);
|
|
SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_address6);
|
|
SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_acq_address4);
|
|
SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_acq_address6);
|
|
SCK_GetLoopbackIPAddress(IPADDR_INET4, &bind_cmd_address4);
|
|
SCK_GetLoopbackIPAddress(IPADDR_INET6, &bind_cmd_address6);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_Finalise(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
|
Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
|
|
ARR_DestroyInstance(hwts_interfaces);
|
|
|
|
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
|
Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name);
|
|
for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++)
|
|
Free(*(char **)ARR_GetElement(ntp_source_dirs, i));
|
|
for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
|
|
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_name);
|
|
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_parameter);
|
|
}
|
|
for (i = 0; i < ARR_GetSize(nts_server_cert_files); i++)
|
|
Free(*(char **)ARR_GetElement(nts_server_cert_files, i));
|
|
for (i = 0; i < ARR_GetSize(nts_server_key_files); i++)
|
|
Free(*(char **)ARR_GetElement(nts_server_key_files, i));
|
|
for (i = 0; i < ARR_GetSize(nts_trusted_certs_paths); i++)
|
|
Free(*(char **)ARR_GetElement(nts_trusted_certs_paths, i));
|
|
|
|
ARR_DestroyInstance(init_sources);
|
|
ARR_DestroyInstance(ntp_sources);
|
|
ARR_DestroyInstance(ntp_source_dirs);
|
|
ARR_DestroyInstance(ntp_source_ids);
|
|
ARR_DestroyInstance(refclock_sources);
|
|
ARR_DestroyInstance(broadcasts);
|
|
|
|
ARR_DestroyInstance(ntp_restrictions);
|
|
ARR_DestroyInstance(cmd_restrictions);
|
|
|
|
ARR_DestroyInstance(nts_server_cert_files);
|
|
ARR_DestroyInstance(nts_server_key_files);
|
|
ARR_DestroyInstance(nts_trusted_certs_paths);
|
|
ARR_DestroyInstance(nts_trusted_certs_ids);
|
|
|
|
Free(drift_file);
|
|
Free(dumpdir);
|
|
Free(hwclock_file);
|
|
Free(keys_file);
|
|
Free(leapsec_tz);
|
|
Free(leapsec_list);
|
|
Free(logdir);
|
|
Free(bind_ntp_iface);
|
|
Free(bind_acq_iface);
|
|
Free(bind_cmd_iface);
|
|
Free(bind_cmd_path);
|
|
Free(ntp_signd_socket);
|
|
Free(pidfile);
|
|
Free(rtc_device);
|
|
Free(rtc_file);
|
|
Free(user);
|
|
Free(mail_user_on_change);
|
|
Free(tempcomp_sensor_file);
|
|
Free(tempcomp_point_file);
|
|
Free(nts_dump_dir);
|
|
Free(nts_ntp_server);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_EnablePrint(void)
|
|
{
|
|
print_config = 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
/* Read the configuration file */
|
|
void
|
|
CNF_ReadFile(const char *filename)
|
|
{
|
|
FILE *in;
|
|
char line[MAX_LINE_LENGTH + 1];
|
|
int i;
|
|
|
|
include_level++;
|
|
if (include_level > MAX_INCLUDE_LEVEL)
|
|
LOG_FATAL("Maximum include level reached");
|
|
|
|
in = UTI_OpenFile(NULL, filename, NULL, 'R', 0);
|
|
|
|
for (i = 1; fgets(line, sizeof(line), in); i++) {
|
|
CNF_ParseLine(filename, i, line);
|
|
}
|
|
|
|
fclose(in);
|
|
|
|
include_level--;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
/* Parse one configuration line */
|
|
void
|
|
CNF_ParseLine(const char *filename, int number, char *line)
|
|
{
|
|
char *p, *command;
|
|
|
|
/* Set global variables used in error messages */
|
|
processed_file = filename;
|
|
line_number = number;
|
|
|
|
/* Detect truncated line */
|
|
if (strlen(line) >= MAX_LINE_LENGTH)
|
|
other_parse_error("String too long");
|
|
|
|
/* Remove extra white-space and comments */
|
|
CPS_NormalizeLine(line);
|
|
|
|
/* Skip blank lines */
|
|
if (!*line) {
|
|
processed_file = NULL;
|
|
return;
|
|
}
|
|
|
|
/* We have a real line, now try to match commands */
|
|
processed_command = command = line;
|
|
p = CPS_SplitWord(line);
|
|
|
|
if (print_config && strcasecmp(command, "include") && strcasecmp(command, "confdir"))
|
|
printf("%s%s%s\n", command, p[0] != '\0' ? " " : "", p);
|
|
|
|
if (!strcasecmp(command, "acquisitionport")) {
|
|
parse_int(p, &acquisition_port);
|
|
} else if (!strcasecmp(command, "allow")) {
|
|
parse_allow_deny(p, ntp_restrictions, 1);
|
|
} else if (!strcasecmp(command, "authselectmode")) {
|
|
parse_authselectmode(p);
|
|
} else if (!strcasecmp(command, "bindacqaddress")) {
|
|
parse_bindacqaddress(p);
|
|
} else if (!strcasecmp(command, "bindacqdevice")) {
|
|
parse_string(p, &bind_acq_iface);
|
|
} else if (!strcasecmp(command, "bindaddress")) {
|
|
parse_bindaddress(p);
|
|
} else if (!strcasecmp(command, "bindcmdaddress")) {
|
|
parse_bindcmdaddress(p);
|
|
} else if (!strcasecmp(command, "bindcmddevice")) {
|
|
parse_string(p, &bind_cmd_iface);
|
|
} else if (!strcasecmp(command, "binddevice")) {
|
|
parse_string(p, &bind_ntp_iface);
|
|
} else if (!strcasecmp(command, "broadcast")) {
|
|
parse_broadcast(p);
|
|
} else if (!strcasecmp(command, "clientloglimit")) {
|
|
parse_clientloglimit(p);
|
|
} else if (!strcasecmp(command, "clockprecision")) {
|
|
parse_double(p, &clock_precision);
|
|
} else if (!strcasecmp(command, "cmdallow")) {
|
|
parse_allow_deny(p, cmd_restrictions, 1);
|
|
} else if (!strcasecmp(command, "cmddeny")) {
|
|
parse_allow_deny(p, cmd_restrictions, 0);
|
|
} else if (!strcasecmp(command, "cmdport")) {
|
|
parse_int(p, &cmd_port);
|
|
} else if (!strcasecmp(command, "cmdratelimit")) {
|
|
parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval,
|
|
&cmd_ratelimit_burst, &cmd_ratelimit_leak);
|
|
} else if (!strcasecmp(command, "combinelimit")) {
|
|
parse_double(p, &combine_limit);
|
|
} else if (!strcasecmp(command, "confdir")) {
|
|
parse_confdir(p);
|
|
} else if (!strcasecmp(command, "corrtimeratio")) {
|
|
parse_double(p, &correction_time_ratio);
|
|
} else if (!strcasecmp(command, "deny")) {
|
|
parse_allow_deny(p, ntp_restrictions, 0);
|
|
} else if (!strcasecmp(command, "driftfile")) {
|
|
parse_string(p, &drift_file);
|
|
} else if (!strcasecmp(command, "dscp")) {
|
|
parse_int(p, &ntp_dscp);
|
|
} else if (!strcasecmp(command, "dumpdir")) {
|
|
parse_string(p, &dumpdir);
|
|
} else if (!strcasecmp(command, "dumponexit")) {
|
|
/* Silently ignored */
|
|
} else if (!strcasecmp(command, "fallbackdrift")) {
|
|
parse_fallbackdrift(p);
|
|
} else if (!strcasecmp(command, "hwclockfile")) {
|
|
parse_string(p, &hwclock_file);
|
|
} else if (!strcasecmp(command, "hwtimestamp")) {
|
|
parse_hwtimestamp(p);
|
|
} else if (!strcasecmp(command, "hwtstimeout")) {
|
|
parse_double(p, &hwts_timeout);
|
|
} else if (!strcasecmp(command, "include")) {
|
|
parse_include(p);
|
|
} else if (!strcasecmp(command, "initstepslew")) {
|
|
parse_initstepslew(p);
|
|
} else if (!strcasecmp(command, "keyfile")) {
|
|
parse_string(p, &keys_file);
|
|
} else if (!strcasecmp(command, "leapsecmode")) {
|
|
parse_leapsecmode(p);
|
|
} else if (!strcasecmp(command, "leapsectz")) {
|
|
parse_string(p, &leapsec_tz);
|
|
} else if (!strcasecmp(command, "leapseclist")) {
|
|
parse_string(p, &leapsec_list);
|
|
} else if (!strcasecmp(command, "local")) {
|
|
parse_local(p);
|
|
} else if (!strcasecmp(command, "lock_all")) {
|
|
lock_memory = parse_null(p);
|
|
} else if (!strcasecmp(command, "log")) {
|
|
parse_log(p);
|
|
} else if (!strcasecmp(command, "logbanner")) {
|
|
parse_int(p, &log_banner);
|
|
} else if (!strcasecmp(command, "logchange")) {
|
|
parse_double(p, &log_change_threshold);
|
|
} else if (!strcasecmp(command, "logdir")) {
|
|
parse_string(p, &logdir);
|
|
} else if (!strcasecmp(command, "mailonchange")) {
|
|
parse_mailonchange(p);
|
|
} else if (!strcasecmp(command, "makestep")) {
|
|
parse_makestep(p);
|
|
} else if (!strcasecmp(command, "manual")) {
|
|
enable_manual = parse_null(p);
|
|
} else if (!strcasecmp(command, "maxchange")) {
|
|
parse_maxchange(p);
|
|
} else if (!strcasecmp(command, "maxclockerror")) {
|
|
parse_double(p, &max_clock_error);
|
|
} else if (!strcasecmp(command, "maxdistance")) {
|
|
parse_double(p, &max_distance);
|
|
} else if (!strcasecmp(command, "maxdrift")) {
|
|
parse_double(p, &max_drift);
|
|
} else if (!strcasecmp(command, "maxjitter")) {
|
|
parse_double(p, &max_jitter);
|
|
} else if (!strcasecmp(command, "maxntsconnections")) {
|
|
parse_int(p, &nts_server_connections);
|
|
} else if (!strcasecmp(command, "maxsamples")) {
|
|
parse_int(p, &max_samples);
|
|
} else if (!strcasecmp(command, "maxslewrate")) {
|
|
parse_double(p, &max_slew_rate);
|
|
} else if (!strcasecmp(command, "maxupdateskew")) {
|
|
parse_double(p, &max_update_skew);
|
|
} else if (!strcasecmp(command, "minsamples")) {
|
|
parse_int(p, &min_samples);
|
|
} else if (!strcasecmp(command, "minsources")) {
|
|
parse_int(p, &min_sources);
|
|
} else if (!strcasecmp(command, "nocerttimecheck")) {
|
|
parse_int(p, &no_cert_time_check);
|
|
} else if (!strcasecmp(command, "noclientlog")) {
|
|
no_client_log = parse_null(p);
|
|
} else if (!strcasecmp(command, "nosystemcert")) {
|
|
no_system_cert = parse_null(p);
|
|
} else if (!strcasecmp(command, "ntpsigndsocket")) {
|
|
parse_string(p, &ntp_signd_socket);
|
|
} else if (!strcasecmp(command, "ntsratelimit")) {
|
|
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval,
|
|
&nts_ratelimit_burst, &nts_ratelimit_leak);
|
|
} else if (!strcasecmp(command, "ntscachedir") ||
|
|
!strcasecmp(command, "ntsdumpdir")) {
|
|
parse_string(p, &nts_dump_dir);
|
|
} else if (!strcasecmp(command, "ntsntpserver")) {
|
|
parse_string(p, &nts_ntp_server);
|
|
} else if (!strcasecmp(command, "ntsport")) {
|
|
parse_int(p, &nts_server_port);
|
|
} else if (!strcasecmp(command, "ntsprocesses")) {
|
|
parse_int(p, &nts_server_processes);
|
|
} else if (!strcasecmp(command, "ntsrefresh")) {
|
|
parse_int(p, &nts_refresh);
|
|
} else if (!strcasecmp(command, "ntsrotate")) {
|
|
parse_int(p, &nts_rotate);
|
|
} else if (!strcasecmp(command, "ntsservercert")) {
|
|
parse_ntsserver(p, nts_server_cert_files);
|
|
} else if (!strcasecmp(command, "ntsserverkey")) {
|
|
parse_ntsserver(p, nts_server_key_files);
|
|
} else if (!strcasecmp(command, "ntstrustedcerts")) {
|
|
parse_ntstrustedcerts(p);
|
|
} else if (!strcasecmp(command, "peer")) {
|
|
parse_source(p, command, 1);
|
|
} else if (!strcasecmp(command, "pidfile")) {
|
|
parse_string(p, &pidfile);
|
|
} else if (!strcasecmp(command, "pool")) {
|
|
parse_source(p, command, 1);
|
|
} else if (!strcasecmp(command, "port")) {
|
|
parse_int(p, &ntp_port);
|
|
} else if (!strcasecmp(command, "ptpport")) {
|
|
parse_int(p, &ptp_port);
|
|
} else if (!strcasecmp(command, "ratelimit")) {
|
|
parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval,
|
|
&ntp_ratelimit_burst, &ntp_ratelimit_leak);
|
|
} else if (!strcasecmp(command, "refclock")) {
|
|
parse_refclock(p);
|
|
} else if (!strcasecmp(command, "refresh")) {
|
|
parse_int(p, &refresh);
|
|
} else if (!strcasecmp(command, "reselectdist")) {
|
|
parse_double(p, &reselect_distance);
|
|
} else if (!strcasecmp(command, "rtcautotrim")) {
|
|
parse_double(p, &rtc_autotrim_threshold);
|
|
} else if (!strcasecmp(command, "rtcdevice")) {
|
|
parse_string(p, &rtc_device);
|
|
} else if (!strcasecmp(command, "rtcfile")) {
|
|
parse_string(p, &rtc_file);
|
|
} else if (!strcasecmp(command, "rtconutc")) {
|
|
rtc_on_utc = parse_null(p);
|
|
} else if (!strcasecmp(command, "rtcsync")) {
|
|
rtc_sync = parse_null(p);
|
|
} else if (!strcasecmp(command, "sched_priority")) {
|
|
parse_int(p, &sched_priority);
|
|
} else if (!strcasecmp(command, "server")) {
|
|
parse_source(p, command, 1);
|
|
} else if (!strcasecmp(command, "smoothtime")) {
|
|
parse_smoothtime(p);
|
|
} else if (!strcasecmp(command, "sourcedir")) {
|
|
parse_sourcedir(p);
|
|
} else if (!strcasecmp(command, "stratumweight")) {
|
|
parse_double(p, &stratum_weight);
|
|
} else if (!strcasecmp(command, "tempcomp")) {
|
|
parse_tempcomp(p);
|
|
} else if (!strcasecmp(command, "user")) {
|
|
parse_string(p, &user);
|
|
} else if (!strcasecmp(command, "commandkey") ||
|
|
!strcasecmp(command, "generatecommandkey") ||
|
|
!strcasecmp(command, "linux_freq_scale") ||
|
|
!strcasecmp(command, "linux_hz")) {
|
|
LOG(LOGS_WARN, "%s directive is no longer supported", command);
|
|
} else {
|
|
other_parse_error("Invalid directive");
|
|
}
|
|
|
|
processed_file = processed_command = NULL;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
parse_string(char *line, char **result)
|
|
{
|
|
check_number_of_args(line, 1);
|
|
Free(*result);
|
|
*result = Strdup(line);
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
parse_int(char *line, int *result)
|
|
{
|
|
check_number_of_args(line, 1);
|
|
if (sscanf(line, "%d", result) != 1) {
|
|
command_parse_error();
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
parse_double(char *line, double *result)
|
|
{
|
|
check_number_of_args(line, 1);
|
|
if (sscanf(line, "%lf", result) != 1) {
|
|
command_parse_error();
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
parse_null(char *line)
|
|
{
|
|
check_number_of_args(line, 0);
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_source(char *line, char *type, int fatal)
|
|
{
|
|
NTP_Source source;
|
|
|
|
if (strcasecmp(type, "peer") == 0) {
|
|
source.type = NTP_PEER;
|
|
source.pool = 0;
|
|
} else if (strcasecmp(type, "pool") == 0) {
|
|
source.type = NTP_SERVER;
|
|
source.pool = 1;
|
|
} else if (strcasecmp(type, "server") == 0) {
|
|
source.type = NTP_SERVER;
|
|
source.pool = 0;
|
|
} else {
|
|
if (fatal)
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
/* Avoid comparing uninitialized data in compare_sources() */
|
|
memset(&source.params, 0, sizeof (source.params));
|
|
|
|
if (!CPS_ParseNTPSourceAdd(line, &source.params)) {
|
|
if (fatal)
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
source.params.name = Strdup(source.params.name);
|
|
ARR_AppendElement(ntp_sources, &source);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_sourcedir(char *line)
|
|
{
|
|
char *s;
|
|
|
|
s = Strdup(line);
|
|
ARR_AppendElement(ntp_source_dirs, &s);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak)
|
|
{
|
|
int n, val;
|
|
char *opt;
|
|
|
|
*enabled = 1;
|
|
|
|
while (*line) {
|
|
opt = line;
|
|
line = CPS_SplitWord(line);
|
|
if (sscanf(line, "%d%n", &val, &n) != 1) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
line += n;
|
|
if (!strcasecmp(opt, "interval"))
|
|
*interval = val;
|
|
else if (!strcasecmp(opt, "burst"))
|
|
*burst = val;
|
|
else if (!strcasecmp(opt, "leak"))
|
|
*leak = val;
|
|
else
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_refclock(char *line)
|
|
{
|
|
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
|
|
int local, max_lock_age, pps_forced, sel_option, stratum, tai;
|
|
uint32_t ref_id, lock_ref_id;
|
|
double offset, delay, precision, max_dispersion, pulse_width;
|
|
char *p, *cmd, *name, *param;
|
|
RefclockParameters *refclock;
|
|
|
|
poll = 4;
|
|
dpoll = 0;
|
|
filter_length = 64;
|
|
local = 0;
|
|
pps_forced = 0;
|
|
pps_rate = 0;
|
|
min_samples = SRC_DEFAULT_MINSAMPLES;
|
|
max_samples = SRC_DEFAULT_MAXSAMPLES;
|
|
sel_options = 0;
|
|
offset = 0.0;
|
|
delay = 1e-9;
|
|
precision = 0.0;
|
|
max_dispersion = 0.0;
|
|
pulse_width = 0.0;
|
|
ref_id = 0;
|
|
max_lock_age = 2;
|
|
lock_ref_id = 0;
|
|
stratum = 0;
|
|
tai = 0;
|
|
|
|
if (!*line) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!*line) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
name = Strdup(p);
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
param = Strdup(p);
|
|
|
|
for (cmd = line; *cmd; line += n, cmd = line) {
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!strcasecmp(cmd, "refid")) {
|
|
if ((n = CPS_ParseRefid(line, &ref_id)) == 0)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "lock")) {
|
|
if ((n = CPS_ParseRefid(line, &lock_ref_id)) == 0)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "poll")) {
|
|
if (sscanf(line, "%d%n", &poll, &n) != 1) {
|
|
break;
|
|
}
|
|
} else if (!strcasecmp(cmd, "dpoll")) {
|
|
if (sscanf(line, "%d%n", &dpoll, &n) != 1) {
|
|
break;
|
|
}
|
|
} else if (!strcasecmp(cmd, "filter")) {
|
|
if (sscanf(line, "%d%n", &filter_length, &n) != 1) {
|
|
break;
|
|
}
|
|
} else if (!strcasecmp(cmd, "local")) {
|
|
n = 0;
|
|
local = 1;
|
|
} else if (!strcasecmp(cmd, "rate")) {
|
|
if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "minsamples")) {
|
|
if (sscanf(line, "%d%n", &min_samples, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "maxlockage")) {
|
|
if (sscanf(line, "%d%n", &max_lock_age, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "maxsamples")) {
|
|
if (sscanf(line, "%d%n", &max_samples, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "offset")) {
|
|
if (sscanf(line, "%lf%n", &offset, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "delay")) {
|
|
if (sscanf(line, "%lf%n", &delay, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "pps")) {
|
|
n = 0;
|
|
pps_forced = 1;
|
|
} else if (!strcasecmp(cmd, "precision")) {
|
|
if (sscanf(line, "%lf%n", &precision, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "maxdispersion")) {
|
|
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "stratum")) {
|
|
if (sscanf(line, "%d%n", &stratum, &n) != 1 ||
|
|
stratum >= NTP_MAX_STRATUM || stratum < 0)
|
|
break;
|
|
} else if (!strcasecmp(cmd, "tai")) {
|
|
n = 0;
|
|
tai = 1;
|
|
} else if (!strcasecmp(cmd, "width")) {
|
|
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
|
|
break;
|
|
} else if ((sel_option = CPS_GetSelectOption(cmd)) != 0) {
|
|
n = 0;
|
|
sel_options |= sel_option;
|
|
} else {
|
|
other_parse_error("Invalid refclock option");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (*cmd) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
refclock = (RefclockParameters *)ARR_GetNewElement(refclock_sources);
|
|
refclock->driver_name = name;
|
|
refclock->driver_parameter = param;
|
|
refclock->driver_poll = dpoll;
|
|
refclock->poll = poll;
|
|
refclock->filter_length = filter_length;
|
|
refclock->local = local;
|
|
refclock->pps_forced = pps_forced;
|
|
refclock->pps_rate = pps_rate;
|
|
refclock->min_samples = min_samples;
|
|
refclock->max_samples = max_samples;
|
|
refclock->sel_options = sel_options;
|
|
refclock->stratum = stratum;
|
|
refclock->tai = tai;
|
|
refclock->offset = offset;
|
|
refclock->delay = delay;
|
|
refclock->precision = precision;
|
|
refclock->max_dispersion = max_dispersion;
|
|
refclock->pulse_width = pulse_width;
|
|
refclock->ref_id = ref_id;
|
|
refclock->max_lock_age = max_lock_age;
|
|
refclock->lock_ref_id = lock_ref_id;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_log(char *line)
|
|
{
|
|
char *log_name;
|
|
do {
|
|
log_name = line;
|
|
line = CPS_SplitWord(line);
|
|
if (*log_name) {
|
|
if (!strcmp(log_name, "rawmeasurements")) {
|
|
do_log_measurements = 1;
|
|
raw_measurements = 1;
|
|
} else if (!strcmp(log_name, "measurements")) {
|
|
do_log_measurements = 1;
|
|
} else if (!strcmp(log_name, "selection")) {
|
|
do_log_selection = 1;
|
|
} else if (!strcmp(log_name, "statistics")) {
|
|
do_log_statistics = 1;
|
|
} else if (!strcmp(log_name, "tracking")) {
|
|
do_log_tracking = 1;
|
|
} else if (!strcmp(log_name, "rtc")) {
|
|
do_log_rtc = 1;
|
|
} else if (!strcmp(log_name, "refclocks")) {
|
|
do_log_refclocks = 1;
|
|
} else if (!strcmp(log_name, "tempcomp")) {
|
|
do_log_tempcomp = 1;
|
|
} else {
|
|
other_parse_error("Invalid log parameter");
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_local(char *line)
|
|
{
|
|
if (!CPS_ParseLocal(line, &local_stratum, &local_orphan, &local_distance))
|
|
command_parse_error();
|
|
enable_local = 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_initstepslew(char *line)
|
|
{
|
|
char *p, *hostname;
|
|
IPAddr ip_addr;
|
|
|
|
/* Ignore the line if chronyd was started with -R. */
|
|
if (restarted) {
|
|
return;
|
|
}
|
|
|
|
ARR_SetSize(init_sources, 0);
|
|
p = CPS_SplitWord(line);
|
|
|
|
if (sscanf(line, "%lf", &init_slew_threshold) != 1) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
while (*p) {
|
|
hostname = p;
|
|
p = CPS_SplitWord(p);
|
|
if (*hostname) {
|
|
if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) {
|
|
ARR_AppendElement(init_sources, &ip_addr);
|
|
} else {
|
|
LOG(LOGS_WARN, "Could not resolve address of initstepslew server %s", hostname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_leapsecmode(char *line)
|
|
{
|
|
if (!strcasecmp(line, "system"))
|
|
leapsec_mode = REF_LeapModeSystem;
|
|
else if (!strcasecmp(line, "slew"))
|
|
leapsec_mode = REF_LeapModeSlew;
|
|
else if (!strcasecmp(line, "step"))
|
|
leapsec_mode = REF_LeapModeStep;
|
|
else if (!strcasecmp(line, "ignore"))
|
|
leapsec_mode = REF_LeapModeIgnore;
|
|
else
|
|
command_parse_error();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_clientloglimit(char *line)
|
|
{
|
|
check_number_of_args(line, 1);
|
|
if (sscanf(line, "%lu", &client_log_limit) != 1) {
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_fallbackdrift(char *line)
|
|
{
|
|
check_number_of_args(line, 2);
|
|
if (sscanf(line, "%d %d", &fb_drift_min, &fb_drift_max) != 2) {
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_makestep(char *line)
|
|
{
|
|
check_number_of_args(line, 2);
|
|
if (sscanf(line, "%lf %d", &make_step_threshold, &make_step_limit) != 2) {
|
|
make_step_limit = 0;
|
|
command_parse_error();
|
|
}
|
|
|
|
/* Disable limited makestep if chronyd was started with -R. */
|
|
if (restarted && make_step_limit > 0) {
|
|
make_step_limit = 0;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_maxchange(char *line)
|
|
{
|
|
check_number_of_args(line, 3);
|
|
if (sscanf(line, "%lf %d %d", &max_offset, &max_offset_delay, &max_offset_ignore) != 3) {
|
|
max_offset_delay = -1;
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_mailonchange(char *line)
|
|
{
|
|
char *address;
|
|
check_number_of_args(line, 2);
|
|
address = line;
|
|
line = CPS_SplitWord(line);
|
|
Free(mail_user_on_change);
|
|
if (sscanf(line, "%lf", &mail_change_threshold) == 1) {
|
|
mail_user_on_change = Strdup(address);
|
|
} else {
|
|
mail_user_on_change = NULL;
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_ntsserver(char *line, ARR_Instance files)
|
|
{
|
|
char *file = NULL;
|
|
|
|
parse_string(line, &file);
|
|
ARR_AppendElement(files, &file);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_ntstrustedcerts(char *line)
|
|
{
|
|
uint32_t id;
|
|
char *path;
|
|
|
|
if (get_number_of_args(line) == 2) {
|
|
path = CPS_SplitWord(line);
|
|
if (sscanf(line, "%"SCNu32, &id) != 1)
|
|
command_parse_error();
|
|
} else {
|
|
check_number_of_args(line, 1);
|
|
path = line;
|
|
id = 0;
|
|
}
|
|
|
|
path = Strdup(path);
|
|
|
|
ARR_AppendElement(nts_trusted_certs_paths, &path);
|
|
ARR_AppendElement(nts_trusted_certs_ids, &id);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
|
|
{
|
|
int all, subnet_bits;
|
|
AllowDeny *node;
|
|
IPAddr ip;
|
|
|
|
if (!CPS_ParseAllowDeny(line, &all, &ip, &subnet_bits))
|
|
command_parse_error();
|
|
|
|
node = ARR_GetNewElement(restrictions);
|
|
node->allow = allow;
|
|
node->all = all;
|
|
node->ip = ip;
|
|
node->subnet_bits = subnet_bits;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_authselectmode(char *line)
|
|
{
|
|
if (!strcasecmp(line, "require"))
|
|
authselect_mode = SRC_AUTHSELECT_REQUIRE;
|
|
else if (!strcasecmp(line, "prefer"))
|
|
authselect_mode = SRC_AUTHSELECT_PREFER;
|
|
else if (!strcasecmp(line, "mix"))
|
|
authselect_mode = SRC_AUTHSELECT_MIX;
|
|
else if (!strcasecmp(line, "ignore"))
|
|
authselect_mode = SRC_AUTHSELECT_IGNORE;
|
|
else
|
|
command_parse_error();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_bindacqaddress(char *line)
|
|
{
|
|
IPAddr ip;
|
|
|
|
check_number_of_args(line, 1);
|
|
if (UTI_StringToIP(line, &ip)) {
|
|
if (ip.family == IPADDR_INET4)
|
|
bind_acq_address4 = ip;
|
|
else if (ip.family == IPADDR_INET6)
|
|
bind_acq_address6 = ip;
|
|
} else {
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_bindaddress(char *line)
|
|
{
|
|
IPAddr ip;
|
|
|
|
check_number_of_args(line, 1);
|
|
if (UTI_StringToIP(line, &ip)) {
|
|
if (ip.family == IPADDR_INET4)
|
|
bind_address4 = ip;
|
|
else if (ip.family == IPADDR_INET6)
|
|
bind_address6 = ip;
|
|
} else {
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_bindcmdaddress(char *line)
|
|
{
|
|
IPAddr ip;
|
|
|
|
check_number_of_args(line, 1);
|
|
|
|
/* Address starting with / is for the Unix domain socket */
|
|
if (line[0] == '/') {
|
|
parse_string(line, &bind_cmd_path);
|
|
/* / disables the socket */
|
|
if (strcmp(bind_cmd_path, "/") == 0) {
|
|
Free(bind_cmd_path);
|
|
bind_cmd_path = NULL;
|
|
}
|
|
} else if (UTI_StringToIP(line, &ip)) {
|
|
if (ip.family == IPADDR_INET4)
|
|
bind_cmd_address4 = ip;
|
|
else if (ip.family == IPADDR_INET6)
|
|
bind_cmd_address6 = ip;
|
|
} else {
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_broadcast(char *line)
|
|
{
|
|
/* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */
|
|
NTP_Broadcast_Destination *destination;
|
|
int port;
|
|
int interval;
|
|
char *p;
|
|
IPAddr ip;
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (sscanf(p, "%d", &interval) != 1) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!UTI_StringToIP(p, &ip)) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (*p) {
|
|
if (sscanf(p, "%d", &port) != 1 || *line) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
} else {
|
|
/* default port */
|
|
port = NTP_PORT;
|
|
}
|
|
|
|
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
|
|
destination->addr.ip_addr = ip;
|
|
destination->addr.port = port;
|
|
destination->interval = interval;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_smoothtime(char *line)
|
|
{
|
|
if (get_number_of_args(line) != 3)
|
|
check_number_of_args(line, 2);
|
|
|
|
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
|
|
smooth_max_freq = 0.0;
|
|
command_parse_error();
|
|
}
|
|
|
|
line = CPS_SplitWord(CPS_SplitWord(line));
|
|
smooth_leap_only = 0;
|
|
|
|
if (*line) {
|
|
if (!strcasecmp(line, "leaponly"))
|
|
smooth_leap_only = 1;
|
|
else
|
|
command_parse_error();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
static void
|
|
parse_tempcomp(char *line)
|
|
{
|
|
char *p;
|
|
int point_form;
|
|
|
|
point_form = get_number_of_args(line) == 3;
|
|
|
|
if (!point_form)
|
|
check_number_of_args(line, 6);
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!*p) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
Free(tempcomp_point_file);
|
|
|
|
if (point_form) {
|
|
if (sscanf(line, "%lf", &tempcomp_interval) != 1) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
tempcomp_point_file = Strdup(CPS_SplitWord(line));
|
|
} else {
|
|
if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval,
|
|
&tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
tempcomp_point_file = NULL;
|
|
}
|
|
|
|
Free(tempcomp_sensor_file);
|
|
tempcomp_sensor_file = Strdup(p);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_hwtimestamp(char *line)
|
|
{
|
|
CNF_HwTsInterface *iface;
|
|
int n, maxpoll_set = 0;
|
|
char *p, filter[5];
|
|
|
|
if (!*line) {
|
|
command_parse_error();
|
|
return;
|
|
}
|
|
|
|
p = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
iface = ARR_GetNewElement(hwts_interfaces);
|
|
iface->name = Strdup(p);
|
|
iface->minpoll = 0;
|
|
iface->min_samples = 2;
|
|
iface->max_samples = 16;
|
|
iface->nocrossts = 0;
|
|
iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
|
|
iface->precision = 100.0e-9;
|
|
iface->tx_comp = 0.0;
|
|
iface->rx_comp = 0.0;
|
|
|
|
for (p = line; *p; line += n, p = line) {
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!strcasecmp(p, "maxsamples")) {
|
|
if (sscanf(line, "%d%n", &iface->max_samples, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "minpoll")) {
|
|
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "maxpoll")) {
|
|
if (sscanf(line, "%d%n", &iface->maxpoll, &n) != 1)
|
|
break;
|
|
maxpoll_set = 1;
|
|
} else if (!strcasecmp(p, "minsamples")) {
|
|
if (sscanf(line, "%d%n", &iface->min_samples, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "precision")) {
|
|
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "rxcomp")) {
|
|
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "txcomp")) {
|
|
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
|
|
break;
|
|
} else if (!strcasecmp(p, "rxfilter")) {
|
|
if (sscanf(line, "%4s%n", filter, &n) != 1)
|
|
break;
|
|
if (!strcasecmp(filter, "none"))
|
|
iface->rxfilter = CNF_HWTS_RXFILTER_NONE;
|
|
else if (!strcasecmp(filter, "ntp"))
|
|
iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
|
|
else if (!strcasecmp(filter, "ptp"))
|
|
iface->rxfilter = CNF_HWTS_RXFILTER_PTP;
|
|
else if (!strcasecmp(filter, "all"))
|
|
iface->rxfilter = CNF_HWTS_RXFILTER_ALL;
|
|
else
|
|
break;
|
|
} else if (!strcasecmp(p, "nocrossts")) {
|
|
n = 0;
|
|
iface->nocrossts = 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*p)
|
|
command_parse_error();
|
|
|
|
if (!maxpoll_set)
|
|
iface->maxpoll = iface->minpoll + 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static const char *
|
|
get_basename(const char *path)
|
|
{
|
|
const char *b = strrchr(path, '/');
|
|
return b ? b + 1 : path;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
compare_basenames(const void *a, const void *b)
|
|
{
|
|
return strcmp(get_basename(*(const char * const *)a),
|
|
get_basename(*(const char * const *)b));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
search_dirs(char *line, const char *suffix, void (*file_handler)(const char *path))
|
|
{
|
|
char *dirs[MAX_CONF_DIRS], buf[MAX_LINE_LENGTH], *path;
|
|
size_t i, j, k, locations, n_dirs;
|
|
glob_t gl;
|
|
|
|
n_dirs = UTI_SplitString(line, dirs, MAX_CONF_DIRS);
|
|
if (n_dirs < 1 || n_dirs > MAX_CONF_DIRS)
|
|
return 0;
|
|
|
|
/* Get the paths of all config files in the specified directories */
|
|
for (i = 0; i < n_dirs; i++) {
|
|
if (snprintf(buf, sizeof (buf), "%s/*%s", dirs[i], suffix) >= sizeof (buf))
|
|
assert(0);
|
|
if (glob(buf, GLOB_NOSORT | (i > 0 ? GLOB_APPEND : 0), NULL, &gl) != 0)
|
|
;
|
|
}
|
|
|
|
if (gl.gl_pathc > 0) {
|
|
/* Sort the paths by filenames */
|
|
qsort(gl.gl_pathv, gl.gl_pathc, sizeof (gl.gl_pathv[0]), compare_basenames);
|
|
|
|
for (i = 0; i < gl.gl_pathc; i += locations) {
|
|
/* Count directories containing files with this name */
|
|
for (j = i + 1, locations = 1; j < gl.gl_pathc; j++, locations++) {
|
|
if (compare_basenames(&gl.gl_pathv[i], &gl.gl_pathv[j]) != 0)
|
|
break;
|
|
}
|
|
|
|
/* Read the first file of this name in the order of the directive */
|
|
for (j = 0; j < n_dirs; j++) {
|
|
for (k = 0; k < locations; k++) {
|
|
path = gl.gl_pathv[i + k];
|
|
if (strncmp(path, dirs[j], strlen(dirs[j])) == 0 &&
|
|
strlen(dirs[j]) + 1 + strlen(get_basename(path)) == strlen(path)) {
|
|
file_handler(path);
|
|
break;
|
|
}
|
|
}
|
|
if (k < locations)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
globfree(&gl);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_confdir(char *line)
|
|
{
|
|
if (!search_dirs(line, ".conf", CNF_ReadFile))
|
|
command_parse_error();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
parse_include(char *line)
|
|
{
|
|
glob_t gl;
|
|
size_t i;
|
|
int r;
|
|
|
|
check_number_of_args(line, 1);
|
|
|
|
if ((r = glob(line,
|
|
#ifdef GLOB_NOMAGIC
|
|
GLOB_NOMAGIC |
|
|
#endif
|
|
GLOB_ERR, NULL, &gl)) != 0) {
|
|
if (r != GLOB_NOMATCH)
|
|
LOG_FATAL("Could not search for files matching %s", line);
|
|
|
|
DEBUG_LOG("glob of %s failed", line);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < gl.gl_pathc; i++)
|
|
CNF_ReadFile(gl.gl_pathv[i]);
|
|
|
|
globfree(&gl);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
load_source_file(const char *filename)
|
|
{
|
|
char line[MAX_LINE_LENGTH + 1];
|
|
FILE *f;
|
|
|
|
f = UTI_OpenFile(NULL, filename, NULL, 'r', 0);
|
|
if (!f)
|
|
return;
|
|
|
|
while (fgets(line, sizeof (line), f)) {
|
|
/* Require lines to be terminated */
|
|
if (line[0] == '\0' || line[strlen(line) - 1] != '\n')
|
|
break;
|
|
|
|
CPS_NormalizeLine(line);
|
|
if (line[0] == '\0')
|
|
continue;
|
|
|
|
parse_source(CPS_SplitWord(line), line, 0);
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
compare_sources(const void *a, const void *b)
|
|
{
|
|
const NTP_Source *sa = a, *sb = b;
|
|
int d;
|
|
|
|
if (!sa->params.name)
|
|
return -1;
|
|
if (!sb->params.name)
|
|
return 1;
|
|
if ((d = strcmp(sa->params.name, sb->params.name)) != 0)
|
|
return d;
|
|
if ((d = (int)sa->type - (int)sb->type) != 0)
|
|
return d;
|
|
if ((d = (int)sa->pool - (int)sb->pool) != 0)
|
|
return d;
|
|
if ((d = (int)sa->params.family - (int)sb->params.family) != 0)
|
|
return d;
|
|
if ((d = (int)sa->params.port - (int)sb->params.port) != 0)
|
|
return d;
|
|
return memcmp(&sa->params.params, &sb->params.params, sizeof (sa->params.params));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
reload_source_dirs(void)
|
|
{
|
|
NTP_Source *prev_sources, *new_sources, *source;
|
|
unsigned int i, j, prev_size, new_size, unresolved;
|
|
uint32_t *prev_ids, *new_ids;
|
|
char buf[MAX_LINE_LENGTH];
|
|
NSR_Status s;
|
|
int d, pass;
|
|
|
|
/* Ignore reload command before adding configured sources */
|
|
if (!conf_ntp_sources_added)
|
|
return;
|
|
|
|
prev_size = ARR_GetSize(ntp_source_ids);
|
|
if (ARR_GetSize(ntp_sources) != prev_size)
|
|
assert(0);
|
|
|
|
/* Save the current sources and their configuration IDs */
|
|
prev_ids = MallocArray(uint32_t, prev_size);
|
|
memcpy(prev_ids, ARR_GetElements(ntp_source_ids), prev_size * sizeof (prev_ids[0]));
|
|
prev_sources = MallocArray(NTP_Source, prev_size);
|
|
memcpy(prev_sources, ARR_GetElements(ntp_sources), prev_size * sizeof (prev_sources[0]));
|
|
|
|
/* Load the sources again */
|
|
ARR_SetSize(ntp_sources, 0);
|
|
for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++) {
|
|
if (snprintf(buf, sizeof (buf), "%s",
|
|
*(char **)ARR_GetElement(ntp_source_dirs, i)) >= sizeof (buf))
|
|
assert(0);
|
|
search_dirs(buf, ".sources", load_source_file);
|
|
}
|
|
|
|
/* Add new and remove existing sources according to the new configuration.
|
|
Avoid removing and adding the same source again to keep its state. */
|
|
|
|
new_size = ARR_GetSize(ntp_sources);
|
|
new_sources = ARR_GetElements(ntp_sources);
|
|
ARR_SetSize(ntp_source_ids, new_size);
|
|
new_ids = ARR_GetElements(ntp_source_ids);
|
|
unresolved = 0;
|
|
|
|
LOG_SetContext(LOGC_SourceFile);
|
|
|
|
qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources);
|
|
|
|
for (pass = 0; pass < 2; pass++) {
|
|
for (i = j = 0; i < prev_size || j < new_size; i += d <= 0, j += d >= 0) {
|
|
if (i < prev_size && j < new_size)
|
|
d = compare_sources(&prev_sources[i], &new_sources[j]);
|
|
else
|
|
d = i < prev_size ? -1 : 1;
|
|
|
|
/* Remove missing sources before adding others to avoid conflicts */
|
|
if (pass == 0 && d < 0 && prev_sources[i].params.name[0] != '\0') {
|
|
NSR_RemoveSourcesById(prev_ids[i]);
|
|
}
|
|
|
|
/* Add new sources */
|
|
if (pass == 1 && d > 0) {
|
|
source = &new_sources[j];
|
|
s = NSR_AddSourceByName(source->params.name, source->params.family, source->params.port,
|
|
source->pool, source->type, &source->params.params,
|
|
&new_ids[j]);
|
|
|
|
if (s == NSR_UnresolvedName) {
|
|
unresolved++;
|
|
} else if (s != NSR_Success) {
|
|
LOG(LOGS_ERR, "Could not add source %s : %s",
|
|
source->params.name, NSR_StatusToString(s));
|
|
|
|
/* Mark the source as not present */
|
|
source->params.name[0] = '\0';
|
|
}
|
|
}
|
|
|
|
/* Keep unchanged sources */
|
|
if (pass == 1 && d == 0)
|
|
new_ids[j] = prev_ids[i];
|
|
}
|
|
}
|
|
|
|
LOG_UnsetContext(LOGC_SourceFile);
|
|
|
|
for (i = 0; i < prev_size; i++)
|
|
Free(prev_sources[i].params.name);
|
|
Free(prev_sources);
|
|
Free(prev_ids);
|
|
|
|
if (unresolved > 0)
|
|
NSR_ResolveSources();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_CreateDirs(uid_t uid, gid_t gid)
|
|
{
|
|
char *dir;
|
|
|
|
/* Create a directory for the Unix domain command socket */
|
|
if (bind_cmd_path) {
|
|
dir = UTI_PathToDir(bind_cmd_path);
|
|
UTI_CreateDirAndParents(dir, 0770, uid, gid);
|
|
|
|
/* Check the permissions and owner/group in case the directory already
|
|
existed. It MUST NOT be accessible by others as permissions on Unix
|
|
domain sockets are ignored on some systems (e.g. Solaris). */
|
|
if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) {
|
|
LOG(LOGS_WARN, "Disabled command socket %s", bind_cmd_path);
|
|
Free(bind_cmd_path);
|
|
bind_cmd_path = NULL;
|
|
}
|
|
|
|
Free(dir);
|
|
}
|
|
|
|
if (logdir)
|
|
UTI_CreateDirAndParents(logdir, 0750, uid, gid);
|
|
if (dumpdir)
|
|
UTI_CreateDirAndParents(dumpdir, 0750, uid, gid);
|
|
if (nts_dump_dir)
|
|
UTI_CreateDirAndParents(nts_dump_dir, 0750, uid, gid);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_CheckReadOnlyAccess(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (keys_file)
|
|
UTI_CheckReadOnlyAccess(keys_file);
|
|
for (i = 0; i < ARR_GetSize(nts_server_key_files); i++)
|
|
UTI_CheckReadOnlyAccess(*(char **)ARR_GetElement(nts_server_key_files, i));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_AddInitSources(void)
|
|
{
|
|
CPS_NTP_Source cps_source;
|
|
NTP_Remote_Address ntp_addr;
|
|
char dummy_hostname[2] = "H";
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARR_GetSize(init_sources); i++) {
|
|
/* Get the default NTP params */
|
|
CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source);
|
|
|
|
/* Add the address as a server specified with the iburst option */
|
|
ntp_addr.ip_addr = *(IPAddr *)ARR_GetElement(init_sources, i);
|
|
ntp_addr.port = cps_source.port;
|
|
cps_source.params.iburst = 1;
|
|
|
|
if (NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params, NULL) != NSR_Success)
|
|
LOG(LOGS_ERR, "Could not add source %s", UTI_IPToString(&ntp_addr.ip_addr));
|
|
}
|
|
|
|
ARR_SetSize(init_sources, 0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_AddSources(void)
|
|
{
|
|
NTP_Source *source;
|
|
unsigned int i;
|
|
NSR_Status s;
|
|
|
|
for (i = 0; i < ARR_GetSize(ntp_sources); i++) {
|
|
source = (NTP_Source *)ARR_GetElement(ntp_sources, i);
|
|
|
|
s = NSR_AddSourceByName(source->params.name, source->params.family, source->params.port,
|
|
source->pool, source->type, &source->params.params, NULL);
|
|
if (s != NSR_Success && s != NSR_UnresolvedName)
|
|
LOG(LOGS_ERR, "Could not add source %s", source->params.name);
|
|
|
|
Free(source->params.name);
|
|
}
|
|
|
|
/* The arrays will be used for sourcedir (re)loading */
|
|
ARR_SetSize(ntp_sources, 0);
|
|
ARR_SetSize(ntp_source_ids, 0);
|
|
conf_ntp_sources_added = 1;
|
|
|
|
reload_source_dirs();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_AddRefclocks(void)
|
|
{
|
|
RefclockParameters *refclock;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
|
|
refclock = ARR_GetElement(refclock_sources, i);
|
|
RCL_AddRefclock(refclock);
|
|
Free(refclock->driver_name);
|
|
Free(refclock->driver_parameter);
|
|
}
|
|
|
|
ARR_SetSize(refclock_sources, 0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_AddBroadcasts(void)
|
|
{
|
|
unsigned int i;
|
|
NTP_Broadcast_Destination *destination;
|
|
|
|
for (i = 0; i < ARR_GetSize(broadcasts); i++) {
|
|
destination = (NTP_Broadcast_Destination *)ARR_GetElement(broadcasts, i);
|
|
NCR_AddBroadcastDestination(&destination->addr, destination->interval);
|
|
}
|
|
|
|
ARR_SetSize(broadcasts, 0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_ReloadSources(void)
|
|
{
|
|
reload_source_dirs();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNTPPort(void)
|
|
{
|
|
return ntp_port;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetAcquisitionPort(void)
|
|
{
|
|
return acquisition_port;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetDriftFile(void)
|
|
{
|
|
return drift_file;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogBanner(void)
|
|
{
|
|
return log_banner;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetLogDir(void)
|
|
{
|
|
return logdir;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetDumpDir(void)
|
|
{
|
|
return dumpdir;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogMeasurements(int *raw)
|
|
{
|
|
*raw = raw_measurements;
|
|
return do_log_measurements;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogSelection(void)
|
|
{
|
|
return do_log_selection;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogStatistics(void)
|
|
{
|
|
return do_log_statistics;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogTracking(void)
|
|
{
|
|
return do_log_tracking;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogRtc(void)
|
|
{
|
|
return do_log_rtc;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogRefclocks(void)
|
|
{
|
|
return do_log_refclocks;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLogTempComp(void)
|
|
{
|
|
return do_log_tempcomp;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetKeysFile(void)
|
|
{
|
|
return keys_file;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetRtcAutotrim(void)
|
|
{
|
|
return rtc_autotrim_threshold;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetRtcFile(void)
|
|
{
|
|
return rtc_file;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetRtcDevice(void)
|
|
{
|
|
return rtc_device;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxUpdateSkew(void)
|
|
{
|
|
return max_update_skew;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxDrift(void)
|
|
{
|
|
return max_drift;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxClockError(void)
|
|
{
|
|
return max_clock_error;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetCorrectionTimeRatio(void)
|
|
{
|
|
return correction_time_ratio;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
SRC_AuthSelectMode
|
|
CNF_GetAuthSelectMode(void)
|
|
{
|
|
return authselect_mode;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxSlewRate(void)
|
|
{
|
|
return max_slew_rate;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetClockPrecision(void)
|
|
{
|
|
return clock_precision;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxDistance(void)
|
|
{
|
|
return max_distance;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetMaxJitter(void)
|
|
{
|
|
return max_jitter;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetReselectDistance(void)
|
|
{
|
|
return reselect_distance;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetStratumWeight(void)
|
|
{
|
|
return stratum_weight;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetCombineLimit(void)
|
|
{
|
|
return combine_limit;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetManualEnabled(void)
|
|
{
|
|
return enable_manual;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetCommandPort(void) {
|
|
return cmd_port;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_AllowLocalReference(int *stratum, int *orphan, double *distance)
|
|
{
|
|
if (enable_local) {
|
|
*stratum = local_stratum;
|
|
*orphan = local_orphan;
|
|
*distance = local_distance;
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetRtcOnUtc(void)
|
|
{
|
|
return rtc_on_utc;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetRtcSync(void)
|
|
{
|
|
return rtc_sync;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetMakeStep(int *limit, double *threshold)
|
|
{
|
|
*limit = make_step_limit;
|
|
*threshold = make_step_threshold;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetMaxChange(int *delay, int *ignore, double *offset)
|
|
{
|
|
*delay = max_offset_delay;
|
|
*ignore = max_offset_ignore;
|
|
*offset = max_offset;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetLogChange(void)
|
|
{
|
|
return log_change_threshold;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetMailOnChange(int *enabled, double *threshold, char **user)
|
|
{
|
|
if (mail_user_on_change) {
|
|
*enabled = 1;
|
|
*threshold = mail_change_threshold;
|
|
*user = mail_user_on_change;
|
|
} else {
|
|
*enabled = 0;
|
|
*threshold = 0.0;
|
|
*user = NULL;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_SetupAccessRestrictions(void)
|
|
{
|
|
AllowDeny *node;
|
|
int status;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARR_GetSize(ntp_restrictions); i++) {
|
|
node = ARR_GetElement(ntp_restrictions, i);
|
|
status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
|
|
if (!status) {
|
|
LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARR_GetSize(cmd_restrictions); i++) {
|
|
node = ARR_GetElement(cmd_restrictions, i);
|
|
status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
|
|
if (!status) {
|
|
LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
|
|
}
|
|
}
|
|
|
|
ARR_SetSize(ntp_restrictions, 0);
|
|
ARR_SetSize(cmd_restrictions, 0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNoClientLog(void)
|
|
{
|
|
return no_client_log;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
unsigned long
|
|
CNF_GetClientLogLimit(void)
|
|
{
|
|
return client_log_limit;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetFallbackDrifts(int *min, int *max)
|
|
{
|
|
*min = fb_drift_min;
|
|
*max = fb_drift_max;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetBindAddress(int family, IPAddr *addr)
|
|
{
|
|
if (family == IPADDR_INET4)
|
|
*addr = bind_address4;
|
|
else if (family == IPADDR_INET6)
|
|
*addr = bind_address6;
|
|
else
|
|
addr->family = IPADDR_UNSPEC;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
|
|
{
|
|
if (family == IPADDR_INET4)
|
|
*addr = bind_acq_address4;
|
|
else if (family == IPADDR_INET6)
|
|
*addr = bind_acq_address6;
|
|
else
|
|
addr->family = IPADDR_UNSPEC;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetBindNtpInterface(void)
|
|
{
|
|
return bind_ntp_iface;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetBindAcquisitionInterface(void)
|
|
{
|
|
return bind_acq_iface;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetBindCommandInterface(void)
|
|
{
|
|
return bind_cmd_iface;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetBindCommandPath(void)
|
|
{
|
|
return bind_cmd_path;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
|
{
|
|
if (family == IPADDR_INET4)
|
|
*addr = bind_cmd_address4;
|
|
else if (family == IPADDR_INET6)
|
|
*addr = bind_cmd_address6;
|
|
else
|
|
addr->family = IPADDR_UNSPEC;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtpDscp(void)
|
|
{
|
|
return ntp_dscp;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetNtpSigndSocket(void)
|
|
{
|
|
return ntp_signd_socket;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetPidFile(void)
|
|
{
|
|
return pidfile;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
REF_LeapMode
|
|
CNF_GetLeapSecMode(void)
|
|
{
|
|
return leapsec_mode;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetLeapSecTimezone(void)
|
|
{
|
|
return leapsec_tz;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetLeapSecList(void)
|
|
{
|
|
return leapsec_list;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetSchedPriority(void)
|
|
{
|
|
return sched_priority;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetLockMemory(void)
|
|
{
|
|
return lock_memory;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak)
|
|
{
|
|
*interval = ntp_ratelimit_interval;
|
|
*burst = ntp_ratelimit_burst;
|
|
*leak = ntp_ratelimit_leak;
|
|
return ntp_ratelimit_enabled;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak)
|
|
{
|
|
*interval = nts_ratelimit_interval;
|
|
*burst = nts_ratelimit_burst;
|
|
*leak = nts_ratelimit_leak;
|
|
return nts_ratelimit_enabled;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak)
|
|
{
|
|
*interval = cmd_ratelimit_interval;
|
|
*burst = cmd_ratelimit_burst;
|
|
*leak = cmd_ratelimit_leak;
|
|
return cmd_ratelimit_enabled;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
|
|
{
|
|
*max_freq = smooth_max_freq;
|
|
*max_wander = smooth_max_wander;
|
|
*leap_only = smooth_leap_only;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2)
|
|
{
|
|
*file = tempcomp_sensor_file;
|
|
*point_file = tempcomp_point_file;
|
|
*interval = tempcomp_interval;
|
|
*T0 = tempcomp_T0;
|
|
*k0 = tempcomp_k0;
|
|
*k1 = tempcomp_k1;
|
|
*k2 = tempcomp_k2;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetUser(void)
|
|
{
|
|
return user;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetMaxSamples(void)
|
|
{
|
|
return max_samples;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetMinSamples(void)
|
|
{
|
|
return min_samples;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetMinSources(void)
|
|
{
|
|
return min_sources;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetHwclockFile(void)
|
|
{
|
|
return hwclock_file;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetInitSources(void)
|
|
{
|
|
return ARR_GetSize(init_sources);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetInitStepThreshold(void)
|
|
{
|
|
return init_slew_threshold;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
|
|
{
|
|
if (index >= ARR_GetSize(hwts_interfaces))
|
|
return 0;
|
|
|
|
*iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
|
|
return 1;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
double
|
|
CNF_GetHwTsTimeout(void)
|
|
{
|
|
return hwts_timeout;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetPtpPort(void)
|
|
{
|
|
return ptp_port;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetRefresh(void)
|
|
{
|
|
return refresh;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetNtsDumpDir(void)
|
|
{
|
|
return nts_dump_dir;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CNF_GetNtsNtpServer(void)
|
|
{
|
|
return nts_ntp_server;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys)
|
|
{
|
|
*certs = ARR_GetElements(nts_server_cert_files);
|
|
*keys = ARR_GetElements(nts_server_key_files);
|
|
|
|
if (ARR_GetSize(nts_server_cert_files) != ARR_GetSize(nts_server_key_files))
|
|
LOG_FATAL("Uneven number of NTS certs and keys");
|
|
|
|
return ARR_GetSize(nts_server_cert_files);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsServerPort(void)
|
|
{
|
|
return nts_server_port;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsServerProcesses(void)
|
|
{
|
|
return nts_server_processes;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsServerConnections(void)
|
|
{
|
|
return nts_server_connections;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsRefresh(void)
|
|
{
|
|
return nts_refresh;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsRotate(void)
|
|
{
|
|
return nts_rotate;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids)
|
|
{
|
|
*paths = ARR_GetElements(nts_trusted_certs_paths);
|
|
*ids = ARR_GetElements(nts_trusted_certs_ids);
|
|
|
|
if (ARR_GetSize(nts_trusted_certs_paths) != ARR_GetSize(nts_trusted_certs_ids))
|
|
assert(0);
|
|
|
|
return ARR_GetSize(nts_trusted_certs_paths);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNoSystemCert(void)
|
|
{
|
|
return no_system_cert;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CNF_GetNoCertTimeCheck(void)
|
|
{
|
|
return no_cert_time_check;
|
|
}
|