#!/bin/bash ### Imports ################################################################### source ScriptFunctions Import Array Import File Import GoboLinux Import Log Import OptionParser ### Options ################################################################### sandboxroot="${goboTemp}/.FiboSandbox$$" scriptDescription="Run the program in a protected sandbox, as a restricted user." scriptCredits="Copyright (C) 2003. Released under the GNU GPL." helpOnNoArguments=yes scriptUsage="[] -- []" scriptExample="-r 0.0 -s '.:${goboPrograms}/NaughtyApp/Current' -- make install" scriptNotes=" To allow mobility within the sandbox, the '.' directory is mounted at a sandbox root (like $sandboxroot). For this reason, use of relative paths like '..' to reach directories higher in the hierarchy than '.' may produce unexpected results. It may also confuse symbolic links that flow through the sandbox. " Add_Option_Boolean "o" "original" "Restore original owners." Add_Option_Entry "r" "restore" "Restore ownership to ." Add_Option_Entry "d" "directory" "The program should be run at . "\ "This path should be either absolute, or relative to the sandbox root." Add_Option_List "s" "sandbox" "Colon-separated list of areas where the restricted user has write access to." "." Add_Option_List "m" "map" "Colon-separated mapping (lhs=rhs) where writes to rhs are mapped to lhs." "" Parse_Options "$@" ### Operation ################################################################# Verify_Superuser Is_Directory "$sandboxroot" && Quiet rmdir "$sandboxroot" Is_Directory "$sandboxroot" && Die "Could not remove $sandboxroot" #Is_Directory "$sandboxroot" && Die "Only one sandbox can run at a time." [ "$1" ] || Die "Please specify a command to be executed inside the sandbox." List_To_Array "sandbox" allowed List_To_Array "map" mapmounts mkdir "$sandboxroot" function cleanup() { # restoring permissions for chown, chgrp etc for i in $(seq 0 $((${#fiboprograms[@]} - 1))) do chmod ${mod[${i}]} "${fiboprograms[${i}]}" chown ${own[${i}]} "${fiboprograms[${i}]}" chgrp ${grp[${i}]} "${fiboprograms[${i}]}" done Log_Verbose "Cleaning up mounts..." For_Each mapmounts 'lhs=$(echo $each | cut -d= -f1) umount $lhs [ "$?" = "0" ] || error=true ' [ "$error" = "false" ] || Log_Error "Unable to unmount map areas" if [ "$domount" = "1" ] then cd ${oldpwd} umount "$sandboxroot" fi rmdir "$sandboxroot" } function finish() { Log_Verbose "Undoing the sandbox..." # Save changed setuid permissions before chown echo -n > "$suidfile" For_Each allowed '[ -e "$each" ] && find "$each" -perm +4000 -printf "chmod u+s \"%p\"\n"'\ >> "$suidfile" if Is_Entry_Set "restore" then For_Each allowed 'chown -R "'`Entry "restore"`'" "$each"' else if ! Boolean "original" then # Catch changes since the permissions were saved make_restore_cmd() { Exists "$1" || { Log_Verbose "'$1' does not exist"; return 1; } find "$1" ! -user fibo -printf "chown %u \"%p\"\n" find "$1" ! -group fibo -printf "chgrp %g \"%p\"\n" } For_Each allowed 'make_restore_cmd "$each"' >> "$permfile" fi # Restore owner and group Log_Verbose "Restoring owner..." Verbose cat "$permfile" source "$permfile" rm -f -- "$permfile" fi # Restore setuid Log_Verbose "Restoring setuid permissions..." Verbose cat "$suidfile" source "$suidfile" rm -f -- "$suidfile" } function fibo_die() { cleanup Die "$1" } trap "fibo_die 'Caught signal. Exiting...'" SIGHUP SIGINT SIGTERM if ! Is_Entry "restore" then # Save owner and group to restore after the sandbox permfile=`Temporary_File` Log_Verbose "Saving owner and group to $permfile..." make_restore_cmd() { Exists "$1" || { Log_Verbose "'$1' does not exist"; return 1; } local owner=`stat -c %u "$1"` local group=`stat -c %g "$1"` # default owner for the directory echo "chown -R $owner:$group \"$1\"" # exceptions find "$1" \( ! -user $owner -o ! -group $group \) -printf "chown %u:%g \"%p\"\n" } For_Each allowed 'make_restore_cmd "$each"' >> "$permfile" fi Log_Verbose "Preparing the sandbox..." newpwd="$PWD" # Save setuid permissions, they are cleared by chmod on Linux suidfile=`Temporary_File` Log_Verbose "Saving setuid permissions to $suidfile..." For_Each allowed '[ -e "$each" ] && find "$each" -perm +4000 -printf "chmod u+s \"%p\"\n"'\ >> "$suidfile" # All hail odd programming! For_Each allowed ' chown -R fibo.fibo "$each" [ "$each" == "." ] && domount=1 ' # Restore suid after chown . "$suidfile" if [ "$domount" = "1" ] then oldpwd="$PWD" mount --bind "." "$sandboxroot" cd "$sandboxroot" fi error="false" For_Each mapmounts 'lhs=$(echo $each | cut -d= -f1) rhs=$(echo $each | cut -d= -f2) Assert_Dir $lhs Assert_Dir $rhs mount -o bind $lhs $rhs [ "$?" = "0" ] || error=true ' [ "$error" = "false" ] || fibo_die "Unable to mount map areas in unmanaged directory" if Is_Entry_Set "directory" then cd `Entry "directory"` fi fiboprograms=( `which chgrp` `which chown` `which chmod` `which depmod 2> /dev/null` ) for i in $(seq 0 $((${#fiboprograms[@]} - 1))) do mod[${i}]=$(stat -c '%a' ${fiboprograms[${i}]}) own[${i}]=$(stat -c '%u' ${fiboprograms[${i}]}) grp[${i}]=$(stat -c '%g' ${fiboprograms[${i}]}) done chown 0 "${fiboprograms[@]}" chgrp fibo "${fiboprograms[@]}" chmod 4770 "${fiboprograms[@]}" eval `Args_To_Array command` sudo -u fibo env SUDO_OK=1 "${command[@]}" result=$? cleanup finish exit $result