Refresh NTP sources specified by hostname periodically (every 2 weeks by default) to avoid long-running instances using a server which is no longer intended for service, even if it is still responding correctly and would not be replaced as unreachable, and help redistributing load in large pools like pool.ntp.org. Only one source is refreshed at a time to not interrupt clock updates if there are multiple selectable servers. The refresh directive configures the interval. A value of 0 disables the periodic refreshment. Suggested-by: Ask Bjørn Hansen <ask@develooper.com>
2645 lines
65 KiB
C
2645 lines
65 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;
|
|
|
|
/* 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;
|
|
|
|
/* 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(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, "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 = sa->pool - sb->pool) != 0)
|
|
return d;
|
|
if ((d = sa->params.port - 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;
|
|
|
|
prev_size = ARR_GetSize(ntp_source_ids);
|
|
if (prev_size > 0 && 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 (i = j = 0; i < prev_size || j < new_size; ) {
|
|
if (i < prev_size && j < new_size)
|
|
d = compare_sources(&prev_sources[i], &new_sources[j]);
|
|
else
|
|
d = i < prev_size ? -1 : 1;
|
|
|
|
if (d < 0) {
|
|
/* Remove the missing source */
|
|
if (prev_sources[i].params.name[0] != '\0')
|
|
NSR_RemoveSourcesById(prev_ids[i]);
|
|
i++;
|
|
} else if (d > 0) {
|
|
/* Add a newly configured source */
|
|
source = &new_sources[j];
|
|
s = NSR_AddSourceByName(source->params.name, 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", source->params.name);
|
|
|
|
/* Mark the source as not present */
|
|
source->params.name[0] = '\0';
|
|
}
|
|
j++;
|
|
} else {
|
|
/* Keep the existing source */
|
|
new_ids[j] = prev_ids[i];
|
|
i++, j++;
|
|
}
|
|
}
|
|
|
|
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.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);
|
|
}
|
|
|
|
ARR_SetSize(ntp_sources, 0);
|
|
|
|
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;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
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;
|
|
}
|