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