#!/usr/bin/perl
#####################################################################################
#
# Usage:
#
# 	setHomePermissions.pl 
#
# Command Description: 
#
# 	This command is used to recursively set file and directory permissions, and umasks on the user's
#	home directory. The permissions and ownership that it will set are the most secure possible, 
#	allowing access to a user's home directory only by the user and no one else. No one other than
#	the user will even have read access to the user's home directory. Also, umasks are set in 
#	order to ensure that newly created files and directories have the correct permissions by default.
#
#	This command will determine the location of a user's home directory from the value of 
#	the ~ system variable, and it will chown files with the username output from the whoami system 
#	command.
#
#	Chown commands are called sudo to ensure that that permissions and ownership on ALL files
#	and subdirectories in the user's homefolder are set to that user. This means that the user running
#	this command must be in the visudo file, wheel group or admin group as appropriate for your distro.
#
#	This command also sets the correct permissions and ownership on all .dmrc files according to
#	Gnome requirements.
#
#	Permissions on the .ssh directory and files contained there in are set to 700 and 600 respectively.
#
#	Symbolic Links - Since permissions are set with sudo, this command will not follow symbolic links. 	
#
# Delegation:
#
#	To allow another user read-only access to your home folder and all subdirectories, add them to your
#	group with the following command:
#
#			usermod -a -G [YOUR_USERNAME] [THEIR_USERNAME]
#
#	On their next log in, they will be able to read and execute any files in your home directory, as well
#	as any files anywhere in the system for which the group owner is your group.
#
# Permissions/Ownerships Set:
#
#	Directories: umask 027, chown USERAME:USERNAME, chmod 770
#	Executable Files: chown USERAME:USERNAME, chmod 750
#	Files: chown USERAME:USERNAME, chmod 640
#	.dmrc file: chown USERNAME:USERNAME, chmod 644
#
#	*IMPORTANT* USERNAME is determined with the whoami command. Thus, you must
#	run this command with the user who should own the home directory.
#
# Case Examples:
# 	
#	-All files with any existing permissions and named .dmrc will be changed to 644.
# 	-Files with permisions 700 will be changed to 750.
# 	-Files with permissons 777 will be changed to 750.
# 	-Files with permissons 000 will be changed to 640.
# 	-Files with permissons 067 will be changed to 640.
# 	-Files with permissons 060 will be changed to 640.
# 	-Files with permissons 660 will be changed to 640.
# 	-Files with permissons 070 will be changed to 640.
# 	-Files in the ~/.ssh directory with any permission will be changed to 600.
# 	-The directory .ssh with permission 777 will be changed to 700.
# 	-Directories with permissons 000 will be changed to 750.
# 	-Directories with permissons 777 will be changed to 750.
# 	-Directories with permissons 067 will be changed to 750.
# 	-Directories with permissons 060 will be changed to 750.
# 	-Directories with permissons 660 will be changed to 750.
# 	-Directories with permissons 070 will be changed to 750.
# 	-Directories with permissons 007 will be changed to 750.
# 	-Directories with permissons 700 will be changed to 750.
#
# Elevated Priviledges
#
# 	In order to perform chowning, the user running this command must have sudo access.
#
# Support:
#
# 	If you have trouble with this script, please contact:
# 			Anthony Hildoer <Anthony@HildoerSystems.com>
#
# Versions:
#
#	1.21_Alpha - 20071203 - Fixed .ssh directory handling.
#	1.2_Alpha - 20071203 - Added support for .ssh directory, which needs to be more restrictive.
#			- Dropped some of the print statments to increase performance.
#	1.1_Alpha - 20071202 - Added support for .dmrc permissions according to Gnome requirements.
#			- Added automatic homedirectory locating by caching the value of ~ from the shell.
#			- Refactored source code organization.
# 	1.0_Alpha - 20070907 - Initial release.
#
# Copyright:
#
# 	Hildoer Systems 2007 : http://www.hildoersystems.com
#
# Warranty:
# 	
# 	This product in no way comes with a warranty. Any use is strictly at your
# 	own risk. If you have any concern regarding program behaviors, please feel
# 	free to contact the developer. See "Support" for contact information. Responses
# 	from or suggestions from the developer do not imply any warranty. Usage of this 
# 	script remains at your own risk.
# 
# Notes on Code:
# 	
# 	As you may notice, the code structure here is a bit over complicated for use
# 	of chmod and chown. Namely, the code handles recursions rather than calling 
# 	-R on both chmod and chown. This structure is intential in order to support
# 	additions to this script that may use commands that do not support recursion
# 	or that have poor support for recursion.
#
#####################################################################################

