Compare commits

...

No commits in common. "c8" and "a9-beta-deprecated" have entirely different histories.

15 changed files with 421 additions and 1383 deletions

View File

@ -1,2 +1,3 @@
0f5de043b395311a58bcf4be9800f7118afd5f59 SOURCES/chrony-4.2.tar.gz
2e1fac8161ea8d92d76532c0b272fb31799bc310 SOURCES/clknetsim-824c48.tar.gz
1395afa521d2e3302a31083edcf568bbc036aafc SOURCES/gpgkey-8F375C7E8D0EE125A3D3BD51537E2B76F7680DAC.asc

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
SOURCES/chrony-4.2.tar.gz
SOURCES/clknetsim-824c48.tar.gz
SOURCES/gpgkey-8F375C7E8D0EE125A3D3BD51537E2B76F7680DAC.asc

View File

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEjzdcfo0O4SWj071RU34rdvdoDawFAmG7LoQACgkQU34rdvdo
Daw47w//fpF3YlqSJWQObHv/hMC6EGQSX6hRVzckXgzq7PFN2HaTX1iZV2UsP1KN
NtXfH3V7PxTdT4jT41bHUw++vN0HXkaAw3ccbm31MVTc353JFv5VUKT/OtK+I8dZ
CKGDy7X4REET7rCYTEfhgvAwjisIlc81xFq9fMYiGasj2LXZD9GUFHqu0JzvvyMz
R0PNGDSYaJX5Ex1GtbgULjDJNF0FRDE+T6SBjs8Xlej020DbNRb4MNZitzygMNum
ChN2MltzEccw/UegrsaN1UYQG2C4/Xgdjeqfa4ioiewBL0/79oPkNyJT0GCtOIUM
TCAdDRrwLuh7d3+Hl6szy8FxKRFN4s/TTjSTinwDCaexqqNgKeSRkJPFWPWhq4l1
2W+hh5cYtToP4wYNpFdadz+LJYrRzYEtAKdFMegYt2Q/MMVtsNji4qeJ/VOnyrUI
cJD6sWqDtrUQnegVky1QDwKIYLzO+h6kDaTEm7ZhaT3pR4gGC47umPR9HAcgch0/
QdmHd1dP1rutDdpiGmXRicvSV48M1Ol6AAs7rUERuQGJ4Tl/zoMGWmN93UQEpisS
9L1PBNdAjdutJaZKA3Bgq49BOPzcRGvhamH63fO5Q+h6uXCzxd9s8MDeY8wh3Idn
2aHcGnx32z3DNbpG/nXtKE3GeiSDbw6FmN4KUmKKBR552lCcgpA=
=F4BS
-----END PGP SIGNATURE-----

View File

@ -1,29 +0,0 @@
diff -up chrony-4.1/examples/chrony.conf.example2.defconfig chrony-4.1/examples/chrony.conf.example2
--- chrony-4.1/examples/chrony.conf.example2.defconfig 2021-05-12 13:06:15.000000000 +0200
+++ chrony-4.1/examples/chrony.conf.example2 2019-05-10 12:22:57.000000000 +0200
@@ -1,5 +1,5 @@
# Use public servers from the pool.ntp.org project.
-# Please consider joining the pool (https://www.pool.ntp.org/join.html).
+# Please consider joining the pool (http://www.pool.ntp.org/join.html).
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
@@ -25,18 +25,9 @@ rtcsync
# Serve time even if not synchronized to a time source.
#local stratum 10
-# Require authentication (nts or key option) for all NTP sources.
-#authselectmode require
-
# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys
-# Save NTS keys and cookies.
-ntsdumpdir /var/lib/chrony
-
-# Insert/delete leap seconds by slewing instead of stepping.
-#leapsecmode slew
-
# Get TAI-UTC offset and leap seconds from the system tz database.
#leapsectz right/UTC

View File

@ -1,8 +0,0 @@
[Unit]
Description=DNS SRV lookup of %I for chrony
After=chronyd.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/libexec/chrony-helper update-dnssrv-servers %I

View File

@ -1,9 +0,0 @@
[Unit]
Description=Periodic DNS SRV lookup of %I for chrony
[Timer]
OnActiveSec=0
OnUnitInactiveSec=1h
[Install]
WantedBy=timers.target

View File

@ -1,108 +0,0 @@
commit 33a1fe7a9ce223d6287ab7b11bca3208e9255cdd
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Mar 9 15:30:16 2022 +0100
ntp: split out conf_id allocation
diff --git a/ntp_sources.c b/ntp_sources.c
index 3cbb2ae7..30770825 100644
--- a/ntp_sources.c
+++ b/ntp_sources.c
@@ -698,21 +698,25 @@ static int get_unused_pool_id(void)
/* ================================================== */
-NSR_Status
-NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
- SourceParameters *params, uint32_t *conf_id)
+static uint32_t
+get_next_conf_id(uint32_t *conf_id)
{
- NSR_Status s;
-
- s = add_source(remote_addr, NULL, type, params, INVALID_POOL, last_conf_id + 1);
- if (s != NSR_Success)
- return s;
-
last_conf_id++;
+
if (conf_id)
*conf_id = last_conf_id;
- return s;
+ return last_conf_id;
+}
+
+/* ================================================== */
+
+NSR_Status
+NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
+ SourceParameters *params, uint32_t *conf_id)
+{
+ return add_source(remote_addr, NULL, type, params, INVALID_POOL,
+ get_next_conf_id(conf_id));
}
/* ================================================== */
@@ -725,6 +729,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
struct SourcePool *sp;
NTP_Remote_Address remote_addr;
int i, new_sources, pool_id;
+ uint32_t cid;
/* If the name is an IP address, add the source with the address directly */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
@@ -770,14 +775,12 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
append_unresolved_source(us);
- last_conf_id++;
- if (conf_id)
- *conf_id = last_conf_id;
+ cid = get_next_conf_id(conf_id);
for (i = 0; i < new_sources; i++) {
if (i > 0)
remote_addr.ip_addr.addr.id = ++last_address_id;
- if (add_source(&remote_addr, name, type, params, us->pool_id, last_conf_id) != NSR_Success)
+ if (add_source(&remote_addr, name, type, params, us->pool_id, cid) != NSR_Success)
return NSR_TooManySources;
}
commit 1219f99935ca9597eb0e4f4c6039e536462cf1a6
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Mar 9 15:34:16 2022 +0100
ntp: keep original source IP address
When an added source is specified by IP address, save the original
string instead of formatting a new string from the parsed address, which
can be different (e.g. compressed vs expanded IPv6 address).
This fixes the chronyc sourcename command and -N option to print the IP
address exactly as it was specified in the configuration file or chronyc
add command.
diff --git a/ntp_sources.c b/ntp_sources.c
index 30770825..d46c211d 100644
--- a/ntp_sources.c
+++ b/ntp_sources.c
@@ -353,7 +353,6 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
record_lock = 1;
record = get_record(slot);
- assert(!name || !UTI_IsStringIP(name));
record->name = Strdup(name ? name : UTI_IPToString(&remote_addr->ip_addr));
record->data = NCR_CreateInstance(remote_addr, type, params, record->name);
record->remote_addr = NCR_GetRemoteAddress(record->data);
@@ -734,7 +733,8 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
/* If the name is an IP address, add the source with the address directly */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
remote_addr.port = port;
- return NSR_AddSource(&remote_addr, type, params, conf_id);
+ return add_source(&remote_addr, name, type, params, INVALID_POOL,
+ get_next_conf_id(conf_id));
}
/* Make sure the name is at least printable and has no spaces */

View File

