xref: /freebsd/libexec/rc/rc.d/ntpd (revision e9dcd83155b39327497e7a2577d8990074144ff3)
1#!/bin/sh
2#
3# $FreeBSD$
4#
5
6# PROVIDE: ntpd
7# REQUIRE: DAEMON ntpdate FILESYSTEMS devfs
8# BEFORE:  LOGIN
9# KEYWORD: nojail shutdown
10
11. /etc/rc.subr
12
13name="ntpd"
14desc="Network Time Protocol daemon"
15rcvar="ntpd_enable"
16command="/usr/sbin/${name}"
17extra_commands="fetch needfetch"
18fetch_cmd="ntpd_fetch_leapfile"
19needfetch_cmd="ntpd_needfetch_leapfile"
20start_precmd="ntpd_precmd"
21
22_ntp_tmp_leapfile="/var/run/ntpd.leap-seconds.list"
23_ntp_default_dir="/var/db/ntp"
24_ntp_default_driftfile="${_ntp_default_dir}/ntpd.drift"
25_ntp_old_driftfile="/var/db/ntpd.drift"
26
27pidfile="${_ntp_default_dir}/${name}.pid"
28
29load_rc_config $name
30
31can_run_nonroot()
32{
33	# If the admin set what uid to use, we don't change it.
34	if [ -n "${ntpd_user}" ]; then
35		return 1
36	fi
37
38	# If the admin set any command line options involving files, we
39	# may not be able to access them as user ntpd.
40	case "${rc_flags}" in
41	    *-f* | *--driftfile* | *-i* | *--jaildir*   | \
42	    *-k* | *--keyfile*   | *-l* | *--logfile*   | \
43	    *-p* | *--pidfile*   | *-s* | *--statsdir* )
44		return 1;;
45	esac
46
47	# If the admin set any options in ntp.conf involving files,
48	# we may not be able to access them as user ntpd.
49	local fileopts="^[ \t]*crypto|^[ \t]*driftfile|^[ \t]*key|^[ \t]*logfile|^[ \t]*statsdir"
50	grep -E -q "${fileopts}" "${ntpd_config}" && return 1
51
52	# Try to set up the the MAC ntpd policy so ntpd can run with reduced
53	# privileges.  Detect whether MAC is compiled into the kernel, load
54	# the policy module if not already present, then check whether the
55	# policy has been disabled via tunable or sysctl.
56	[ -n "$(sysctl -qn security.mac.version)" ] || return 1
57	sysctl -qn security.mac.ntpd >/dev/null || kldload -qn mac_ntpd || return 1
58	[ "$(sysctl -qn security.mac.ntpd.enabled)" == "1" ] || return 1
59
60	# On older existing systems, the ntp dir may by owned by root, change
61	# it to ntpd to give the daemon create/write access to the driftfile.
62	if [ "$(stat -f %u ${_ntp_default_dir})" = "0" ]; then
63		chown ntpd:ntpd "${_ntp_default_dir}" || return 1
64		chmod 0755 "${_ntp_default_dir}" || return 1
65		logger -s -t "rc.d/ntpd" -p daemon.notice \
66		    "${_ntp_default_dir} updated to owner ntpd:ntpd, mode 0755"
67	fi
68
69	# If the driftfile exists in the standard location for older existing
70	# systems, move it into the ntp dir and fix the ownership if we can.
71	if [ -f "${_ntp_old_driftfile}" ] && [ ! -L "${_ntp_old_driftfile}" ]; then
72		mv "${_ntp_old_driftfile}" "${_ntp_default_driftfile}" &&
73		   chown ntpd:ntpd "${_ntp_default_driftfile}" || return 1
74		logger -s -t "rc.d/ntpd" -p daemon.notice \
75		    "${_ntp_default_driftfile} updated to owner ntpd:ntpd"
76		logger -s -t "rc.d/ntpd" -p daemon.notice \
77		    "${_ntp_old_driftfile} moved to ${_ntp_default_driftfile}"
78	fi
79}
80
81ntpd_precmd()
82{
83	local driftopt
84
85	# If we can run as a non-root user, switch uid to ntpd and use the
86	# new default location for the driftfile inside the ntpd-owned dir.
87	# Otherwise, figure out what to do about the driftfile option.  If set
88	# by the admin, we don't add the option.  If the file exists in the old
89	# default location we use that, else we use the new default location.
90	if can_run_nonroot; then
91		_user="ntpd"
92		driftopt="-f ${_ntp_default_driftfile}"
93	elif [ -z "${rc_flags##*-f*}" ] ||
94	     [ -z "${rc_flags##*--driftfile*}" ] ||
95	     grep -q "^[ \t]*driftfile" "${ntpd_config}"; then
96		driftopt="" # admin set the option, we don't need to add it.
97	elif [ -f "${_ntp_old_driftfile}" ]; then
98		driftopt="-f ${_ntp_old_driftfile}"
99	else
100		driftopt="-f ${_ntp_default_driftfile}"
101	fi
102
103	# Set command_args based on the various config vars.
104	command_args="-p ${pidfile} -c ${ntpd_config} ${driftopt}"
105	if checkyesno ntpd_sync_on_start; then
106		command_args="${command_args} -g"
107	fi
108
109	# Make sure the leapfile is ready to use.
110	ntpd_init_leapfile
111	if [ ! -f "${ntp_db_leapfile}" ]; then
112		ntpd_fetch_leapfile
113	fi
114}
115
116current_ntp_ts() {
117	# Seconds between 1900-01-01 and 1970-01-01
118	# echo $(((70*365+17)*86400))
119	ntp_to_unix=2208988800
120
121	echo $(($(date -u +%s)+$ntp_to_unix))
122}
123
124get_ntp_leapfile_ver() {
125	# Leapfile update date (version number).
126	expr "$(awk '$1 == "#$" { print $2 }' "$1" 2>/dev/null)" : \
127		'^\([1-9][0-9]*\)$' \| 0
128}
129
130get_ntp_leapfile_expiry() {
131	# Leapfile expiry date.
132	expr "$(awk '$1 == "#@" { print $2 }' "$1" 2>/dev/null)" : \
133		'^\([1-9][0-9]*\)$' \| 0
134}
135
136ntpd_init_leapfile() {
137	# Refresh working leapfile with an invalid hash due to
138	# FreeBSD id header. Ntpd will ignore leapfiles with a
139	# mismatch hash. The file must be the virgin file from
140	# the source.
141	if [ ! -f $ntp_db_leapfile ]; then
142		cp -p $ntp_src_leapfile $ntp_db_leapfile
143	fi
144}
145
146ntpd_needfetch_leapfile() {
147	local rc verbose
148
149	if checkyesno ntp_leapfile_fetch_verbose; then
150		verbose=echo
151	else
152		verbose=:
153	fi
154
155	ntp_ver_no_src=$(get_ntp_leapfile_ver $ntp_src_leapfile)
156	ntp_expiry_src=$(get_ntp_leapfile_expiry $ntp_src_leapfile)
157	ntp_ver_no_db=$(get_ntp_leapfile_ver $ntp_db_leapfile)
158	ntp_expiry_db=$(get_ntp_leapfile_expiry $ntp_db_leapfile)
159	$verbose ntp_src_leapfile version is $ntp_ver_no_src expires $ntp_expiry_src
160	$verbose ntp_db_leapfile version is $ntp_ver_no_db expires $ntp_expiry_db
161
162	if [ "$ntp_ver_no_src" -gt "$ntp_ver_no_db" -o \
163	     "$ntp_ver_no_src" -eq "$ntp_ver_no_db" -a \
164	     "$ntp_expiry_src" -gt "$ntp_expiry_db" ]; then
165		$verbose replacing $ntp_db_leapfile with $ntp_src_leapfile
166		cp -p $ntp_src_leapfile $ntp_db_leapfile
167		ntp_ver_no_db=$ntp_ver_no_src
168	else
169		$verbose not replacing $ntp_db_leapfile with $ntp_src_leapfile
170	fi
171	ntp_leapfile_expiry_seconds=$((ntp_leapfile_expiry_days*86400))
172	ntp_leap_expiry=$(get_ntp_leapfile_expiry $ntp_db_leapfile)
173	ntp_leap_fetch_date=$((ntp_leap_expiry-ntp_leapfile_expiry_seconds))
174	if [ $(current_ntp_ts) -ge $ntp_leap_fetch_date ]; then
175		$verbose Within ntp leapfile expiry limit, initiating fetch
176		# Return code 0: ntp leapfile fetch needed
177		return 0
178	fi
179	# Return code 1: ntp leapfile fetch not needed
180	return 1
181}
182
183ntpd_fetch_leapfile() {
184	if checkyesno ntp_leapfile_fetch_verbose; then
185		verbose=echo
186	else
187		verbose=:
188	fi
189
190	if ntpd_needfetch_leapfile ; then
191		for url in $ntp_leapfile_sources ; do
192			$verbose fetching $url
193			fetch $ntp_leapfile_fetch_opts -o $_ntp_tmp_leapfile $url && break
194		done
195		ntp_ver_no_tmp=$(get_ntp_leapfile_ver $_ntp_tmp_leapfile)
196		ntp_expiry_tmp=$(get_ntp_leapfile_expiry $_ntp_tmp_leapfile)
197		if [ "$ntp_expiry_tmp" -gt "$ntp_expiry_db" -o \
198		     "$ntp_expiry_tmp" -eq "$ntp_expiry_db" -a \
199		     "$ntp_ver_no_tmp" -gt "$ntp_ver_no_db" ]; then
200			$verbose using $url as $ntp_db_leapfile
201			mv -f $_ntp_tmp_leapfile $ntp_db_leapfile ||
202			    $verbose "warning: cannot replace $ntp_db_leapfile (read-only fs?)"
203		else
204			$verbose using existing $ntp_db_leapfile
205		fi
206	fi
207}
208
209run_rc_command "$1"
210