I want to jail an "normal" user with the special group developer for SFTP and SSH.
The user can only navigate in /srv/DEVELOPMENT (SSH/SFTP) AND over SSH, the user can only execute a limit of commands (see the script at the bottom).
Why i want this?
I work on a little project. Last days, another developers wan't to support the project with their experiences. The developer can be edit the "developer-website" and can start/stop/restart an Node.js application over SSH. The next think is: The user must use the shell to change their account password.
Currently, i have configured the SSH-Deamon with following steps:
Jail over SFTP
Match Group developer
X11Forwarding no
AllowTcpForwarding yes
ChrootDirectory /srv/DEVELOPMENT
ForceCommand internal-sftp
The user was added by following commands/options:
useradd --base-dir /srv/ --home-dir /srv/ --no-user-group --shell /srv/shell.sh $USERNAME
usermod -G developer $USERNAME
id $USERNAME
passwd $USERNAME
Current Directory Permissions
/srv developer:root 0755
/srv/DEVELOPMENT developer:root 0750
/srv/DEVELOPMENT/* developer:root 0777
With SFTP it work's correctly. The second part to jail the user over SSH is currently little bit harder. This step won't work currently, and thats is my question.
The chroot is limited on internal-sfpt. When i try to login, the connection will be aborted with the message, that the connection is only allowed for sftp:
ssh TestUser#example.com
TestUser#example.com's password:
This service allows sftp connections only.
Connection to example.com closed.
Here, i had remove ForceCommand on the SSH-Deamon config > The Login will be succeed.
But here is my problem
When i try to login, no executables cant be used:
ssh TestUser#example.com
TestUser#example.com's password:
Linux example.com 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26) x86_64
Last login: Sun Jul 30 18:00:11 2017 from ****************
/srv/shell.sh: No such file or directory
Connection to example.com closed.
/srv/shell.sh is a custom shell-script to limit the commands, for sample:
#!/bin/bash
commands=("man" "passwd" "ls" "account", "whoami", "clear", "cd")
RED='\033[0;31m'
YELLOW='\033[0;33m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
INDENTATION=' '
SYSTEM_UPTIME=`uptime --pretty`
SYSTEM_USERS=`who -q`
SYSTEM_QUOTA="None"
SYSTEM_RAM="None"
timestamp(){
date +"%Y-%m-%d %H:%M:%S"
}
log(){
echo -e "[$(timestamp)]\t$1\t$(whoami)\t$2" >> /var/log/developer-user/shell.log;
}
execute() {
# EXIT
if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
then
exit
# HELP
elif [[ "$ln" == "help" ]]
then
echo "Type exit or q to quit."
echo "Commands you can use:"
echo " account"
echo " help"
echo " echo"
echo " man <ManPage>"
echo " passwd"
echo " ls"
echo " clear"
echo " cd"
# CD
elif [[ "$ln" =~ ^cd\ .*$ ]]
then
LAST=`pwd`
$ln
CURRENT=`pwd`
if [[ $CURRENT == "/srv" ]]
then
log CHANGE_DIR FAILED_PERMISSIONS "$ln"
echo -e "${RED}ERROR:${NC} Sorry, you can't change to the previous directory ${YELLOW}\"${CURRENT}\"${NC}."
cd $LAST
elif [[ ! "$CURRENT" =~ ^/srv/DEVELOPMENT ]]
then
log CHANGE_DIR FAILED_PERMISSIONS "$ln"
echo -e "${RED}ERROR:${NC} Sorry, you can't change to the directory ${YELLOW}\"${CURRENT}\"${NC}."
cd $LAST
elif [[ `stat -c "%G" ${CURRENT}` == "friendlounge" ]]
then
log CHANGE_DIR "$ln"
else
log CHANGE_DIR FAILED_PERMISSIONS "$ln"
echo -e "${RED}ERROR:${NC} You have no permissions on ${YELLOW}\"${CURRENT}\"${NC}."
cd $LAST
fi
# ECHO
elif [[ "$ln" =~ ^echo\ .*$ ]]
then
$ln
log COMMAND "$ln"
# ACCOUNT
elif [[ "$ln" = "account" ]]
then
echo -e "YOUR ACCOUNT:"
echo -e "Username: $(whoami)"
# OTHERS
else
ok=false
for cmd in "${commands[#]}"
do
if [[ "$cmd" == "$ln" ]]
then
ok=true
fi
done
if $ok
then
$ln
else
echo -e "${RED}ERROR:${NC} You have no permissions to execute ${YELLOW}\"${ln}\"${NC}."
log DENIED "$ln"
fi
fi
}
# WELCOME MESSAGE
echo -e "${INDENTATION}${MAGENTA}Account:${NC}${INDENTATION}$(whoami)"
echo -e "${INDENTATION}${MAGENTA}Date:${NC}${INDENTATION}${INDENTATION}$(timestamp)"
echo -e "${INDENTATION}${MAGENTA}Uptime:${NC}${INDENTATION}${INDENTATION}${SYSTEM_UPTIME}"
echo -e "${INDENTATION}${MAGENTA}Users:${NC}${INDENTATION}${INDENTATION}${SYSTEM_USERS}"
echo -e "${INDENTATION}${MAGENTA}Quota:${NC}${INDENTATION}${INDENTATION}${SYSTEM_QUOTA}"
echo -e "${INDENTATION}${MAGENTA}RAM:${NC}${INDENTATION}${INDENTATION}${SYSTEM_RAM}"
log LOGIN "$#"
cd
trap "trap=\"\";log LOGOUT;exit" EXIT
# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user#host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
shift
execute "$#"
else
while echo -e -n "${RED}$(whoami)${YELLOW}#${CYAN}$(hostname) ${YELLOW}$(pwd) ${MAGENTA}#${NC} " && read ln
do
execute "$ln"
done
fi
This shell-script checks the permission of the user and force only to the /srv/DEVELOPMENT directory or subdirectorys.
It's irrelevant to set another login-shells like /bin/bash or other - On each login, the SSH-Demon close the connection after the error message XXXX: No such file or directory.
I had try to set different permissions and other. i can't resolve the problem to connect over ssh.
Anyone have an idea?
Before you answer
yes, i known the possible security reasons (for sample, to manage the permissions over my "own" shell-login-script)
no, i don't want to install huge alternatives like schroot or jailkit (found on google, reading the first minutes says, that these alternatives uses a completely decoupled system like a virtual-machine(?) - inform me, when it's wrong with explicit informations)
You may try this, It's is very easy to use.
you can jail a user in 3 steps.
add user
create a jail with a simple configuration file.
jail this user.
The tool is located at :https://github.com/pymumu/jail-shell
Related
I'm trying to get this script to loop back and restart if the user inputs a response that does not match the choices allowed but then enters a correct response the second time around. I tried using continue, but it loops infinitely. Any thoughts?
`
#!/bin/bash
#Obtaing user selection and input
echo " Gathering list of users on this machine..."
sleep 2
echo "$( ls /Users )"
echo "From the list above, which user did you want to work with?"
read userSelection
echo "What is that user's password?"
#Hiding User's Password
stty -echo
read userSelectionPassword
stty echo
echo "Did you want [enable], [disable], or check the current [status] of Secure Token for $userSelection?"
read taskSelection
#Converting input to lowercase
taskSelectionLower=$(echo $taskSelection | tr '[:upper:]' '[:lower:]')
#Running commands
while [ true ]
do
if [[ $taskSelectionLower == "enable" ]]; then
echo "Enabling..."
echo "$(sysadminctl -adminUser AdminUser -adminPassword AdminPass -secureTokenOn $userSelection -password $userSelectionPassword)"
break
elif [[ $taskSelectionLower == "status" ]]; then
echo "Displaying $userSelection current Secure Token status..."
echo "$( sysadminctl -secureTokenStatus $userSelection )"
break
elif [[ $taskSelectionLower == "disable" ]]; then
echo "Disabling..."
echo "$(sysadminctl -adminUser AdminUser -adminPassword AdminPass -secureTokenOff $userSelection -password $userSelectionPassword)"
break
else
echo "Incorrect selection made..."
echo "Did you want [enable], [disable], or check the current [status] of Secure Token for $userSelection?"
read taskSelection
exit
fi
done
`
Attempted using continue at the end of the condition, but loops infinitely.
Expected outcome would be for the for loop to restart, allowing the user to input a correct response and get the correct output.
The select command was designed exactly for this sort of interactive script.
Some hopefully useful observations -
echo " Gathering list of users on this machine..."
sleep 2 # why?
This sleep seems to serve no purpose but to annoy the user.
echo "$( ls /Users )" # why?? Don't do this.
This is exactly the same as
ls /Users # same output. Keep it simple.
Also, since you are bash instead of sh, rather than
taskSelectionLower=$(echo $taskSelection | tr '[:upper:]' '[:lower:]')
try declaring the variable as lowercase -
declare -l taskSelectionLower
read taskSelectionLower
or handle it with parameter parsing syntax -
read taskSelectionLower
taskSelectionLower="${taskSelectionLower,,}"
but why let them possibly mistype at all?
Consider using a select statement.
Rather than building your own loop, presenting options, worrying about formatting, etc, let tools that already do that handle it for you.
My rewrite using echo to show the commands to be executed - take those out and it should run fine.
#!/bin/bash
cd /c/Users
echo "Please select a valid user from this system."
select u in */; do
if [[ -d "$u" ]]
then userSelection="${u%/}"; break
else echo "Please enter a number from the presented options."
fi
done # get just the username
cd $OLDPWD # if needed
admSet() { # no reason to ask for the password just to get status...
read -sp "what's $userSelection's password? " userSelectionPassword
echo # reading the password leaves the cursor on the previous line
echo sysadminctl -adminUser AdminUser -adminPassword AdminPass \
-secureToken$1 "$userSelection" -password "$userSelectionPassword"
}
select taskSelection in enable disable status; do # case is controlled
case "$taskSelection" in
status) echo "Displaying $userSelection current Secure Token status..."
echo sysadminctl -secureTokenStatus $userSelection ;;
enable) echo "Enabling..." ; admSet On ;;
disable) echo "Disabling..." ; admSet Off ;;
*) echo "Please enter a number from the presented options."
continue ;;
esac
break
done
This is a question about your opinion on a script I wrote.
At my workplace I wrote a bash-script to execute commands on Linux-Systems (redhat). Since we got Ansible and Puppet nobody was interessted in the script. And to be true: if you got Ansible or Puppet and you are working in a team, it isnt advised to use such a solution... BUT (and thats why I want to post it here and ask for your opinion/improvements on it) if you just want to manage a few Linux hosts and dont want to buy any licence etc. this script may help you out.
the script is called "rotator" and it works like this:
It takes a serverlist and a functionfile. It breaks the Serverlist up into a given maximum number of tmp-lists and executes the commands in the functionfile in the background. Then it waits for all the parallel processes to finish. At the end it checks if all the hosts were visited.
code of rotator.sh:
\#!/bin/bash
usage ()
{
echo ""
echo ""
echo ""
echo "ERROR: $1"
echo ""
echo "You need to provide a serverlist and a"
echo "function file as parameter."
echo "e.g.: sh check_rpm.sh \<server.list\> \<funktions-file.sh\>"
echo "note that the master pushes the config to the client mashines"
echo ""
echo ""
exit 1
}
if \[\[ $# -eq 0 || "$#" == "-h" || "$#" == "--help" || "$#" == "-?" \]\]
then
usage "missing parameter"
exit 1
fi
\######################
# Variablendeklaration
\######################
basedir=$(dirname $0)
hosts=$(cat $1)
funcfile=$2
myhostname=$(hostname -a)
maxlists=100
i=0
j=0
templist=${basedir}/tmp/templist${j}
num=$(cat $1 | wc -l)
length=0
divisor=1
\###################################
# determine num of temp-lists
\###################################
if \[\[ num -gt $maxlists \]\]
then
length=$((num/$maxlists))
((length++))
else
length=1
fi
\######################################
# delete existing old temp lists
\######################################
if \[ ! -z "$(ls -A tmp)" \];
then
rm ./tmp/\*
fi
\######################
# create temp lists
\######################
echo "cutting hostlist"
for host in $hosts;
do
if \[\[ ! "${host^^}" == "${myhostname^^}" \]\]
then
echo $host \>\> $templist
((i++))
fi
if \[\[ $i -eq $length \]\]
then
((j++))
templist=${basedir}/tmp/templist${j}
i=0
fi
done
if \[\[ $j -eq 0 \]\]
then
j=1
fi
\##################################################
# start func-file for all lists and remember PID
\##################################################
k=0
for ((i=0;i\<$j;i++));
do
sleep 0.2
sh $funcfile ${basedir}/tmp/templist${i} &
pids\[${k}\]=$!
((k++))
done
\######################################
# wait till all processes terminate
\######################################
echo "waiting till all processes are done"
for pid in ${pids\[\*\]};
do
wait $pid
done
\#######################
# cleanup temp lists
\#######################
for ((i=0;i\<$j;i++));
do
rm -f ${basedir}/tmp/templist${i}
done
\##########################################
# determine if all hosts were visited
\##########################################
echo "determine if all hosts were visited..."
checkhosts=$(cat tmp/check.list)
done=false
absenthosts=""
for host in $hosts
do
for server in $checkhosts
do
host=$(echo ${host^^})
server=$(echo ${server^^})
if \[\[ "$host" == "$server" \]\]
then
done=true
fi
done
if \[\[ "$done" == "false" \]\]
then
absenthosts+="$host "
else
done=false
fi
done
rm tmp/check.list
\############################################
# tell user which hosts were not visited
\############################################
echo "the following hosts werent visited and need to be handled manually"
echo ""
for host in $absenthosts
do
echo "$host"
done
**# END OF SCRIPT**
Here is an example of a function-file:
\#!/bin/bash
#
#
#
# ================||
# PLEASE BE AWARE ||
# ================||
# Add the code, which should be executed within the marked space
# instead of using "ssh" use $SSHOPTS
#
#
hosts=$(cat $1)
SSHOPTS="ssh -q -o BatchMode=yes -o ConnectTimeout=10"
for host in $hosts
do
$SSHOPTS $host "hostname" \>\> /opt/c2tools/serverliste_kontrollskripten/rotator/tmp/check.list
#
# MARK: add code after this mark
#
#
# MARK: add code before this mark
#
done
**# END OF SCRIPT**
I would say, that if you combine the rotator with cron-job, you could more or less use it as an free alternative to puppet or ansible, with the bonus that you can write the function-files in the bash scripting language.
Please share your opinion
The script runs, but could be improved
I am a beginner and trying to write a script that takes a config file (example below) and sets the rights for the users, if that user or group doesn´t exist, they get added.
For every line in the file, I am cutting out the user or the group and check if they exist.
Right now I only check for users.
#!/bin/bash
function SetRights()
{
if [[ $# -eq 1 && -f $1 ]]
then
for line in $1
do
var1=$(cut -d: -f2 $line)
var2=$(cat /etc/passwd | grep $var1 | wc -l)
if [[ $var2 -eq 0 ]]
then
sudo useradd $var1
else
setfacl -m $line
fi
done
else
echo Enter the correct path of the configuration file.
fi
}
SetRights $1
The config file looks like this:
u:TestUser:- /home/temp
g:TestGroup:rw /home/temp/testFolder
u:TestUser2:r /home/temp/1234.txt
The output:
grep: TestGroup: No such file or directory
grep: TestUser: No such file or directory
"The useradd help menu"
If you could give me a hint what I should look for in my research, I would be very grateful.
Is it possible to reset var1 and var2? Using unset didn´t work for me and I couldn´t find variables could only be set once.
It's not clear how you are looping over the contents of the file -- if $1 contains the file name, you should not be seeing the errors you report.
But anyway, here is a refactored version which hopefully avoids your problems.
# Avoid Bash-only syntax for function definition
SetRights() {
# Indent function body
# Properly quote "$1"
if [[ $# -eq 1 && -f "$1" ]]
then
# Read lines in file
while read -r acl file
do
# Parse out user
user=${acl#*:}
user=${user%:*}
# Avoid useless use of cat
# Anchor regex correctly
if ! grep -q "^$user:" /etc/passwd
then
# Quote user
sudo useradd "$user"
else
setfacl -m "$acl" "$file"
fi
done <"$1"
else
# Error message to stderr
echo Enter the correct path of the configuration file. >&2
# Signal failure to the caller
return 1
fi
}
# Properly quote argument
SetRights "$1"
I am trying to make this script handle file with spaces in them. it is supposed show and execute the content of files in a directory. when I select a file with a space in it, bash fails with bash: foo: no such file or directory, What am I missing to make this handle files correctly
# /etc/skel/.bashrc
#Interactive shell detection
if [[ $- != *i* ]] ; then
# Shell is non-interactive. Be done now!
return
fi
#kv-bash (easy) var database & setup of info
echo "type 'menu' for a bash menu"
#done####################
#to easily launch crouton enviroments
addentry() {
cd ~/.sslm
echo "Name your menu entry."
read entry
sleep 1s
if [ -e "$entry " ]
then
echo "Error, Menu entry already exists"
addentry
else
echo "what do you want the entry to do?"
read entryexec
echo "$entryexec && menu"> ~/.sslm/"$entry"
echo "done"
cd ~/
fi
sleep 1s
}
###################
delentry() {
cd ~/.sslm
ls -x
echo "what entry do you want to delete?"
read del
rm "$del"
echo "the work has been done, he is dead"
}
###################
menu() {
clear
cd ~/.sslm
echo "-- simple shell launcher menu v1.o --"
# set the prompt used by select, replacing "#?"
PS3="Use number to select a file or 'exit' to leave: "
# allow the user to choose a file
select filename in *
do
# leave the loop if the user says 'stop'
if [[ "$REPLY" == exit ]]; then
cd ~/
break
fi
# complain if no file was selected, and loop to ask again
if [[ "$filename" == "" ]]
then
echo "'$REPLY' is not a valid number"
sleep 1s
continue
fi
# now we can use the selected file, trying to get it to run the shell
script
. $filename
# it'll ask for another unless we leave the loop
break
done
}
menu
also, this is on a chromebook, so there is no apt.
At this part:
script
. $filename
I just needed to change to . "$filename"
thx #PesaThe
I'm working on a script to automate the creation of a .gitconfig file.
This is my main script that calls a function which in turn execute another file.
dotfile.sh
COMMAND_NAME=$1
shift
ARG_NAME=$#
set +a
fail() {
echo "";
printf "\r[${RED}FAIL${RESET}] $1\n";
echo "";
exit 1;
}
set -a
sub_setup() {
info "This may overwrite existing files in your computer. Are you sure? (y/n)";
read -p "" -n 1;
echo "";
if [[ $REPLY =~ ^[Yy]$ ]]; then
for ARG in $ARG_NAME; do
local SCRIPT="~/dotfiles/setup/${ARG}.sh";
[ -f "$SCRIPT" ] && echo "Applying '$ARG'" && . "$SCRIPT" || fail "Unable to find script '$ARG'";
done;
fi;
}
case $COMMAND_NAME in
"" | "-h" | "--help")
sub_help;
;;
*)
CMD=${COMMAND_NAME/*-/}
sub_${CMD} $ARG_NAME 2> /dev/null;
if [ $? = 127 ]; then
fail "'$CMD' is not a known command or has errors.";
fi;
;;
esac;
git.sh
git_config() {
if [ ! -f "~/dotfiles/git/gitconfig_template" ]; then
fail "No gitconfig_template file found in ~/dotfiles/git/";
elif [ -f "~/dotfiles/.gitconfig" ]; then
fail ".gitconfig already exists. Delete the file and retry.";
else
echo "Setting up .gitconfig";
GIT_CREDENTIAL="cache"
[ "$(uname -s)" == "Darwin" ] && GIT_CREDENTIAL="osxkeychain";
user " - What is your GitHub author name?";
read -e GIT_AUTHORNAME;
user " - What is your GitHub author email?";
read -e GIT_AUTHOREMAIL;
user " - What is your GitHub username?";
read -e GIT_USERNAME;
if sed -e "s/AUTHORNAME/$GIT_AUTHORNAME/g" \
-e "s/AUTHOREMAIL/$GIT_AUTHOREMAIL/g" \
-e "s/USERNAME/$GIT_USERNAME/g" \
-e "s/GIT_CREDENTIAL_HELPER/$GIT_CREDENTIAL/g" \
"~/dotfiles/git/gitconfig_template" > "~/dotfiles/.gitconfig"; then
success ".gitconfig has been setup";
else
fail ".gitconfig has not been setup";
fi;
fi;
}
git_config
In the console
$ ./dotfile.sh --setup git
[ ?? ] This may overwrite existing files in your computer. Are you sure? (y/n)
y
Applying 'git'
Setting up .gitconfig
[ .. ] - What is your GitHub author name?
Then I cannot see what I'm typing...
At the bottom of dotfile.sh, I redirect any error that occurs during my function call to /dev/null. But I should normally see what I'm typing. If I remove 2> /dev/null from this line sub_${CMD} $ARG_NAME 2> /dev/null;, it works!! But I don't understand why.
I need this line to prevent my script to echo an error in case my command doesn't exists. I only want my own message.
e.g.
$ ./dotfile --blahblah
./dotfiles: line 153: sub_blahblah: command not found
[FAIL] 'blahblah' is not a known command or has errors
I really don't understand why the input in my sub script is redirected to /dev/null as I mentioned only stderr to be redirected to /dev/null.
Thanks
Do you need the -e option in your read statements?
I did a quick test in an interactive shell. The following command does not echo characters :
read -e TEST 2>/dev/null
The following does echo the characters
read TEST 2>/dev/null