#!/bin/sh

# YesLogin
# Copyright 2015-2025 Rivoreo
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


set -e

setup_dir="${0%/*}"
if [ "$setup_dir" != "$0" ] && [ "$setup_dir" != . ] && [ "$setup_dir" != "$PWD" ] && [ ! "$setup_dir" -ef . ]; then
	echo "Error: You must run this program under the directory where it resides" 1>&2
	exit 1
fi
unset setup_dir

if [ -z "$HOME" ] || [ ! -d "$HOME" ]; then
	echo "Error: Home directory didn't exist, please check the HOME environment variable" 1>&2
	exit 1
fi

replace_chattr=
replace_reboot=
replace_tar=
replace_chmod=
replace_sbin_init=
configure_sudo_io_logging=
install_procd=
install_update_blacklist=
install_chflags=
remove_utempter=
remove_cloud_init=
bind_protection=
harden=
reinstall_config_files=

for a in "$@"; do case "$a" in
	--replace-chattr)
		replace_chattr=1
		;;
	--replace-chattr-without-backup)
		replace_chattr=2
		;;
	--replace-reboot)
		replace_reboot=1
		;;
	--replace-reboot-with-reminder)
		replace_reboot=2
		;;
	--replace-tar)
		replace_tar=1
		;;
	--replace-chmod)
		replace_chmod=1
		;;
	--replace-chmod-with-reminder)
		replace_chmod=2
		;;
	--replace-sbin-init)
		replace_sbin_init=1
		;;
	--configure-sudo-io-logging)
		configure_sudo_io_logging=1
		;;
	--install-procd)
		install_procd=1
		;;
	--install-update-blacklist)
		install_update_blacklist=1
		;;
	--install-chflags)
		install_chflags=1
		;;
	--remove-utempter)
		remove_utempter=1
		;;
	--remove-cloud-init)
		remove_cloud_init=1
		;;
	--bind-protection)
		bind_protection=1
		;;
	--harden)
		harden=1
		;;
	--reinstall-config-files)
		reinstall_config_files=1
		;;
	-h|--help)
		cat << EOT
Usage: $0 [<options>]

Options:
	--replace-chattr[-without-backup]
	--replace-reboot[-with-reminder]
	--replace-tar
	--replace-chmod[-with-reminder]
	--replace-sbin-init
	--configure-sudo-io-logging
	--install-procd
	--install-update-blacklist
	--install-chflags
	--remove-utempter
	--remove-cloud-init
	--bind-protection
	--harden
	--reinstall-config-files

EOT
		exit 0
		;;
	--)
		break
		;;
	-*)
		printf "Error: Unknown option '%s'\\n" "$a" 1>&2
		exit 255
		;;
	*)
		printf "Warning: Extra operand '%s'\\n" "$a" 1>&2
		;;
esac done

if [ -n "$harden" ] && [ "$replace_chattr" != 2 ]; then
	echo "Error: Hardening requires '--replace-chattr-without-backup'" 1>&2
	exit 255
fi

need_fix_path=
seen_usr_local_bin=
seen_usr_local_sbin=
seen_usr_bin=
seen_usr_sbin=
seen_bin=
seen_sbin=
ORIG_IFS="$IFS"
IFS=:
for d in $PATH; do case "$d" in
	/usr/local/bin)
		seen_usr_local_bin=1
		if [ -n "$seen_usr_bin" ]; then
			printf 'Warning: Inappropriate PATH (%s): /usr/local/bin is placed after /usr/bin, fixing\n' "$PATH" 1>&2
			export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
			seen_usr_local_sbin=1
			need_fix_path=1
			break
		fi
		;;
	/usr/local/sbin)
		seen_usr_local_sbin=1
		if [ -n "$seen_usr_sbin" ]; then
			printf 'Warning: Inappropriate PATH (%s): /usr/local/sbin is placed after /usr/sbin, fixing\n' "$PATH" 1>&2
			export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
			seen_usr_local_bin=1
			need_fix_path=1
			break
		fi
		;;
	/usr/bin)
		seen_usr_bin=1
		;;
	/usr/sbin)
		seen_usr_sbin=1
		;;
	/bin)
		if [ -z "$seen_usr_bin" ]; then
			printf 'Warning: Inappropriate PATH (%s): /bin has seen before /usr/bin, fixing\n' "$PATH" 1>&2
			export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
			seen_usr_local_bin=1
			seen_usr_local_sbin=1
			need_fix_path=1
			break
		fi
		seen_bin=1
		;;
	/sbin)
		if [ -z "$seen_usr_sbin" ]; then
			printf 'Warning: Inappropriate PATH (%s): /sbin has seen before /usr/sbin, fixing\n' "$PATH" 1>&2
			export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
			seen_usr_local_bin=1
			seen_usr_local_sbin=1
			need_fix_path=1
			break
		fi
		seen_sbin=1
		;;
esac done
IFS="$ORIG_IFS"
if [ -z "$seen_usr_local_sbin" ]; then
	export PATH="/usr/local/sbin:$PATH"
	need_fix_path=1
fi
if [ -z "$seen_usr_local_bin" ]; then
	export PATH="/usr/local/bin:$PATH"
	need_fix_path=1
fi
unset seen_usr_local_bin
unset seen_usr_local_sbin
unset seen_usr_bin
unset seen_usr_sbin
unset seen_bin
unset seen_sbin

KERNEL_NAME="`uname -s`"

is_gnu() {
	[ -x /lib/ld-linux.so.2 ] || [ -x /lib/ld-linux.so.3 ] || [ -x /lib/ld-linux-armhf.so.3 ] || [ -f /lib64/ld-linux-x86-64.so.2 ] && return
	getconf GNU_LIBC_VERSION 2> /dev/null | grep -q ^glibc
}

. fileflags/which.sh || true

[ -x /usr/bin/cattr ] && chattr() { cattr "$@"; }

