lintian FHS

This commit is contained in:
Patrick Schleizer 2021-08-03 12:52:10 -04:00
parent 6607c1e4bd
commit 4fadaad8c0
No known key found for this signature in database
GPG key ID: CB8D50BB77BB3C48
16 changed files with 0 additions and 0 deletions

View file

@ -1,32 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
sigterm_trap() {
if [ "$lastpid" = "" ]; then
exit 143
fi
ps -p "$lastpid" >/dev/null 2>&1
if [ ! "$?" = "0" ]; then
## Already terminated.
exit 143
fi
kill -s sigterm "$lastpid"
exit 143
}
trap "sigterm_trap" SIGTERM SIGINT
[ -n "$timeout_after" ] || timeout_after="600"
[ -n "$kill_after" ] || kill_after="10"
timeout \
--kill-after="$kill_after" \
"$timeout_after" \
apt-get update --error-on=any "$@" &
lastpid="$!"
wait "$lastpid"
exit "$?"

View file

@ -1,11 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
set -x
set -e
set -o pipefail
wc -L "/var/lib/apt/lists/"*InRelease
wc -L "/var/lib/apt/lists/"*InRelease | awk '$1 > 1024 {print; exit 1}'

View file

@ -1,10 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
set -e
title="$0: password required for $(whoami) to perform action as superuser"
zenity --password --title="$title"

View file

@ -1,8 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
set -e
echo "$PATH"

View file

