#!/usr/bin/env bash

# Check for potentially incorrect file or group ownership within each user's
# home directory. This can happen quite easily when using sudo to perform
# configuration of a package which will be running under a particular user
# account. Note that an account being flagged by this function does *not*
# guarantee an issue, just that there *may* be one which should be verified.

# A better class of script...
set -o errexit          # Exit on most errors (see the manual)
set -o errtrace         # Make sure any error trap is inherited
set -o nounset          # Disallow expansion of unset variables
set -o pipefail         # Use last non-zero exit code in a pipeline
#set -o xtrace          # Trace the execution of the script (debug)

# DESC: Find some important paths we need before script_init() is called
# ARGS: None
# OUTS: $script_real_path: The full canonicalized path to the script
#       $script_real_dir: The canonicalized directory path of the script
#       $script_real_name: The canonicalized file name of the script
#       $dotfiles_path: The dotfiles directory path
#       $dotfiles_name: The dotfiles directory name
# shellcheck disable=SC2034
function early_init() {
    # Determine the physical directory this script resides in. This approach is
    # necessarily clumsy as simple methods like "readlink -f" and "realpath"
    # are not platform independent. We have to work on Linux, BSD, OS X, etc...
    script_real_path="$(perl -MCwd -le 'print Cwd::abs_path(shift)' "${BASH_SOURCE[0]}")"
    script_real_dir="$(dirname "$script_real_path")"
    script_real_name="$(basename "$script_real_path")"
    readonly script_real_path script_real_dir script_real_name

    # Dotfiles directory path & name
    dotfiles_path="$(cd -P "$script_real_dir/../../" && pwd)"
    dotfiles_name="$(basename "$dotfiles_path")"
    readonly dotfiles_path dotfiles_name
}

# DESC: Check permissions on a user's home directory
# ARGS: $1 (required): User name to check
function check_user_home_perms() {
    if [[ $# -ne 1 ]]; then
        script_exit 'Invalid arguments passed to check_user_home_perms()!' 2
    fi

    local user_name user_entry
    user_name="$1"
    user_entry="$(getent passwd "$user_name" || true)"
    if [[ -z $user_entry ]]; then
        script_exit "Unable to find details for user: $user_name"
    fi

    local user_uid user_gid user_home
    user_uid="$(id -u "$user_name")"
    user_gid="$(id -g "$user_name")"
    user_home="$(echo "$user_entry" | cut -d: -f6)"

    if [[ $user_home = '/' ]]; then
        pretty_print "Skipping user with root home dir: $user_name" "$fg_yellow"
        return
    fi

    pretty_print "Checking permissions for $user_name ... " "$fg_green" 'true'
    local find_results find_status
    # The hard-coded exclusion of the directory for storing Vim's undo files as
    # used in our .vimrc is a hack, but a more durable solution isn't worth it.
    # shellcheck disable=SC2311
    find_results="$(run_as_root find "$user_home" \
                        -not -path '*/.vim/undo/*' \
                     \( -not -uid "$user_uid" -or \
                        -not -gid "$user_gid" \) 2>&1)"
    find_status=$?

    if [[ $find_status -eq 0 && -z $find_results ]]; then
        pretty_print 'OK'
    elif [[ $find_status -ne 0 ]]; then
        pretty_print 'find returned non-zero exit status!' "$fg_yellow"
    else
        pretty_print 'found potential issues:' "$fg_red"
        pretty_print "$find_results"
    fi
}

# DESC: Main control flow
# ARGS: $@ (optional): Arguments provided to the script
function main() {
    early_init

    # shellcheck source=scripts/bin/bash-template.sh
    source "$script_real_dir/bash-template.sh"

    trap script_trap_err ERR
    trap script_trap_exit EXIT

    script_init "$@"
    colour_init

    # shellcheck disable=SC2119,SC2310
    if ! check_superuser; then
        script_exit 'Superuser access (via root or sudo) is required.' 1
    fi

    # shellcheck disable=SC2034
    getent passwd | while IFS=: read -r login pw uid gid gecos home shell; do {
        if [[ $home =~ ^(/root|/home/[A-Za-z]) ]]; then
            if [[ -d $home ]]; then
                check_user_home_perms "$login"
            fi
        fi
    } < /dev/null; done
}

# Check user home directory permissions
main "$@"

# vim: syntax=sh cc=80 tw=79 ts=4 sw=4 sts=4 et sr