@ -1,3 +1,146 @@
commit 5bd13c8d593a74ad168057efe94dd2b3aeeffe14
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Feb 7 13:27:25 2022 +0100
examples: support DHCPv6 NTP servers in NM dispatcher script
Latest NetworkManager code provides NTP servers from the DHCPv6 NTP
option (RFC 5908) in the DHCP6_DHCP6_NTP_SERVERS variable to dispatcher
scripts.
Check for invalid characters (which can come from the FQDN suboption)
and include the servers in the interface-specific sources file.
diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
index 6ea4c370..4454f037 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -1,8 +1,7 @@
#!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to update
-# its NTP sources passed from DHCP options. Note that this script is
-# specific to NetworkManager-dispatcher due to use of the
-# DHCP4_NTP_SERVERS environment variable.
+# its NTP sources with servers from DHCP options passed by NetworkManager
+# in the DHCP4_NTP_SERVERS and DHCP6_DHCP6_NTP_SERVERS environment variables.
export LC_ALL=C
@@ -10,17 +9,19 @@ interface=$1
action=$2
chronyc=/usr/bin/chronyc
-default_server_options=iburst
+server_options=iburst
server_dir=/var/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
-# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
-nm_dhcp_servers=$DHCP4_NTP_SERVERS
+dhcp_ntp_servers="$DHCP4_NTP_SERVERS $DHCP6_DHCP6_NTP_SERVERS"
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
- for server in $nm_dhcp_servers; do
- echo "server $server $default_server_options" >> "$dhcp_server_file"
+ for server in $dhcp_ntp_servers; do
+ # Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
+ printf '%s\n' "$server" | grep -E -q '^[-A-Za-z0-9:.]{1,255}$' || continue
+
+ printf 'server %s %s\n' "$server" "$server_options" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
@@ -34,10 +35,11 @@ clear_servers_from_dhcp() {
mkdir -p $server_dir
-if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
- add_servers_from_dhcp
-elif [ "$action" = "down" ]; then
- clear_servers_from_dhcp
-fi
+case "$action" in
+ up|dhcp4-change|dhcp6-change)
+ add_servers_from_dhcp;;
+ down)
+ clear_servers_from_dhcp;;
+esac
exit 0
commit e55f174bd3a7ae82fb24afd43443d0b55d5536cf
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Feb 7 13:27:48 2022 +0100
examples: handle more actions in NM dispatcher script
Run the chronyc onoffline command also when the connectivity-change
and dhcp6-change actions are reported by the NetworkManager dispatcher.
The latter should not be necessary, but there currently doesn't seem to
be any action for IPv6 becoming routable after duplicate address
detection, so at least in networks using DHCPv6, IPv6 NTP servers should
not be stuck in the offline state from a previously reported action.
diff --git a/examples/chrony.nm-dispatcher.onoffline b/examples/chrony.nm-dispatcher.onoffline
index 34cfa0db..01e6fdb1 100644
--- a/examples/chrony.nm-dispatcher.onoffline
+++ b/examples/chrony.nm-dispatcher.onoffline
@@ -7,8 +7,18 @@ export LC_ALL=C
chronyc=/usr/bin/chronyc
-# For NetworkManager consider only up/down events
-[ $# -ge 2 ] && [ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
+# For NetworkManager consider only selected events
+if [ $# -ge 2 ]; then
+ case "$2" in
+ up|down|connectivity-change)
+ ;;
+ dhcp6-change)
+ # No other action is reported for routable IPv6
+ ;;
+ *)
+ exit 0;;
+ esac
+fi
# Note: for networkd-dispatcher routable.d ~= on and off.d ~= off
commit fca8966adaaf8376536af86ba2afe02501463588
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Mar 23 15:17:03 2022 +0100
examples: replace grep command in NM dispatcher script
Some grep implementations detect binary data and return success without
matching whole line. This might be an issue for the DHCPv6 NTP FQDN
check. The GNU grep in the C locale seems to check only for the NUL
character, which cannot be passed in an environment variable, but other
implementations might behave differently and there doesn't seem to be a
portable way to force matching the whole line.
Instead of the grep command, check for invalid characters by comparing
the length of the input passed through "tr -d -c".
diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
index 4454f037..547ce83f 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -19,7 +19,11 @@ add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
for server in $dhcp_ntp_servers; do
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
- printf '%s\n' "$server" | grep -E -q '^[-A-Za-z0-9:.]{1,255}$' || continue
+ len1=$(printf '%s' "$server" | wc -c)
+ len2=$(printf '%s' "$server" | tr -d -c 'A-Za-z0-9:.-' | wc -c)
+ if [ "$len1" -ne "$len2" ] || [ "$len2" -lt 1 ] || [ "$len2" -gt 255 ]; then
+ continue
+ fi
printf 'server %s %s\n' "$server" "$server_options" >> "$dhcp_server_file"
done
From: Robert Fairley <rfairley@redhat.com>
Date: Wed, 17 Jun 2020 10:14:19 -0400
Subject: [PATCH] examples/nm-dispatcher.dhcp: use sysconfig
@ -11,90 +154,29 @@ diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.
index 6ea4c37..a6ad35a 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -6,16 +6,24 @@
chronyc=/usr/bin/chronyc
default_server_options=iburst
-server_dir=/var/run/chrony-dhcp
+server_dir=/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
nm_dhcp_servers=$DHCP4_NTP_SERVERS
@@ -8,15 +8,23 @@ export LC_ALL=C
interface=$1
action=$2
+[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
+[ -f /etc/sysconfig/network-scripts/ifcfg-"${interface}" ] && \
+ . /etc/sysconfig/network-scripts/ifcfg-"${interface}"
+
chronyc=/usr/bin/chronyc
-server_options=iburst
-server_dir=/var/run/chrony-dhcp
+server_options=${NTPSERVERARGS:-iburst}
+server_dir=/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
dhcp_ntp_servers="$DHCP4_NTP_SERVERS $DHCP6_DHCP6_NTP_SERVERS"
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
+
+ # Don't add NTP servers if PEERNTP=no specified; return early.
+ [ "$PEERNTP" = "no" ] && return
+
for server in $nm_dhcp_servers; do
- echo "server $server $default_server_options" >> "$dhcp_server_file"
+ echo "server $server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
--
2.29.2
Use chrony-helper instead of chronyc to avoid changes in default chrony.conf
diff -up chrony-4.1/examples/chrony.nm-dispatcher.dhcp.nm-dispatcher-dhcp chrony-4.1/examples/chrony.nm-dispatcher.dhcp
--- chrony-4.1/examples/chrony.nm-dispatcher.dhcp.nm-dispatcher-dhcp 2021-06-09 11:10:30.997416152 +0200
+++ chrony-4.1/examples/chrony.nm-dispatcher.dhcp 2021-06-09 11:16:23.598381336 +0200
@@ -9,11 +9,12 @@ export LC_ALL=C
interface=$1
action=$2
-chronyc=/usr/bin/chronyc
+helper=/usr/libexec/chrony-helper
default_server_options=iburst
-server_dir=/run/chrony-dhcp
+server_dir=/run/chrony-helper
-dhcp_server_file=$server_dir/$interface.sources
+dhcp_server_tmpfile=$server_dir/tmp-nm-dhcp.$interface
+dhcp_server_file=$server_dir/nm-dhcp.$interface
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
nm_dhcp_servers=$DHCP4_NTP_SERVERS
@@ -24,24 +24,30 @@ nm_dhcp_servers=$DHCP4_NTP_SERVERS
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
+ # Remove servers saved by the dhclient script before it detected NM.
+ rm -f "/var/lib/dhclient/chrony.servers.$interface"
+
# Don't add NTP servers if PEERNTP=no specified; return early.
[ "$PEERNTP" = "no" ] && return
+ # Create the directory with correct SELinux context.
+ $helper create-helper-directory > /dev/null 2>&1
+
for server in $nm_dhcp_servers; do
- echo "server $server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_file"
+ echo "$server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_tmpfile"
done
+ [ -e "$dhcp_server_tmpfile" ] && mv "$dhcp_server_tmpfile" "$dhcp_server_file"
- $chronyc reload sources > /dev/null 2>&1 || :
+
+ $helper update-daemon > /dev/null 2>&1 || :
}
clear_servers_from_dhcp() {
if [ -f "$dhcp_server_file" ]; then
rm -f "$dhcp_server_file"
- $chronyc reload sources > /dev/null 2>&1 || :
+ $helper update-daemon > /dev/null 2>&1 || :
fi
}
-mkdir -p $server_dir
-
if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
add_servers_from_dhcp
elif [ "$action" = "down" ]; then
for server in $dhcp_ntp_servers; do
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
len1=$(printf '%s' "$server" | wc -c)

View File

