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