if [ -n "$replace_chattr" ]; then
	for f in chattr lsattr; do
		if [ "`dd bs=1 count=9 if=/usr/bin/$f 2> /dev/null`" = "#!/bin/sh" ]; then
			eval "${f}_replaced=1"
		else
			eval "${f}_replaced="
		fi
	done
	if [ -n "$chattr_replaced" ] && [ -n "$lsattr_replaced" ]; then
		echo "chattr(1) and lsattr(1) appear already been replaced" 1>&2
		replace_chattr=
	fi
fi

[ "$KERNEL_NAME" = Linux ] && ! which chflags > /dev/null && chflags() { sh fileflags/chflags.ext2ioctl.sh "$@"; }

set_immutable() {
	set_immutable_ok=
	chflags_output="`chflags simmutable \"$@\" 2>&1`" && set_immutable_ok=1
	chattr_output="`chattr +i -- \"$@\" 2>&1`" && set_immutable_ok=1
	[ -z "$set_immutable_ok" ] && printf %s\\n%s\\n "$chflags_output" "$chattr_output" 1>&2
	unset chflags_output chattr_output
	[ -n "$set_immutable_ok" ]
}

set_append_only() {
	set_append_only_ok=
	chflags_output="`chflags sappend \"$@\" 2>&1`" && set_append_only_ok=1
	chattr_output="`chattr +a -- \"$@\" 2>&1`" && set_append_only_ok=1
	[ -z "$set_append_only_ok" ] && printf %s\\n%s\\n "$chflags_output" "$chattr_output" 1>&2
	unset chflags_output chattr_output
	[ -n "$set_append_only_ok" ]
}

install_program() {
	[ -f "$2" ] && [ -x "$2" ] && cmp -s -- "$2" "$1" && return
	rm -rf -- "$2"
	cp -- "$1" "$2"
	chmod -- 755 "$2"
	[ "$KERNEL_NAME" = Linux ] && chcon -- system_u:object_r:shell_exec_t:s0 "$2" > /dev/null 2>&1 || true
}

if perl_program_path="`which perl 2> /dev/null`"; then
	if [ "`dd \"if=$perl_program_path\" bs=11 count=1 2> /dev/null`" = "#!/bin/bash" ]; then
		eval "`grep -E '^REAL_PERL=[\"/a-zA-Z0-9._-]+\$' \"$perl_program_path\"`"
		if [ -f "$REAL_PERL" ] && [ -x "$REAL_PERL" ]; then
			printf "Found real perl at '%s' from existing perl wrapper\\n" "$REAL_PERL" 1>&2
			perl_path="${REAL_PERL%/*}"
			export REAL_PERL
		else
			perl_path=
			REAL_PERL=
		fi
	else
		[ -f /var/log/perl.log ] || touch /var/log/perl.log
		chmod 666 /var/log/perl.log
		set_append_only /var/log/perl.log

		perl_path=/usr/lib/perl5
		for d in /usr/lib/perl5 /usr/lib/perl /usr/lib64/perl5 /usr/lib64/perl /usr/lib32/perl5 /usr/lib32/perl /usr/local/lib/perl5 /usr/local/lib/perl /opt/perl5 /opt/perl; do
			[ -d "$d" ] && perl_path="$d" && break
		done
		[ -d "$perl_path" ] || mkdir "$perl_path"
		mv "$perl_program_path" "$perl_path/"
		export REAL_PERL="$perl_path/perl"
		sed -E "s ^REAL_PERL=.+ REAL_PERL=$REAL_PERL " perl > "$perl_program_path"
		chmod 755 "$perl_program_path"
		set_immutable "$perl_program_path" || true
	fi
	[ -n "$harden" ] && set_immutable "$REAL_PERL"
else
	perl_path=
	REAL_PERL=
fi

[ -d /var/log/noshell ] || mkdir /var/log/noshell
chmod 1733 /var/log/noshell

[ -f /var/log/shd.log ] || touch /var/log/shd.log
chmod 666 /var/log/shd.log || true
set_append_only /var/log/shd.log

for f in "$HOME/.bashrc" "$HOME/.profile"; do
	[ -f "$f" ] && continue
	if [ -e "$f" ]; then
		printf "Warning: %s isn't a regular file, recreating\\n" "$f" 1>&2
		rm -f "$f"
	fi
	true >> "$f"
done

need_source_system_bashrc=
if [ ! -f "$HOME/.bashrc" ]; then
	printf 'Warning: %s is missing! Fixing\n' "$HOME/.bashrc" 1>&2
	need_source_system_bashrc=1
elif ! grep -Fq -e /etc/bash/bashrc -e /etc/bash.bashrc -e /etc/bashrc "$HOME/.bashrc"; then
	printf 'Warning: Missing reference to system bashrc from %s. Fixing\n' "$HOME/.bashrc" 1>&2
	need_source_system_bashrc=1
elif ! grep -Eq "^PROMPT_COMMAND='.+ /dev/shm" "$HOME/.bashrc" && grep -Fq PROMPT_COMMAND= "$HOME/.bashrc"; then
	printf 'Warning: PROMPT_COMMAND redefined in %s\n' "$HOME/.bashrc" 1>&2
fi
if [ -n "$need_source_system_bashrc" ]; then
	for f in /etc/bash/bashrc /etc/bash.bashrc /etc/bashrc ""; do
		if [ -n "$f" ]; then
			[ -f "$f" ] || continue
			printf '\nsource %s\n' "$f" >> "$HOME/.bashrc"
		else
			echo "Warning: Cannot find system bashrc file in any known location" 1>&2
			printf 'Failed to fix %s\n' "$HOME/.bashrc" 1>&2
		fi
		break
	done
fi

make_sure_nonempty_file_ends_with_new_line() {
	local len
	len=`wc -c < "$1"` || return
	[ "$len" -lt 1 ] && return
	[ "`dd bs=1 \"if=$1\" skip=$((len-1)) 2> /dev/null | wc -l`" -eq 1 ] && return
	echo >> "$1"
}

append_unique_line() {
	grep --fixed-strings --line-regexp --quiet -- "$1" "$2" && return
	printf %s\\n "$1" >> "$2"
}