@ -1,96 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
set -e
sysfs_whitelist=1
cpuinfo_whitelist=1
## https://www.whonix.org/wiki/Security-misc#selinux
selinux=1
shopt -s nullglob
## Allows for disabling the whitelist.
for i in /etc/hide-hardware-info.d/*.conf
do
bash -n "${i}"
source "${i}"
done
create_whitelist() {
if [ "${1}" = "sysfs" ]; then
whitelist_path="/sys"
elif [ "${1}" = "cpuinfo" ]; then
whitelist_path="/proc/cpuinfo"
else
echo "ERROR: ${1} is not a correct parameter."
exit 1
fi
if grep -q "${1}" /etc/group; then
## Changing the permissions of /sys recursively
## causes errors as the permissions of /sys/kernel/debug
## and /sys/fs/cgroup cannot be changed.
chgrp -fR "${1}" "${whitelist_path}" || true
chmod o-rwx "${whitelist_path}"
else
echo "ERROR: The ${1} group does not exist, the ${1} whitelist was not created."
fi
}
## sysfs and debugfs expose a lot of information
## that should not be accessible by an unprivileged
## user which includes hardware info, debug info and
## more. This restricts /sys, /proc/cpuinfo, /proc/bus
## and /proc/scsi to the root user only. This hides
## many hardware identifiers from ordinary users
## and increases security.
for i in /proc/cpuinfo /proc/bus /proc/scsi /sys
do
if [ -e "${i}" ]; then
if [ "${i}" = "/sys" ]; then
## Whitelist for /sys.
if [ "${sysfs_whitelist}" = "1" ]; then
create_whitelist sysfs
else
chmod og-rwx /sys
echo "INFO: The sysfs whitelist is not enabled. Some things may not work properly."
fi
elif [ "${i}" = "/proc/cpuinfo" ]; then
## Whitelist for /proc/cpuinfo.
if [ "${cpuinfo_whitelist}" = "1" ]; then
create_whitelist cpuinfo
else
chmod og-rwx /proc/cpuinfo
echo "INFO: The cpuinfo whitelist is not enabled. Some things may not work properly."
fi
else
chmod og-rwx "${i}"
fi
else
## /proc/scsi doesn't exist on Debian so errors
## are expected here.
if ! [ "${i}" = "/proc/scsi" ]; then
echo "ERROR: ${i} could not be found."
fi
fi
done
## https://www.whonix.org/wiki/Security-misc#selinux
##
## on SELinux systems, at least /sys/fs/selinux
## must be visible to unprivileged users, else
## SELinux userspace utilities will not function
## properly
if [ -d /sys/fs/selinux ]; then
if [ "${selinux}" = "1" ]; then
chmod o+rx /sys /sys/fs /sys/fs/selinux
echo "INFO: SELinux mode enabled. Restrictions loosened slightly in order to allow userspace utilities to function."
else
echo "INFO: SELinux detected, but SELinux mode is not enabled. Some userspace utilities may not work properly."
fi
fi

View file

@ -1,47 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## This is only a usability feature to avoid needlessly bumping pam_tally2
## counter. This is not a security feature.
## https://forums.whonix.org/t/restrict-root-access/7658/1
passwd_bin="$(type -P "passwd")"
if ! test -x "$passwd_bin" ; then
echo "\
$0: ERROR: passwd_bin \"$passwd_bin\" is not executable.
See https://www.whonix.org/wiki/SUID_Disabler_and_Permission_Hardener#passwd" >&2
## Identifiable exit codes in case stdout / stderr is not logged in journal.
exit 2
fi
if ! passwd_output="$("$passwd_bin" -S "$PAM_USER" 2>/dev/null)" ; then
echo "$0: ERROR: user \"$PAM_USER\" does not exist." >&2
exit 3
fi
if [ "$(echo "$passwd_output" | cut -d ' ' -f 2)" = "P" ]; then
true "INFO: Password not locked."
else
echo "$0: INFO: Password for user \"$PAM_USER\" is locked."
if [ -f /usr/share/whonix/marker ] || [ -f /usr/share/kicksecure/marker ]; then
if [ "$PAM_USER" = "root" ]; then
echo "$0: ERROR: root account is locked by default. See:" >&2
echo "https://www.whonix.org/wiki/root" >&2
echo "" >&2
exit 4
fi
fi
## Should not unconditionally 'exit 1' here.
## Locked user accounts might have valid sudoers exceptions.
## https://forums.whonix.org/t/pam-abort-on-locked-password-and-running-privileged-command-from-web-browser/10521
## 'exit 1' would be good for usability here because then the user would get
## faster feedback. A new login attempt would not be needlessly delayed.
exit 0
fi
exit 0

View file

@ -1,21 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## https://serverfault.com/questions/134471/success-n-control-syntax-in-pam-conf-pam-d-files
set -x
true "PAM_SERVICE: $PAM_SERVICE"
if [ "$PAM_SERVICE" = "login" ]; then
## FIXME:
## Creates unwanted journal log entry.
## pam_exec(login:account): /usr/lib/security-misc/pam_only_if_login failed: exit code 1
exit 1
else
## exit success so [success=1 default=ignore] will result in skipping the
## next pam module.
exit 0
fi

View file

@ -1,153 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
grep_result="$(grep "accessfile=/etc/security/access-security-misc.conf" /etc/pam.d/common-account 2>/dev/null)"
## Check if grep matched something.
if [ ! "$grep_result" = "" ]; then
## Yes, grep matched.
## Check if not out commented.
if ! echo "$grep_result" | grep -q "#" ; then
## Not out commented indeed.
## https://forums.whonix.org/t/etc-security-hardening-console-lockdown/8592
if id --name --groups --zero "$PAM_USER" | grep --quiet --null-data --line-regexp --fixed-strings "console"; then
console_allowed=true
fi
if id --name --groups --zero "$PAM_USER" | grep --quiet --null-data --line-regexp --fixed-strings "console-unrestricted"; then
console_allowed=true
fi
if [ ! "$console_allowed" = "true" ]; then
echo "$0: ERROR: PAM_USER: '$PAM_USER' is not a member of group 'console'" >&2
echo "$0: To unlock, run the following command as superuser:" >&2
echo "$0: (If you still have a sudo/root shell somewhere.)" >&2
echo "" >&2
echo "addgroup $PAM_USER console" >&2
echo "" >&2
echo "$0: However, possibly unlock procedure is required." >&2
echo "$0: First boot into recovery mode at grub boot menu and then run above command." >&2
echo "$0: See also:" >&2
echo "https://www.whonix.org/wiki/root#console" >&2
echo "" >&2
exit 0
fi
fi
fi
## https://forums.whonix.org/t/how-strong-do-linux-user-account-passwords-have-to-be-when-using-full-disk-encryption-fde-too/7698
if [ ! "$(id -u)" = "0" ]; then
## as user "user"
## /sbin/pam_tally2 -u user
## pam_tally2: Error opening /var/log/tallylog for update: Permission denied
## /sbin/pam_tally2: Authentication error
##
## xscreensaver runs as user "user", therefore pam_tally2 cannot function.
## xscreensaver has its own failed login counter.
##
## https://askubuntu.com/questions/983183/how-lock-the-unlock-screen-after-wrong-password-attempts
##
## https://www.whonix.org/pipermail/whonix-devel/2019-September/001439.html
true "$0: not started as root, exiting."
exit 0
fi
## Does not work (yet) for login, pam_securetty runs before and aborts.
## Also this should only run for login since securetty covers only login.
# if [ "$PAM_USER" = "root" ]; then
# if [ -f /etc/securetty ]; then
# grep_result="$(grep "^[^#]" /etc/securetty)"
# if [ "$grep_result" = "" ]; then
# echo "$0: ERROR: Root login is disabled." >&2
# echo "$0: ERROR: This is because /etc/securetty is empty." >&2
# echo "$0: See also:" >&2
# echo "https://www.whonix.org/wiki/root#login" >&2
# echo "" >&2
# exit 0
# fi
# fi
# fi
## Using || true to not break read-only disk boot without ro-mode-init or grub-live.
pam_tally2_output="$(pam_tally2 --user "$PAM_USER")" || true
if [ "$pam_tally2_output" = "" ]; then
true "$0: no failed login"
exit 0
fi
## Example:
#Login Failures Latest failure From
#user 0
pam_tally2_output_last_line="$(echo "$pam_tally2_output" | tail -1)"
## Example:
#user 0
arr=($pam_tally2_output_last_line)
user_name="${arr[0]}"
failed_login_counter="${arr[1]}"
if [ ! "$PAM_USER" = "$user_name" ]; then
echo "$0: ERROR: PAM_USER: '$PAM_USER' does not equal user_name: '$user_name'." >&2
echo "$0: ERROR: Please report this bug." >&2
echo "" >&2
exit 0
fi
if [ "$failed_login_counter" = "0" ]; then
true "$0: INFO: Failed login counter is 0, ok."
exit 0
fi
deny_line="$(cat /etc/pam.d/common-auth | grep deny=)"
## Example:
#auth requisite pam_tally2.so even_deny_root deny=50 onerr=fail audit debug
for word in $deny_line ; do
if echo "$word" | grep -q "deny=" ; then
deny="$(echo "$word" | cut -d "=" -f 2)"
break
fi
done
if [[ "$deny" == *[!0-9]* ]]; then
echo "$0: ERROR: deny is not numeric." >&2
echo "$0: ERROR: Please report this bug." >&2
echo "" >&2
exit 0
fi
remaining_attempts="$(( $deny - $failed_login_counter ))"
if [ "$remaining_attempts" -le "0" ]; then
echo "$0: ERROR: Login blocked after $failed_login_counter attempts." >&2
echo "$0: To unlock, run the following command as superuser:" >&2
echo "$0: (If you still have a sudo/root shell somewhere.)" >&2
echo "" >&2
echo "pam_tally2 --quiet -r --user $PAM_USER" >&2
echo "" >&2
echo "$0: However, most likely unlock procedure is required." >&2
echo "$0: First boot into recovery mode at grub boot menu and then run above command." >&2
echo "$0: See also:" >&2
echo "https://www.whonix.org/wiki/root#unlock" >&2
echo "" >&2
exit 0
fi
echo "$0: WARNING: $failed_login_counter failed login attempts." >&2
echo "$0: Login will be blocked after $deny attempts." >&2
echo "$0: You have $remaining_attempts more attempts before unlock procedure is required." >&2
echo "" >&2
if [ "$PAM_SERVICE" = "su" ]; then
echo "$0: NOTE: Type the password. When entering the password, no password feedback (no asterisk (\"*\") symbol) will be shown." >&2
echo "" >&2
fi
exit 0

View file

@ -1,42 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## https://serverfault.com/questions/134471/success-n-control-syntax-in-pam-conf-pam-d-files
set -x
true "PAM_SERVICE: $PAM_SERVICE"
## PAM configuration notes
##
## success=$num
## "will specify how many rules to skip when successful."
## https://serverfault.com/questions/134471/success-n-control-syntax-in-pam-conf-pam-d-files
##
## ignore
## "when used with a stack of modules, the module's return status will not contribute to the return code the application obtains."
## http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html
## - Failed dovecot logins should not result in account getting locked.
## - Failed SSH public key authentication attempts do not increase pam_tally2
## counter for some reason.
## This list can later be extended as needed.
pam_service_exclusion_list="dovecot"
for pam_service_exclusion_item in $pam_service_exclusion_list ; do
if [ "$PAM_SERVICE" = "$pam_service_exclusion_item" ]; then
## exit success so [success=1 default=ignore] will result in skipping the
## next PAM module (the pam_tally2 module).
exit 0
fi
done
## exit failure so [success=1 default=ignore] will result in running the
## next PAM module (the pam_tally2 module).
##
## Causes confusing error message:
## pam_exec(sudo:auth): /usr/lib/security-misc/pam_tally2_not_if_x failed: exit code 1
## https://github.com/linux-pam/linux-pam/issues/329
exit 1

View file

@ -1,18 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
set -e
if [ -f /usr/libexec/helper-scripts/pre.bsh ]; then
## pre.bsh would `source` the following folders:
## /etc/panic-on-oops_pre.d/*.conf
## /usr/local/etc/panic-on-oops_pre.d/*.conf
source /usr/libexec/helper-scripts/pre.bsh
fi
## Makes the kernel panic on oopses. This prevents the kernel
## from continuing to run a flawed processes. Many kernel exploits
## will also cause an oops which this will make the kernel kill.
sysctl kernel.panic_on_oops=1

View file

@ -1,478 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## https://forums.whonix.org/t/disable-suid-binaries/7706
## https://forums.whonix.org/t/re-mount-home-and-other-with-noexec-and-nosuid-among-other-useful-mount-options-for-better-security/7707
## To view previous modes and how these were changed:
## meld /var/lib/permission-hardening/existing_mode/statoverride /var/lib/permission-hardening/new_mode/statoverride
## To undo:
## sudo /usr/lib/security-misc/permission-hardening-undo
#set -x
set -e
set -o pipefail
exit_code=0
mkdir -p /var/lib/permission-hardening/existing_mode
mkdir -p /var/lib/permission-hardening/new_mode
dpkg_admindir_parameter_existing_mode="--admindir /var/lib/permission-hardening/existing_mode"
dpkg_admindir_parameter_new_mode="--admindir /var/lib/permission-hardening/new_mode"
echo_wrapper_ignore() {
echo "run: $@"
"$@" 2>/dev/null || true
}
echo_wrapper_silent_ignore() {
#echo "run: $@"
"$@" 2>/dev/null || true
}
echo_wrapper_audit() {
echo "run: $@"
return_code=0
"$@" || \
{ \
return_code="$?" ; \
exit_code=203 ; \
echo "ERROR: above command failed with exit code '$return_code'! calling function name: '${FUNCNAME[1]}'" >&2 ; \
};
}
echo_wrapper_silent_audit() {
#echo "run (debugging): $@"
return_code=0
"$@" || \
{ \
return_code="$?" ; \
exit_code=204 ; \
echo "ERROR: above command '$@' failed with exit code '$return_code'! calling function name: '${FUNCNAME[1]}'" >&2 ; \
};
}
sanity_tests() {
echo_wrapper_silent_audit which \
capsh getcap setcap stat find dpkg-statoverride getent xargs grep 1>/dev/null
}
add_nosuid_statoverride_entry() {
local fso_to_process
fso_to_process="$fso"
local should_be_counter
should_be_counter="$(find "$fso_to_process" -perm /u=s,g=s | wc -l)" || true
local counter_actual
counter_actual=0
local line
while read -r line; do
true "line: $line"
counter_actual="$(( counter_actual + 1 ))"
local arr file_name existing_mode existing_owner existing_group
arr=($line)
file_name="${arr[0]}"
existing_mode="${arr[1]}"
existing_owner="${arr[2]}"
existing_group="${arr[3]}"
if [ "$arr" = "" ]; then
echo "ERROR: arr is empty. line: '$line'" >&2
continue
fi
if [ "$file_name" = "" ]; then
echo "ERROR: file_name is empty. line: '$line'" >&2
continue
fi
if [ "$existing_mode" = "" ]; then
echo "ERROR: existing_mode is empty. line: '$line'" >&2
continue
fi
if [ "$existing_owner" = "" ]; then
echo "ERROR: existing_owner is empty. line: '$line'" >&2
continue
fi
if [ "$existing_group" = "" ]; then
echo "ERROR: existing_group is empty. line: '$line'" >&2
continue
fi
## -h file True if file is a symbolic Link.
## -u file True if file has its set-user-id bit set.
## -g file True if file has its set-group-id bit set.
if test -h "$file_name" ; then
## https://forums.whonix.org/t/disable-suid-binaries/7706/14
true "skip symlink: $file_name"
continue
fi
if test -d "$file_name" ; then
true "skip directory: $file_name"
continue
fi
local setuid setuid_output setsgid setsgid_output
setuid=""
setuid_output=""
if test -u "$file_name" ; then
setuid=true
setuid_output="set-user-id"
fi
setsgid=""
setsgid_output=""
if test -g "$file_name" ; then
setsgid=true
setsgid_output="set-group-id"
fi
local setuid_or_setsgid
setuid_or_setsgid=""
if [ "$setuid" = "true" ] || [ "$setsgid" = "true" ]; then
setuid_or_setsgid=true
fi
if [ "$setuid_or_setsgid" = "" ]; then
continue
fi
## Remove suid / gid and execute permission for 'group' and 'others'.
## Similar to: chmod og-ugx /path/to/filename
## Removing execution permission is useful to make binaries such as 'su' fail closed rather
## than fail open if suid was removed from these.
## Do not remove read access since no security benefit and easier to manually undo for users.
## Are there suid or sgid binaries which are still useful if suid / sgid has been removed from these?
new_mode="744"
local is_exact_whitelisted
is_exact_whitelisted=""
for white_list_entry in $exact_white_list ; do
if [ "$file_name" = "$white_list_entry" ]; then
is_exact_whitelisted="true"
## Stop looping through the whitelist.
break
fi
done
local is_match_whitelisted
is_match_whitelisted=""
for matchwhite_list_entry in $match_white_list ; do
if echo "$file_name" | grep -q "$matchwhite_list_entry" ; then
is_match_whitelisted="true"
## Stop looping through the match_white_list.
break
fi
done
local is_disable_whitelisted
is_disable_whitelisted=""
for disablematch_list_entry in $disable_white_list ; do
if echo "$file_name" | grep -q "$disablematch_list_entry" ; then
is_disable_whitelisted="true"
## Stop looping through the disablewhitelist.
break
fi
done
if [ "$whitelists_disable_all" = "true" ]; then
true "INFO: whitelists_disable_all=true - $setuid_output $setsgid_output found - file_name: '$file_name' | existing_mode: '$existing_mode'"
elif [ "$is_disable_whitelisted" = "true" ]; then
echo "INFO: white list disabled - $setuid_output $setsgid_output found - file_name: '$file_name' | existing_mode: '$existing_mode'"
else
if [ "$is_exact_whitelisted" = "true" ]; then
echo "INFO: SKIP whitelisted - $setuid_output $setsgid_output found - file_name: '$file_name' | existing_mode: '$existing_mode'"
continue
fi
if [ "$is_match_whitelisted" = "true" ]; then
echo "INFO: SKIP matchwhitelisted - $setuid_output $setsgid_output found - file_name: '$file_name' | existing_mode: '$existing_mode' | matchwhite_list_entry: '$matchwhite_list_entry'"
continue
fi
fi
echo "INFO: $setuid_output $setsgid_output found - file_name: '$file_name' | existing_mode: '$existing_mode' | new_mode: '$new_mode'"
if dpkg-statoverride $dpkg_admindir_parameter_existing_mode --list "$file_name" >/dev/null ; then
true "OK Existing mode already saved previously. No need to save again."
else
## Save existing_mode in separate database.
## Not using --update as not intending to enforce existing_mode.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_existing_mode --add "$existing_owner" "$existing_group" "$existing_mode" "$file_name"
fi
## No need to check "dpkg-statoverride --list" for existing entries.
## If existing_mode was correct already, we would not have reached this point.
## Since existing_mode is incorrect, remove from dpkg-statoverride and re-add.
## Remove from real database.
echo_wrapper_silent_ignore dpkg-statoverride --remove "$file_name"
## Remove from separate database.
echo_wrapper_silent_ignore dpkg-statoverride $dpkg_admindir_parameter_new_mode --remove "$file_name"
## Add to real database and use --update to make changes on disk.
echo_wrapper_audit dpkg-statoverride --add --update "$existing_owner" "$existing_group" "$new_mode" "$file_name"
## Not using --update as this is only for recording.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_new_mode --add "$existing_owner" "$existing_group" "$new_mode" "$file_name"
## /lib will hit ARG_MAX if using bash 'shopt -s globstar' and '/lib/**'.
## Using 'find' with '-perm /u=s,g=s' is faster and avoids ARG_MAX.
## https://forums.whonix.org/t/disable-suid-binaries/7706/17
done < <( find "$fso_to_process" -perm /u=s,g=s -print0 | xargs -I{} -0 stat -c "%n %a %U %G" {} )
## Sanity test.
if [ ! "$should_be_counter" = "$counter_actual" ]; then
echo "INFO: fso_to_process: '$fso_to_process' | counter_actual : '$counter_actual'"
echo "INFO: fso_to_process: '$fso_to_process' | should_be_counter: '$should_be_counter'"
exit_code=202
echo "ERROR: counter does not check out." >&2
fi
}
set_file_perms() {
echo "INFO: START parsing config_file: '$config_file'"
local line
while read -r line; do
if [ "$line" = "" ]; then
continue
fi
if [[ "$line" =~ ^# ]]; then
continue
fi
if [[ "$line" =~ [0-9a-zA-Z/] ]]; then
true "OK line contains only white listed characters."
else
exit_code=200
echo "ERROR: cannot parse line with invalid character. line: '$line'" >&2
## Safer to exit with error in this case.
## https://forums.whonix.org/t/disable-suid-binaries/7706/59
exit "$exit_code"
fi
if [ "$line" = 'whitelists_disable_all=true' ]; then
whitelists_disable_all=true
echo "INFO: whitelists_disable_all=true - all whitelists disabled."
continue
fi
#global fso
local mode_from_config owner_from_config group_from_config capability_from_config
if ! read -r fso mode_from_config owner_from_config group_from_config capability_from_config <<< "$line" ; then
exit_code=201
echo "ERROR: cannot parse. line: '$line'" >&2
## Debugging.
du -hs /tmp || true
echo "test -w /tmp: '$(test -w /tmp)'" >&2 || true
## Safer to exit with error in this case.
## https://forums.whonix.org/t/disable-suid-binaries/7706/59
exit "$exit_code"
fi
local fso_without_trailing_slash
fso_without_trailing_slash="${fso%/}"
if [ "$mode_from_config" = "disablewhitelist" ]; then
## TODO: test/add white spaces inside file name support
disable_white_list+="$fso "
continue
fi
if [ "$mode_from_config" = "exactwhitelist" ]; then
## TODO: test/add white spaces inside file name support
exact_white_list+="$fso "
continue
fi
if [ "$mode_from_config" = "matchwhitelist" ]; then
## TODO: test/add white spaces inside file name support
match_white_list+="$fso "
continue
fi
if [ ! -e "$fso" ]; then
echo "INFO: fso: '$fso' - does not exist. This is likely normal."
continue
fi
## Use dpkg-statoverride so permissions are not reset during upgrades.
if [ "$mode_from_config" = "nosuid" ]; then
## If mode_from_config is "nosuid" the config does not set owner and
## group. Therefore do not enforce owner/group check.
add_nosuid_statoverride_entry
else
local string_length_of_mode_from_config
string_length_of_mode_from_config="${#mode_from_config}"
if [ "$string_length_of_mode_from_config" -gt "4" ]; then
echo "ERROR: Mode '$mode_from_config' is invalid!" >&2
continue
fi
if [ "$string_length_of_mode_from_config" -lt "3" ]; then
echo "ERROR: Mode '$mode_from_config' is invalid!" >&2
continue
fi
if ! getent passwd | grep -q "^${owner_from_config}:" ; then
echo "ERROR: owner_from_config '$owner_from_config' does not exist!" >&2
continue
fi
if ! getent group | grep -q "^${group_from_config}:" ; then
echo "ERROR: group_from_config '$group_from_config' does not exist!" >&2
continue
fi
local mode_for_grep
mode_for_grep="$mode_from_config"
first_character_of_mode_from_config="${mode_from_config::1}"
if [ "$first_character_of_mode_from_config" = "0" ]; then
## Remove leading '0'.
mode_for_grep="${mode_from_config:1}"
fi
local stat_output
stat_output=""
if ! stat_output="$(stat -c "%n %a %U %G" "$fso_without_trailing_slash")" ; then
echo "ERROR: failed to run 'stat' for fso_without_trailing_slash: '$fso_without_trailing_slash'!" >&2
continue
fi
local arr file_name existing_mode existing_owner existing_group
arr=($stat_output)
file_name="${arr[0]}"
existing_mode="${arr[1]}"
existing_owner="${arr[2]}"
existing_group="${arr[3]}"
if [ "$arr" = "" ]; then
echo "ERROR: arr is empty. stat_output: '$stat_output' | line: '$line'" >&2
continue
fi
if [ "$file_name" = "" ]; then
echo "ERROR: file_name is empty. stat_output: '$stat_output' | line: '$line'" >&2
continue
fi
if [ "$existing_mode" = "" ]; then
echo "ERROR: existing_mode is empty. stat_output: '$stat_output' | line: '$line'" >&2
continue
fi
if [ "$existing_owner" = "" ]; then
echo "ERROR: existing_owner is empty. stat_output: '$stat_output' | line: '$line'" >&2
continue
fi
if [ "$existing_group" = "" ]; then
echo "ERROR: $existing_group is empty. stat_output: '$stat_output' | line: '$line'" >&2
continue
fi
## Check there is an entry for the fso.
##
## example: dpkg-statoverride --list | grep /home
## output:
## root root 755 /home
##
## dpkg-statoverride does not show leading '0'.
local dpkg_statoverride_list_output=""
local dpkg_statoverride_list_exit_code=0
dpkg_statoverride_list_output="$(dpkg-statoverride --list "$fso_without_trailing_slash")" || { dpkg_statoverride_list_exit_code=$? ; true; };
if [ "$dpkg_statoverride_list_exit_code" = "0" ]; then
true "There is an fso entry. Check if owner/group/mode match."
local grep_line
grep_line="$owner_from_config $group_from_config $mode_for_grep $fso_without_trailing_slash"
if echo "$dpkg_statoverride_list_output" | grep -q "$grep_line" ; then
true "OK The owner/group/mode matches. No further action required."
else
true "The owner/group/mode do not match, therefore remove and re-add the entry to update it."
## fso_without_trailing_slash instead of fso to prevent
## "dpkg-statoverride: warning: stripping trailing /"
if dpkg-statoverride $dpkg_admindir_parameter_existing_mode --list "$fso_without_trailing_slash" >/dev/null ; then
true "OK Existing mode already saved previously. No need to save again."
else
## Save existing_mode in separate database.
## Not using --update as not intending to enforce existing_mode.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_existing_mode --add "$existing_owner" "$existing_group" "$existing_mode" "$fso_without_trailing_slash"
fi
echo_wrapper_silent_ignore dpkg-statoverride $dpkg_admindir_parameter_new_mode --remove "$fso_without_trailing_slash"
## Remove from and add to real database.
echo_wrapper_silent_ignore dpkg-statoverride --remove "$fso_without_trailing_slash"
echo_wrapper_audit dpkg-statoverride --add --update "$owner_from_config" "$group_from_config" "$mode_from_config" "$fso_without_trailing_slash"
## Save in separate database.
## Not using --update as this is only for saving.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_new_mode --add "$owner_from_config" "$group_from_config" "$mode_from_config" "$fso_without_trailing_slash"
fi
else
true "There is no fso entry. Therefore add one."
if dpkg-statoverride $dpkg_admindir_parameter_existing_mode --list "$fso_without_trailing_slash" >/dev/null ; then
true "OK Existing mode already saved previously. No need to save again."
else
## Save existing_mode in separate database.
## Not using --update as not intending to enforce existing_mode.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_existing_mode --add "$existing_owner" "$existing_group" "$existing_mode" "$fso_without_trailing_slash"
fi
## Add to real database.
echo_wrapper_audit dpkg-statoverride --add --update "$owner_from_config" "$group_from_config" "$mode_from_config" "$fso_without_trailing_slash"
## Save in separate database.
## Not using --update as this is only for saving.
echo_wrapper_silent_audit dpkg-statoverride $dpkg_admindir_parameter_new_mode --add "$owner_from_config" "$group_from_config" "$mode_from_config" "$fso_without_trailing_slash"
fi
fi
if [ "$capability_from_config" = "" ]; then
continue
fi
if [ "$capability_from_config" = "none" ]; then
## https://forums.whonix.org/t/disable-suid-binaries/7706/45
# sudo setcap -r /bin/ping 2>/dev/null
# Failed to set capabilities on file `/bin/ping' (No data available)
# The value of the capability argument is not permitted for a file. Or the file is not a regular (non-symlink) file
## Therefore use echo_wrapper_ignore.
echo_wrapper_ignore setcap -r "$fso"
getcap_output="$(getcap "$fso")"
if [ ! "$getcap_output" = "" ]; then
exit_code=205
echo "ERROR: removing capabilities for fso '$fso' failed!" >&2
continue
fi
else
if ! capsh --print | grep "Bounding set" | grep -q "$capability_from_config" ; then
echo "ERROR: capability_from_config '$capability_from_config' does not exist!" >&2
continue
fi
## feature request: dpkg-statoverride: support for capabilities
## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=502580
echo_wrapper_audit setcap "${capability_from_config}+ep" "$fso"
fi
done < "$config_file"
echo "INFO: END parsing config_file: '$config_file'"
}
parse_config_folder() {
shopt -s nullglob
for config_file in /etc/permission-hardening.d/*.conf /usr/local/etc/permission-hardening.d/*.conf; do
set_file_perms
done
}
sanity_tests
parse_config_folder
if [ ! "$exit_code" = "0" ]; then
echo "ERROR: Will exit with non-zero exit code: '$exit_code'" >&2
fi
exit "$exit_code"

View file

@ -1,136 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
#set -x
set -e
set -o pipefail
if [ "$1" = "all" ]; then
remove_file="all"
elif [ ! "$1" = "" ]; then
remove_file="$1"
else
echo "ERROR: need to give parameter 'all' or a filename.
examples:
$0 all
$0 /usr/bin/newgrp
" >&2
fi
exit_code=0
dpkg_admindir_parameter_existing_mode="--admindir /var/lib/permission-hardening/existing_mode"
dpkg_admindir_parameter_new_mode="--admindir /var/lib/permission-hardening/new_mode"
undo_permission_hardening() {
if [ ! -f /var/lib/permission-hardening/existing_mode/statoverride ]; then
return 0
fi
local line
while read -r line; do
## example line:
## root root 4755 /usr/lib/eject/dmcrypt-get-device
local owner group mode file_name
if ! read -r owner group mode file_name <<< "$line" ; then
exit_code=201
echo "ERROR: cannot parse line: $line" >&2
continue
fi
true "owner: '$owner' group: '$group' mode: '$mode' file_name: '$file_name'"
if [ "$remove_file" = "all" ]; then
do_proceed=true
verbose_maybe=""
else
if [ "$remove_file" = "$file_name" ]; then
do_proceed=true
verbose_maybe="--verbose"
remove_one=true
else
do_proceed=false
verbose_maybe=""
fi
fi
if [ "$do_proceed" = "false" ]; then
continue
fi
if [ "$remove_one" = "true" ]; then
set -x
fi
if test -e "$file_name" ; then
chown $verbose_maybe "${owner}:${group}" "$file_name" || exit_code=202
## chmod need to be run after chown since chown removes suid.
## https://unix.stackexchange.com/questions/53665/chown-removes-setuid-bit-bug-or-feature
chmod $verbose_maybe "$mode" "$file_name" || exit_code=203
else
echo "INFO: file_name: '$file_name' - does not exist. This is likely normal."
fi
dpkg-statoverride --remove "$file_name" &>/dev/null || true
dpkg-statoverride $dpkg_admindir_parameter_existing_mode --remove "$file_name" &>/dev/null || true
dpkg-statoverride $dpkg_admindir_parameter_new_mode --remove "$file_name" &>/dev/null || true
if [ "$remove_one" = "true" ]; then
set +x
break
fi
done < "/var/lib/permission-hardening/existing_mode/statoverride"
}
undo_permission_hardening
if [ ! "$remove_file" = "all" ]; then
if [ ! "$remove_one" = "true" ]; then
echo "INFO: none removed.
File '$remove_file' has not removed from SUID Disabler and Permission Hardener during this invocation of this program.
Note: This is expected if already done earlier.
Note: This program expects the full path to the file. Example:
$0 /usr/bin/newgrp
The following syntax will not work:
$0 program-name
The following example will not work:
$0 newgrp
To remove all:
$0 all
This change might not be permanent (because of the permission-hardening.service systemd unit). For full instructions, see:
https://www.whonix.org/wiki/SUID_Disabler_and_Permission_Hardener
To view list of changed by SUID Disabler and Permission Hardener:
https://www.whonix.org/wiki/SUID_Disabler_and_Permission_Hardener#View_List_of_Permissions_Changed_by_SUID_Disabler_and_Permission_Hardener
For re-enabling any specific SUID binary:
https://www.whonix.org/wiki/SUID_Disabler_and_Permission_Hardener#Re-Enable_Specific_SUID_Binaries
For completely disabling SUID Disabler and Permission Hardener:
https://www.whonix.org/wiki/SUID_Disabler_and_Permission_Hardener#Disable_SUID_Disabler_and_Permission_Hardener"
fi
fi
if [ ! "$exit_code" = "0" ]; then
echo "ERROR: Will exit with non-zero exit code: '$exit_code'" >&2
fi
exit "$exit_code"

View file

@ -1,68 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## Doing this for all users would create many issues.
# /usr/lib/security-misc/permission-lockdown: user: root | chmod o-rwx "/root"
# /usr/lib/security-misc/permission-lockdown: user: daemon | chmod o-rwx "/usr/sbin"
# /usr/lib/security-misc/permission-lockdown: user: bin | chmod o-rwx "/bin"
# /usr/lib/security-misc/permission-lockdown: user: sys | chmod o-rwx "/dev"
# /usr/lib/security-misc/permission-lockdown: user: sync | chmod o-rwx "/bin"
# /usr/lib/security-misc/permission-lockdown: user: games | chmod o-rwx "/usr/games"
# /usr/lib/security-misc/permission-lockdown: user: man | chmod o-rwx "/var/cache/man"
# /usr/lib/security-misc/permission-lockdown: user: mail | chmod o-rwx "/var/mail"
# /usr/lib/security-misc/permission-lockdown: user: proxy | chmod o-rwx "/bin"
# /usr/lib/security-misc/permission-lockdown: user: backup | chmod o-rwx "/var/backups"
# /usr/lib/security-misc/permission-lockdown: user: systemd-timesync | chmod o-rwx "/run/systemd"
# /usr/lib/security-misc/permission-lockdown: user: systemd-network | chmod o-rwx "/run/systemd/netif"
# /usr/lib/security-misc/permission-lockdown: user: messagebus | chmod o-rwx "/var/run/dbus"
# /usr/lib/security-misc/permission-lockdown: user: tinyproxy | chmod o-rwx "/run/tinyproxy"
# /usr/lib/security-misc/permission-lockdown: user: rtkit | chmod o-rwx "/proc"
# /usr/lib/security-misc/permission-lockdown: user: colord | chmod o-rwx "/var/lib/colord"
# /usr/lib/security-misc/permission-lockdown: user: Debian-exim | chmod o-rwx "/var/spool/exim4"
# /usr/lib/security-misc/permission-lockdown: user: debian-tor | chmod o-rwx "/var/lib/tor"
# /usr/lib/security-misc/permission-lockdown: user: stunnel4 | chmod o-rwx "/var/run/stunnel4"
# /usr/lib/security-misc/permission-lockdown: user: iodine | chmod o-rwx "/var/run/iodine"
# /usr/lib/security-misc/permission-lockdown: user: apt-cacher-ng | chmod o-rwx "/var/cache/apt-cacher-ng"
# /usr/lib/security-misc/permission-lockdown: user: statd | chmod o-rwx "/var/lib/nfs"
# /usr/lib/security-misc/permission-lockdown: user: timidity | chmod o-rwx "/etc/timidity"
# /usr/lib/security-misc/permission-lockdown: user: uuidd | chmod o-rwx "/run/uuidd"
# /usr/lib/security-misc/permission-lockdown: user: _rpc | chmod o-rwx "/run/rpcbind"
# /usr/lib/security-misc/permission-lockdown: user: geoclue | chmod o-rwx "/var/lib/geoclue"
home_folder_access_rights_lockdown() {
shopt -s nullglob
## Not using dotglob.
## touch /var/cache/security-misc/state-files//home/.Trash
## touch: cannot touch '/var/cache/security-misc/state-files//home/.Trash': No such file or directory
local folder_name base_name
for folder_name in /home/* ; do
base_name="$(basename "$folder_name")"
if [ -f "/var/cache/security-misc/state-files/$base_name" ]; then
continue
fi
if [ ! -d "$folder_name" ]; then
continue
fi
if [ "$folder_name" = "/home/" ]; then
continue
fi
mkdir -p /var/cache/security-misc/state-files
echo "$0: chmod o-rwx \"$folder_name\""
chmod o-rwx "$folder_name"
## Create a state-file so we do this only once.
## Therefore a user who will manually undo this, will not get
## annoyed by this being done over and over again.
touch "/var/cache/security-misc/state-files/$base_name"
done
shopt -u nullglob
}
home_folder_access_rights_lockdown
exit 0

View file

@ -1,130 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## noexec in /tmp and/or /home can break some malware but also legitimate
## applications.
## https://forums.whonix.org/t/re-mount-home-and-other-with-noexec-and-nosuid-among-other-useful-mount-options-for-better-security/7707
set -x
set -e
if [ -f /usr/libexec/helper-scripts/pre.bsh ]; then
## pre.bsh would `source` the following folders:
## /etc/remount-secure_pre.d/*.conf
## /usr/local/etc/remount-secure_pre.d/*.conf
source /usr/libexec/helper-scripts/pre.bsh
fi
if [ -e /etc/remount-disable ] || [ -e /usr/local/etc/remount-disable ]; then
echo "INFO: file /etc/remount-disable exists. Doing nothing."
exit 0
fi
if [ -e /etc/exec ] || [ -e /usr/local/etc/exec ]; then
noexec=false
echo "INFO: Will remount with exec because file /etc/exec or /usr/local/etc/exec exists."
else
if [ -e /etc/noexec ] || [ -e /usr/local/etc/noexec ]; then
noexec=true
echo "INFO: Will remount with noexec because file /etc/noexec or /usr/local/etc/noexec exists."
else
echo "INFO: Will not remount with noexec because file /etc/noexec or /usr/local/etc/noexec does not exist."
fi
fi
mkdir --parents "/var/run/remount-secure"
if [ "$noexec" = "true" ]; then
noexec_maybe=",noexec"
fi
exit_code=0
mount_output="$(mount)"
remount_secure() {
## ${FUNCNAME[1]} is the name of the calling function. I.e. the function
## which called this function.
status_file_name="${FUNCNAME[1]}"
## example status_file_name:
## _home
status_file_full_path="/var/run/remount-secure/${status_file_name}"
## example status_file_full_path:
## /var/run/remount-secure/_home
## str_replace is provided by package helper-scripts.
mount_folder="$(echo "${status_file_name}" | str_replace "_" "/")"
## example mount_folder:
## /home
mount_line_of_mount_folder="$(echo "$mount_output" | grep "$mount_folder ")" || true
if echo "$mount_line_of_mount_folder" | grep -q "$new_mount_options" ; then
echo "INFO: $mount_folder has already intended mount options."
return 0
fi
if [ -e "$status_file_full_path" ]; then
echo "INFO: $mount_folder already remounted earlier. Not remounting again."
return 0
fi
## BUG: echo: write error: Broken pipe
if echo "$mount_output" | grep -q "$mount_folder " ; then
## Already mounted. Using remount.
echo mount -o "remount,${new_mount_options}" "$mount_folder"
mount -o "remount,${new_mount_options}" "$mount_folder" || exit_code=100
else
## Not yet mounted. Using mount bind.
echo mount -o "$new_mount_options" --bind "$mount_folder" "$mount_folder"
mount -o "$new_mount_options" --bind "$mount_folder" "$mount_folder" || exit_code=101
fi
touch "$status_file_full_path"
}
_home() {
new_mount_options="nosuid,nodev${noexec_maybe}"
remount_secure "$@"
}
_run() {
## https://lists.freedesktop.org/archives/systemd-devel/2015-February/028456.html
new_mount_options="nosuid,nodev${noexec_maybe}"
remount_secure "$@"
}
_dev_shm() {
new_mount_options="nosuid,nodev${noexec_maybe}"
remount_secure "$@"
}
_tmp() {
new_mount_options="nosuid,nodev${noexec_maybe}"
remount_secure "$@"
}
## https://forums.whonix.org/t/re-mount-home-and-other-with-noexec-and-nosuid-among-other-useful-mount-options-for-better-security/7707/25
# _lib() {
# ## Not using noexec on /lib.
# new_mount_options="nosuid,nodev"
# remount_secure "$@"
# }
end() {
exit $exit_code
}
main() {
_home "$@"
_run "$@"
_dev_shm "$@"
_tmp "$@"
#_lib "$@"
end "$@"
}
main "$@"

View file

@ -1,37 +0,0 @@
#!/bin/bash
## Copyright (C) 2012 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
if [ -f /usr/libexec/helper-scripts/pre.bsh ]; then
## pre.bsh would `source` the following folders:
## /etc/remove-system.map_pre.d/*.conf
## /usr/local/etc/remove-system.map_pre.d/*.conf
source /usr/libexec/helper-scripts/pre.bsh
fi
shopt -s nullglob
system_map_location="/boot/System.map* /usr/src/*/System.map* /lib/modules/*/*/System.map* /System.map*"
counter=0
for filename in ${system_map_location} ; do
counter=$(( counter + 1 ))
done
if [ "$counter" -ge "1" ]; then
echo "Deleting system.map files..."
fi
## Removes the System.map files as they are only used for debugging or malware.
for filename in ${system_map_location} ; do
if [ -f "${filename}" ]; then
## 'shred' with '--verbose' is too chatty. (7 lines)
shred --force --zero -u "${filename}"
echo "removed '${filename}'"
fi
done
if [ "$counter" -ge "1" ]; then
echo "Done. Success."
fi

