xref: /freebsd/libexec/rc/rc.d/ntpd (revision 97ca2ada80b870edbbb4f66b26e274cf8e55e0bc)
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		driftopt="-f ${_ntp_default_driftfile}"
105	elif grep -q "^[ \t]*driftfile" "${ntpd_config}" ||
106	     [ -n "${rc_flags}" ] &&
107	     ( [ -z "${rc_flags##*-f*}" ] ||
108	       [ -z "${rc_flags##*--driftfile*}" ] ); then
109		driftopt="" # admin set the option, we don't need to add it.
110	elif [ -f "${_ntp_old_driftfile}" ]; then
111		driftopt="-f ${_ntp_old_driftfile}"
112	else
113		driftopt="-f ${_ntp_default_driftfile}"
114	fi
115
116	# Set command_args based on the various config vars.
117	command_args="-p ${pidfile} -c ${ntpd_config} ${driftopt} -u ${ntpd_user:=ntpd:ntpd}"
118
119	# Unset ntpd_user because rc.subr uses $${name}_user to determine
120	# whether to invoke su(1) to setuid() to $ntpd_user for us. We want
121	# ntpd to do the setuid() itself through the -u argument, above.
122	unset ntpd_user
123
124	if checkyesno ntpd_sync_on_start; then
125		command_args="${command_args} -g"
126	fi
127
128	# Make sure the leapfile is ready to use, unless leapfile
129	# handling is disabled.
130	if leapfile_is_disabled; then
131		return
132	fi
133
134	ntpd_init_leapfile
135	if [ ! -f "${ntp_db_leapfile}" ]; then
136		ntpd_fetch_leapfile
137	fi
138}
139
140current_ntp_ts() {
141	# Seconds between 1900-01-01 and 1970-01-01
142	# echo $(((70*365+17)*86400))
143	ntp_to_unix=2208988800
144
145	echo $(($(date -u +%s)+$ntp_to_unix))
146}
147
148get_ntp_leapfile_ver() {
149	# Leapfile update date (version number).
150	expr "$(awk '$1 == "#$" { print $2 }' "$1" 2>/dev/null)" : \
151		'^\([1-9][0-9]*\)$' \| 0
152}
153
154get_ntp_leapfile_expiry() {
155	# Leapfile expiry date.
156	expr "$(awk '$1 == "#@" { print $2 }' "$1" 2>/dev/null)" : \
157		'^\([1-9][0-9]*\)$' \| 0
158}
159
160ntpd_init_leapfile() {
161
162	if leapfile_is_disabled; then
163		return
164	fi
165
166	# Refresh working leapfile with an invalid hash due to
167	# FreeBSD id header. Ntpd will ignore leapfiles with a
168	# mismatch hash. The file must be the virgin file from
169	# the source.
170	if [ ! -f $ntp_db_leapfile ]; then
171		cp -p $ntp_src_leapfile $ntp_db_leapfile
172	fi
173}
174
175ntpd_needfetch_leapfile() {
176	local rc verbose
177
178	if leapfile_is_disabled; then
179		# Return code 1: ntp leapfile fetch not needed
180		return 1
181	fi
182
183	if checkyesno ntp_leapfile_fetch_verbose; then
184		verbose=echo
185	else
186		verbose=:
187	fi
188
189	ntp_ver_no_src=$(get_ntp_leapfile_ver $ntp_src_leapfile)
190	ntp_expiry_src=$(get_ntp_leapfile_expiry $ntp_src_leapfile)
191	ntp_ver_no_db=$(get_ntp_leapfile_ver $ntp_db_leapfile)
192	ntp_expiry_db=$(get_ntp_leapfile_expiry $ntp_db_leapfile)
193	$verbose ntp_src_leapfile version is $ntp_ver_no_src expires $ntp_expiry_src
194	$verbose ntp_db_leapfile version is $ntp_ver_no_db expires $ntp_expiry_db
195
196	if [ "$ntp_ver_no_src" -gt "$ntp_ver_no_db" -o \
197	     "$ntp_ver_no_src" -eq "$ntp_ver_no_db" -a \
198	     "$ntp_expiry_src" -gt "$ntp_expiry_db" ]; then
199		$verbose replacing $ntp_db_leapfile with $ntp_src_leapfile
200		cp -p $ntp_src_leapfile $ntp_db_leapfile
201		ntp_ver_no_db=$ntp_ver_no_src
202	else
203		$verbose not replacing $ntp_db_leapfile with $ntp_src_leapfile
204	fi
205	ntp_leapfile_expiry_seconds=$((ntp_leapfile_expiry_days*86400))
206	ntp_leap_expiry=$(get_ntp_leapfile_expiry $ntp_db_leapfile)
207	ntp_leap_fetch_date=$((ntp_leap_expiry-ntp_leapfile_expiry_seconds))
208	if [ $(current_ntp_ts) -ge $ntp_leap_fetch_date ]; then
209		$verbose Within ntp leapfile expiry limit, initiating fetch
210		# Return code 0: ntp leapfile fetch needed
211		return 0
212	fi
213	# Return code 1: ntp leapfile fetch not needed
214	return 1
215}
216
217ntpd_fetch_leapfile() {
218
219	if leapfile_is_disabled; then
220		return
221	fi
222
223	if checkyesno ntp_leapfile_fetch_verbose; then
224		verbose=echo
225	else
226		verbose=:
227	fi
228
229	if ntpd_needfetch_leapfile ; then
230		for url in $ntp_leapfile_sources ; do
231			$verbose fetching $url
232			# Circumvent umask 027 and 077 in login.conf(5)
233			umask 022
234			fetch $ntp_leapfile_fetch_opts -o $_ntp_tmp_leapfile $url && break
235		done
236		ntp_ver_no_tmp=$(get_ntp_leapfile_ver $_ntp_tmp_leapfile)
237		ntp_expiry_tmp=$(get_ntp_leapfile_expiry $_ntp_tmp_leapfile)
238		if [ "$ntp_expiry_tmp" -gt "$ntp_expiry_db" -o \
239		     "$ntp_expiry_tmp" -eq "$ntp_expiry_db" -a \
240		     "$ntp_ver_no_tmp" -gt "$ntp_ver_no_db" ]; then
241			$verbose using $url as $ntp_db_leapfile
242			mv -f $_ntp_tmp_leapfile $ntp_db_leapfile ||
243			    $verbose "warning: cannot replace $ntp_db_leapfile (read-only fs?)"
244		else
245			$verbose using existing $ntp_db_leapfile
246		fi
247	fi
248}
249
250ntpd_resume()
251{
252	run_rc_command restart
253}
254
255run_rc_command "$1"
256