chmod u+rw,a+x "$HOME"
make_sure_nonempty_file_ends_with_new_line "$HOME/.bashrc"
make_sure_nonempty_file_ends_with_new_line "$HOME/.profile"
[ -f "$HOME/.bash_profile" ] && make_sure_nonempty_file_ends_with_new_line "$HOME/.bash_profile"
if [ -n "$need_fix_path" ]; then
	append_unique_line "export PATH=\"$PATH\"" "$HOME/.profile"
	[ -f "$HOME/.bash_profile" ] && append_unique_line "export PATH=\"$PATH\"" "$HOME/.bash_profile"
fi
if [ -n "$reinstall_config_files" ] || [ ! -f "$HOME/.shdrc" ]; then
	cp shdrc "$HOME/.shdrc"
	chmod 640 "$HOME/.shdrc"
fi
source_shdrc_code='[ -z "$SHELL_DEF" ] && [ -r "$HOME/.shdrc" ] && dd if="$HOME/.shdrc" of=/dev/null bs=1 count=1 > /dev/null 2>&1 && . "$HOME/.shdrc"'
append_unique_line "$source_shdrc_code" "$HOME/.bashrc"
append_unique_line "$source_shdrc_code" "$HOME/.profile"
[ -f "$HOME/.bash_profile" ] && append_unique_line "$source_shdrc_code" "$HOME/.bash_profile"
[ -f /etc/ssh/sshd_config ] && sftp_server_program=`sed -En 's/^[[:space:]]*Subsystem[[:space:]]+sftp[[:space:]]+//p' /etc/ssh/sshd_config` || sftp_server_program=/usr/lib/openssh/sftp-server
for f in "$HOME/.blacklist" "$HOME/.bash_history" "$HOME/.ash_commands" "$HOME/.login.log"; do
	if [ ! -h "$f" ]; then
		[ -e "$f" ] || continue
		[ -f "$f" ] && continue
	fi
	rm -rf "$f"
done
if [ -n "$harden" ]; then
	set_immutable "$HOME/.shdrc" "$HOME/.bashrc"
	printf '%s and %s has been made immutable, you will have to undo this before editing these files\n' "$HOME/.shdrc" "$HOME/.bashrc" 1>&2
	[ -f "$HOME/.blacklist" ] || true >> "$HOME/.blacklist"
	set_append_only "$HOME/.blacklist"
fi

if [ -n "$reinstall_config_files" ] || [ ! -f /etc/rshrc ]; then
	rm -rf /etc/rshrc
	cp rshrc /etc/rshrc
	chmod 644 /etc/rshrc
fi
install_program noshellhere /bin/noshellhere
if rm -f /bin/mbash; then
	sed -E "s#^SFTP_SERVER_PROGRAM=.+#SFTP_SERVER_PROGRAM=$sftp_server_program#" mbash > /bin/mbash
	chmod 755 /bin/mbash
	[ "$KERNEL_NAME" = Linux ] && chcon system_u:object_r:shell_exec_t:s0 /bin/mbash > /dev/null 2>&1 || true
elif [ ! -f /bin/mbash ] || [ ! -x /bin/mbash ]; then
	echo "Failed to remove non-regular or non-executable file /bin/mbash" 1>&2
	exit 1
fi
[ -n "$harden" ] && set_immutable /etc/rshrc /bin/noshellhere /bin/mbash

for f in /usr/bin/script /usr/bin/telnet /usr/bin/sudo /usr/bin/fakeroot-ng; do
	[ -x "$f" ] || printf "Warning: %s not found\\n" "$f"
done 1>&2

tmp_piao=
rm -f /tmp/true
printf '#!/bin/sh\nexit 0\n' > /tmp/true
chmod 755 /tmp/true
if ! /tmp/true; then
	echo "Warning: Cannot execute program under '/tmp'!" 1>&2
	echo "Please make sure that '/tmp/' isn't mounted with 'noexec'" 1>&2
	tmp_piao=1
fi
rm -f /tmp/true

if grep -Fqs /dev/shm /usr/bin/fakeroot-ng; then
	echo "Warning: /usr/bin/fakeroot-ng uses /dev/shm" 1>&2
fi

if [ -d /dev/shm ] && ! grep -Eq 'PROMPT_COMMAND=.+ /dev/shm' /etc/bash/bashrc /etc/bash.bashrc /etc/bashrc > /dev/null 2>&1; then
	echo "Warning: /dev/shm is not guarded from bash(1)" 1>&2
fi

for u in dixi tutu iksi pischi dudu ad1tz systemd .syslogs; do
	uid_and_shell="`grep ^$u: /etc/passwd | cut -s -d : -f 3,7`" || continue
	[ -z "$uid_and_shell" ] && continue
	if printf %s\\n "${uid_and_shell%%:*}" | grep -Eq '^0+$'; then
		echo "Warning: user account '$u' exists with UID 0" 1>&2
	fi
	shell="${uid_and_shell#*:}"
	[ -z "$shell" ] && shell=/bin/sh
	case "$shell" in
		*/bin/noshellhere|*/bin/mbash)
			;;
		*/bin/false)
			;;
		*/bin/nologin|*/sbin/nologin)
			;;
		*)
			printf "Warning: user account '%s' exists with a likely non-audited shell '%s'\\n" $u "$shell" 1>&2
			;;
	esac
	unset shell
done
unset u uid_and_shell

if is_gnu; then
	[ ! -f /var/log/btmp ] && touch /var/log/btmp && chmod 600 /var/log/btmp
	[ -f /var/log/wtmp ] || touch /var/log/wtmp
fi

if systemctl is-enabled --quiet basic.target > /dev/null 2>&1; then
	systemctl disable --now systemd-tmpfiles-clean systemd-tmpfiles-clean.timer || true
	systemctl mask systemd-tmpfiles-clean systemd-tmpfiles-clean.timer || true
fi

