diff --git a/.chrony.metadata b/.chrony.metadata
index 776de31..c42eda1 100644
--- a/.chrony.metadata
+++ b/.chrony.metadata
@@ -1,2 +1,2 @@
-79e9aeace143550300387a99f17bff04b45673f7 SOURCES/chrony-3.5.tar.gz
-84d41ec6da2317dab5e41d9b73ec028c78325700 SOURCES/clknetsim-3f5ef9.tar.gz
+15dc1976653f17d290b65007a4779e3f4ac1833e SOURCES/chrony-4.1.tar.gz
+6f953389765ec334465ebdef4199e25c0290646e SOURCES/clknetsim-f89702.tar.gz
diff --git a/.gitignore b/.gitignore
index e3ad503..49fef1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-SOURCES/chrony-3.5.tar.gz
-SOURCES/clknetsim-3f5ef9.tar.gz
+SOURCES/chrony-4.1.tar.gz
+SOURCES/clknetsim-f89702.tar.gz
diff --git a/README.debrand b/README.debrand
deleted file mode 100644
index 01c46d2..0000000
--- a/README.debrand
+++ /dev/null
@@ -1,2 +0,0 @@
-Warning: This package was configured for automatic debranding, but the changes
-failed to apply.
diff --git a/SOURCES/chrony-defconfig.patch b/SOURCES/chrony-defconfig.patch
new file mode 100644
index 0000000..b471de8
--- /dev/null
+++ b/SOURCES/chrony-defconfig.patch
@@ -0,0 +1,29 @@
+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
+ 
diff --git a/SOURCES/chrony-nm-dispatcher-dhcp.patch b/SOURCES/chrony-nm-dispatcher-dhcp.patch
new file mode 100644
index 0000000..7d132c1
--- /dev/null
+++ b/SOURCES/chrony-nm-dispatcher-dhcp.patch
@@ -0,0 +1,100 @@
+From: Robert Fairley <rfairley@redhat.com>
+Date: Wed, 17 Jun 2020 10:14:19 -0400
+Subject: [PATCH] examples/nm-dispatcher.dhcp: use sysconfig
+
+Use the PEERNTP and NTPSERVERARGS environment variables from
+/etc/sysconfig/network{-scripts}.
+
+Co-Authored-By: Christian Glombek <cglombek@redhat.com>
+
+diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
+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
+ 
++[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
++[ -f /etc/sysconfig/network-scripts/ifcfg-"${interface}" ] && \
++    . /etc/sysconfig/network-scripts/ifcfg-"${interface}"
++
+ 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
diff --git a/SOURCES/chrony-service-helper.patch b/SOURCES/chrony-service-helper.patch
index 6376e0b..5b7f8d3 100644
--- a/SOURCES/chrony-service-helper.patch
+++ b/SOURCES/chrony-service-helper.patch
@@ -1,11 +1,12 @@
-diff -up chrony-3.5/examples/chronyd.service.service-helper chrony-3.5/examples/chronyd.service
---- chrony-3.5/examples/chronyd.service.service-helper	2019-05-10 12:22:57.000000000 +0200
-+++ chrony-3.5/examples/chronyd.service	2019-05-14 13:42:38.069516800 +0200
-@@ -10,6 +10,7 @@ Type=forking
+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
diff --git a/SOURCES/chrony.dhclient b/SOURCES/chrony.dhclient
index be17e2a..d5398e8 100644
--- a/SOURCES/chrony.dhclient
+++ b/SOURCES/chrony.dhclient
@@ -3,6 +3,9 @@
 SERVERFILE=$SAVEDIR/chrony.servers.$interface
 
 chrony_config() {
+	# Disable modifications if called from a NM dispatcher script
+	[ -n "$NM_DISPATCHER_ACTION" ] && return 0
+
 	rm -f "$SERVERFILE"
 	if [ "$PEERNTP" != "no" ]; then
 		for server in $new_ntp_servers; do
@@ -13,6 +16,8 @@ chrony_config() {
 }
 
 chrony_restore() {
+	[ -n "$NM_DISPATCHER_ACTION" ] && return 0
+
 	if [ -f "$SERVERFILE" ]; then
 		rm -f "$SERVERFILE"
 		/usr/libexec/chrony-helper update-daemon || :
diff --git a/SOURCES/chrony.helper b/SOURCES/chrony.helper
index 95414af..16deb61 100644
--- a/SOURCES/chrony.helper
+++ b/SOURCES/chrony.helper
@@ -8,10 +8,11 @@
 chronyc=/usr/bin/chronyc
 chrony_conf=/etc/chrony.conf
 chrony_service=chronyd.service
-helper_dir=/var/run/chrony-helper
+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@
@@ -27,6 +28,7 @@ is_running() {
 }
 
 get_servers_files() {
+    [ "$PEERNTP" != "no" ] && echo "$nm_servers_files"
     [ "$PEERNTP" != "no" ] && echo "$dhclient_servers_files"
     echo "$dnssrv_servers_files"
 }
@@ -38,11 +40,15 @@ is_update_needed() {
     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
-        rm -f $added_servers_file
+        remove_daemon_state
         return 0
     fi
 
@@ -217,7 +223,9 @@ 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"
@@ -229,10 +237,16 @@ print_help() {
 }
 
 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
         ;;
diff --git a/SPECS/chrony.spec b/SPECS/chrony.spec
index ee7d947..e6202a1 100644
--- a/SPECS/chrony.spec
+++ b/SPECS/chrony.spec
@@ -1,10 +1,11 @@
 %global _hardened_build 1
-%global clknetsim_ver 3f5ef9
+%global clknetsim_ver f89702
 %global ntp2chrony_ver 2a0512
 %bcond_without debug
+%bcond_without nts
 
 Name:           chrony
-Version:        3.5
+Version:        4.1
 Release:        1%{?dist}
 Summary:        An NTP client/server
 
@@ -22,15 +23,21 @@ Source10:       https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/c
 Source11:       https://github.com/mlichvar/ntp2chrony/raw/%{ntp2chrony_ver}/ntp2chrony/ntp2chrony.py
 %{?gitpatch:Patch0: chrony-%{version}%{?prerelease}-%{gitpatch}.patch.gz}
 
+# modify NetworkManager DHCP dispatcher to work with chrony-helper and
+# follow distribution-specific configuration
+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
 
 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 bison systemd
+BuildRequires:  gcc gcc-c++ make bison systemd
 BuildRequires:  kernel-headers > 4.18.0-87
+%{?with_nts:BuildRequires: gnutls-devel gnutls-utils}
 
 Requires(pre):  shadow-utils
 %{?systemd_requires}
@@ -55,18 +62,21 @@ service to other computers in the network.
 %prep
 %setup -q -n %{name}-%{version}%{?prerelease} -a 10
 %{?gitpatch:%patch0 -p1}
+%patch1 -p1 -b .nm-dispatcher-dhcp
 %patch2 -p1 -b .service-helper
+%patch3 -p1 -b .defconfig
 
 %{?gitpatch: echo %{version}-%{gitpatch} > version.txt}
 
 # review changes in packaged configuration files and scripts
 md5sum -c <<-EOF | (! grep -v 'OK$')
-        47ad7eccc410b981d2f2101cf5682616  examples/chrony-wait.service
+        bc563c1bcf67b2da774bd8c2aef55a06  examples/chrony-wait.service
         e473a9fab7fe200cacce3dca8b66290b  examples/chrony.conf.example2
         96999221eeef476bd49fe97b97503126  examples/chrony.keys.example
         6a3178c4670de7de393d9365e2793740  examples/chrony.logrotate
-        8748a663f0b1943ea491858f414a6b26  examples/chrony.nm-dispatcher
-        b23bcc3bd78e195ca2849459e459f3ed  examples/chronyd.service
+        fabb5b3f127b802c27c82837feff0fe6  examples/chrony.nm-dispatcher.dhcp
+        8f5a98fcb400a482d355b929d04b5518  examples/chrony.nm-dispatcher.onoffline
+        56d221eba8ce8a2e03d3e0dd87999a81  examples/chronyd.service
 EOF
 
 # don't allow packaging without vendor zone
@@ -95,10 +105,13 @@ install -m 644 -p %{SOURCE11} ntp2chrony.py
 %{?with_debug: --enable-debug} \
         --enable-ntp-signd \
         --enable-scfilter \
+%{!?with_nts: --disable-nts} \
+        --chronyrundir=/run/chrony \
         --docdir=%{_docdir} \
         --with-ntp-era=$(date -d '1970-01-01 00:00:00+00:00' +'%s') \
         --with-user=chrony \
         --with-hwclockfile=%{_sysconfdir}/adjtime \
+        --with-pidfile=/run/chrony/chronyd.pid \
         --with-sendmail=%{_sbindir}/sendmail
 make %{?_smp_mflags}
 
@@ -118,8 +131,10 @@ 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 \
-        $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony
+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} \
         $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d/chrony.sh
 install -m 644 -p examples/chrony.logrotate \
@@ -183,7 +198,7 @@ fi
 %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}/NetworkManager/dispatcher.d/20-chrony*
 %{_sysconfdir}/dhcp/dhclient.d/chrony.sh
 %{_bindir}/chronyc
 %{_sbindir}/chronyd
@@ -192,12 +207,21 @@ fi
 %{_unitdir}/chrony*.service
 %{_unitdir}/chrony*.timer
 %{_mandir}/man[158]/%{name}*.[158]*
-%dir %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony
+%dir %attr(750,chrony,chrony) %{_localstatedir}/lib/chrony
 %ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/drift
 %ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/rtc
-%dir %attr(-,chrony,chrony) %{_localstatedir}/log/chrony
+%dir %attr(750,chrony,chrony) %{_localstatedir}/log/chrony
 
 %changelog
+* 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
+- 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)