View file

@ -1,354 +0,0 @@
#!/bin/bash
## Copyright (C) 2019 - 2021 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.
## VirusForget is inspired by Christopher Laprise.
## tasket@protonmail.com
## https://github.com/tasket
## https://www.patreon.com/tasket/creators
## Because of his work on Qubes-VM-Hardening.
## https://github.com/tasket/Qubes-VM-hardening
#set -x
set -e
error_handler() {
## TODO
exit 1
}
trap error_handler ERR
root_check() {
if [ "$(id -u)" != "0" ]; then
echo "ERROR: must be run as root! sudo $0"
exit 1
fi
}
parse_cmd_options() {
## Thanks to:
## http://mywiki.wooledge.org/BashFAQ/035
while :
do
case $1 in
--user)
user_name="$2"
if [ "$user_name" = "" ]; then
echo "ERROR: --user needs username as argument!" >&2
shift
exit 1
else
shift 2
fi
;;
--simulate)
test_mode="true"
shift
;;
--unittest)
unit_test="true"
shift
;;
--commit)
commit="true"
shift
;;
--clean)
clean="true"
shift
;;
--check)
check="true"
shift
;;
--)
shift
break
;;
-*)
echo "ERROR: unknown option: $1" >&2
exit 1
;;
*)
break
;;
esac
done
## If there are input files (for example) that follow the options, they
## will remain in the "$@" positional parameters.
if [ "$user_name" = "" ]; then
echo "ERROR: must set --user username" >&2
exit 1
fi
}
variables() {
chfiles+=" .bashrc "
chfiles+=" .bash_profile "
chfiles+=" .bash_login "
chfiles+=" .bash_logout "
chfiles+=" .profile "
chfiles+=" .pam_environment "
chfiles+=" .xprofile "
chfiles+=" .xinitrc "
chfiles+=" .xserverrc "
chfiles+=" .Xsession "
chfiles+=" .xsession "
chfiles+=" .xsessionrc "
chfiles+=" .virusforgetunitestone "
chfiles+=" .virusforgetunitesttwo "
chdirs+=" bin "
chdirs+=" .local/bin "
chdirs+=" .config/autostart "
chdirs+=" .config/plasma-workspace/env "
chdirs+=" .config/plasma-workspace/shutdown "
chdirs+=" .config/autostart-scripts "
chdirs+=" .config/systemd "
## TODO
privdirs+=" /rw/config "
privdirs+=" /rw/usrlocal "
privdirs+=" /rw/bind-dirs "
backup_folder="/home/virusforget/backup"
dangerous_folder="/home/virusforget/dangerous"
}
init() {
adduser --home /home/virusforget --quiet --system --group virusforget
home_folder="/home/$user_name"
}
process_file_system_objects() {
if [ "$store" = "true" ]; then
if [ "$test_mode" = "true" ]; then
echo Simulate: rm -r -f "$backup_folder"
else
rm -r -f "$backup_folder"
fi
fi
if [ "$test_mode" = "true" ]; then
true
else
mkdir -p "$backup_folder"
fi
process_files
process_folders
}
process_files() {
for file_name in $chfiles ; do
full_path_original="$home_folder/$file_name"
full_path_original_dirname="${full_path_original%/*}"
full_path_backup="$backup_folder/$file_name"
full_path_dangerous="$dangerous_folder/$file_name"
full_path_dangerous_dirname="${full_path_dangerous%/*}"
if [ "$store" = "true" ]; then
if [ -e "$full_path_original" ]; then
if [ "$test_mode" = "true" ]; then
echo Simulate: cp --no-dereference --archive "$full_path_original" "$backup_folder/"
else
cp --no-dereference --archive "$full_path_original" "$backup_folder/"
fi
fi
else
check_file_walker
fi
done
}
process_folders() {
for folder_name in $chdirs ; do
full_folder_name="$home_folder/$folder_name"
if [ -e "$full_folder_name" ]; then
find "$full_folder_name" -print0 | \
while IFS= read -r -d '' line; do
true "line: $line"
if [ "$full_folder_name" = "$line" ]; then
continue
fi
full_path_original="$line"
full_path_original_dirname="${full_path_original%/*}"
## remove prepeneded $home_folder from $full_path_original
temp_one="$home_folder/"
temp="${full_path_original/#$temp_one/""}"
full_path_backup="$backup_folder/$temp"
full_path_backup_dirname="${full_path_backup%/*}"
full_path_dangerous="$dangerous_folder/$temp"
full_path_dangerous_dirname="${full_path_dangerous%/*}"
if [ "$store" = "true" ]; then
if [ -d "$full_path_original" ]; then
true "ok"
else
## Not needed since starting with new backup folder anyhow.
#if [ -e "$full_path_backup" ]; then
# echo chattr -i "$full_path_backup"
# echo rm "$full_path_backup"
#fi
if [ "$test_mode" = "true" ]; then
echo Simulate: cp --no-dereference --archive "$full_path_original" "$full_path_backup_dirname/"
else
mkdir -p "$full_path_backup_dirname"
cp --no-dereference --archive "$full_path_original" "$full_path_backup_dirname/"
fi
fi
else
check_file_walker
fi
done
fi
done
}
check_file_walker() {
if [ -e "$full_path_backup" ]; then
if [ -e "$full_path_original" ]; then
if [ -d "$full_path_original" ]; then
## REVIEW: ok to skip directory?
true
return 0
fi
if diff "$full_path_original" "$full_path_backup" &>/dev/null ; then
true "OK"
else
echo "Difference detected! changed file: $full_path_original backup: $full_path_backup" >&2
unexpected_file "$full_path_original"
fi
else
echo "Missing file detected! missing: $full_path_original" >&2
restore_file
fi
else
if [ -e "$full_path_original" ]; then
if [ -d "$full_path_original" ]; then
## REVIEW: ignore ok?
true
return 0
fi
echo "Extraneous file! $full_path_original" >&2
unexpected_file "$full_path_original"
else
true "OK"
fi
fi
}
unexpected_file() {
if [ -d "$full_path_original" ]; then
## REVIEW: ignore ok?
true
return 0
fi
mkdir -p "$full_path_dangerous_dirname"
if [ "$test_mode" = "true" ]; then
echo "Simulate backup of current version... $full_path_original" >&2
echo cp "$full_path_original" --no-dereference --archive --backup=existing "$full_path_dangerous"
elif [ "$clean" = "true" ]; then
echo "Creating backup of current version... $full_path_original" >&2
echo cp "$full_path_original" --no-dereference --archive --backup=existing "$full_path_dangerous"
cp "$full_path_original" --no-dereference --archive --backup=existing "$full_path_dangerous"
echo "Created backup." >&2
fi
if test -h "$full_path_original" ; then
echo "is a symlink: $full_path_original" >&2
if [ "$test_mode" = "true" ]; then
echo "Simulate only. unexpected symlink. Removing... unlink '$full_path_original'" >&2
echo unlink "$full_path_original"
elif [ "$clean" = "true" ]; then
echo "unexpected symlink. Removing... unlink '$full_path_original'" >&2
unlink "$full_path_original"
echo "Removed unexpect symlink." >&2
fi
else
if [ "$test_mode" = "true" ]; then
echo "Simulate deleting modified version '$full_path_original'." >&2
echo rm "$full_path_original" >&2
elif [ "$clean" = "true" ]; then
## chattr fails on symlinks such as symlink to /dev/random.
chattr -i "$full_path_original"
echo "Deleting modified version '$full_path_original'." >&2
rm "$full_path_original" >&2
echo "Deleted '$full_path_original'." >&2
fi
echo "View the diff:" >&2
echo "diff $full_path_original $full_path_dangerous" >&2
fi
echo "" >&2
restore_file
}
restore_file() {
if [ "$test_mode" = "true" ]; then
echo "Simulate restoring file... $full_path_original" >&2
echo cp --no-dereference --archive "$full_path_backup" "$full_path_original"
echo "" >&2
elif [ "$clean" = "true" ]; then
echo "Restoring file... $full_path_original" >&2
echo mkdir --parents "$full_path_original_dirname" >&2
mkdir --parents "$full_path_original_dirname"
if [ ! "$home_folder" = "$full_path_original_dirname" ]; then
chown --recursive "$user_name:$user_name" "$full_path_original_dirname"
fi
echo cp --no-dereference --archive "$full_path_backup" "$full_path_original"
cp --no-dereference --archive "$full_path_backup" "$full_path_original" >&2
echo "Restored." >&2
echo "" >&2
fi
}
unit_test_one() {
if [ ! "$unit_test" = "true" ]; then
return 0
fi
echo "x" >> /home/user/.virusforgetunitestone
test -f /home/user/.virusforgetunitestone
}
unit_test_two() {
if [ ! "$unit_test" = "true" ]; then
return 0
fi
rm /home/user/.virusforgetunitestone
echo "x" >> /home/user/.virusforgetunitesttwo
test -f /home/user/.virusforgetunitesttwo
echo "x" >> /home/user/.config/systemd/user/virusforgetunittest
test -f /home/user/.config/systemd/user/virusforgetunittest
if test -h /home/user/.config/systemd/user/virusforgetunittestsymlink ; then
unlink /home/user/.config/systemd/user/virusforgetunittestsymlink
fi
ln -s /dev/random /home/user/.config/systemd/user/virusforgetunittestsymlink
}
root_check
parse_cmd_options "$@"
init
variables
unit_test_one
if [ "$commit" = "true" ]; then
store=true
process_file_system_objects
fi
unit_test_two
if [ "$check" = "true" ]; then
store=false
process_file_system_objects
fi