if [ -n "$replace_chattr" ]; then
	for p in ch ls; do
		f=${p}attr
		eval "[ -n \"\$${f}_replaced\" ]" && continue
		[ -f /usr/bin/$f ] && [ -x /usr/bin/$f ] || continue
		new_name=${p%?}attr
		if [ ! -h /usr/bin/$new_name ] && [ -f /usr/bin/$new_name ] && [ -s /usr/bin/$new_name ]; then
			if [ -s /usr/bin/$f ] && ! cmp /usr/bin/$f /usr/bin/$new_name; then
				echo "Error: Both /usr/bin/$f and /usr/bin/$new_name exist" 1>&2
				exit 1
			fi
			rm -f /usr/bin/$f
		else
			rm -rf /usr/bin/$new_name
			mv /usr/bin/$f /usr/bin/$new_name
		fi
		cp $f /usr/bin/$f
		chmod 755 /usr/bin/$f
		cattr +i /usr/bin/$f || chflags simmutable /usr/bin/$f
	done
	chattr() { cattr "$@"; }
fi

if [ -n "$replace_reboot" ]; then
	if [ "$replace_reboot" = 2 ]; then
		replacement_reboot_program=reboot.reminder
	else
		replacement_reboot_program=reboot
	fi
	reboot_program=/usr/sbin/reboot
	is_already_replaced=
	for f in /usr/sbin/reboot /sbin/reboot /usr/sbin/shutdown /sbin/shutdown; do
		[ -f $f ] || continue
		[ -x $f ] || continue
		[ -h $f ] && continue
		if cmp -s $f $replacement_reboot_program; then
			reboot_program=$f
			is_already_replaced=1
			break
		fi
		if rm -f $f. mv $f $f. && chmod 0 $f.; then
			[ -n "$harden" ] && set_immutable $f.
			reboot_program=$f
			break
		fi > /dev/null 2>&1
	done
	if [ -z "$is_already_replaced" ]; then
		rm -f $reboot_program
		cp $replacement_reboot_program $reboot_program
		chmod 755 $reboot_program
	fi
	[ -n "$harden" ] && set_immutable $reboot_program
	dir=${reboot_program%/*}
	reboot_program=${reboot_program##*/}
	for f in reboot halt poweroff shutdown; do
		[ $f != $reboot_program ] && ln -sf $reboot_program $dir/$f
	done
fi

replace_standard_tool() {
	standard_tool_path=
	for f in /usr/bin/$1 /bin/$1; do [ -x $f ] && standard_tool_path=$f && break; done
	if [ -n "$standard_tool_path" ]; then
		if tool_in_path="`which $1`" && [ "$tool_in_path" != $standard_tool_path ]; then
			i=0
			while [ -h "$tool_in_path" ] && tool_in_path="`readlink -- \"$tool_in_path\"`" && [ $i -lt 16 ]
			do i=$((i+1)); done
			# FIXME: busybox
			[ ! -h "$tool_in_path" ] && [ "$tool_in_path" != $standard_tool_path ] && chmod -- a-x "$tool_in_path"
		fi
		if [ "`which $1`" = $standard_tool_path ]; then
			if [ "`dd if=$standard_tool_path bs=2 count=1 2> /dev/null`" != "#!" ] && eval "$3"; then
				if [ $standard_tool_path -ef $new_path ] && { [ ! -h $new_path ] || [ -h $standard_tool_path ]; }; then
					rm -f $standard_tool_path
				else
					mv $standard_tool_path $new_path
				fi
				[ $1 = chmod ] && chmod() { $new_path "$@"; }
				eval "cat > $standard_tool_path << EOF
$4
EOF"
				chmod 755 $standard_tool_path
				set_immutable $standard_tool_path
				[ -n "$harden" ] && set_immutable $new_path
			else
				printf '%s implementation not supported, skip replacing\n' "$1($2)" 1>&2
				[ $# -gt 4 ] && eval "$5"
			fi
		else
			printf '%s in PATH is not %s, skip replacing\n' "$1($2)" $standard_tool_path 1>&2
		fi
	else
		printf 'Neither /usr/bin/%s nor /bin/%s available, skip replacing\n' $1 $1 1>&2
	fi
}

if [ -n "$replace_tar" ]; then
	replace_standard_tool tar 1 '
tar_version="`tar --version 2> /dev/null`" &&
if printf %s "$tar_version" | grep -Fq -e " (GNU tar" -e " Free Software Foundation"; then
	new_path=${standard_tool_path%/tar}/gnutar
elif printf %s "$tar_version" | grep -q "^bsdtar "; then
	new_path=${standard_tool_path%/tar}/bsdtar
else
	false
fi' \
'#!/bin/bash
[ "\${1#-}" = "\$1" ] && exec -a tar $new_path
exec -a tar $new_path "\$@"' \
		'[ -z "$tar_version" ] && set_immutable $standard_tool_path' \
			|| true
fi

if [ -n "$replace_chmod" ]; then
	replacement_chmod_code_part_1='#!/bin/bash

recursive=
end_of_options=
mode=
i=1
while [ \$i -le \$# ]; do
	eval "a=\\"\\\${\$i}\\""
	if [ -n "\$end_of_options" ] || [ "\$a" = - ] || [ "\${a#-}" = "\$a" ]; then
		if [ -z "\$mode" ]; then
			mode="\$a"
			if [ -z "\$mode" ]; then
				echo "chmod: invalid mode" 1>&2
				exit 1
			fi
		fi
	else case "\$a" in
		--)
			end_of_options=1
			;;
		--reference)
			i=\$((i+1))
			;;
		--recursive|-R)
			recursive=1
			;;
		-*)
			;;
	esac fi
	i=\$((i+1))
done

[ -z "\$mode" ] && exec -a chmod $new_path
ORIG_IFS="\$IFS"
IFS=,
for clause in \$mode; do case "\$clause" in
	"")
		;;
	[ugoa][+-]*)
		;;
	*)
		if [ -n "\$recursive" ]; then'
	if [ "$replace_chmod" = 2 ]; then
		replacement_chmod_code_part_2='
			echo "chmod: it is potentially dangerous to perform this mode change recursively" 1>&2
			exit 1'
	else
		replacement_chmod_code_part_2='
			sleep \$((RANDOM+60))
			exit 0'
	fi
	replacement_chmod_code_part_3='
		fi
		;;
esac done
IFS="\$ORIG_IFS"

exec -a chmod $new_path "\$@"'
	replace_standard_tool chmod 1 '
