1#!/bin/sh
2#
3# $FreeBSD$
4#
5
6# PROVIDE: named
7# REQUIRE: SERVERS FILESYSTEMS
8# KEYWORD: shutdown
9
10. /etc/rc.subr
11
12name="named"
13rcvar=named_enable
14
15extra_commands="reload"
16
17start_precmd="named_prestart"
18start_postcmd="named_poststart"
19reload_cmd="named_reload"
20stop_cmd="named_stop"
21stop_postcmd="named_poststop"
22
23# If running in a chroot cage, ensure that the appropriate files
24# exist inside the cage, as well as helper symlinks into the cage
25# from outside.
26#
27# As this is called after the is_running and required_dir checks
28# are made in run_rc_command(), we can safely assume ${named_chrootdir}
29# exists and named isn't running at this point (unless forcestart
30# is used).
31#
32chroot_autoupdate()
33{
34	local file
35
36	# Create (or update) the chroot directory structure
37	#
38	if [ -r /etc/mtree/BIND.chroot.dist ]; then
39		mtree -deU -f /etc/mtree/BIND.chroot.dist \
40		    -p ${named_chrootdir}
41	else
42		warn "/etc/mtree/BIND.chroot.dist missing,"
43		warn "chroot directory structure not updated"
44	fi
45
46	# Create (or update) the configuration directory symlink
47	#
48	if [ ! -L "${named_conf%/*}" ]; then
49		if [ -d "${named_conf%/*}" ]; then
50			warn "named chroot: ${named_conf%/*} is a directory!"
51		elif [ -e "${named_conf%/*}" ]; then
52			warn "named chroot: ${named_conf%/*} exists!"
53		else
54			ln -s ${named_confdir} ${named_conf%/*}
55		fi
56	else
57		# Make sure it points to the right place.
58		ln -shf ${named_confdir} ${named_conf%/*}
59	fi
60
61	# Mount a devfs in the chroot directory if needed
62	#
63	if [ `${SYSCTL_N} security.jail.jailed` -eq 0 ]; then
64		umount ${named_chrootdir}/dev 2>/dev/null
65		devfs_domount ${named_chrootdir}/dev devfsrules_hide_all
66		devfs -m ${named_chrootdir}/dev rule apply path null unhide
67		devfs -m ${named_chrootdir}/dev rule apply path random unhide
68	else
69		if [ -c ${named_chrootdir}/dev/null -a \
70		    -c ${named_chrootdir}/dev/random ]; then
71			info "named chroot: using pre-mounted devfs."
72		else
73			err 1 "named chroot: devfs cannot be mounted from" \
74			    "within a jail. Thus a chrooted named cannot" \
75			    "be run from within a jail." \
76			    "To run named without chrooting it, set" \
77			    "named_chrootdir=\"\" in /etc/rc.conf."
78		fi
79	fi
80
81	# Copy and/or update key files to the chroot /etc
82	#
83	for file in localtime protocols services; do
84		if [ -r /etc/$file ]; then
85			cmp -s /etc/$file "${named_chrootdir}/etc/$file" ||
86			    cp -p /etc/$file "${named_chrootdir}/etc/$file"
87		fi
88	done
89}
90
91# Make symlinks to the correct pid file
92#
93make_symlinks()
94{
95	checkyesno named_symlink_enable &&
96	    ln -fs "${named_chrootdir}${pidfile}" ${pidfile}
97}
98
99named_poststart () {
100	make_symlinks
101
102	if checkyesno named_wait; then
103		until ${command%/sbin/named}/bin/host $named_wait_host >/dev/null 2>&1; do
104			echo "	Waiting for nameserver to resolve $named_wait_host"
105			sleep 1
106		done
107	fi
108}
109
110named_reload()
111{
112	${command%/named}/rndc reload
113}
114
115find_pidfile()
116{
117	if get_pidfile_from_conf pid-file $named_conf; then
118		pidfile="$_pidfile_from_conf"
119	else
120		pidfile="/var/run/named/pid"
121	fi
122}
123
124named_stop()
125{
126	find_pidfile
127
128	# This duplicates an undesirably large amount of code from the stop
129	# routine in rc.subr in order to use rndc to shut down the process,
130	# and to give it a second chance in case rndc fails.
131	rc_pid=$(check_pidfile $pidfile $command)
132	if [ -z "$rc_pid" ]; then
133		[ -n "$rc_fast" ] && return 0
134		_run_rc_notrunning
135		return 1
136	fi
137	echo 'Stopping named.'
138	if ${command%/named}/rndc stop 2>/dev/null; then
139		wait_for_pids $rc_pid
140	else
141		echo -n 'rndc failed, trying kill: '
142		kill -TERM $rc_pid
143		wait_for_pids $rc_pid
144  	fi
145}
146
147named_poststop()
148{
149	if [ -n "${named_chrootdir}" -a -c ${named_chrootdir}/dev/null ]; then
150		if [ `${SYSCTL_N} security.jail.jailed` -eq 0 ]; then
151			umount ${named_chrootdir}/dev 2>/dev/null || true
152		else
153			warn "named chroot:" \
154			    "cannot unmount devfs from inside jail!"
155		fi
156	fi
157}
158
159create_file () {
160	if [ -e "$1" ]; then
161		unlink $1
162	fi
163	> $1
164	chown root:wheel $1
165	chmod 644 $1
166}
167
168named_prestart()
169{
170	find_pidfile
171
172	if [ -n "$named_pidfile" ]; then
173		warn 'named_pidfile: now determined from the conf file'
174	fi
175
176	command_args="-u ${named_uid:=root}"
177
178	if [ ! "$named_conf" = '/etc/namedb/named.conf' ]; then
179		case "$named_flags" in
180		-c*|*' -c'*) ;;		# No need to add it
181		*) command_args="-c $named_conf $command_args" ;;
182		esac
183	fi
184
185	local line nsip firstns
186
187	# Is the user using a sandbox?
188	#
189	if [ -n "$named_chrootdir" ]; then
190		rc_flags="$rc_flags -t $named_chrootdir"
191		checkyesno named_chroot_autoupdate && chroot_autoupdate
192	else
193		named_symlink_enable=NO
194	fi
195
196	# Create an rndc.key file for the user if none exists
197	#
198	confgen_command="${command%/named}/rndc-confgen -a -b256 -u $named_uid \
199	    -c ${named_confdir}/rndc.key"
200	if [ -s "${named_confdir}/rndc.conf" ]; then
201		unset confgen_command
202	fi
203	if [ -s "${named_confdir}/rndc.key" ]; then
204		case `stat -f%Su ${named_confdir}/rndc.key` in
205		root|$named_uid) ;;
206		*) $confgen_command ;;
207		esac
208	else
209		$confgen_command
210	fi
211
212	local checkconf
213
214	checkconf="${command%/named}/named-checkconf"
215	if ! checkyesno named_chroot_autoupdate && [ -n "$named_chrootdir" ]; then
216		checkconf="$checkconf -t $named_chrootdir"
217	fi
218
219	# Create a forwarder configuration based on /etc/resolv.conf
220	if checkyesno named_auto_forward; then
221		if [ ! -s /etc/resolv.conf ]; then
222			warn "named_auto_forward enabled, but no /etc/resolv.conf"
223
224			# Empty the file in case it is included in named.conf
225			[ -s "${named_confdir}/auto_forward.conf" ] &&
226			    create_file ${named_confdir}/auto_forward.conf
227
228			$checkconf $named_conf ||
229			    err 3 'named-checkconf for $named_conf failed'
230			return
231		fi
232
233		create_file /var/run/naf-resolv.conf
234		create_file /var/run/auto_forward.conf
235
236		echo '	forwarders {' > /var/run/auto_forward.conf
237
238		while read line; do
239			case "$line" in
240			'nameserver '*|'nameserver	'*)
241				nsip=${line##nameserver[         ]}
242
243				if [ -z "$firstns" ]; then
244					if [ ! "$nsip" = '127.0.0.1' ]; then
245						echo 'nameserver 127.0.0.1'
246						echo "		${nsip};" >> /var/run/auto_forward.conf
247					fi
248
249					firstns=1
250				else
251					[ "$nsip" = '127.0.0.1' ] && continue
252					echo "		${nsip};" >> /var/run/auto_forward.conf
253				fi
254				;;
255			esac
256
257			echo $line
258		done < /etc/resolv.conf > /var/run/naf-resolv.conf
259
260		echo '	};' >> /var/run/auto_forward.conf
261		echo '' >> /var/run/auto_forward.conf
262		if checkyesno named_auto_forward_only; then
263			echo "	forward only;" >> /var/run/auto_forward.conf
264		else
265			echo "	forward first;" >> /var/run/auto_forward.conf
266		fi
267
268		if cmp -s /etc/resolv.conf /var/run/naf-resolv.conf; then
269			unlink /var/run/naf-resolv.conf
270		else
271			[ -e /etc/resolv.conf ] && unlink /etc/resolv.conf
272			mv /var/run/naf-resolv.conf /etc/resolv.conf
273		fi
274
275		if cmp -s ${named_confdir}/auto_forward.conf \
276		    /var/run/auto_forward.conf; then
277			unlink /var/run/auto_forward.conf
278		else
279			[ -e "${named_confdir}/auto_forward.conf" ] &&
280			    unlink ${named_confdir}/auto_forward.conf
281			mv /var/run/auto_forward.conf \
282			    ${named_confdir}/auto_forward.conf
283		fi
284	else
285		# Empty the file in case it is included in named.conf
286		[ -s "${named_confdir}/auto_forward.conf" ] &&
287		    create_file ${named_confdir}/auto_forward.conf
288	fi
289
290	$checkconf $named_conf || err 3 'named-checkconf for $named_conf failed'
291}
292
293load_rc_config $name
294
295# Updating the following variables requires that rc.conf be loaded first
296#
297required_dirs="$named_chrootdir"	# if it is set, it must exist
298
299named_confdir="${named_chrootdir}${named_conf%/*}"
300
301run_rc_command "$1"
302