@ -0,0 +1,31 @@
commit 8bb8f15a7d049ed26c69d95087065b381f76ec4d
Author: Michael Hudson-Doyle <michael.hudson@canonical.com>
Date: Wed Feb 9 09:06:13 2022 +0100
sys_linux: allow rseq in seccomp filter
Libc 2.35 will use rseq syscalls [1][2] by default and thereby
break chrony in seccomp isolation.
[1]: https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/
[2]: https://sourceware.org/pipermail/libc-alpha/2022-February/136040.html
Tested-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Reviewed-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Signed-off-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
diff --git a/sys_linux.c b/sys_linux.c
index 9cab2efa..cc3c9311 100644
--- a/sys_linux.c
+++ b/sys_linux.c
@@ -497,6 +497,9 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext context)
SCMP_SYS(getrlimit),
SCMP_SYS(getuid),
SCMP_SYS(getuid32),
+#ifdef __NR_rseq
+ SCMP_SYS(rseq),
+#endif
SCMP_SYS(rt_sigaction),
SCMP_SYS(rt_sigreturn),
SCMP_SYS(rt_sigprocmask),

View File

@ -1,12 +0,0 @@
diff -up chrony-4.1/examples/chronyd.service.service-helper chrony-4.1/examples/chronyd.service
--- chrony-4.1/examples/chronyd.service.service-helper 2021-05-12 13:06:15.000000000 +0200
+++ chrony-4.1/examples/chronyd.service 2021-06-15 09:01:56.948968576 +0200
@@ -10,6 +10,8 @@ Type=forking
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
+ExecStartPost=/usr/libexec/chrony-helper update-daemon
+ExecStopPost=/usr/libexec/chrony-helper remove-daemon-state
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

View File

@ -1,83 +1,38 @@
diff --git a/examples/chrony-wait.service b/examples/chrony-wait.service
index 72b028f2..b3aa7aa2 100644
--- a/examples/chrony-wait.service
+++ b/examples/chrony-wait.service
@@ -16,32 +16,5 @@ TimeoutStartSec=180
RemainAfterExit=yes
StandardOutput=null
-CapabilityBoundingSet=
-DevicePolicy=closed
-DynamicUser=yes
-IPAddressAllow=localhost
-IPAddressDeny=any
-LockPersonality=yes
-MemoryDenyWriteExecute=yes
-PrivateDevices=yes
-PrivateUsers=yes
-ProcSubset=pid
-ProtectClock=yes
-ProtectControlGroups=yes
-ProtectHome=yes
-ProtectHostname=yes
-ProtectKernelLogs=yes
-ProtectKernelModules=yes
-ProtectKernelTunables=yes
-ProtectProc=invisible
-ProtectSystem=strict
-RestrictAddressFamilies=AF_INET AF_INET6
-RestrictNamespaces=yes
-RestrictRealtime=yes
-SystemCallArchitectures=native
-SystemCallFilter=@system-service
-SystemCallFilter=~@privileged @resources
-UMask=0777
-
[Install]
WantedBy=multi-user.target
diff --git a/examples/chronyd.service b/examples/chronyd.service
index 4fb930ef..289548cb 100644
--- a/examples/chronyd.service
+++ b/examples/chronyd.service
@@ -10,40 +10,9 @@ Type=forking
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
-
-CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
-CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE
-CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD CAP_SYS_ADMIN
-CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_PACCT
-CapabilityBoundingSet=~CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM
-DeviceAllow=char-pps rw
-DeviceAllow=char-ptp rw
-DeviceAllow=char-rtc rw
-DevicePolicy=closed
-LockPersonality=yes
-MemoryDenyWriteExecute=yes
-NoNewPrivileges=yes
PrivateTmp=yes
-ProcSubset=pid
-ProtectControlGroups=yes
ProtectHome=yes
-ProtectHostname=yes
-ProtectKernelLogs=yes
-ProtectKernelModules=yes
-ProtectKernelTunables=yes
-ProtectProc=invisible
diff -up chrony-4.2/examples/chronyd.service.services chrony-4.2/examples/chronyd.service
--- chrony-4.2/examples/chronyd.service.services 2021-12-16 13:17:42.000000000 +0100
+++ chrony-4.2/examples/chronyd.service 2022-01-19 13:55:59.066677473 +0100
@@ -32,8 +32,7 @@ ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
-ProtectSystem=strict
-ReadWritePaths=/run /var/lib/chrony -/var/log
-RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
-RestrictNamespaces=yes
-RestrictSUIDSGID=yes
-SystemCallArchitectures=native
-SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @swap
-
-# Adjust restrictions for /usr/sbin/sendmail (mailonchange directive)
-NoNewPrivileges=no
-ReadWritePaths=-/var/spool
-RestrictAddressFamilies=AF_NETLINK
+ProtectSystem=full
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictSUIDSGID=yes
@@ -42,7 +41,6 @@ SystemCallFilter=~@cpu-emulation @debug
# Adjust restrictions for /usr/sbin/sendmail (mailonchange directive)
NoNewPrivileges=no
-ReadWritePaths=-/var/spool
RestrictAddressFamilies=AF_NETLINK
[Install]
WantedBy=multi-user.target
Avoid a SELinux issue
diff --git a/examples/chrony-wait.service b/examples/chrony-wait.service
index 72b028f2..57646950 100644
--- a/examples/chrony-wait.service
+++ b/examples/chrony-wait.service
@@ -18,7 +18,7 @@ StandardOutput=null
CapabilityBoundingSet=
DevicePolicy=closed
-DynamicUser=yes
+#DynamicUser=yes
IPAddressAllow=localhost
IPAddressDeny=any
LockPersonality=yes

View File