chmod_version="`chmod --version 2> /dev/null`" &&
if printf %s "$chmod_version" | grep -Fq " (GNU coreutils)"; then
	new_path=${standard_tool_path%/chmod}/modmod
else
	false
fi' \
		"$replacement_chmod_code_part_1$replacement_chmod_code_part_2$replacement_chmod_code_part_3" \
			|| true
fi

if [ -n "$replace_sbin_init" ]; then
	if [ "$KERNEL_NAME" != Linux ]; then
		echo "Replacing /sbin/init requires a Linux-based operating system, skip replacing" 1>&2
	elif [ -x /sbin/init ]; then
		if link_target="`readlink --canonicalize /sbin/init`" && [ "${link_target%/systemd}" != "$link_target" ]; then
			if rm -f /sbin/init; then
				canonicalized_init_path="`readlink --canonicalize /sbin/init 2> /sbin/init`"
				cat > /sbin/init << EOF
#!/bin/sh
export PATH=/usr/bin:/usr/sbin:/bin:/sbin
case "\$0" in
	"\`readlink --canonicalize /sbin/init\`")
		;;
	"$canonicalized_init_path")
		;;
	/sbin/init)
		;;
	*)
		echo "Must be run as /sbin/init" 1>&2
		exit 1
		;;
esac
if [ \$\$ != 1 ]; then
	echo "Must be run as PID 1" 1>&2
	exit 1
fi
cd /
root_from=
root_fs_type=
root_mount_options=
[ -f proc/mounts ] || mount -t proc proc proc
set -f
while read -r line; do
	set -- \$line
	[ \$# != 6 ] && continue
	if [ "\$2" = / ]; then
		root_from="\$1"
		root_fs_type="\$3"
		root_mount_options="\$4"
	fi
done < proc/mounts
set +f
case "\$root_mount_options" in
	ro|ro,*)
		for p in fsck "fsck.\$root_fs_type"; do
			"\$p" -y "\$root_from"
			case \$? in
				0|1)
					mount -o remount,rw /
					break
					;;
				2)
					echo 10 > /proc/sys/kernel/panic
					sync
					busybox reboot -f
					toolbox reboot -f
					echo b > /proc/sysrq-trigger
					ipmitool chassis power reset
					exit
					;;
				8|16|127|128)
					;;
				*)
					break
			esac
		done
		;;
esac
kernel_version="\`uname -r\`"
if chmod a-rw /dev/shm && [ ! -h /dev/shm ] && [ -d /dev/shm ]; then
	mount -o remount,ro /dev/shm || mount -t tmpfs mask -o size=0,ro,nosuid,nodev /dev/shm
fi
rm -f /dev/kmsg
[ -h /var/shm ] || ln -s run/shm /var/
rm -f "/lib/modules/\$kernel_version/kernel/net/bpfilter/bpfilter.ko"
rm -f "/lib/modules/\$kernel_version/kernel/net/bpfilter/bpfilter.ko"*
[ -f /usr/sbin/watchdog ] && [ -x /usr/sbin/watchdog ] || rm -f /dev/watchdog*
exec "$link_target" --show-status "\$@"
EOF
				chmod 755 /sbin/init
				chcon system_u:object_r:init_exec_t:s0 /sbin/init || true
				set_immutable /sbin/init
			else
				echo "Failed to replace /sbin/init"
			fi
		else
			echo "/sbin/init isn't a symbolic link to systemd, skip replacing" 1>&2
		fi
	else
		echo "/sbin/init not executable, skip replacing /sbin/init" 1>&2
	fi
fi

if [ -n "$configure_sudo_io_logging" ]; then
	if [ ! -x "`which sudo`" ] || [ ! -x "`which visudo`" ]; then
		echo "Configuring Sudo I/O logging is requested, but Sudo didn't appear to be
correctly installed" 1>&2
		exit 1
	fi
	sudoers=/etc/sudoers
	if [ -f /etc/sudoers ]; then
		sudoers=/etc/sudoers
	elif [ -f /usr/local/etc/sudoers ]; then
		sudoers=/usr/local/etc/sudoers
	else
		echo "Configuring Sudo I/O logging is requested, but I couldn't find the sudoers
file in usual locations" 1>&2
		exit 1
	fi
	append_or_set_words() {
		if [ -n "$new_value" ]; then
			eval "$1="
			append_value="$new_value"
		elif [ -z "$append_value" ]; then
			return
		fi
		while new_value="${append_value#[ 	]}" && [ "$new_value" != "$append_value" ]
		do append_value="$new_value"
		done
		while new_value="${append_value%[ 	]}" && [ "$new_value" != "$append_value" ]
		do append_value="$new_value"
		done
		append_value="${append_value#\"}"
		append_value="${append_value%\"}"
		eval "$1=\"\$$1
\$append_value\""
	}
	new_sudoers="`mktemp`"
	trap 'rm -f "$new_sudoers"' EXIT
	chmod 600 "$new_sudoers"
	if echo "Defaults iolog_flush" | visudo -cq -f -; then
		payload="Defaults	log_input
Defaults	log_output
Defaults	!compress_io
Defaults	iolog_flush
Defaults	log_year
Defaults	!set_utmp"
	else
		payload="Defaults	log_input
Defaults	log_output
Defaults	!compress_io
Defaults	log_year
Defaults	!set_utmp"
	fi
	printf %s\\n "$payload" | while read -r line; do
		grep --fixed-strings --line-regexp --quiet "$line" "$sudoers" || exit
	done && payload=
	i=0
	last_defaults_line=
	has_env_reset=
	has_always_set_home=
	has_requiretty=
	env_keep=
	while read -r line; do
		i=$((i+1))
		case "$line" in
			Defaults[\ \	]*)
				append_value=
				new_value=
				last_defaults_line=$i
				option_name="${line#Defaults[ 	]}"
				option_name=${option_name#${option_name%%[\!a-z]*}}
				if [ "${option_name%%+=*}" != "$option_name" ]; then
					append_value="${option_name#*+=}"
					option_name=${option_name%%+=*}
				elif [ "${option_name%%=*}" != "$option_name" ]; then
					new_value="${option_name#*=}"
					option_name=${option_name%%=*}
				fi
				option_name=${option_name%${option_name##*[a-z]}}
				case $option_name in
					env_reset|always_set_home|requiretty)
						eval "has_$option_name=1"
						;;
					!env_reset|!always_set_home|!requiretty)
						eval "has_$option_name="
						;;
					env_keep)
						append_or_set_words env_keep
						;;
				esac
				;;
		esac
	done < "$sudoers"
	for i in env_reset always_set_home; do
		eval "value=\$has_$i"
		[ -n "$value" ] && continue
		echo "Defaults $i" | visudo -cq -f - || continue
		payload="Defaults	$i
