| #!/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 |