@ -1,6 +1,7 @@
#!/bin/bash
SERVERFILE=$SAVEDIR/chrony.servers.$interface
CHRONY_SOURCEDIR=/run/chrony-dhcp
SERVERFILE=$CHRONY_SOURCEDIR/$interface.sources
chrony_config() {
# Disable modifications if called from a NM dispatcher script
@ -8,10 +9,11 @@ chrony_config() {
rm -f "$SERVERFILE"
if [ "$PEERNTP" != "no" ]; then
mkdir -p $CHRONY_SOURCEDIR
for server in $new_ntp_servers; do
echo "$server ${NTPSERVERARGS:-iburst}" >> "$SERVERFILE"
echo "server $server ${NTPSERVERARGS:-iburst}" >> "$SERVERFILE"
done
/usr/libexec/chrony-helper update-daemon || :
/usr/bin/chronyc reload sources > /dev/null 2>&1 || :
fi
}
@ -20,6 +22,6 @@ chrony_restore() {
if [ -f "$SERVERFILE" ]; then
rm -f "$SERVERFILE"
/usr/libexec/chrony-helper update-daemon || :
/usr/bin/chronyc reload sources > /dev/null 2>&1 || :
fi
}

View File

@ -1,285 +0,0 @@
#!/bin/bash
# This script configures running chronyd to use NTP servers obtained from
# DHCP and _ntp._udp DNS SRV records. Files with servers from DHCP are managed
# externally (e.g. by a dhclient script). Files with servers from DNS SRV
# records are updated here using the dig utility. The script can also list
# and set static sources in the chronyd configuration file.
chronyc=/usr/bin/chronyc
chrony_conf=/etc/chrony.conf
chrony_service=chronyd.service
helper_dir=/run/chrony-helper
added_servers_file=$helper_dir/added_servers
network_sysconfig_file=/etc/sysconfig/network
nm_servers_files="$helper_dir/nm-dhcp.*"
dhclient_servers_files="/var/lib/dhclient/chrony.servers.*"
dnssrv_servers_files="$helper_dir/dnssrv@*"
dnssrv_timer_prefix=chrony-dnssrv@
. $network_sysconfig_file &> /dev/null
chrony_command() {
$chronyc -n -m "$@"
}
is_running() {
chrony_command "tracking" &> /dev/null
}
get_servers_files() {
[ "$PEERNTP" != "no" ] && echo "$nm_servers_files"
[ "$PEERNTP" != "no" ] && echo "$dhclient_servers_files"
echo "$dnssrv_servers_files"
}
is_update_needed() {
for file in $(get_servers_files) $added_servers_file; do
[ -e "$file" ] && return 0
done
return 1
}
remove_daemon_state() {
rm -f $added_servers_file
}
update_daemon() {
local all_servers_with_args all_servers added_servers
if ! is_running; then
remove_daemon_state
return 0
fi
all_servers_with_args=$(cat $(get_servers_files) 2> /dev/null)
all_servers=$(
echo "$all_servers_with_args" |
while read -r server serverargs; do
echo "$server"
done | sort -u)
added_servers=$( (
cat $added_servers_file 2> /dev/null
echo "$all_servers_with_args" |
while read -r server serverargs; do
[ -z "$server" ] && continue
chrony_command "add server $server $serverargs" &> /dev/null &&
echo "$server"
done) | sort -u)
comm -23 <(echo -n "$added_servers") <(echo -n "$all_servers") |
while read -r server; do
chrony_command -c sources -a 2>/dev/null |
while IFS=, read -r type _ address _; do
[ "$type" = "^" ] || continue
[ "$(chrony_command "sourcename $address")" = "$server" ] || continue
chrony_command "delete $address" &> /dev/null
break
done
done
added_servers=$(comm -12 <(echo -n "$added_servers") <(echo -n "$all_servers"))
if [ -n "$added_servers" ]; then
echo "$added_servers" > $added_servers_file
else
rm -f $added_servers_file
fi
}
get_dnssrv_servers() {
local name=$1 output
if ! command -v dig &> /dev/null; then
echo "Missing dig (DNS lookup utility)" >&2
return 1
fi
output=$(dig "$name" srv +short +ndots=2 +search 2> /dev/null) || return 0
echo "$output" | while read -r _ _ port target; do
server=${target%.}
[ -z "$server" ] && continue
echo "$server port $port ${NTPSERVERARGS:-iburst}"
done
}
check_dnssrv_name() {
local name=$1
if [ -z "$name" ]; then
echo "No DNS SRV name specified" >&2
return 1
fi
if [ "${name:0:9}" != _ntp._udp ]; then
echo "DNS SRV name $name doesn't start with _ntp._udp" >&2
return 1
fi
}
update_dnssrv_servers() {
local name=$1
local srv_file=$helper_dir/dnssrv@$name servers
check_dnssrv_name "$name" || return 1
servers=$(get_dnssrv_servers "$name")
if [ -n "$servers" ]; then
echo "$servers" > "$srv_file"
else
rm -f "$srv_file"
fi
}
set_dnssrv_timer() {
local state=$1 name=$2
local srv_file=$helper_dir/dnssrv@$name servers
local timer
timer=$dnssrv_timer_prefix$(systemd-escape "$name").timer || return 1
check_dnssrv_name "$name" || return 1
if [ "$state" = enable ]; then
systemctl enable "$timer"
systemctl start "$timer"
elif [ "$state" = disable ]; then
systemctl stop "$timer"
systemctl disable "$timer"
rm -f "$srv_file"
fi
}
list_dnssrv_timers() {
systemctl --all --full -t timer list-units | grep "^$dnssrv_timer_prefix" | \
sed "s|^$dnssrv_timer_prefix\(.*\)\.timer.*|\1|" |
while read -r name; do
systemd-escape --unescape "$name"
done
}
prepare_helper_dir() {
mkdir -p $helper_dir
exec 100> $helper_dir/lock
if ! flock -w 20 100; then
echo "Failed to lock $helper_dir" >&2
return 1
fi
}
is_source_line() {
local pattern="^[ \t]*(server|pool|peer|refclock)[ \t]+[^ \t]+"
[[ "$1" =~ $pattern ]]
}
list_static_sources() {
while read -r line; do
if is_source_line "$line"; then
echo "$line"
fi
done < $chrony_conf
}
set_static_sources() {
local new_config tmp_conf
new_config=$(
sources=$(
while read -r line; do
is_source_line "$line" && echo "$line"
done)
while read -r line; do
if ! is_source_line "$line"; then
echo "$line"
continue
fi
tmp_sources=$(
local removed=0
echo "$sources" | while read -r line2; do
if [ "$removed" -ne 0 ] || [ "$line" != "$line2" ]; then
echo "$line2"
else
removed=1
fi
done)
[ "$sources" == "$tmp_sources" ] && continue
sources=$tmp_sources
echo "$line"
done < $chrony_conf
echo "$sources"
)
tmp_conf=${chrony_conf}.tmp
cp -a $chrony_conf $tmp_conf &&
echo "$new_config" > $tmp_conf &&
mv $tmp_conf $chrony_conf || return 1
systemctl try-restart $chrony_service
}
print_help() {
echo "Usage: $0 COMMAND"
echo
echo "Commands:"
echo " create-helper-directory"
echo " update-daemon"
echo " remove-daemon-state"
echo " update-dnssrv-servers NAME"
echo " enable-dnssrv NAME"
echo " disable-dnssrv NAME"
echo " list-dnssrv"
echo " list-static-sources"
echo " set-static-sources < sources.list"
echo " is-running"
echo " command CHRONYC-COMMAND"
}
case "$1" in
create-helper-directory)
prepare_helper_dir
;;
update-daemon|add-dhclient-servers|remove-dhclient-servers)
is_update_needed || exit 0
prepare_helper_dir && update_daemon
;;
remove-daemon-state)
remove_daemon_state
;;
update-dnssrv-servers)
prepare_helper_dir && update_dnssrv_servers "$2" && update_daemon
;;
enable-dnssrv)
set_dnssrv_timer enable "$2"
;;
disable-dnssrv)
set_dnssrv_timer disable "$2" && prepare_helper_dir && update_daemon
;;
list-dnssrv)
list_dnssrv_timers
;;
list-static-sources)
list_static_sources
;;
set-static-sources)
set_static_sources
;;
is-running)
is_running
;;
command|forced-command)
chrony_command "$2"
;;
*)
print_help
exit 2
esac
exit $?

View File