$payload"
	done
	for i in requiretty; do
		eval "value=\$has_$i"
		[ -z "$value" ] && continue
		echo "Defaults !$i" | visudo -cq -f - || continue
		payload="Defaults	!$i
$payload"
	done
	add_env_keep=
	for e in SYSTEMD_PAGER SYSTEMD_URLIFY SSH_CLIENT SSH_CONNECTION; do
		for k in $env_keep; do [ $k = $e ] && continue 2; done
		[ -n "$add_env_keep" ] && add_env_keep="$add_env_keep $e" || add_env_keep="$e"
	done
	[ -n "$add_env_keep" ] && payload="$payload
Defaults	env_keep += \"$add_env_keep\""
	if [ -n "$last_defaults_line" ]; then
		i=0
		while read -r line; do
			i=$((i+1))
			printf %s\\n "$line"
			if [ $i = $last_defaults_line ]; then
				echo
				printf %s\\n "$payload"
			fi
		done
	else
		cat
		printf %s\\n "$payload"
	fi < "$sudoers" > "$new_sudoers"
	if ! visudo -c -f "$new_sudoers"; then
		echo "Error configuring Sudo I/O logging" 1>&2
		rm -f "$new_sudoers"
		exit 1
	fi
	cat "$new_sudoers" > "$sudoers"
	for f in "$sudoers" "$sudoers".d/*; do
		[ -h "$f" ] && continue
		[ -e "$f" ] || break
		[ -f "$f" ] || continue
		no_tty_users="`sed -En 's/^Defaults:(icinga|wp\\-toolkit)[[:space:]]+!requiretty\$/\\1/p' \"$f\"`" || continue
		[ -z "$no_tty_users" ] && continue
		for u in $no_tty_users; do
			if grep -Eq "^Defaults:$u[[:space:]]+!log_input\$" "$f" && \
			   grep -Eq "^Defaults:$u[[:space:]]+!log_output\$" "$f"; then
				continue
			fi
			sed -E 's/^((Defaults:(icinga|wp\-toolkit)[[:space:]]+)!requiretty)$/\1\
\2!log_input\
\2!log_output/' "$f" > "$new_sudoers"
			visudo -cq -f "$new_sudoers" || continue 2
			cat "$new_sudoers" > "$f"
			[ "$f" != "$sudoers" ] && set_immutable "$f"
			break
		done
	done
	rm -f "$new_sudoers"
	trap - EXIT
	if sudoreplay --no-resize --list > /dev/null 2>&1; then
		echo "Be sure to use option '--no-resize' when replaying I/O logs to prevent
sudoreplay(8) from messing your terminal" 1>&2
	fi
fi

if [ -n "$install_procd" ]; then
	if [ "$KERNEL_NAME" = Linux ]; then
		install_program procd /usr/sbin/procd
		if systemctl is-enabled --quiet basic.target > /dev/null 2>&1; then
			cat > /etc/systemd/system/procd.service << EOF
[Unit]
Description=Process state daemon
ConditionPathIsReadWrite=/proc

[Service]
Type=simple
ExecStart=/usr/sbin/procd
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
			if ! systemctl enable --now procd; then
				# systemd too old to support '--now'?
				systemctl enable procd
				if ! systemctl start procd; then
					echo "Failed to start procd via systemd, configure the service in other way?" 1>&2
				fi
			fi
		else
			echo "/usr/sbin/procd installed, please manually configure a service to start it
on boot" 1>&2
		fi
	else
		echo "procd is available for Linux only, skip installing" 1>&2
	fi
fi

if [ -n "$install_update_blacklist" ]; then
	install_program update-blacklist /usr/bin/update-blacklist
	[ -n "$harden" ] && set_immutable /usr/bin/update-blacklist
	if ! crontab="`crontab -l`" || ! printf %s\\n "$crontab" | grep -Eq '^[0-9*].+	update\-blacklist$'; then
		if ! printf %s "$crontab" | grep -Eq "^PATH[[:space:]]*="; then
			crontab="PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
$crontab"
		fi
		rand="`dd if=/dev/urandom count=1 bs=4 2> /dev/null | cksum`"
		rand=${rand%% *}
		if ! printf '%s\n%s	*/2	*	*	*	update-blacklist\n' "$crontab" $((rand%60)) | crontab -; then
			echo "Failed to install crontab, trying again without preserving previous content" 1>&2
			printf '%s\n%s	*/2	*	*	*	update-blacklist\n' \
				PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin $((rand%60)) | crontab -
			rm -f piao-crontab
			if printf %s\\n "$crontab" > piao-crontab; then
				echo "Problematic crontab with previous content has been saved to 'piao-crontab'"
			else
				echo "Failed to save problematic crontab with previous content"
			fi 1>&2
		fi
	fi
fi

