#!/bin/bash
#********************************************* UFPM ************************************************
#**** Last Modified On: 09 Mar 2010 by John Schneiderman                        Version: 1.5.0 *****
#**** Desc: This script changes the files and folders to be appropriate for a users home folder*****
#****       Changes the permissions of directories to 750, regular files to 640, and backup    *****
#****       files (those with ~ at the end of the file name) to 440. Hidden files and folders  *****
#****       have their group settings set to zero.                                             *****
#***************************************************************************************************
#****           Copyright (C) 2006, 2009, 2010  John Schneiderman <JohnMS@member.fsf.org>      *****
#****                                                                                          *****
#*****          This program is free software: you can redistribute it and/or modify           *****
#*****          it under the terms of the GNU General Public License as published by           *****
#*****          the Free Software Foundation, either version 3 of the License, or              *****
#*****          (at your option) any later version.                                            *****
#*****                                                                                         *****
#*****          This program is distributed in the hope that it will be useful,                *****
#*****          but WITHOUT ANY WARRANTY; without even the implied warranty of                 *****
#*****          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                  *****
#*****          GNU General Public License for more details.                                   *****
#*****                                                                                         *****
#*****          You should have received a copy of the GNU General Public License              *****
#*****          along with this program.  If not, see <http://www.gnu.org/licenses/>.          *****
#*************************************** Change Log ************************************************
#**** 1.0.0 on 09 Feb 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Changes all file permissions to 640.                                            *****
#****          Changes all directory permissions to 750.                                       *****
#****          Changes all backup file permissions to 440.                                     *****
#**** 1.1.0 on 19 Feb 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Added a special file permission for those files and folders that are hidden.    *****
#****          Fixed documentation problems.                                                   *****
#****          Added a function to determine and handle file permissions.                      *****
#**** 1.1.1 on 25 Feb 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Made the permission variables to be integers.                                   *****
#**** 1.1.2 on 23 Mar 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Added version information from the command line.                                *****
#**** 1.2.0 on 07 Aug 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Changed the ssh folder file permissions.                                        *****
#****          Script files now will retain their executing bit.                               *****
#****          Changed the temporary location to /tmp.                                         *****
#**** 1.3.0 on 20 Aug 2006 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Changed the name fpm to ufpm to no longer conflict with the other FSS project.  *****
#****          Added a verbose mode, now files are not displayed by default.                   *****
#****          Added a silent mode, do not display directories we're working on.               *****
#****          Added an elf execute enable mode.                                               *****
#****     mangleFilenames:                                                                     *****
#****          Now will use TMPDIR if it exists, /tmp is still the default.                    *****
#****     modifyFileTypePermissions:                                                           *****
#****          Bug fix: ssh files now have proper permissions.                                 *****
#****          No longer sets file permissions for temporary files                             *****
#****          Bug fix: no longer complains about symbolic links, pipes, or missing files.     *****
#**** 1.4.0 on 02 Dec 2006 by John Schneiderman                                                *****
#****      ufpm:                                                                               *****
#****           Added user and group changing options.                                         *****
#****           Moved the copyright notice to the line below the programme name.               *****
#****           Removed potentially confusing status messages with a "." at the end.           *****
#****      changePermissions:                                                                  *****
#****           Sets the owner to user if ENABLE_USER is true.                                 *****
#****           Sets the group to group if ENABLE_GROUP is true.                               *****
#****      mangleFilenames:                                                                    *****
#****           Checks to be sure we use the correct home folder.                              *****
#****           Will exit if we can't list the home folder.                                    *****
#**** 1.4.1 on 14 Sep 2009 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          Fixed function declarations.                                                    *****
#****          Fixed function variable declarations.                                           *****
#****          Updated to GPL v3                                                               *****
#**** 1.5.0 on 09 Mar 2010 by John Schneiderman                                                *****
#****     ufpm:                                                                                *****
#****          File name and directories are no longer mangled before parsing.                 *****
#****     changePermissions:                                                                   *****
#****          Files and directories that already have the correct permissions are left alone. *****
#***************************************************************************************************
shopt -s -o nounset  #Don't allow the use of variables that haven't been declared
shopt -s extglob  #Allow the use of the extra pattern