@ -1,680 +0,0 @@
#!/usr/bin/python3
#
# Convert ntp configuration to chrony
#
# Copyright (C) 2018-2019 Miroslav Lichvar <mlichvar@redhat.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse
import ipaddress
import logging
import os
import re
import subprocess
import sys
# python2 compatibility hacks
if sys.version_info[0] < 3:
from io import open
reload(sys)
sys.setdefaultencoding("utf-8")
class NtpConfiguration(object):
def __init__(self, root_dir, ntp_conf, step_tickers):
self.root_dir = root_dir if root_dir != "/" else ""
self.ntp_conf_path = ntp_conf
self.step_tickers_path = step_tickers
# Read and write files using an 8-bit transparent encoding
self.file_encoding = "latin-1"
self.enabled_services = set()
self.step_tickers = []
self.time_sources = []
self.fudges = {}
self.restrictions = {
# Built-in defaults
ipaddress.ip_network(u"0.0.0.0/0"): set(),
ipaddress.ip_network(u"::/0"): set(),
}
self.keyfile = ""
self.keys = []
self.trusted_keys = []
self.driftfile = ""
self.statistics = []
self.leapfile = ""
self.tos_options = {}
self.ignored_directives = set()
self.ignored_lines = []
# self.detect_enabled_services()
self.parse_step_tickers()
self.parse_ntp_conf()
def detect_enabled_services(self):
for service in ["ntpdate", "ntpd", "ntp-wait"]:
service_path = os.path.join(self.root_dir,
"etc/systemd/system/multi-user.target.wants/{}.service".format(service))
if os.path.islink(service_path):
self.enabled_services.add(service)
logging.info("Enabled services found in /etc/systemd/system: %s",
" ".join(self.enabled_services))
def parse_step_tickers(self):
if not self.step_tickers_path:
return
path = os.path.join(self.root_dir, self.step_tickers_path)
if not os.path.isfile(path):
logging.info("Missing %s", path)
return
with open(path, encoding=self.file_encoding) as f:
for line in f:
line = line[:line.find('#')]
words = line.split()
if not words:
continue
self.step_tickers.extend(words)
def parse_ntp_conf(self, path=None):
if path is None:
path = os.path.join(self.root_dir, self.ntp_conf_path)
with open(path, encoding=self.file_encoding) as f:
logging.info("Reading %s", path)
for line in f:
line = line[:line.find('#')]
words = line.split()
if not words:
continue
if not self.parse_directive(words):
self.ignored_lines.append(line)
def parse_directive(self, words):
name = words.pop(0)
if name.startswith("logconfig"):
name = "logconfig"
if words:
if name in ["server", "peer", "pool"]:
return self.parse_source(name, words)
elif name == "fudge":
return self.parse_fudge(words)
elif name == "restrict":
return self.parse_restrict(words)
elif name == "tos":
return self.parse_tos(words)
elif name == "includefile":
return self.parse_includefile(words)
elif name == "keys":
return self.parse_keys(words)
elif name == "trustedkey":
return self.parse_trustedkey(words)
elif name == "driftfile":
self.driftfile = words[0]
elif name == "statistics":
self.statistics = words
elif name == "leapfile":
self.leapfile = words[0]
else:
self.ignored_directives.add(name)
return False
else:
self.ignored_directives.add(name)
return False
return True
def parse_source(self, source_type, words):
ipv4_only = False
ipv6_only = False
source = {
"type": source_type,
"options": []
}
if words[0] == "-4":
ipv4_only = True
words.pop(0)
elif words[0] == "-6":
ipv6_only = True
words.pop(0)
if not words:
return False
source["address"] = words.pop(0)
# Check if -4/-6 corresponds to the address and ignore hostnames
if ipv4_only or ipv6_only:
try:
version = ipaddress.ip_address(source["address"]).version
if (ipv4_only and version != 4) or (ipv6_only and version != 6):
return False
except ValueError:
return False
if source["address"].startswith("127.127."):
if not source["address"].startswith("127.127.1."):
# Ignore non-LOCAL refclocks
return False
while words:
if len(words) >= 2 and words[0] in ["minpoll", "maxpoll", "version", "key"]:
source["options"].append((words[0], words[1]))
words = words[2:]
elif words[0] in ["burst", "iburst", "noselect", "prefer", "true", "xleave"]:
source["options"].append((words[0],))
words.pop(0)
else:
return False
self.time_sources.append(source)
return True
def parse_fudge(self, words):
address = words.pop(0)
options = {}
while words:
if len(words) >= 2 and words[0] in ["stratum"]:
if not words[1].isdigit():
return False
options[words[0]] = int(words[1])
words = words[2:]
elif len(words) >= 2:
words = words[2:]
else:
return False
self.fudges[address] = options
return True
def parse_restrict(self, words):
ipv4_only = False
ipv6_only = False
flags = set()
mask = ""
if words[0] == "-4":
ipv4_only = True
words.pop(0)
elif words[0] == "-6":
ipv6_only = True
words.pop(0)
if not words:
return False
address = words.pop(0)
while words:
if len(words) >= 2 and words[0] == "mask":
mask = words[1]
words = words[2:]
else:
if words[0] not in ["kod", "nomodify", "notrap", "nopeer", "noquery",
"limited", "ignore", "noserve"]:
return False
flags.add(words[0])
words.pop(0)
# Convert to IP network(s), ignoring restrictions with hostnames
networks = []
if address == "default" and not mask:
if not ipv6_only:
networks.append(ipaddress.ip_network(u"0.0.0.0/0"))
if not ipv4_only:
networks.append(ipaddress.ip_network(u"::/0"))
else:
try:
if mask:
# Count bits in the mask (ipaddress does not support
# expanded IPv6 netmasks)
mask_ip = ipaddress.ip_address(mask)
mask_str = "{0:0{1}b}".format(int(mask_ip), mask_ip.max_prefixlen)
networks.append(ipaddress.ip_network(
u"{}/{}".format(address, len(mask_str.rstrip('0')))))
else:
networks.append(ipaddress.ip_network(address))
except ValueError:
return False
if (ipv4_only and networks[-1].version != 4) or \
(ipv6_only and networks[-1].version != 6):
return False
for network in networks:
self.restrictions[network] = flags
return True
def parse_tos(self, words):
options = {}
while words:
if len(words) >= 2 and words[0] in ["minsane", "orphan"]:
if not words[1].isdigit():
return False
options[words[0]] = int(words[1])
words = words[2:]
elif len(words) >= 2 and words[0] in ["maxdist"]:
# Check if it is a float value
if not words[1].replace('.', '', 1).isdigit():
return False
options[words[0]] = float(words[1])
words = words[2:]
else:
return False
self.tos_options.update(options)
return True
def parse_includefile(self, words):
path = os.path.join(self.root_dir, words[0])
if not os.path.isfile(path):
return False
self.parse_ntp_conf(path)
return True
def parse_keys(self, words):
keyfile = words[0]
path = os.path.join(self.root_dir, keyfile)
if not os.path.isfile(path):
logging.info("Missing %s", path)
return False
with open(path, encoding=self.file_encoding) as f:
logging.info("Reading %s", path)
keys = []
for line in f:
words = line.split()
if len(words) < 3 or not words[0].isdigit():
continue
keys.append((int(words[0]), words[1], words[2]))
self.keyfile = keyfile
self.keys = keys
return True
def parse_trustedkey(self, words):
key_ranges = []
for word in words:
if word.isdigit():
key_ranges.append((int(word), int(word)))
elif re.match("^[0-9]+-[0-9]+$", word):
first, last = word.split("-")
key_ranges.append((int(first), int(last)))
else:
return False
self.trusted_keys = key_ranges
return True
def write_chrony_configuration(self, chrony_conf_path, chrony_keys_path,
dry_run=False, backup=False):
chrony_conf = self.get_chrony_conf(chrony_keys_path)
logging.debug("Generated %s:\n%s", chrony_conf_path, chrony_conf)
if not dry_run:
self.write_file(chrony_conf_path, 0o644, chrony_conf, backup)
chrony_keys = self.get_chrony_keys()
if chrony_keys:
logging.debug("Generated %s:\n%s", chrony_keys_path, chrony_keys)
if not dry_run:
self.write_file(chrony_keys_path, 0o640, chrony_keys, backup)
def get_processed_time_sources(self):
# Convert {0,1,2,3}.*pool.ntp.org servers to 2.*pool.ntp.org pools
# Make shallow copies of all sources (only type will be modified)
time_sources = [s.copy() for s in self.time_sources]
pools = {}
for source in time_sources:
if source["type"] != "server":
continue
m = re.match("^([0123])(\\.\\w+)?\\.pool\\.ntp\\.org$", source["address"])
if m is None:
continue
number = m.group(1)
zone = m.group(2)
if zone not in pools:
pools[zone] = []
pools[zone].append((int(number), source))
remove_servers = set()
for zone, pool in pools.items():
# sort and skip all pools not in [0, 3] range
pool.sort()
if [number for number, source in pool] != [0, 1, 2, 3]:
# only exact group of 4 servers can be converted, nothing to do here
continue
# verify that parameters are the same for all servers in the pool
if not all([p[1]["options"] == pool[0][1]["options"] for p in pool]):
break
remove_servers.update([pool[i][1]["address"] for i in [0, 1, 3]])
pool[2][1]["type"] = "pool"
processed_sources = []
for source in time_sources:
if source["type"] == "server" and source["address"] in remove_servers:
continue
processed_sources.append(source)
return processed_sources
def get_chrony_conf_sources(self):
conf = ""
if self.step_tickers:
conf += "# Specify NTP servers used for initial correction.\n"
conf += "initstepslew 0.1 {}\n".format(" ".join(self.step_tickers))
conf += "\n"
conf += "# Specify time sources.\n"
for source in self.get_processed_time_sources():
address = source["address"]
if address.startswith("127.127."):
if address.startswith("127.127.1."):
continue
# No other refclocks are expected from the parser
assert False
else:
conf += "{} {}".format(source["type"], address)
for option in source["options"]:
if option[0] in ["minpoll", "maxpoll", "version", "key",
"iburst", "noselect", "prefer", "xleave"]:
conf += " {}".format(" ".join(option))
elif option[0] == "burst":
conf += " presend 6"
elif option[0] == "true":
conf += " trust"
else:
# No other options are expected from the parser
assert False
conf += "\n"
conf += "\n"
return conf
def get_chrony_conf_allows(self):
allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and
"noserve" not in self.restrictions[n],
self.restrictions.keys())
conf = ""
for network in sorted(allowed_networks, key=lambda n: (n.version, n)):
if network.num_addresses > 1:
conf += "allow {}\n".format(network)
else:
conf += "allow {}\n".format(network.network_address)
if conf:
conf = "# Allow NTP client access.\n" + conf
conf += "\n"
return conf
def get_chrony_conf_cmdallows(self):
allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and
"noquery" not in self.restrictions[n] and
n != ipaddress.ip_network(u"127.0.0.1/32") and
n != ipaddress.ip_network(u"::1/128"),
self.restrictions.keys())
ip_versions = set()
conf = ""
for network in sorted(allowed_networks, key=lambda n: (n.version, n)):
ip_versions.add(network.version)
if network.num_addresses > 1:
conf += "cmdallow {}\n".format(network)
else:
conf += "cmdallow {}\n".format(network.network_address)
if conf:
conf = "# Allow remote monitoring.\n" + conf
if 4 in ip_versions:
conf += "bindcmdaddress 0.0.0.0\n"
if 6 in ip_versions:
conf += "bindcmdaddress ::\n"
conf += "\n"
return conf
def get_chrony_conf(self, chrony_keys_path):
local_stratum = 0
maxdistance = 0.0
minsources = 1
orphan_stratum = 0
logs = []
for source in self.time_sources:
address = source["address"]
if address.startswith("127.127.1."):
if address in self.fudges and "stratum" in self.fudges[address]:
local_stratum = self.fudges[address]["stratum"]
else:
local_stratum = 5
if "maxdist" in self.tos_options:
maxdistance = self.tos_options["maxdist"]
if "minsane" in self.tos_options:
minsources = self.tos_options["minsane"]
if "orphan" in self.tos_options:
orphan_stratum = self.tos_options["orphan"]
if "clockstats" in self.statistics:
logs.append("refclocks")
if "loopstats" in self.statistics:
logs.append("tracking")
if "peerstats" in self.statistics:
logs.append("statistics")
if "rawstats" in self.statistics:
logs.append("measurements")
conf = "# This file was converted from {}{}.\n".format(
self.ntp_conf_path,
" and " + self.step_tickers_path if self.step_tickers_path else "")
conf += "\n"
if self.ignored_lines:
conf += "# The following directives were ignored in the conversion:\n"
for line in self.ignored_lines:
# Remove sensitive information
line = re.sub(r"\s+pw\s+\S+", " pw XXX", line.rstrip())
conf += "# " + line + "\n"
conf += "\n"
conf += self.get_chrony_conf_sources()
conf += "# Record the rate at which the system clock gains/losses time.\n"
if not self.driftfile:
conf += "#"
conf += "driftfile /var/lib/chrony/drift\n"
conf += "\n"
conf += "# Allow the system clock to be stepped in the first three updates\n"
conf += "# if its offset is larger than 1 second.\n"
conf += "makestep 1.0 3\n"
conf += "\n"
conf += "# Enable kernel synchronization of the real-time clock (RTC).\n"
conf += "rtcsync\n"
conf += "\n"
conf += "# Enable hardware timestamping on all interfaces that support it.\n"
conf += "#hwtimestamp *\n"
conf += "\n"
if maxdistance > 0.0:
conf += "# Specify the maximum distance of sources to be selectable.\n"
conf += "maxdistance {}\n".format(maxdistance)
conf += "\n"
conf += "# Increase the minimum number of selectable sources required to adjust\n"
conf += "# the system clock.\n"
if minsources > 1:
conf += "minsources {}\n".format(minsources)
else:
conf += "#minsources 2\n"
conf += "\n"
conf += self.get_chrony_conf_allows()
conf += self.get_chrony_conf_cmdallows()
conf += "# Serve time even if not synchronized to a time source.\n"
if orphan_stratum > 0 and orphan_stratum < 16:
conf += "local stratum {} orphan\n".format(orphan_stratum)
elif local_stratum > 0 and local_stratum < 16:
conf += "local stratum {}\n".format(local_stratum)
else:
conf += "#local stratum 10\n"
conf += "\n"
conf += "# Specify file containing keys for NTP authentication.\n"
conf += "keyfile {}\n".format(chrony_keys_path)
conf += "\n"
conf += "# Get TAI-UTC offset and leap seconds from the system tz database.\n"
conf += "leapsectz right/UTC\n"
conf += "\n"
conf += "# Specify directory for log files.\n"
conf += "logdir /var/log/chrony\n"
conf += "\n"
conf += "# Select which information is logged.\n"
if logs:
conf += "log {}\n".format(" ".join(logs))
else:
conf += "#log measurements statistics tracking\n"
return conf
def get_chrony_keys(self):
if not self.keyfile:
return ""
keys = "# This file was converted from {}.\n".format(self.keyfile)
keys += "\n"
for key in self.keys:
key_id = key[0]
key_type = key[1]
password = key[2]
if key_type in ["m", "M"]:
key_type = "MD5"
elif key_type == "AES128CMAC":
key_type = "AES128"
elif key_type not in ["MD5", "SHA1", "SHA256", "SHA384", "SHA512"]:
continue
prefix = "ASCII" if len(password) <= 20 else "HEX"
for first, last in self.trusted_keys:
if first <= key_id <= last:
trusted = True
break
else:
trusted = False
# Disable keys that were not marked as trusted
if not trusted:
keys += "#"
keys += "{} {} {}:{}\n".format(key_id, key_type, prefix, password)
return keys
def write_file(self, path, mode, content, backup):
path = self.root_dir + path
if backup and os.path.isfile(path):
os.rename(path, path + ".old")
with open(os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, mode), "w",
encoding=self.file_encoding) as f:
logging.info("Writing %s", path)
f.write(u"" + content)
# Fix SELinux context if restorecon is installed
try:
subprocess.call(["restorecon", path])
except OSError:
pass
def main():
parser = argparse.ArgumentParser(description="Convert ntp configuration to chrony.")
parser.add_argument("-r", "--root", dest="roots", default=["/"], nargs="+",
metavar="DIR", help="specify root directory (default /)")
parser.add_argument("--ntp-conf", action="store", default="/etc/ntp.conf",
metavar="FILE", help="specify ntp config (default /etc/ntp.conf)")
parser.add_argument("--step-tickers", action="store", default="",
metavar="FILE", help="specify ntpdate step-tickers config (no default)")
parser.add_argument("--chrony-conf", action="store", default="/etc/chrony.conf",
metavar="FILE", help="specify chrony config (default /etc/chrony.conf)")
parser.add_argument("--chrony-keys", action="store", default="/etc/chrony.keys",
metavar="FILE", help="specify chrony keyfile (default /etc/chrony.keys)")
parser.add_argument("-b", "--backup", action="store_true", help="backup existing configs before writing")
parser.add_argument("-L", "--ignored-lines", action="store_true", help="print ignored lines")
parser.add_argument("-D", "--ignored-directives", action="store_true",
help="print names of ignored directives")
parser.add_argument("-n", "--dry-run", action="store_true", help="don't make any changes")
parser.add_argument("-v", "--verbose", action="count", default=0, help="increase verbosity")
args = parser.parse_args()
logging.basicConfig(format="%(message)s",
level=[logging.ERROR, logging.INFO, logging.DEBUG][min(args.verbose, 2)])
for root in args.roots:
conf = NtpConfiguration(root, args.ntp_conf, args.step_tickers)
if args.ignored_lines:
for line in conf.ignored_lines:
print(line)
if args.ignored_directives:
for directive in conf.ignored_directives:
print(directive)
conf.write_chrony_configuration(args.chrony_conf, args.chrony_keys, args.dry_run, args.backup)
if __name__ == "__main__":
main()