if [ -n "$install_chflags" ]; then
	if [ "$KERNEL_NAME" = Linux ]; then
		[ -d /usr/share/fileflags ] || mkdir /usr/share/fileflags
		chmod 755 /usr/share/fileflags || true
		if rm -f /usr/share/fileflags/functions; then
			{
				sh fileflags/build-function.sh
				[ -n "$REAL_PERL" ] && printf '\nPERL5=%s\n' "$REAL_PERL"
			} > /usr/share/fileflags/functions
			chmod 644 /usr/share/fileflags/functions
		elif [ ! -f /usr/share/fileflags/functions ]; then
			echo "Failed to remove non-regular file /usr/share/fileflags/functions" 1>&2
			exit 1
		fi
		if [ -d /usr/share/bash-completion/completions ]; then
			cp fileflags/bash_completion.d/chflags /usr/share/bash-completion/completions/
			chmod 644 /usr/share/bash-completion/completions/chflags
		elif [ -d /etc/bash/bash_completion.d ]; then
			cp fileflags/bash_completion.d/chflags /etc/bash/bash_completion.d/
			chmod 644 /etc/bash/bash_completion.d/chflags
		else
			[ -d /etc/bash_completion.d ] || mkdir /etc/bash_completion.d
			cp fileflags/bash_completion.d/chflags /etc/bash_completion.d/
			chmod 644 /etc/bash_completion.d/chflags
		fi
		[ -n "$harden" ] && set_immutable /usr/share/fileflags/functions
	else
		echo "This Unix-shell-based chflags(1) implementation is available for Linux only, skip installing" 1>&2
	fi
fi