#Programme Variables
#___________________________________________________________________________________________________
declare -rx script=${0##*/}  #Name of the script
declare -r version="1.5.0"  #Current Version
declare -r copyright_years="2006 - 2010"  #The current (C) years
declare -r OPT_STRING="vhVseu:g:"  #Command line options
declare OPT_RESULT="EMPTY"  #Used to parse the options
declare IS_VERBOSE="false"  #Enables verbose mode output
declare IS_SILENT="false"  #Enables silent mode
declare ENABLE_ELF="false"  #Enables executable ELFs
declare ENABLE_USER="false"  #Enables the user setting
declare ENABLE_GROUP="false"  #Enables the group setting
declare user=`id -nu`  #Current user
declare group=`id -nu`  #Current group
declare -ri filePermissions=640  #The permissions to set files to
declare -ri backupFilePermissions=440  #The permissions to set backup files to
declare -ri hiddenFilePermissions=600  #The permissions to set hidden files to
declare -ri scriptFilePermissions=740  #The permissions to set script files to
declare -ri elfFilePermissions=700  #The permissions to set elf files to
declare -ri directoryPermissions=750  #The permissions to set directories to
declare -ri hiddenDirectoryPermissions=700  #The permissions to set hidden directories to
declare files="Empty"  #All of the users files
declare File="Empty"  #A users file
declare Path="Empty"  #The current parent path we are examining.
declare FUNCTION_RESULT="Empty"  #The result from a function
#Programme Commands
#___________________________________________________________________________________________________
# We currently have none.

#Functions
#___________________________________________________________________________________________________
function changePermissions()
#Changes the permissions and/or owner(s) of the file.
#Parameters are: path, file name, and permissions respectively.
#Return a 0 if we successfully change the permissions a 1 if we do not.
{
    local filePath=$1
    local filename=$2
    local permissions=$3
    local fileUser=`stat --format=%U $filePath/$filename`
    local fileGroup=`stat --format=%G $filePath/$filename`
    local currentFilePermissions=`stat --format=%a $filePath/$filename`

    if [ \( "$ENABLE_USER" = "true" \) -a \( "$fileUser" != "$user" \) ]
    then  #Change the owner of the file
        chown $user "${filePath}${filename}"
        if [ $? -ne 0 ]
        then
            return 1
        fi
    fi

    if [ \( "$ENABLE_GROUP" = "true" \) -a \( "$fileGroup" != "$group" \) ]
    then  #Change the group owner of the file
        chgrp $group "${filePath}${filename}"
        if [ $? -ne 0 ]
        then
            return 1
        fi
    fi

    if [ "$currentFilePermissions" != "$permissions" ]
    then  # File permissions need to be changed
        if [ \( "$IS_VERBOSE" = "true" \) ]
        then
            if [ -z $filename ]
            then
                printf "Changing %s to %d\n" "$filePath" "$permissions"
            else
                printf "Changing %s to %d\n" "$filename" "$permissions"
            fi
        fi
        chmod $permissions "${filePath}${filename}"
    elif [ \( "$IS_VERBOSE" = "true" \) ]
    then
        if [ -z $filename ]
        then
            printf "Determined %s already is %d\n" "$filePath" "$permissions"
        else
            printf "Determined %s already is %d\n" "$filename" "$permissions"
        fi
    fi

    if [ $? -eq 0 ]
    then
        return 0
    else
        return 1
    fi
}
readonly -f changePermissions
declare -t changePermissions

function modifyFileTypePermissions()
#Determines and handles files based on their type
#The first parameter is the path, and the second parameter is the file name.
#Returns 0 if we can handle the file type, a 1 if we don't know what to do with the file.
{
    local path=$1
    local file=$2

    if [ ! -e "${path}${file}" ]
    then  #Assumed to have been a temp file
        printf "Must have been a temporary file: %s%s\n" "$path" "$file"
        return 0
    elif [ -h "$path$file" ]
    then  #File is a symbolic link
        return 0
    elif [ -S "$path$file" ]
    then  #File is a socket
        return 0
    elif [ -f "$path$file" ]
    then  #Change permissions of a file
        if [[ "$path" = *tmp* ]]
        then  #Don't change temporary files
            return 0
        elif [[ "$path" = *temp* ]]
        then
            return 0
        fi
        isSpecialFile "$path" "$file"
        if [ "$FUNCTION_RESULT" = "script" ]
        then  #Script file
            changePermissions "$path" "$file" "$scriptFilePermissions"
        elif [ "$FUNCTION_RESULT" = "elf" ]
        then  #ELF file
            changePermissions "$path" "$file" "$elfFilePermissions"
        elif [[ "$file" = *~ ]]
        then  #Backup file
            changePermissions "$path" "$file" "$backupFilePermissions"
        elif [[ "$file" = .* ]]
        then  #Hidden file
            changePermissions "$path" "$file" "$hiddenFilePermissions"
        elif [[ "$path" = *.ssh* ]]
        then  #ssh file
            changePermissions "$path" "$file" "$hiddenFilePermissions"
        else  #Normal file
            changePermissions "$path" "$file" "$filePermissions"
        fi
    elif [ -d "$path$file" ]
    then  #Change permissions of a directory
        if [[ "$file" = .* ]]
        then  #Hidden directory
            changePermissions "$path" "$file" "$hiddenDirectoryPermissions"
        else  #Normal directory
            changePermissions "$path" "$file" "$directoryPermissions"
        fi
    else
        printf "*** %s%s is neither a file nor a directory! Doing nothing. ***\n" "$path" "$file"
        return 1
    fi
    return 0
}
readonly -f modifyFileTypePermissions
declare -t modifyFileTypePermissions

function isSpecialFile()
#Determines if a file is a special type of file
#The first parameter is the path, and the second parameter is the file name.
#FUNCTION_RESULT has script if the file is a script, elf if it's an ELF file and elf is enabled
#Returns 0 if it can determine the special file type, 1 if it cannot.
{
    local path=$1
    local file=$2
    local result="EMPTY"

    result=`file -b $path$file`
    if [[ $result = *script* ]]
    then
        FUNCTION_RESULT="script"
        return 0
    elif [ $ENABLE_ELF = "true" ]
    then
        if [[ $result = *ELF* ]]
        then
            FUNCTION_RESULT="elf"
            return 0
        fi
    else
        FUNCTION_RESULT="EMPTY"
        return 1
    fi
}
readonly -f isSpecialFile
declare -t isSpecialFile

#Sanity Checks
#___________________________________________________________________________________________________
while getopts "$OPT_STRING" OPT_RESULT
do  #Parse command line options
    case $OPT_RESULT in
    e)  #Enable ELFs
        ENABLE_ELF="true"
        ;;
    g)  #Group name to use for files and directories
        group="$OPTARG"
        ENABLE_GROUP="true"
        ;;
    h)  #Show help
        printf "usage: $script [options]\n"
        printf "Options:\n"
        printf "  -e                       Enables ELFs to be executable.\n"
        printf "  -v                       Shows the version information.\n"
        printf "\nFor more information see the man page.\n"
        printf "For bug reporting instructions, please see the man page.\n"
        exit 0
        ;;
    s)  #Enable Silent mode
        IS_SILENT="true"
        ;;
    u)  #User name to use for files and directories
        user="$OPTARG"
        ENABLE_USER="true"
        ;;
    v)  #Version information
        printf "$script version $version\nCopyright (C) ${copyright_years} John Schneiderman\n"
        exit 0
        ;;
    V)  #Enable verbose mode
        IS_VERBOSE="true"
        ;;
    \?)  #Invalid argument given
        exit 2
        ;;
    *)
        printf "Passed argument is not known."
        exit 2
        ;;
    esac