View File

@ -1,53 +1,44 @@
%global _hardened_build 1
%global clknetsim_ver 824c48
%global ntp2chrony_ver 233b75
%bcond_without debug
%bcond_without nts
%ifarch %{ix86} x86_64 %{arm} aarch64 mipsel mips64el ppc64 ppc64le s390 s390x
%bcond_without seccomp
%endif
Name: chrony
Version: 4.2
Release: 1%{?dist}
Release: 1%{?dist}.alma
Summary: An NTP client/server
Group: System Environment/Daemons
License: GPLv2
URL: https://chrony.tuxfamily.org
Source0: https://download.tuxfamily.org/chrony/chrony-%{version}%{?prerelease}.tar.gz
Source1: chrony.dhclient
Source2: chrony.helper
Source3: chrony-dnssrv@.service
Source4: chrony-dnssrv@.timer
Source1: https://download.tuxfamily.org/chrony/chrony-%{version}%{?prerelease}-tar-gz-asc.txt
Source2: https://chrony.tuxfamily.org/gpgkey-8F375C7E8D0EE125A3D3BD51537E2B76F7680DAC.asc
Source3: chrony.dhclient
# simulator for test suite
Source10: https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz
# script for converting ntp configuration to chrony
Source11: https://github.com/mlichvar/ntp2chrony/raw/%{ntp2chrony_ver}/ntp2chrony/ntp2chrony.py
%{?gitpatch:Patch0: chrony-%{version}%{?prerelease}-%{gitpatch}.patch.gz}
# revert upstream changes in packaged service files
Patch0: chrony-services.patch
# modify NetworkManager DHCP dispatcher to work with chrony-helper and
# follow distribution-specific configuration
# add IPv6 support and distribution-specific bits to DHCP dispatcher
Patch1: chrony-nm-dispatcher-dhcp.patch
# add NTP servers from DHCP when starting service
Patch2: chrony-service-helper.patch
# revert upstream changes in packaged chrony.conf example
Patch3: chrony-defconfig.patch
# fix chronyc sourcename command to print IP address in original format
Patch4: chrony-ipsourcename.patch
# update seccomp filter for new glibc
Patch2: chrony-seccomp.patch
# revert some hardening options in service files
Patch3: chrony-services.patch
BuildRequires: libcap-devel libedit-devel nettle-devel pps-tools-devel
%ifarch %{ix86} x86_64 %{arm} aarch64 mipsel mips64el ppc64 ppc64le s390 s390x
BuildRequires: libseccomp-devel
%endif
BuildRequires: gcc gcc-c++ make bison systemd
BuildRequires: kernel-headers > 4.18.0-87
%{?with_nts:BuildRequires: gnutls-devel gnutls-utils}
BuildRequires: gnutls-devel libcap-devel libedit-devel pps-tools-devel
BuildRequires: gcc gcc-c++ make bison systemd gnupg2
%{?with_nts:BuildRequires: gnutls-utils}
%{?with_seccomp:BuildRequires: libseccomp-devel}
Requires(pre): shadow-utils
%{?systemd_requires}
# install timedated implementation that can control chronyd service
Recommends: timedatex
# Old NetworkManager expects the dispatcher scripts in a different place
Conflicts: NetworkManager < 1.20
# suggest drivers for hardware reference clocks
Suggests: ntp-refclock
@ -60,29 +51,28 @@ can also operate as an NTPv4 (RFC 5905) server and peer to provide a time
service to other computers in the network.
%if 0%{!?vendorzone:1}
%global vendorzone %(source /etc/os-release && echo ${ID}.)
%global vendorzone cloudlinux.
%endif
%prep
%{gpgverify} --keyring=%{SOURCE2} --signature=%{SOURCE1} --data=%{SOURCE0}
%setup -q -n %{name}-%{version}%{?prerelease} -a 10
%{?gitpatch:%patch0 -p1}
%patch0 -p1 -b .services
%patch1 -p1 -b .nm-dispatcher-dhcp
%patch2 -p1 -b .service-helper
%patch3 -p1 -b .defconfig
%patch4 -p1 -b .ipsourcename
%patch2 -p1 -b .seccomp
%patch3 -p1 -b .services
%{?gitpatch: echo %{version}-%{gitpatch} > version.txt}
# review changes in packaged configuration files and scripts
md5sum -c <<-EOF | (! grep -v 'OK$')
bc563c1bcf67b2da774bd8c2aef55a06 examples/chrony-wait.service
e473a9fab7fe200cacce3dca8b66290b examples/chrony.conf.example2
222e652b95027289877fa77146d3b9b1 examples/chrony-wait.service
2d01b94bc1a7b7fb70cbee831488d121 examples/chrony.conf.example2
96999221eeef476bd49fe97b97503126 examples/chrony.keys.example
6a3178c4670de7de393d9365e2793740 examples/chrony.logrotate
fabb5b3f127b802c27c82837feff0fe6 examples/chrony.nm-dispatcher.dhcp
8f5a98fcb400a482d355b929d04b5518 examples/chrony.nm-dispatcher.onoffline
56d221eba8ce8a2e03d3e0dd87999a81 examples/chronyd.service
c3992e2f985550739cd1cd95f98c9548 examples/chrony.nm-dispatcher.dhcp
2b81c60c020626165ac655b2633608eb examples/chrony.nm-dispatcher.onoffline
619dd00009ea312c7201beefde10341a examples/chronyd.service
EOF
# don't allow packaging without vendor zone
@ -92,9 +82,11 @@ test -n "%{vendorzone}"
# - use our vendor zone (2.*pool.ntp.org names include IPv6 addresses)
# - enable leapsectz to get TAI-UTC offset and leap seconds from tzdata
# - enable keyfile
# - use NTP servers from DHCP
sed -e 's|^\(pool \)\(pool.ntp.org\)|\12.%{vendorzone}\2|' \
-e 's|#\(leapsectz\)|\1|' \
-e 's|#\(keyfile\)|\1|' \
-e 's|^pool.*pool.ntp.org.*|&\n\n# Use NTP servers from DHCP.\nsourcedir /run/chrony-dhcp|' \
< examples/chrony.conf.example2 > chrony.conf
touch -r examples/chrony.conf.example2 chrony.conf
@ -104,13 +96,11 @@ rm -f getdate.c
mv clknetsim-%{clknetsim_ver}* test/simulation/clknetsim
install -m 644 -p %{SOURCE11} ntp2chrony.py
%build
%configure \
%{?with_debug: --enable-debug} \
--enable-ntp-signd \
--enable-scfilter \
%{?with_seccomp: --enable-scfilter} \
%{!?with_nts: --disable-nts} \
--chronyrundir=/run/chrony \
--docdir=%{_docdir} \
@ -118,46 +108,45 @@ install -m 644 -p %{SOURCE11} ntp2chrony.py
--with-user=chrony \
--with-hwclockfile=%{_sysconfdir}/adjtime \
--with-pidfile=/run/chrony/chronyd.pid \
--with-sendmail=%{_sbindir}/sendmail
make %{?_smp_mflags}
--with-sendmail=%{_sbindir}/sendmail \
--without-nettle \
--without-nss \
--without-tomcrypt
%make_build
%install
make install DESTDIR=$RPM_BUILD_ROOT
%make_install
rm -rf $RPM_BUILD_ROOT%{_docdir}
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/{sysconfig,logrotate.d}
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/{lib,log}/chrony
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d
mkdir -p $RPM_BUILD_ROOT%{_libexecdir}
mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d
mkdir -p $RPM_BUILD_ROOT{%{_unitdir},%{_prefix}/lib/systemd/ntp-units.d}
install -m 644 -p chrony.conf $RPM_BUILD_ROOT%{_sysconfdir}/chrony.conf
install -m 640 -p examples/chrony.keys.example \
$RPM_BUILD_ROOT%{_sysconfdir}/chrony.keys
install -m 755 -p examples/chrony.nm-dispatcher.onoffline \
$RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony-onoffline
install -m 755 -p examples/chrony.nm-dispatcher.dhcp \
$RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony-dhcp
install -m 755 -p %{SOURCE1} \
install -m 755 -p %{SOURCE3} \
$RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d/chrony.sh
install -m 644 -p examples/chrony.logrotate \
$RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/chrony
install -m 644 -p examples/chronyd.service \
$RPM_BUILD_ROOT%{_unitdir}/chronyd.service
install -m 755 -p examples/chrony.nm-dispatcher.onoffline \
$RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d/20-chrony-onoffline
install -m 755 -p examples/chrony.nm-dispatcher.dhcp \
$RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d/20-chrony-dhcp
install -m 644 -p examples/chrony-wait.service \
$RPM_BUILD_ROOT%{_unitdir}/chrony-wait.service
install -m 644 -p %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.service
install -m 644 -p %{SOURCE4} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.timer
install -m 755 -p %{SOURCE2} $RPM_BUILD_ROOT%{_libexecdir}/chrony-helper
cat > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/chronyd <<EOF
# Command-line options for chronyd
OPTIONS=""
OPTIONS="%{?with_seccomp:-F 2}"
EOF
touch $RPM_BUILD_ROOT%{_localstatedir}/lib/chrony/{drift,rtc}
@ -167,8 +156,8 @@ echo 'chronyd.service' > \
%check
# set random seed to get deterministic results
export CLKNETSIM_RANDOM_SEED=24502
make %{?_smp_mflags} -C test/simulation/clknetsim
export CLKNETSIM_RANDOM_SEED=24505
%make_build -C test/simulation/clknetsim
make quickcheck
%pre
@ -178,16 +167,16 @@ getent passwd chrony > /dev/null || /usr/sbin/useradd -r -g chrony \
:
%post
# fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2
if grep -q 'PIDFile=%{_localstatedir}/run/chronyd.pid' \
%{_sysconfdir}/systemd/system/chronyd.service 2> /dev/null && \
! grep -qi '^[ '$'\t'']*pidfile' %{_sysconfdir}/chrony.conf 2> /dev/null
then
sed -i '/PIDFile=/s|/run/|/run/chrony/|' \
%{_sysconfdir}/systemd/system/chronyd.service
# migrate from chrony-helper to sourcedir directive
if test -a %{_libexecdir}/chrony-helper; then
grep -qi 'sourcedir /run/chrony-dhcp$' %{_sysconfdir}/chrony.conf 2> /dev/null || \
echo -e '\n# Use NTP servers from DHCP.\nsourcedir /run/chrony-dhcp' >> \
%{_sysconfdir}/chrony.conf
mkdir -p /run/chrony-dhcp
for f in %{_localstatedir}/lib/dhclient/chrony.servers.*; do
sed 's|.*|server &|' < $f > /run/chrony-dhcp/"${f##*servers.}.sources"
done 2> /dev/null
fi
# workaround for late reload of unit file (#1614751)
%{_bindir}/systemctl daemon-reload
%systemd_post chronyd.service chrony-wait.service
%preun
@ -199,19 +188,17 @@ fi
%files
%{!?_licensedir:%global license %%doc}
%license COPYING
%doc FAQ NEWS README ntp2chrony.py
%doc FAQ NEWS README
%config(noreplace) %{_sysconfdir}/chrony.conf
%config(noreplace) %verify(not md5 size mtime) %attr(640,root,chrony) %{_sysconfdir}/chrony.keys
%config(noreplace) %{_sysconfdir}/logrotate.d/chrony
%config(noreplace) %{_sysconfdir}/sysconfig/chronyd
%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony*
%{_sysconfdir}/dhcp/dhclient.d/chrony.sh
%{_bindir}/chronyc
%{_sbindir}/chronyd
%{_libexecdir}/chrony-helper
%{_prefix}/lib/NetworkManager
%{_prefix}/lib/systemd/ntp-units.d/*.list
%{_unitdir}/chrony*.service
%{_unitdir}/chrony*.timer
%{_mandir}/man[158]/%{name}*.[158]*
%dir %attr(750,chrony,chrony) %{_localstatedir}/lib/chrony
%ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/drift
@ -219,42 +206,136 @@ fi
%dir %attr(750,chrony,chrony) %{_localstatedir}/log/chrony
%changelog
* Thu Jul 14 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.2-1
- update to 4.2 (#2062356)
- fix chrony-helper to delete sources by their original name (#2061660)
- update ntp2chrony script (#2018045 #2063766)
* Wed Sep 28 2022 Eduard Abdullin <eabdullin@almalinux.org> - 4.2-1.alma.plus
- use cloudlinux ntp pool
* Tue Jun 15 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-1
- update to 4.1 (#1895003 #1847853 #1929157)
- add NetworkManager dispatcher script to add servers from DHCP even without
dhclient (#1933139)
- restrict permissions of /var/lib/chrony and /var/log/chrony (#1939295)
- reset chrony-helper state after stopping chronyd (#1971697)
- add gcc-c++ and make to build requirements
* Wed Mar 23 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.2-1
- update to 4.2 (#2051441)
- fully switch from nettle to gnutls (#1953463 #1954483)
- use NTP servers from DHCPv6 NTP server option (#2047415)
- drop obsolete workaround in scriptlet
* Tue Aug 10 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-3
- update seccomp filter for new glibc (#1990589)
- remove unnecessary build requirement
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 4.1-2
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Thu May 13 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-1
- update to 4.1
- enable seccomp filter by default (incompatible with mailonchange directive)
* Thu Apr 22 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-0.1.pre1
- update to 4.1-pre1
- rework NM-dispatcher/dhclient detection
- enable LTO on s390x
* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 4.0-4
- Rebuilt for updated systemd-rpm-macros
See https://pagure.io/fesco/issue/2583.
* Tue Feb 02 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.0-3
- update NM DHCP dispatcher script
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
- Add BuildRequires: make
- drop dnssrv service and timer
* Wed Oct 07 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-1
- update to 4.0
- update directory permissions to follow upstream
* Wed Sep 16 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.9.pre4
- update to 4.0-pre4
* Wed Aug 26 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.8.pre3
- update to 4.0-pre3
- switch to sourcedir directive for loading servers from DHCP
- add NetworkManager dispatcher script to save servers from DHCP when
dhclient is not installed (Robert Fairley)
- drop old migration code from scriptlet
- move default paths in /var/run to /run
* Tue May 21 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-1
- update to 3.5 (#1685469 #1677218)
- fix shellcheck warnings in helper scripts (#1711948)
- update ntp2chrony script
* Mon Aug 10 2020 Jeff Law <law@redhat.com> - 4.0-0.7.pre2
- Disable LTO on s390x
* Mon Aug 13 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-3
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-0.6.pre2
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-0.5.pre2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 13 2020 Tom Stellard <tstellar@redhat.com> 4.0-0.4.pre2
- use make macros
* Mon May 04 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.3.pre2
- rebuild for new nettle
* Mon Apr 20 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.2.pre2
- update to 4.0-pre2
* Tue Mar 17 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.1.pre1
- update to 4.0-pre1
- add net-tools to build requirements for testing
- add missing dependency on coreutils
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.5-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Mon Jan 20 2020 Miroslav Lichvar <mlichvar@redhat.com> 3.5-7
- fix testing with new glibc (#1792854)
* Wed Oct 09 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-6
- drop timedatex recommendation
- verify upstream signatures
* Thu Aug 22 2019 Lubomir Rintel <lkundrak@v3.sk> - 3.5-5
- Move the NetworkManager dispatcher script out of /etc
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.5-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Tue Jul 16 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-3
- rebuild for new nettle
* Thu May 23 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-2
- fix shellcheck warnings in helper scripts
* Tue May 14 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-1
- update to 3.5
* Thu May 02 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-0.1.pre1
- update to 3.5-pre1
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Wed Sep 19 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.4-1
- update to 3.4
* Fri Aug 31 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.4-0.1.pre1
- update to 3.4-pre1
* Mon Aug 13 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-5
- fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2
(#1614800)
- add workaround for late reload of unit file (#1614751)
* Mon Jul 16 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-4
- add gcc-c++ to build requirements
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.3-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jun 18 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-2
- move pidfile to /var/run/chrony to allow chronyd to remove it on exit
(#1584585)
- avoid blocking in getrandom system call (#1592425)
- avoid blocking in getrandom system call
* Thu Apr 05 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-1
* Wed Apr 04 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-1
- update to 3.3
- enable keyfile by default again
- update ntp2chrony script
* Mon Mar 19 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.2.pre1
- include ntp2chrony script in documentation (#1530987)
* Thu Mar 15 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.1.pre1
- update to 3.3-pre1