use strict;
use warnings;

my $index = 0;
my $whoami = `whoami`;
my $start = `echo ~`;

# clear newlines at end of values
$whoami =~ s/\n$//;
$start =~ s/\n$//;

if ($whoami =~ /^root$/) {
	print "Do not run this command as root. Set permissions on $start directory manually.\n";
	exit 0;
}

if ( -d $start ) {

	# cache current directory.
	my $pwd = `pwd`;

	# remove trailing newline.
	$pwd =~ s/\n/g/;

	# set permissions on .ssh directory first, because it is most important!
	processSSH($start, $whoami);
	
	# start processing home directory and subdirectories.
	processDirectory($start, $pwd, $whoami, "");

	print "Done.\n";

} elsif ( -f $start ) {

	print "'$start' is not a directory.\n";

}

exit 0;

# subroutines

# check contents of $directory, process any directories contained therein. 
sub processDirectory {

	my ($directory, $returnDirectory, $whoami, $indent) = @_;

        my $dirHandle;
	my $file;
	my @directories;

	# symbolic links are not followed because if they link out of the home
	# directory, we do not want to set their permissions. If the link is to
	# another spot in the home directory, the contents will still get set
	# when the script gets to the directory which is linked to.
	if (-l $directory) {
		#print $indent."Skipping symbolic link $directory\n";
		return 0;
	} else {
		print $indent."Processing directory: $directory\n";
		$indent .= "\t";
	}

	# sets permissions on directory before trying to enter and change its contents.
	processFile($directory, $whoami, $indent);

	# enter directory and continue processing contents.
	if (chdir($directory)) {

		# set the permission mask for the current directory
		umask 027;

		# dirHandle allows access to filenames
		opendir($dirHandle, ".");
	
		# iterate through contents of the directory
       		foreach $file (sort readdir($dirHandle)) {

			# do not process the . and .. relative directory references
			if ( $file !~ /^\.$/ && $file !~ /^\.\.$/ ) {

				# if file is a directory, process it's contents.
				if ( -d $file && $file !~ /\/.ssh$/) {
					processDirectory($directory."/".$file, $directory, $whoami, $indent);
				} elsif (-f $file) {
					# sets permissions on files
					processFile($file, $whoami, $indent);
				}

			}

		}

		# exit this directory
		chdir($returnDirectory);

	} else {

		print $indent."Could not open directory: $directory. Skipping.\n";

	}
}

# set ownership and permissions on files/directories.
sub processSSH {

	my ($directory) = @_;

	print "Setting Permissions on .ssh Directory\n";
	
	print `sudo chmod -R 600 "$directory/.ssh" 2>&1`;
	print `sudo chmod 700 "$directory/.ssh" 2>&1`;

	return 0;
}

# set ownership and permissions on files/directories.
sub processFile {

	my ($file, $whoami, $indent) = @_;

	# this function also sets permissions on directories, but the
	# processDirectory function handles user updates for directories.
	if (-f $file) {
		# update the user on what is going on
		#print $indent."Processing file: $file\n";
	}

	# escape possible double quotes in filename
	$file =~ s/"/\\"/g;

	# set ownership
	print `sudo chown $whoami:$whoami "$file" 2>&1`;

	# owner gets rwx on directories and rw on files, plus x on files that are already executable.
	print `sudo chmod u+rwX "$file" 2>&1`;

	# group gets r-x on directories and r- on files, plus x on files that are already executable.
	print `sudo chmod g+rX "$file" 2>&1`;
	print `sudo chmod g-w "$file" 2>&1`;

	# others get --- on everything.
	print `sudo chmod o-rwx "$file" 2>&1`;

	# sets correct permissions on all .dmrc files. 
	if ($file =~ /^.dmrc$/) {
		print `sudo chmod 644 "$file" 2>&1`;
	}

}

