/* $Header: /cvs/src/chrony/conf.c,v 1.45 2003/09/22 21:22:30 richard Exp $ ======================================================================= chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 * * 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., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * ********************************************************************** ======================================================================= Module that reads and processes the configuration file. 1999-12-19 Kalle Olavi Niemitalo * conf.c: Added a new configuration setting "acquisitionport" and a function CNF_GetAcquisitionPort to read its value. (acquisition_port): New variable. (parse_port): Delegate most work to new function parse_some_port. (parse_acquisitionport): New function. (commands): Added "acquisitionport". (CNF_GetAcquisitionPort): New function. */ #include "sysincl.h" #include "conf.h" #include "ntp_sources.h" #include "ntp_core.h" #include "cmdmon.h" #include "srcparams.h" #include "logging.h" #include "nameserv.h" #include "memory.h" #include "acquire.h" #include "cmdparse.h" #include "broadcast.h" /* ================================================== */ #define DEFAULT_CONF_FILE "/etc/chrony.conf" /* ================================================== */ /* Forward prototypes */ static void parse_commandkey(const char *); static void parse_driftfile(const char *); static void parse_dumpdir(const char *); static void parse_dumponexit(const char *); static void parse_keyfile(const char *); static void parse_rtcfile(const char *); static void parse_log(const char *); static void parse_logdir(const char *); static void parse_maxupdateskew(const char *); static void parse_peer(const char *); static void parse_acquisitionport(const char *); static void parse_port(const char *); static void parse_server(const char *); static void parse_local(const char *); static void parse_manual(const char *); static void parse_initstepslew(const char *); static void parse_allow(const char *); static void parse_deny(const char *); static void parse_cmdallow(const char *); static void parse_cmddeny(const char *); static void parse_cmdport(const char *); static void parse_rtconutc(const char *); static void parse_noclientlog(const char *); static void parse_logchange(const char *); static void parse_mailonchange(const char *); static void parse_bindaddress(const char *); static void parse_bindcmdaddress(const char *); static void parse_rtcdevice(const char *); static void parse_pidfile(const char *); static void parse_broadcast(const char *); static void parse_linux_hz(const char *); static void parse_linux_freq_scale(const char *); /* ================================================== */ /* Configuration variables */ static char *rtc_device = "/dev/rtc"; static int acquisition_port = 0; /* 0 means let kernel choose port */ static int ntp_port = 123; static char *keys_file = NULL; static char *drift_file = NULL; static char *rtc_file = NULL; static unsigned long command_key_id; static double max_update_skew = DBL_MAX; static int cmd_port = -1; static int do_log_measurements = 0; static int do_log_statistics = 0; static int do_log_tracking = 0; static int do_log_rtc = 0; static int do_dump_on_exit = 0; static char *logdir = "."; static char *dumpdir = "."; static int enable_local=0; #define DEFAULT_LOCAL_STRATUM 8 static int local_stratum; static int do_init_stepslew = 0; static int n_init_srcs; /* Threshold (in seconds) - if absolute value of initial error is less than this, slew instead of stepping */ static int init_slew_threshold = -1; #define MAX_INIT_SRCS 8 static unsigned long init_srcs_ip[MAX_INIT_SRCS]; 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; /* Flag set if we should log to syslog when a time adjustment exceeding the threshold is initiated */ static int do_log_change = 0; static double log_change_threshold = 0.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; /* IP address (host order) for binding the NTP socket to. 0 means INADDR_ANY will be used */ static unsigned long bind_address = 0UL; /* IP address (host order) for binding the command socket to. 0 means use the value of bind_address */ static unsigned long bind_cmd_address = 0UL; /* Filename to use for storing pid of running chronyd, to prevent multiple * chronyds being started. */ static char *pidfile = "/var/run/chronyd.pid"; /* Boolean for whether the Linux HZ value has been overridden, and the * new value. */ static int set_linux_hz = 0; static int linux_hz; /* Boolean for whether the Linux frequency scaling value (i.e. the one that's * approx (1<= MAX_INIT_SRCS) { break; } } else { /* If we get invalid trailing syntax, forget it ... */ break; } p += n; } if (n_init_srcs > 0) { do_init_stepslew = 1; init_slew_threshold = threshold; } else { LOG(LOGS_WARN, LOGF_Configure, "No usable initstepslew servers at line %d\n", line_number); } } /* ================================================== */ static void parse_manual(const char *line) { enable_manual = 1; } /* ================================================== */ static void parse_rtconutc(const char *line) { rtc_on_utc = 1; } /* ================================================== */ static void parse_noclientlog(const char *line) { no_client_log = 1; } /* ================================================== */ static void parse_logchange(const char *line) { if (sscanf(line, "%lf", &log_change_threshold) == 1) { do_log_change = 1; } else { do_log_change = 0; LOG(LOGS_WARN, LOGF_Configure, "Could not read threshold for logging clock changes at line %d\n", line_number); } } /* ================================================== */ #define BUFLEN 2047 #define SBUFLEN "2047" static void parse_mailonchange(const char *line) { char buffer[BUFLEN+1]; if (sscanf(line, "%" SBUFLEN "s%lf", buffer, &mail_change_threshold) == 2) { mail_user_on_change = MallocArray(char, strlen(buffer)+1); strcpy(mail_user_on_change, buffer); } else { mail_user_on_change = NULL; LOG(LOGS_WARN, LOGF_Configure, "Could not read user or threshold for clock change mail notify at line %d\n", line_number); } } /* ================================================== */ static void parse_allow_deny(const char *line, AllowDeny *list, int allow) { const char *p; unsigned long a, b, c, d, n; int all = 0; AllowDeny *new_node = NULL; unsigned long ip_addr; p = line; while (*p && isspace((unsigned char)*p)) p++; if (!strncmp(p, "all", 3)) { all = 1; p += 3; } while (*p && isspace((unsigned char)*p)) p++; if (!*p) { /* Empty line applies to all addresses */ new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; new_node->ip = 0UL; new_node->subnet_bits = 0; } else { char *slashpos; slashpos = strchr(p, '/'); if (slashpos) *slashpos = 0; n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); if (n >= 1) { new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; a &= 0xff; b &= 0xff; c &= 0xff; d &= 0xff; switch (n) { case 1: new_node->ip = (a<<24); new_node->subnet_bits = 8; break; case 2: new_node->ip = (a<<24) | (b<<16); new_node->subnet_bits = 16; break; case 3: new_node->ip = (a<<24) | (b<<16) | (c<<8); new_node->subnet_bits = 24; break; case 4: new_node->ip = (a<<24) | (b<<16) | (c<<8) | d; new_node->subnet_bits = 32; break; default: assert(0); } if (slashpos) { int specified_subnet_bits, n; n = sscanf(slashpos+1, "%d", &specified_subnet_bits); if (n == 1) { new_node->subnet_bits = specified_subnet_bits; } else { LOG(LOGS_WARN, LOGF_Configure, "Could not read subnet size at line %d", line_number); } } } else { ip_addr = DNS_Name2IPAddress(p); if (ip_addr != DNS_Failed_Address) { new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; new_node->ip = ip_addr; new_node->subnet_bits = 32; } else { LOG(LOGS_WARN, LOGF_Configure, "Could not read address at line %d", line_number); } } } if (new_node) { new_node->prev = list->prev; new_node->next = list; list->prev->next = new_node; list->prev = new_node; } } /* ================================================== */ static void parse_allow(const char *line) { parse_allow_deny(line, &ntp_auth_list, 1); } /* ================================================== */ static void parse_deny(const char *line) { parse_allow_deny(line, &ntp_auth_list, 0); } /* ================================================== */ static void parse_cmdallow(const char *line) { parse_allow_deny(line, &cmd_auth_list, 1); } /* ================================================== */ static void parse_cmddeny(const char *line) { parse_allow_deny(line, &cmd_auth_list, 0); } /* ================================================== */ static unsigned long parse_an_address(const char *line, const char *errmsg) { unsigned long a, b, c, d; int n; n = sscanf(line, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); if (n == 4) { return (((a&0xff)<<24) | ((b&0xff)<<16) | ((c&0xff)<<8) | (d&0xff)); } else { LOG(LOGS_WARN, LOGF_Configure, errmsg, line_number); return 0UL; } } /* ================================================== */ static void parse_bindaddress(const char *line) { bind_address = parse_an_address(line, "Could not read bind address at line %d\n"); } /* ================================================== */ static void parse_bindcmdaddress(const char *line) { bind_cmd_address = parse_an_address(line, "Could not read bind command address at line %d\n"); } /* ================================================== */ static void parse_pidfile(const char *line) { pidfile = MallocArray(char, 1 + strlen(line)); sscanf(line, "%s", pidfile); strip_trailing_spaces(pidfile); } /* ================================================== */ typedef struct { /* Both in host (not necessarily network) order */ unsigned long addr; unsigned short port; int interval; } NTP_Broadcast_Destination; static NTP_Broadcast_Destination *broadcasts = NULL; static int max_broadcasts = 0; static int n_broadcasts = 0; /* ================================================== */ static void parse_broadcast(const char *line) { /* Syntax : broadcast [] */ int port; unsigned int a, b, c, d; int n; int interval; unsigned long addr; n = sscanf(line, "%d %u.%u.%u.%u %d", &interval, &a, &b, &c, &d, &port); if (n < 5) { LOG(LOGS_WARN, LOGF_Configure, "Could not parse broadcast directive at line %d", line_number); return; } else if (n == 5) { /* default port */ port = 123; } else if (n > 6) { LOG(LOGS_WARN, LOGF_Configure, "Too many fields in broadcast directive at line %d", line_number); } addr = ((unsigned long) a << 24) | ((unsigned long) b << 16) | ((unsigned long) c << 8) | ((unsigned long) d ); if (max_broadcasts == n_broadcasts) { /* Expand array */ max_broadcasts += 8; if (broadcasts) { broadcasts = ReallocArray(NTP_Broadcast_Destination, max_broadcasts, broadcasts); } else { broadcasts = MallocArray(NTP_Broadcast_Destination, max_broadcasts); } } broadcasts[n_broadcasts].addr = addr; broadcasts[n_broadcasts].port = port; broadcasts[n_broadcasts].interval = interval; ++n_broadcasts; } /* ================================================== */ static void parse_linux_hz(const char *line) { if (1 == sscanf(line, "%d", &linux_hz)) { set_linux_hz = 1; } else { LOG(LOGS_WARN, LOGF_Configure, "Could not parse linux_hz directive at line %d", line_number); } } /* ================================================== */ static void parse_linux_freq_scale(const char *line) { if (1 == sscanf(line, "%lf", &linux_freq_scale)) { set_linux_freq_scale = 1; } else { LOG(LOGS_WARN, LOGF_Configure, "Could not parse linux_freq_scale directive at line %d", line_number); } } /* ================================================== */ void CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything) { if (do_init_stepslew) { ACQ_StartAcquisition(n_init_srcs, init_srcs_ip, init_slew_threshold, after_hook, anything); } else { (after_hook)(anything); } } /* ================================================== */ void CNF_AddSources(void) { NTP_Remote_Address server; int i; for (i=0; inext) { status = NCR_AddAccessRestriction(node->ip, node->subnet_bits, node->allow, node->all); if (!status) { LOG(LOGS_WARN, LOGF_Configure, "Bad subnet for %08lx", node->ip); } } for (node = cmd_auth_list.next; node != &cmd_auth_list; node = node->next) { status = CAM_AddAccessRestriction(node->ip, node->subnet_bits, node->allow, node->all); if (!status) { LOG(LOGS_WARN, LOGF_Configure, "Bad subnet for %08lx", node->ip); } } return; } /* ================================================== */ int CNF_GetNoClientLog(void) { return no_client_log; } /* ================================================== */ void CNF_GetBindAddress(unsigned long *addr) { *addr = bind_address; } /* ================================================== */ void CNF_GetBindCommandAddress(unsigned long *addr) { *addr = bind_cmd_address ? bind_cmd_address : bind_address; } /* ================================================== */ char * CNF_GetPidFile(void) { return pidfile; } /* ================================================== */ void CNF_GetLinuxHz(int *set, int *hz) { *set = set_linux_hz; *hz = linux_hz; } /* ================================================== */ void CNF_GetLinuxFreqScale(int *set, double *freq_scale) { *set = set_linux_freq_scale; *freq_scale = linux_freq_scale ; }