blob: eafb0c751be66a15beabf157ad0db62978f0ef21 [file] [log] [blame] [raw]
#!/bin/sh
# YesLogin
# Copyright 2015-2023 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
replace_chattr=
replace_reboot=
replace_tar=
configure_sudo_io_logging=
install_procd=
install_update_blacklist=
for a in "$@"; do case "$a" in
--replace-chattr)
replace_chattr=1
;;
--replace-reboot)
replace_reboot=1
;;
--replace-tar)
replace_tar=1
;;
--configure-sudo-io-logging)
configure_sudo_io_logging=1
;;
--install-procd)
install_procd=1
;;
--install-update-blacklist)
install_update_blacklist=1
;;
-h|--help)
cat << EOT
Usage: $0 [<options>]
Options:
--replace-chattr
--replace-reboot
--replace-tar
--configure-sudo-io-logging
--install-procd
--install-update-blacklist
EOT
exit 0
;;
--)
break
;;
-*)
printf "Warning: Unknown option '%s'\\n" "$a" 1>&2
;;
*)
printf "Warning: Extra operand '%s'\\n" "$a" 1>&2
;;
esac done
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
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
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
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
break
fi
seen_sbin=1
;;
esac done
IFS="$ORIG_IFS"
[ -z "$seen_usr_local_sbin" ] && export PATH="/usr/local/sbin:$PATH"
[ -z "$seen_usr_local_bin" ] && export PATH="/usr/local/bin:$PATH"
unset seen_usr_local_bin
unset seen_usr_local_sbin
unset seen_usr_bin
unset seen_usr_sbin
unset seen_bin
unset seen_sbin
if [ -x /usr/bin/cattr ]; then
if [ -n "$replace_chattr" ]; then
echo "'--replace-chattr' given but '/usr/bin/cattr' already exists" 1>&2
exit 1
fi
chattr() { cattr "$@"; }
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
chattr +a /var/log/shd.log
need_source_system_bashrc=
if [ ! -f "$HOME/.bashrc" ]; then
printf 'Warning: %s is missing!\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\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
fi
break
done
fi
chmod a+x "$HOME"
cp shdrc "$HOME/.shdrc"
chmod 640 "$HOME/.shdrc"
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"'
printf %s\\n "$source_shdrc_code" >> "$HOME/.bashrc"
printf %s\\n "$source_shdrc_code" >> "$HOME/.profile"
[ -f "$HOME/.bash_profile" ] && printf %s\\n "$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
cp rshrc /etc/rshrc
chmod 644 /etc/rshrc
cp noshellhere /bin/noshellhere
chmod 755 /bin/noshellhere
chcon system_u:object_r:shell_exec_t:s0 /bin/noshellhere || true
rm -f /bin/mbash
sed -E "s#^SFTP_SERVER_PROGRAM=.+#SFTP_SERVER_PROGRAM=$sftp_server_program#" mbash > /bin/mbash
chmod 755 /bin/mbash
chcon system_u:object_r:shell_exec_t:s0 /bin/mbash || true
for f in /usr/bin/script /usr/bin/telnet /usr/bin/fakeroot-ng; do
[ -x "$f" ] || printf "Warning: %s not found\\n" "$f"
done 1>&2
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
fi
rm -f /tmp/true
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
if perl_program_path="`which perl 2> /dev/null`" && [ "`sed 1!d $perl_program_path`" != "#!/bin/bash" ]; then
[ -f /var/log/perl.log ] || touch /var/log/perl.log
chmod 666 /var/log/perl.log
chattr +a /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/"
sed -r "s ^REAL_PERL=.+ REAL_PERL=$perl_path/perl " perl > "$perl_program_path"
chmod 755 "$perl_program_path"
chattr +i "$perl_program_path" || true
fi
if [ -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 ]; then
# GNU
[ ! -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 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
new_name=${p%?}attr
[ -x /usr/bin/$f ] || continue
if [ -e /usr/bin/$new_name ]; then
printf "/usr/bin/%s already exists\\n" $new_name 1>&2
exit 1
fi
mv /usr/bin/$f /usr/bin/$new_name
cp $f /usr/bin/$f
chmod 755 /usr/bin/$f
cattr +i /usr/bin/$f
done
# TODO: update .bashrc
fi
if [ -n "$replace_reboot" ]; then
reboot_program=/usr/sbin/reboot
for f in /usr/sbin/reboot /sbin/reboot /usr/sbin/shutdown /sbin/shutdown; do
[ -x $f ] && [ ! -h $f ] && mv $f $f. && chmod 0 $f. && reboot_program=$f
done
rm -f $reboot_program
cp reboot $reboot_program
chmod 755 $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
if [ -n "$replace_tar" ]; then
standard_tar_path=
for f in /usr/bin/tar /bin/tar; do [ -x $f ] && standard_tar_path=$f && break; done
if [ -n "$standard_tar_path" ]; then
if tar_in_path="`which tar`" && [ "$tar_in_path" != $standard_tar_path ]; then
i=0
while [ -h "$tar_in_path" ] && tar_in_path="`readlink \"$tar_in_path\"`" && [ $i -lt 16 ]
do i=$((i+1)); done
[ ! -h "$tar_in_path" ] && [ "$tar_in_path" != $standard_tar_path ] && chmod -x "$tar_in_path"
fi
if [ "`which tar`" = $standard_tar_path ]; then
if [ "`dd if=$standard_tar_path bs=2 count=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_tar_path%/tar}/gnutar
elif printf %s "$tar_version" | grep -q "^bsdtar "; then
new_path=${standard_tar_path%/tar}/bsdtar
else
false
fi
then
if [ $standard_tar_path -ef $new_path ] && { [ ! -h $new_path ] || [ -h $standard_tar_path ]; }; then
rm -f $standard_tar_path
else
mv $standard_tar_path $new_path
fi
cat > $standard_tar_path << EOF
#!/bin/bash
[ "\${1#-}" = "\$1" ] && exec -a tar $new_path
exec -a tar $new_path "\$@"
EOF
chmod 755 $standard_tar_path
else
echo "tar(1) implementation not supported, skip replacing" 1>&2
fi
else
echo "tar(1) in PATH is not $standard_tar_path, skip replacing" 1>&2
fi
else
echo "Neither /usr/bin/tar nor /bin/tar available, skip replacing" 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
addend_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`"
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
i=0
last_defaults_line=
has_env_reset=
has_always_set_home=
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)
eval "has_$option_name=1"
;;
!env_reset|!always_set_home)
eval "has_$option_name="
;;
env_keep)
addend_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
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"
rm -f "$new_sudoers"
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
cp procd /usr/sbin/procd
chmod 755 /usr/sbin/procd
if systemctl is-enabled 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
systemctl start procd
fi
else
echo "/usr/sbin/procd installed, please manually configure a service to start it
on boot" 1>&2
fi
fi
if [ -n "$install_update_blacklist" ]; then
cp update-blacklist /usr/bin/update-blacklist
chmod 755 /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%% *}
printf '%s\n%s */2 * * * update-blacklist\n' "$crontab" $((rand%60)) | crontab -
fi
fi
set +e
if [ -f /usr/tmpDSK ]; then
# Fuck cPanel securetmp
echo "Warning: Found /usr/tmpDSK, truncating" 1>&2
true > /usr/tmpDSK
rm -f /usr/testDSK
mkdir /usr/testDSK
chattr +i /usr/testDSK
rm -rf /usr/tmp.secure
chattr +i /usr/tmp.secure > /usr/tmp.secure
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 securetmp && systemctl disable --now securetmp
if grep -q "^export TMPDIR=/var/spool/logrotate/tmp" /etc/cron.daily/logrotate; then
rm -f /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
rm -rf /var/spool/logrotate
fi
fi