xref: /openbsd-src/etc/rc (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1#	$OpenBSD: rc,v 1.486 2016/07/10 09:08:18 rpe Exp $
2
3# System startup script run by init on autoboot or after single-user.
4# Output and error are redirected to console by init, and the console is the
5# controlling terminal.
6
7# Turn off Strict Bourne shell.
8set +o sh
9
10# Subroutines (have to come first).
11
12
13# Strip in- and whole-line comments from a file.
14# Strip leading and trailing whitespace if IFS is set.
15# Usage: stripcom /path/to/file
16stripcom() {
17	local _file=$1 _line
18
19	[[ -s $_file ]] || return
20
21	while read _line ; do
22		_line=${_line%%#*}
23		[[ -n $_line ]] && print -r -- "$_line"
24	done <$_file
25}
26
27# Update resource limits based on login.conf settings.
28# Usage: update_limit -flag capability
29update_limit() {
30	local _flag=$1		# ulimit flag
31	local _cap=$2 _val	# login.conf capability and its value
32	local _suffix
33
34	for _suffix in {,-cur,-max}; do
35		_val=$(getcap -f /etc/login.conf -s ${_cap}${_suffix} daemon 2>/dev/null)
36		[[ -n $_val ]] || continue
37		[[ $_val == infinity ]] && _val=unlimited
38
39		case $_suffix in
40		-cur)	ulimit -S $_flag $_val
41			;;
42		-max)	ulimit -H $_flag $_val
43			;;
44		*)	ulimit $_flag $_val
45			return
46			;;
47		esac
48	done
49}
50
51# Apply sysctl.conf(5) settings.
52sysctl_conf() {
53	stripcom /etc/sysctl.conf |
54	while read _line; do
55		sysctl "$_line"
56
57		case $_line in
58		kern.maxproc=*)
59			update_limit -p maxproc;;
60		kern.maxfiles=*)
61			update_limit -n openfiles;;
62		esac
63	done
64}
65
66# Apply mixerctl.conf(5) settings.
67mixerctl_conf() {
68	stripcom /etc/mixerctl.conf |
69	while read _line; do
70		mixerctl -q "$_line" 2>/dev/null
71	done
72}
73
74# Apply wsconsctl.conf(5) settings.
75wsconsctl_conf() {
76	[[ -x /sbin/wsconsctl ]] || return
77
78	stripcom /etc/wsconsctl.conf |
79	while read _line; do
80		eval "wsconsctl $_line"
81	done
82}
83
84random_seed() {
85	# push the old seed into the kernel
86	dd if=/var/db/host.random of=/dev/random bs=65536 count=1 status=none
87	chmod 600 /var/db/host.random
88	# ... and create a future seed
89	dd if=/dev/random of=/var/db/host.random bs=65536 count=1 status=none
90	# and create a seed file for the boot-loader
91	dd if=/dev/random of=/etc/random.seed bs=512 count=1 status=none
92	chmod 600 /etc/random.seed
93}
94
95# Populate net.inet.(tcp|udp).baddynamic with the contents of /etc/services so
96# as to avoid randomly allocating source ports that correspond to well-known
97# services.
98# Usage: fill_baddynamic tcp|udp
99fill_baddynamic() {
100	local _service=$1
101	local _sysctl="net.inet.${_service}.baddynamic"
102
103	stripcom /etc/services |
104	{
105		_ban=
106		while IFS=" 	/" read _name _port _srv _junk; do
107			[[ $_srv == $_service ]] || continue
108
109			_ban="${_ban:+$_ban,}+$_port"
110
111			# Flush before argv gets too long
112			if ((${#_ban} > 1024)); then
113				sysctl -q "$_sysctl=$_ban"
114				_ban=
115			fi
116		done
117		[[ -n $_ban ]] && sysctl -q "$_sysctl=$_ban"
118	}
119}
120
121# Start daemon using the rc.d daemon control scripts.
122# Usage: start_daemon daemon1 daemon2 daemon3
123start_daemon() {
124	local _daemon
125
126	for _daemon; do
127		eval "_do=\${${_daemon}_flags}"
128		[[ $_do != NO ]] && /etc/rc.d/${_daemon} start
129	done
130}
131
132# Generate keys for isakmpd, iked and sshd if they don't exist yet.
133make_keys() {
134	local _isakmpd_key=/etc/isakmpd/private/local.key
135	local _isakmpd_pub=/etc/isakmpd/local.pub
136	local _iked_key=/etc/iked/private/local.key
137	local _iked_pub=/etc/iked/local.pub
138
139	if [[ ! -f $_isakmpd_key ]]; then
140		echo -n "openssl: generating isakmpd/iked RSA keys... "
141		if openssl genrsa -out $_isakmpd_key 2048 >/dev/null 2>&1 &&
142			chmod 600 $_isakmpd_key &&
143			openssl rsa -out $_isakmpd_pub -in $_isakmpd_key \
144			    -pubout >/dev/null 2>&1; then
145			echo done.
146		else
147			echo failed.
148		fi
149	fi
150
151	if [[ ! -f $_iked_key ]]; then
152		# Just copy the generated isakmpd key
153		cp $_isakmpd_key $_iked_key
154		chmod 600 $_iked_key
155		cp $_isakmpd_pub $_iked_pub
156	fi
157
158	ssh-keygen -A
159}
160
161# Re-link libraries, placing the objects in a random order.
162reorder_libs() {
163	local _l _liba _libas _tmpdir _remount=false _error=false
164	local _dkdev=$(df /usr/lib | sed '1d;s/ .*//')
165	local _mp=$(mount | grep "^$_dkdev")
166
167	# Skip if /usr/lib is on a nfs mounted filesystem.
168	[[ $_mp == *' type nfs '* ]] && return
169
170	echo -n 'reordering libraries:'
171
172	# Only choose the latest version of the libraries.
173	for _liba in /usr/lib/libc.so.*.a; do
174		_liba=$(ls ${_liba%%.[0-9]*}*.a | sort -V | tail -1)
175		for _l in $_libas; do
176			[[ $_l == $_liba ]] && continue 2
177		done
178		_libas="$_libas $_liba"
179	done
180
181	# Remount read-write, if /usr/lib is on a read-only ffs filesystem.
182	if [[ $_mp == *' type ffs '*'read-only'* ]]; then
183		if mount -u -w $_dkdev; then
184			_remount=true
185		else
186			echo ' failed.'
187			return
188		fi
189	fi
190
191	for _liba in $_libas; do
192		_tmpdir=$(mktemp -dq /tmp/_librebuild.XXXXXXXXXXXX) && (
193			set -o errexit
194			_lib=${_liba#/usr/lib/}
195			_lib=${_lib%.a}
196			cd $_tmpdir
197			ar x ${_liba}
198			cc -shared -o $_lib $(ls *.so | sort -R) $(cat .ldadd)
199			[[ -s $_lib ]] && file $_lib | fgrep -q 'shared object'
200			LD_BIND_NOW=1 LD_LIBRARY_PATH=$_tmpdir awk 'BEGIN {exit 0}'
201			install -F -S -o root -g bin -m 0444 $_lib /usr/lib/$_lib
202		) || { _error=true; break; }
203	done
204
205	rm -rf /tmp/_librebuild.*
206
207	# Restore previous mount state if it was changed.
208	if $_remount; then
209		mount -u -r $_dkdev || _error=true
210	fi
211
212	if $_error; then
213		echo ' failed.'
214	else
215		echo ' done.'
216	fi
217}
218
219# Run rc.* script and email output to root.
220# Usage: run_upgrade_script firsttime|sysmerge
221run_upgrade_script() {
222	local _suffix=$1
223	[[ -n $_suffix ]] || return 1
224	if [[ -f /etc/rc.$_suffix ]]; then
225		mv /etc/rc.$_suffix /etc/rc.$_suffix.run
226		. /etc/rc.$_suffix.run 2>&1 | tee /dev/tty |
227			mail -Es "$(hostname) rc.$_suffix output" root >/dev/null
228	fi
229	rm -f /etc/rc.$_suffix.run
230}
231
232# Check filesystems, optionally by using a fsck(8) flag.
233# Usage: do_fsck [-flag]
234do_fsck() {
235	fsck -p "$@"
236	case $? in
237	0)	;;
238	2)	exit 1
239		;;
240	4)	echo "Rebooting..."
241		reboot
242		echo "Reboot failed; help!"
243		exit 1
244		;;
245	8)	echo "Automatic file system check failed; help!"
246		exit 1
247		;;
248	12)	echo "Boot interrupted."
249		exit 1
250		;;
251	130)	# Interrupt before catcher installed.
252		exit 1
253		;;
254	*)	echo "Unknown error; help!"
255		exit 1
256		;;
257	esac
258}
259
260# End subroutines.
261
262stty status '^T'
263
264# Set shell to ignore SIGINT (2), but not children; shell catches SIGQUIT (3)
265# and returns to single user after fsck.
266trap : 2
267trap : 3	# Shouldn't be needed.
268
269export HOME=/
270export INRC=1
271export PATH=/sbin:/bin:/usr/sbin:/usr/bin
272
273# Must set the domainname before rc.conf, so YP startup choices can be made.
274if [[ -s /etc/defaultdomain ]]; then
275	domainname "$(stripcom /etc/defaultdomain)"
276fi
277
278# Need to get local functions from rc.subr.
279FUNCS_ONLY=1 . /etc/rc.d/rc.subr
280
281# Load rc.conf into scope.
282_rc_parse_conf
283
284if [[ $1 == shutdown ]]; then
285	if echo 2>/dev/null >>/var/db/host.random || \
286	    echo 2>/dev/null >>/etc/random.seed; then
287		random_seed
288	else
289		echo warning: cannot write random seed to disk
290	fi
291
292	# If we are in secure level 0, assume single user mode.
293	if (($(sysctl -n kern.securelevel) == 0)); then
294		echo 'single user: not running shutdown scripts'
295	else
296		pkg_scripts=${pkg_scripts%%*( )}
297		if [[ -n $pkg_scripts ]]; then
298			echo -n 'stopping package daemons:'
299			while [[ -n $pkg_scripts ]]; do
300				_d=${pkg_scripts##* }
301				pkg_scripts=${pkg_scripts%%*( )$_d}
302				[[ -x /etc/rc.d/$_d ]] && /etc/rc.d/$_d stop
303			done
304			echo '.'
305		fi
306
307		[[ -f /etc/rc.shutdown ]] && sh /etc/rc.shutdown
308	fi
309
310	# Bring carp interfaces down gracefully.
311	ifconfig | while read _if _junk; do
312		[[ $_if == carp+([0-9]): ]] && ifconfig ${_if%:} down
313	done
314
315	exit 0
316fi
317
318# Add swap block-devices.
319swapctl -A -t blk
320
321if [[ -e /fastboot ]]; then
322	echo "Fast boot: skipping disk checks."
323elif [[ $1 == autoboot ]]; then
324	echo "Automatic boot in progress: starting file system checks."
325	do_fsck
326fi
327
328trap "echo 'Boot interrupted.'; exit 1" 3
329
330umount -a >/dev/null 2>&1
331mount -a -t nonfs,vnd
332mount -uw /		# root on nfs requires this, others aren't hurt.
333rm -f /fastboot		# XXX (root now writeable)
334
335# Set flags on ttys.  (Do early, in case they use tty for SLIP in netstart.)
336echo 'setting tty flags'
337ttyflags -a
338
339# Set keyboard encoding.
340if [[ -x /sbin/kbd && -s /etc/kbdtype ]]; then
341	kbd "$(cat /etc/kbdtype)"
342fi
343
344wsconsctl_conf
345
346# Set initial temporary pf rule set.
347if [[ $pf != NO ]]; then
348	RULES="block all"
349	RULES="$RULES\npass on lo0"
350	RULES="$RULES\npass in proto tcp from any to any port ssh keep state"
351	RULES="$RULES\npass out proto { tcp, udp } from any to any port domain keep state"
352	RULES="$RULES\npass out inet proto icmp all icmp-type echoreq keep state"
353	RULES="$RULES\npass out inet proto udp from any port bootpc to any port bootps"
354	RULES="$RULES\npass in inet proto udp from any port bootps to any port bootpc"
355	if ifconfig lo0 inet6 >/dev/null 2>&1; then
356		RULES="$RULES\npass out inet6 proto icmp6 all icmp6-type neighbrsol"
357		RULES="$RULES\npass in inet6 proto icmp6 all icmp6-type neighbradv"
358		RULES="$RULES\npass out inet6 proto icmp6 all icmp6-type routersol"
359		RULES="$RULES\npass in inet6 proto icmp6 all icmp6-type routeradv"
360		RULES="$RULES\npass out inet6 proto udp from any port dhcpv6-client to any port dhcpv6-server"
361		RULES="$RULES\npass in inet6 proto udp from any port dhcpv6-server to any port dhcpv6-client"
362	fi
363	RULES="$RULES\npass in proto carp keep state (no-sync)"
364	RULES="$RULES\npass out proto carp !received-on any keep state (no-sync)"
365	if [[ $(sysctl vfs.mounts.nfs 2>/dev/null) == *[1-9]* ]]; then
366		# Don't kill NFS.
367		RULES="set reassemble yes no-df\n$RULES"
368		RULES="$RULES\npass in proto { tcp, udp } from any port { sunrpc, nfsd } to any"
369		RULES="$RULES\npass out proto { tcp, udp } from any to any port { sunrpc, nfsd } !received-on any"
370	fi
371	print -- "$RULES" | pfctl -f -
372	pfctl -e
373fi
374
375# Fill net.inet.(tcp|udp).baddynamic lists from /etc/services.
376fill_baddynamic udp
377fill_baddynamic tcp
378
379sysctl_conf
380
381echo 'starting network'
382
383# Set carp interlock by increasing the demotion counter.
384# Prevents carp from preempting until the system is booted.
385ifconfig -g carp carpdemote 128
386
387# Recover resolv.conf in case dhclient died hard.
388if [[ -f /etc/resolv.conf.save ]]; then
389	mv -f /etc/resolv.conf.save /etc/resolv.conf
390	touch /etc/resolv.conf
391fi
392
393sh /etc/netstart
394
395dmesg >/dev/random	# Any write triggers a rekey.
396
397# Load pf rules and bring up pfsync interface.
398if [[ $pf != NO ]]; then
399	if [[ -f /etc/pf.conf ]]; then
400		pfctl -f /etc/pf.conf
401	fi
402	if [[ -f /etc/hostname.pfsync0 ]]; then
403		sh /etc/netstart pfsync0
404	fi
405fi
406
407mount -s /usr >/dev/null 2>&1
408mount -s /var >/dev/null 2>&1
409
410random_seed
411
412reorder_libs
413
414# Clean up left-over files.
415rm -f /etc/nologin /var/spool/lock/LCK.* /var/spool/uucp/STST/*
416(cd /var/run && { rm -rf -- *; install -c -m 664 -g utmp /dev/null utmp; })
417(cd /var/authpf && rm -rf -- *)
418
419dmesg >/var/run/dmesg.boot	# Save a copy of the boot messages.
420
421make_keys
422
423echo -n 'starting early daemons:'
424start_daemon syslogd ldattach pflogd nsd rebound unbound ntpd
425start_daemon iscsid isakmpd iked sasyncd ldapd npppd
426echo '.'
427
428# Load IPsec rules.
429if [[ $ipsec != NO && -f /etc/ipsec.conf ]]; then
430	ipsecctl -f /etc/ipsec.conf
431fi
432
433echo -n 'starting RPC daemons:'
434start_daemon portmap ypldap
435rm -f /var/run/ypbind.lock
436if [[ -n $(domainname) ]]; then
437	start_daemon ypserv ypbind
438fi
439start_daemon mountd nfsd lockd statd amd
440echo '.'
441
442# Check and mount remaining file systems and enable additional swap.
443mount -a
444swapctl -A -t noblk
445do_fsck -N
446mount -a -N
447
448# /var/crash should be a directory or a symbolic link to the crash directory
449# if core dumps are to be saved.
450if [[ -d /var/crash ]]; then
451	savecore $savecore_flags /var/crash
452fi
453
454if [[ $check_quotas == YES ]]; then
455	echo -n 'checking quotas:'
456	quotacheck -a
457	echo ' done.'
458	quotaon -a
459fi
460
461# Build kvm(3) and /dev databases.
462kvm_mkdb
463dev_mkdb
464
465# Set proper permission for the tty device files.
466chmod 666 /dev/tty[pqrstuvwxyzPQRST]*
467chown root:wheel /dev/tty[pqrstuvwxyzPQRST]*
468
469# Check the password temp/lock file.
470if [[ -f /etc/ptmp ]]; then
471	logger -s -p auth.err \
472	    'password file may be incorrect -- /etc/ptmp exists'
473fi
474
475echo clearing /tmp
476
477# Prune quickly with one rm, then use find to clean up /tmp/[lqv]*
478# (not needed with mfs /tmp, but doesn't hurt there...).
479(cd /tmp && rm -rf [a-km-pr-uw-zA-Z]*)
480(cd /tmp &&
481    find . -maxdepth 1 ! -name . ! -name lost+found ! -name quota.user \
482	! -name quota.group ! -name vi.recover -execdir rm -rf -- {} \;)
483
484# Create Unix sockets directories for X if needed and make sure they have
485# correct permissions.
486[[ -d /usr/X11R6/lib ]] && mkdir -m 1777 /tmp/.{X11,ICE}-unix
487
488[[ -f /etc/rc.securelevel ]] && sh /etc/rc.securelevel
489
490# rc.securelevel did not specifically set -1 or 2, so select the default: 1.
491(($(sysctl -n kern.securelevel) == 0)) && sysctl kern.securelevel=1
492
493
494# Patch /etc/motd.
495if [[ ! -f /etc/motd ]]; then
496	install -c -o root -g wheel -m 664 /dev/null /etc/motd
497fi
498if T=$(mktemp /tmp/_motd.XXXXXXXXXX); then
499	sysctl -n kern.version | sed 1q >$T
500	echo "" >>$T
501	sed '1,/^$/d' </etc/motd >>$T
502	cmp -s $T /etc/motd || cp $T /etc/motd
503	rm -f $T
504fi
505
506if [[ $accounting == YES ]]; then
507	[[ ! -f /var/account/acct ]] && touch /var/account/acct
508	echo 'turning on accounting'
509	accton /var/account/acct
510fi
511
512if [[ -x /sbin/ldconfig ]]; then
513	echo 'creating runtime link editor directory cache.'
514	[[ -d /usr/local/lib ]] && shlib_dirs="/usr/local/lib $shlib_dirs"
515	[[ -d /usr/X11R6/lib ]] && shlib_dirs="/usr/X11R6/lib $shlib_dirs"
516	ldconfig $shlib_dirs
517fi
518
519echo 'preserving editor files.'; /usr/libexec/vi.recover
520
521# If rc.sysmerge exists, run it just once, and make sure it is deleted.
522run_upgrade_script sysmerge
523
524echo -n 'starting network daemons:'
525start_daemon ldomd vmd sshd snmpd ldpd ripd ospfd ospf6d bgpd ifstated
526start_daemon relayd dhcpd dhcrelay mrouted dvmrpd radiusd eigrpd
527
528if ifconfig lo0 inet6 >/dev/null 2>&1; then
529	if (($(sysctl -n net.inet6.ip6.forwarding) == 1)); then
530		start_daemon route6d rtadvd
531	fi
532fi
533
534start_daemon hostapd lpd smtpd slowcgi httpd ftpd
535start_daemon ftpproxy ftpproxy6 tftpd tftpproxy identd inetd rarpd bootparamd
536start_daemon rbootd mopd spamd spamlogd sndiod
537echo '.'
538
539# If rc.firsttime exists, run it just once, and make sure it is deleted.
540run_upgrade_script firsttime
541
542# Run rc.d(8) scripts from packages.
543if [[ -n $pkg_scripts ]]; then
544	echo -n 'starting package daemons:'
545	for _daemon in $pkg_scripts; do
546		if [[ -x /etc/rc.d/$_daemon ]]; then
547			start_daemon $_daemon
548		else
549			echo -n " ${_daemon}(absent)"
550		fi
551	done
552	echo '.'
553fi
554
555[[ -f /etc/rc.local ]] && sh /etc/rc.local
556
557ifconfig -g carp -carpdemote 128	# Disable carp interlock.
558
559mixerctl_conf
560
561echo -n 'starting local daemons:'
562start_daemon apmd sensorsd hotplugd watchdogd cron wsmoused xdm
563echo '.'
564
565date
566exit 0
567