done
if test -z "$BASH"
then  #Shell check
    printf "$script:$LINENO: Please run this script with the BASH shell.\n" >&2
    exit 2
fi

#Begin Programme Execution
#___________________________________________________________________________________________________
printf "$script version ${version}\n"
printf "Copyright (C) ${copyright_years} John Schneiderman\n"
printf "$script comes with ABSOLUTELY NO WARRANTY;\n"
printf "This is free software, and you are welcome to redistribute it\n"
printf "under certain conditions; see the COPYING file for details,\n"
printf "or the Free Software Foundation's GPL.\n\n"

# Display the home directory being worked on
if [ $ENABLE_USER = "true" ]
then
    printf "$script is examining files in /home/${user}...\n"
else
    printf "$script is examining files in $HOME...\n"
fi

printf "$script is setting the file permissions...\n"
IFS=$'\n'
for File in `ls --almost-all --recursive --escape /home/${user}/`
do
    if [[ "$File" = *: ]]
    then
        Path="${File//:}"
        if [ "$IS_SILENT" = "false" ]
        then
            printf "Examining directory %s\n" "$Path"
        fi
        modifyFileTypePermissions "$Path" ""
    else
        modifyFileTypePermissions "$Path/" "${File//\\}"
    fi
done
printf "$script is done setting permissions.\n"