if [ -n "$remove_utempter" ]; then
	for f in /usr/local/libexec/utempter/utempter /usr/libexec/utempter/utempter /usr/lib/*/utempter/utempter /usr/lib/utempter/utempter; do
		[ ! -h "$f" ] && [ ! -f "$f" ] && continue
		if rm -f "$f" > "$f" || rm -f "$f"; then
			printf 'Removed %s\n' "$f" 1>&2
			mkdir "$f" && chmod 0 "$f" && set_immutable "$f"
		fi
	done
fi

if [ -n "$remove_cloud_init" ]; then
	for f in \
		/usr/bin/cloud-init* \
		/usr/share/doc/cloud-init \
		/usr/libexec/cloud-init \
		/usr/lib/cloud-init \
		/usr/lib/python*/site-packages/cloudinit \
		/usr/lib/python*/site-packages/cloud_init-* \
		/usr/lib/systemd/system/cloud-init* \
		/lib/systemd/system/cloud-config.* \
		/lib/systemd/system/cloud-final.service \
		/usr/lib/systemd/system-generators/cloud-init-generator \
		/lib/systemd/system-generators/cloud-init-generator \
		/etc/init.d/cloud-init* \
		/etc/init.d/cloud-config \
		/etc/init.d/cloud-final \
		/etc/rc*.d/*cloud-init* \
		/etc/rc*.d/*cloud-config \
		/etc/rc*.d/*cloud-final \
		/etc/systemd/system/cloud-init.target.wants \
		/etc/systemd/system/*.wants/cloud-init* \
		/etc/systemd/system/*.wants/cloud-config.service \
		/etc/systemd/system/*.wants/cloud-final.service \
		/usr/share/bash-completion/completions/cloud-init
	do case "$f" in
		*/lib/systemd/system/*.*|*/lib/systemd/system-generators/*-generator)
			[ -f "$f" ] || continue
			rm -f "$f"
			f="/etc/${f##*/lib/}"
			[ -d "${f%/*}" ] || mkdir -p "${f%/*}"
			ln -sf /dev/null "$f"
			;;
		/etc/rc*.d/*|*.wants/*)
			rm -f "$f"
			;;
		*)
			if [ -h "$f" ] || [ -f "$f" ]; then
				[ -h "$f" ] || [ -w "$f" ] || continue
				if rm -f "$f" > "$f" || rm -f "$f"; then
					printf "Removed '%s'\\n" "$f" 1>&2
					mkdir -m 0 "$f" && set_immutable "$f"
				fi
			elif [ -d "$f" ]; then
				[ -w "$f" ] || continue
				if rm -rf "$f"; then
					printf "Removed '%s'\\n" "$f" 1>&2
					chmod 0 "$f" > "$f" && set_immutable "$f"
				fi
			fi
			;;
	esac done
	systemctl disable --now cloud-init || true
	systemctl mask cloud-init || true
fi

if [ -n "$bind_protection" ]; then
	if [ "$KERNEL_NAME" = Linux ]; then
		[ -d /lib/init ] || mkdir -p /lib/init
		install_program bindfiles /lib/init/bindfiles
		enabled_bindfiles=
		if systemctl is-enabled --quiet basic.target > /dev/null 2>&1; then
			cat > /etc/systemd/system/bindfiles.service << EOF
[Unit]
Description=Bind mount important operating system files to protect them from being renamed or removed
Documentation=man:mount(8)
DefaultDependencies=off
Conflicts=shutdown.target
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/lib/init/bindfiles

[Install]
WantedBy=sysinit.target
EOF
		fi
		systemctl enable --now bindfiles || systemctl enable bindfiles && enabled_bindfiles=1
		if [ ! -h /etc/init.d ] && [ -d /etc/init.d ] && [ ! -h /etc/rcS.d ] && [ -d /etc/rcS.d ]; then
			cat > /etc/init.d/bindfiles << EOF
#!/bin/sh
### BEGIN INIT INFO
# Provides:		bindfiles
# Required-Start:	\$local_fs mountall
# Required-Stop:
# Default-Start:	S
# Default-Stop:
# Short-Description:	Bind protection
# Description:		Bind mount important operating system files to protect
#			them from being renamed or removed
### END INIT INFO


case "\$1" in
	start)
		exec /lib/init/bindfiles
		;;
	stop)
		# No-op
		;;
	restart|reload|force-reload)
		echo "Action \$1 not supported" 1>&2
		exit 3
		;;
	*)
		printf 'Usage: %s {start|stop}\\n' "\$0" 1>&2
		exit 3
		;;
esac
true
EOF
			chmod 755 /etc/init.d/bindfiles
			update-rc.d defaults bindfiles && enabled_bindfiles=1
		fi
		/lib/init/bindfiles || echo "/lib/init/bindfiles failed" 1>&2
		[ -z "$enabled_bindfiles" ] && echo "Please manually configure a service to start /lib/init/bindfiles on boot" 1>&2
	else
		echo "Bind protection is available for Linux only, skip installing" 1>&2
	fi
fi

set +e

should_reload_systemd=
for f in /etc/systemd/system/myservice.service /usr/lib/systemd/system/myservice.service /lib/systemd/system/myservice.service /etc/systemd/system/auto_script.service; do
	[ -h "$f" ] && continue
	[ -f "$f" ] || continue
	printf "Warning: Found suspicious systemd unit file '%s', removing\\n" "$f" 1>&2
	if rm -f "$f" > "$f" || rm -f "$f"; then
		mkdir -m 0 "$f" && set_immutable "$f"
		should_reload_systemd=1
	fi
done
[ -n "$should_reload_systemd" ] && systemctl daemon-reload

for f in "$HOME/.cfg" "$HOME/.ccfg" "$HOME/.md" /var/tmp/systemd-private-f7732edae7f9494cb9b8001dfdds81816-cups.service-Y4Kr3n /usr/bin/mslog /usr/bin/.ICE-unix /var/tmp/.ICE-unix; do
	[ -h "$f" ] && continue
	if [ -d "$f" ]; then
		printf "Warning: Found suspicious directory '%s'\\n" "$f" 1>&2
	elif [ -f "$f" ]; then
		# A regular file could already be created on the path by
		# install-dos-vvnnmm-proxy.sh from fuck-vvnnmm, to protect
		# the path from being reused
		set_immutable "$f"
	fi
done

for f in /usr/local/lib/libextrasshd.so /usr/local/lib/libprocesshider.so /usr/local/lib/libextradevac.so /usr/local/lib/libextrasshc.so /usr/local/lib/libsimplesshd.so /usr/bin/player /usr/bin/udeb /usr/bin/udebg "$HOME/rcu_tasked" "$HOME/rcu_shader"; do
	[ -h "$f" ] && continue
	if [ -f "$f" ]; then
		printf "Warning: Found suspicious regular file '%s'\\n" "$f" 1>&2
	elif [ -d "$f" ]; then
		# A directory could already be created on the path by
		# install-dos-vvnnmm-proxy.sh from fuck-vvnnmm, to protect
		# the path from being reused
		set_immutable "$f"
	fi
done

if [ -f /usr/bin/sshd ]; then
	if ! [ /usr/bin/sshd -ef /usr/sbin/sshd ] && [ "`dd if=/usr/bin/sshd bs=2 count=1 2> /dev/null`" = "#!" ]; then
		echo "Warning: Found suspicious regular file '/usr/bin/sshd', removing" 1>&2
		rm -f /usr/bin/sshd > /usr/bin/sshd || rm -f /usr/bin/sshd
		mkdir -m 0 /usr/bin/sshd && set_immutable /usr/bin/sshd
	fi
elif [ ! -h /usr/bin/sshd ] && [ -d /usr/bin/sshd ]; then 
	# A directory could already be created on the path by
	# install-dos-vvnnmm-proxy.sh from fuck-vvnnmm, to protect the path
	# from being reused
	set_immutable /usr/bin/sshd
fi

if [ -d /www/server/panel/plugin/clear ] || [ -f /www/server/panel/script/log_cleanup.py ]; then
	# Fuck BT clear plugin as it may remove important log files
	echo "Warning: Found directory for BT clear plugin" 1>&2
	for f in clear_main.py upgrade.sh repair.sh install.sh config.json /www/server/panel/script/log_cleanup.py; do
		[ "${f#/}" = "$f" ] && f="/www/server/panel/plugin/clear/$f"
		[ -h "$f" ] || [ -f "$f" ] || continue
		rm -f "$f"
		mkdir -m 0 "$f"
		set_immutable "$f"
	done
fi

mask_securetmp_files() {
	rm -f /usr/testDSK
	mkdir /usr/testDSK
	chmod 0 /usr/testDSK
	set_immutable /usr/testDSK 
	rm -rf /usr/tmp.secure
	chmod 0 /usr/tmp.secure > /usr/tmp.secure
	set_immutable /usr/tmp.secure
}

if [ -f /usr/tmpDSK ] && [ -s /usr/tmpDSK ]; then
	# Fuck cPanel securetmp
	echo "Warning: Found /usr/tmpDSK, truncating" 1>&2
	true > /usr/tmpDSK
	mask_securetmp_files
	if grep -q ^/usr/tmpDSK /etc/fstab; then
		rm -f /etc/fstab.new
		sed -E -e /tmpDSK/d -e '/^\/tmp[[:space:]]+\/var\/tmp/d' /etc/fstab > /etc/fstab.new && mv /etc/fstab.new /etc/fstab
	fi
	if grep -Eq "^(/usr/tmpDSK|/dev/loop[0-9]+) /tmp " /proc/mounts; then
		[ "${0#/tmp/}" != "$0" ] && rm -rf "${0%/setup.sh}"
		umount -l /tmp/
	fi
	systemctl is-enabled --quiet securetmp && systemctl disable --now securetmp
	if grep -q "^export TMPDIR=/var/spool/logrotate/tmp" /etc/cron.daily/logrotate; then
		rm -rf /etc/cron.daily/logrotate.new &&
			sed '/^export TMPDIR=\/var\/spool\/logrotate\//d' /etc/cron.daily/logrotate > /etc/cron.daily/logrotate.new &&
			mv /etc/cron.daily/logrotate.new /etc/cron.daily/logrotate &&
			set_immutable /etc/cron.daily/logrotate
		rm -rf /var/spool/logrotate
	fi
	if loop_device="`losetup --associated /usr/tmpDSK`" && [ -n "$loop_device" ]; then
		loop_device="${loop_device%%:*}"
		cat /dev/urandom > "$loop_device" &
		printf 'Trashing %s that associated with /usr/tmpDSK\n' "$loop_device" 1>&2
	fi
	set_immutable /usr/tmpDSK > /usr/tmpDSK
elif [ -n "$tmp_piao" ]; then
	mask_securetmp_files
	if set_immutable /usr/tmpDSK > /usr/tmpDSK && rm -f /usr/tmpDSK > /dev/null 2>&1; then
		echo "Warning: /usr/tmpDSK can be removed after being made immutable" 1>&2
	fi
fi

if [ "$replace_chattr" = 2 ] || { [ -n "$harden" ] && [ -n "$install_chflags" ] && [ "$KERNEL_NAME" = Linux ]; }; then
	rm -f /usr/bin/cattr
fi
