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