1#	$OpenBSD: rc,v 1.575 2024/05/17 00:33:43 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/libexec/sshd-session \
245	    $_relink/usr/bin/ssh-agent ; do
246		_tmpdir=$(mktemp -dq $_relink/_rebuild.XXXXXXXXXXXX) &&
247		(
248		set -o errexit
249		cd $_tmpdir
250		_binn=${_bin##*/}
251		_bint=${_bin}/${_binn}.tar
252		if [[ -f $_bint ]]; then
253			echo " $_binn"
254			tar xf $_bint
255			if [[ -f install.sh ]]; then
256				sh install.sh >/dev/null 2>&1
257			else
258				make -f Makefile.relink relink >/dev/null 2>&1
259			fi
260		fi
261		) || { _error=true; break; }
262	done
263
264	rm -rf $_relink/_rebuild.*
265
266	# Restore previous mount state if it was changed.
267	for _mp in $_ro_list; do
268		mount -u -r $_mp || _error=true
269	done
270
271	if $_error; then
272		echo '(failed).'
273	else
274		echo '.'
275	fi
276}
277
278# Read output of reorder_libs co-process and output on console.
279wait_reorder_libs() {
280	local _line
281
282	[[ $library_aslr == NO ]] && return
283
284	while IFS= read -p _line; do
285		echo -n "$_line"
286	done
287	echo
288}
289
290# Run rc.* script and email output to root.
291# Usage: run_upgrade_script firsttime|sysmerge
292run_upgrade_script() {
293	local _suffix=$1
294
295	[[ -n $_suffix ]] || return 1
296
297	if [[ -f /etc/rc.$_suffix ]]; then
298		echo "running rc.$_suffix"
299		mv /etc/rc.$_suffix /etc/rc.$_suffix.run
300		. /etc/rc.$_suffix.run 2>&1 | tee /dev/tty |
301			mail -Es "$(hostname) rc.$_suffix output" root >/dev/null
302	fi
303	rm -f /etc/rc.$_suffix.run
304}
305
306# Check filesystems, optionally by using a fsck(8) flag.
307# Usage: do_fsck [-flag]
308do_fsck() {
309	fsck -p "$@"
310	case $? in
311	0)	;;
312	2)	exit 1
313		;;
314	4)	echo "Rebooting..."
315		reboot
316		echo "Reboot failed; help!"
317		exit 1
318		;;
319	8)	echo "Automatic file system check failed; help!"
320		exit 1
321		;;
322	12)	echo "Boot interrupted."
323		exit 1
324		;;
325	130)	# Interrupt before catcher installed.
326		exit 1
327		;;
328	*)	echo "Unknown error; help!"
329		exit 1
330		;;
331	esac
332}
333
334# End subroutines.
335
336stty status '^T'
337
338# Set shell to ignore SIGINT (2), but not children; shell catches SIGQUIT (3)
339# and returns to single user after fsck.
340trap : 2
341trap : 3	# Shouldn't be needed.
342
343export HOME=/
344export INRC=1
345export PATH=/sbin:/bin:/usr/sbin:/usr/bin
346
347# /etc/myname contains my symbolic name.
348if [[ -f /etc/myname ]]; then
349	hostname "$(stripcom /etc/myname)"
350fi
351
352# Must set the domainname before rc.conf, so YP startup choices can be made.
353if [[ -s /etc/defaultdomain && -z "$(sysctl -n kern.domainname)" ]]; then
354	domainname "$(stripcom /etc/defaultdomain)"
355fi
356
357# Get local functions from rc.subr to load rc.conf into scope.
358FUNCS_ONLY=1 . /etc/rc.d/rc.subr
359_rc_parse_conf
360
361# If executed with the 'shutdown' parameter by the halt, reboot or shutdown:
362# - update seed files
363# - execute the rc.d scripts specified by $pkg_scripts in reverse order
364# - bring carp interfaces down gracefully
365if [[ $1 == shutdown ]]; then
366	if echo 2>/dev/null >>/var/db/host.random ||
367	    echo 2>/dev/null >>/etc/random.seed; then
368		random_seed
369	else
370		echo warning: cannot write random seed to disk
371	fi
372
373	# If we are in secure level 0, assume single user mode.
374	if (($(sysctl -n kern.securelevel) == 0)); then
375		echo 'single user: not running shutdown scripts'
376	else
377		set -A _d -- $pkg_scripts
378		_i=${#_d[*]}
379		if ((_i)); then
380			echo -n 'stopping package daemons:'
381			while ((--_i >= 0)); do
382				[[ -x /etc/rc.d/${_d[_i]} ]] &&
383					/etc/rc.d/${_d[_i]} stop
384			done
385			echo '.'
386		fi
387
388		if /etc/rc.d/vmd check > /dev/null; then
389			echo -n 'stopping VMs'
390			/etc/rc.d/vmd stop > /dev/null
391			echo '.'
392		fi
393
394		[[ -f /etc/rc.shutdown ]] && sh /etc/rc.shutdown
395	fi
396
397	ifconfig | while read _if _junk; do
398		[[ $_if == carp+([0-9]): ]] && ifconfig ${_if%:} down
399	done
400
401	exit 0
402fi
403
404# If bootblocks failed to give us random, try to cause some churn
405(dmesg; sysctl hw.{uuid,serialno,sensors} ) >/dev/random 2>&1
406
407# Add swap block-devices.
408swapctl -A -t blk
409
410# Run filesystem check unless a /fastboot file exists.
411if [[ -e /fastboot ]]; then
412	echo "Fast boot: skipping disk checks."
413elif [[ $1 == autoboot ]]; then
414	echo "Automatic boot in progress: starting file system checks."
415	do_fsck
416fi
417
418# From now on, allow user to interrupt (^C) the boot process.
419trap "echo 'Boot interrupted.'; exit 1" 3
420
421# Unmount all filesystems except root.
422umount -a >/dev/null 2>&1
423
424# Mount all filesystems except those of type NFS and VND.
425mount -a -t nonfs,vnd
426
427# Re-mount the root filesystem read/writeable. (root on nfs requires this,
428# others aren't hurt.)
429mount -uw /
430chmod og-rwx /bsd
431ln -fh /bsd /bsd.booted
432
433rm -f /fastboot
434
435# Set flags on ttys.
436ttyflags -a
437
438# Set keyboard encoding.
439if [[ -x /sbin/kbd && -s /etc/kbdtype ]]; then
440	kbd "$(</etc/kbdtype)"
441fi
442
443wsconsctl_conf
444
445# Set initial temporary pf rule set.
446if [[ $pf != NO ]]; then
447	RULES="
448	block all
449	pass on lo0
450	pass in proto tcp from any to any port ssh keep state
451	pass out proto { tcp, udp } from any to any port domain keep state
452	pass out inet proto icmp all icmp-type echoreq keep state
453	pass out inet proto udp from any port bootpc to any port bootps
454	pass in inet proto udp from any port bootps to any port bootpc"
455
456	if ifconfig lo0 inet6 >/dev/null 2>&1; then
457		RULES="$RULES
458		pass out inet6 proto icmp6 all icmp6-type neighbrsol
459		pass inet6 proto icmp6 all icmp6-type neighbradv no state
460		pass out inet6 proto icmp6 all icmp6-type routersol
461		pass in inet6 proto icmp6 all icmp6-type routeradv
462		pass out inet6 proto udp from any port dhcpv6-client to any port dhcpv6-server
463		pass in inet6 proto udp from any port dhcpv6-server to any port dhcpv6-client"
464	fi
465
466	RULES="$RULES
467	pass in proto carp keep state (no-sync)
468	pass out proto carp !received-on any keep state (no-sync)"
469
470	if (($(sysctl -n vfs.mounts.nfs 2>/dev/null)+0 > 0)); then
471		# Don't kill NFS.
472		RULES="set reassemble yes no-df
473		$RULES
474		pass in proto { tcp, udp } from any port { sunrpc, nfsd } to any
475		pass out proto { tcp, udp } from any to any port { sunrpc, nfsd } !received-on any"
476	fi
477
478	print -- "$RULES" | pfctl -f -
479	pfctl -e
480fi
481
482fill_baddynamic udp
483fill_baddynamic tcp
484
485sysctl_conf
486
487mount -s /var >/dev/null 2>&1		# cannot be on NFS
488mount -s /var/log >/dev/null 2>&1	# cannot be on NFS
489mount -s /usr >/dev/null 2>&1		# if NFS, fstab must use IP address
490
491reorder_libs 2>&1 |&
492
493start_daemon slaacd dhcpleased resolvd >/dev/null 2>&1
494
495echo 'starting network'
496
497# Set carp interlock by increasing the demotion counter.
498# Prevents carp from preempting until the system is booted.
499ifconfig -g carp carpdemote 128
500
501sh /etc/netstart
502
503start_daemon unwind >/dev/null 2>&1
504
505random_seed
506
507wait_reorder_libs
508
509# Load pf rules and bring up pfsync interface.
510if [[ $pf != NO ]]; then
511	if [[ -f /etc/pf.conf ]]; then
512		pfctl -f /etc/pf.conf
513	fi
514	if [[ -f /etc/hostname.pfsync0 ]]; then
515		sh /etc/netstart pfsync0
516	fi
517fi
518
519# Clean up left-over files.
520rm -f /etc/nologin /var/spool/lock/LCK.*
521(cd /var/run && { rm -rf -- *; install -c -m 664 -g utmp /dev/null utmp; })
522(cd /var/authpf && rm -rf -- *)
523
524# Save a copy of the boot messages.
525dmesg >/var/run/dmesg.boot
526
527make_keys
528
529echo -n 'starting early daemons:'
530start_daemon syslogd ldattach pflogd nsd unbound ntpd
531start_daemon iscsid isakmpd iked sasyncd ldapd npppd
532echo '.'
533
534# Load IPsec rules.
535if [[ $ipsec != NO && -f /etc/ipsec.conf ]]; then
536	ipsecctl -f /etc/ipsec.conf
537fi
538
539echo -n 'starting RPC daemons:'
540start_daemon portmap
541if [[ -n $(domainname) ]]; then
542	start_daemon ypldap ypserv ypbind
543fi
544start_daemon mountd nfsd lockd statd amd
545echo '.'
546
547# Check and mount remaining file systems and enable additional swap.
548mount -a
549swapctl -A -t noblk
550do_fsck -N
551mount -a -N
552
553# Build kvm(3) and /dev databases.
554kvm_mkdb
555dev_mkdb
556
557# /var/crash should be a directory or a symbolic link to the crash directory
558# if core dumps are to be saved.
559if [[ -d /var/crash ]]; then
560	savecore $savecore_flags /var/crash
561fi
562
563# Store ACPI tables in /var/db/acpi to be used by sendbug(1).
564if [[ -x /usr/sbin/acpidump ]]; then
565	acpidump -q -o /var/db/acpi/
566fi
567
568if [[ $check_quotas == YES ]]; then
569	echo -n 'checking quotas:'
570	quotacheck -a
571	echo ' done.'
572	quotaon -a
573fi
574
575# Set proper permission for the tty device files.
576chmod 666 /dev/tty[pqrstuvwxyzPQRST]*
577chown root:wheel /dev/tty[pqrstuvwxyzPQRST]*
578
579# Check for the password temp/lock file.
580if [[ -f /etc/ptmp ]]; then
581	logger -s -p auth.err \
582	    'password file may be incorrect -- /etc/ptmp exists'
583fi
584
585echo clearing /tmp
586
587# Prune quickly with one rm, then use find to clean up /tmp/[lqv]*
588# (not needed with mfs /tmp, but doesn't hurt there...).
589(cd /tmp && rm -rf [a-km-pr-uw-zA-Z]*)
590(cd /tmp &&
591    find . -maxdepth 1 ! -name . ! -name lost+found ! -name quota.user \
592	! -name quota.group ! -name vi.recover -execdir rm -rf -- {} \;)
593
594# Create Unix sockets directories for X if needed and make sure they have
595# correct permissions.
596[[ -d /usr/X11R6/lib ]] && mkdir -m 1777 /tmp/.{X11,ICE}-unix
597
598[[ -f /etc/rc.securelevel ]] && sh /etc/rc.securelevel
599
600# rc.securelevel did not specifically set -1 or 2, so select the default: 1.
601(($(sysctl -n kern.securelevel) == 0)) && sysctl kern.securelevel=1
602
603
604# Patch /etc/motd.
605if [[ ! -f /etc/motd ]]; then
606	install -c -o root -g wheel -m 664 /dev/null /etc/motd
607fi
608if T=$(mktemp /tmp/_motd.XXXXXXXXXX); then
609	sysctl -n kern.version | sed 1q >$T
610	sed -n '/^$/,$p' </etc/motd >>$T
611	cmp -s $T /etc/motd || cp $T /etc/motd
612	rm -f $T
613fi
614
615if [[ $accounting == YES ]]; then
616	[[ ! -f /var/account/acct ]] && touch /var/account/acct
617	echo 'turning on accounting'
618	accton /var/account/acct
619fi
620
621if [[ -x /sbin/ldconfig ]]; then
622	echo 'creating runtime link editor directory cache.'
623	[[ -d /usr/local/lib ]] && shlib_dirs="/usr/local/lib $shlib_dirs"
624	[[ -d /usr/X11R6/lib ]] && shlib_dirs="/usr/X11R6/lib $shlib_dirs"
625	ldconfig $shlib_dirs
626fi
627
628echo 'preserving editor files.'; /usr/libexec/vi.recover
629
630# If rc.sysmerge exists, run it just once, and make sure it is deleted.
631run_upgrade_script sysmerge
632
633echo -n 'starting network daemons:'
634start_daemon ldomd sshd snmpd ldpd ripd ospfd ospf6d bgpd ifstated
635start_daemon relayd dhcpd dhcrelay mrouted dvmrpd radiusd eigrpd route6d
636start_daemon rad hostapd lpd smtpd slowcgi bgplgd httpd ftpd
637start_daemon ftpproxy ftpproxy6 tftpd tftpproxy identd inetd rarpd bootparamd
638start_daemon rbootd mopd vmd spamd spamlogd sndiod
639echo '.'
640
641# If rc.firsttime exists, run it just once, and make sure it is deleted.
642run_upgrade_script firsttime
643
644# Run rc.d(8) scripts from packages.
645if [[ -n $pkg_scripts ]]; then
646	echo -n 'starting package daemons:'
647	for _daemon in $pkg_scripts; do
648		if [[ -x /etc/rc.d/$_daemon ]]; then
649			start_daemon $_daemon
650		else
651			echo -n " ${_daemon}(absent)"
652		fi
653	done
654	echo '.'
655fi
656
657[[ -f /etc/rc.local ]] && sh /etc/rc.local
658
659# Disable carp interlock.
660ifconfig -g carp -carpdemote 128
661
662mixerctl_conf
663
664echo -n 'starting local daemons:'
665start_daemon apmd sensorsd hotplugd watchdogd cron wsmoused xenodm
666echo '.'
667
668# Re-link the kernel, placing the objects in a random order.
669# Replace current with relinked kernel and inform root about it.
670/usr/libexec/reorder_kernel &
671
672date
673exit 0
674