How to logout an ssh session from within a perl script? - linux

I have a perl script to do a second layer of authentication after an ssh shell is opened. It asks for password, and after n number of invalid attempts, the script should log out the user. This runs on a Debian system.
Now, the problem is that usually an ssh shell is closed interactively with the command exit.
When run from backticks, or system() from within a perl script, exit is not recognized as a valid command. So how can I logout the user from an ssh session, from within a perl script? The script is not responsible for the ssh session. It runs on the remote, and kicks in from .bashrc.
This is the relevant segment of code:
while ($actualpass ne $password) {
++$attempts;
if ( $attempts > $maxattempts ) {
`/bin/bash /root/ascii_breach`;
`/bin/bash exit`;
}
The /bin/bash exit obviously does not work.

Sounds like you have this a bit backwards. I think what you are doing is ssh'ing to the remote host which runs a shell, the shell runs perl and then perl wants to exit the shell. The better way of doing this is to ssh to the host to run the perl script directly. Only if the authentication passes should the perl script start up the shell.
You can configure sshd to run your authentication script in the authorized_keys file assuming that is how the user is getting in.

You could launch the authentication script, check the exit status and logout the shell on failure:
perl auth.pl; if [ $? -ne 0 ]; then exit; fi
Then in the Perl script:
if ( $attempts > $maxattempts ) {
die 'Authentication failed';
}
You would also need to stop the user skipping the authentication with ctrl+c or ctrl+z:
trap "echo no" SIGINT SIGTSTP
perl auth.pl; if [ $? -ne 0 ]; then exit; fi

Related

Launching a bash shell from a sudo-ed environment

Apologies for the confusing Question title. I am trying to launch an interactive bash shell from a shell script ( say shel2.sh) which has been launched by a parent script (shel1.sh) in a sudo-ed environment. ( I am creating a guided deployment
script for my software which needs to be installed as super-user , hence the sudo, but may need the user to access the shell. )
Here's shel1.sh
#!/bin/bash
set -x
sudo bash << EOF
echo $?
./shel2.sh
EOF
echo shel1 done
And here's shel2.sh
#!/bin/bash
set -x
bash --norc --verbose --noprofile -i
echo $?
echo done
I expected this to launch an interactive bash shell which waits for my input before returning to shel1.sh. This is what I see:
+ ./shel1.sh
+ sudo bash
0
+ bash --norc --verbose --noprofile -i
bash-4.3# exit
+ echo 0
0
+ echo done
done
+ echo shel1 done
shel1 done
The bash-4.3# calls an exit automatically and quits. Interestingly if I invoke the bash shell with -l (or --login) the automatic entry is logout !
Can someone explain what is happening here ?
When you use a here document, you are tying up the shell's -- and its spawned child processes' -- standard input to the here document input.
You can avoid using a here document in many situations. For example, replace the here document with a single-quoted string.
#!/bin/bash
set -x
sudo bash -c '
# Aside: How is this actually useful?
echo $?
# Spawned script inherits the stdin of "sudo bash"
./shel2.sh'
echo shel1 done
Without more details, it's hard to see where exactly you want to go with this, but most modern Linux platforms have package managers which allow all kinds of hooks for installation, so that you would typically not need to do this sort of thing. Have you looked into that?

How to retrieve bash shell return code in Windows Server with ssh?

We have a remote bash shell script on a Linux Server.
We have a local Windows Server 2008 box to use ssh to execute the remote shell script.
We cant seem to get the remote return code.
we tried
ssh remote "./remote_shell.sh test" <-- returns 1
echo %errorlevel%
How do we do it right ?
Thanks
If it's really bash; then the return code is $?
ssh remote "./remote_shell.sh test"
echo $?
ssh remote "./remote_shell.sh test; echo $?"
The echo command will print the exit status of the preceding command. It would be necessary to parse the number from the ssh output. You could make that a little easier by tagging the value:
ssh remote "./remote_shell.sh test; echo exit value was: $?"

Read command in bash script not waiting for user input when piped to bash?

Here is what I'm entering in Terminal:
curl --silent https://raw.githubusercontent.com/githubUser/repoName/master/installer.sh | bash
The WordPress installing bash script contains a "read password" command that is supposed to wait for users to input their MySQL password. But, for some reason, that doesn't happen when I run it with the "curl githubURL | bash" command. When I download the script via wget and run it via "sh installer.sh", it works fine.
What could be the cause of this? Any help is appreciated!
If you want to run a script on a remote server without saving it locally, you can try this.
#!/bin/bash
RunThis=$(lynx -dump http://127.0.0.1/example.sh)
if [ $? = 0 ] ; then
bash -c "$RunThis"
else
echo "There was a problem downloading the script"
exit 1
fi
In order to test it, I wrote an example.sh:
#!/bin/bash
# File /var/www/example.sh
echo "Example read:"
read line
echo "You typed: $line"
When I run Script.sh, the output looks like this.
$ ./Script.sh
Example read:
Hello World!
You typed: Hello World!
Unless you absolutely trust the remote scripts, I would avoid doing this without examining it before executing.
It wouldn't stop for read:
As when you are piping in a way you are forking a child which has been given input from parent shell.
You cannot give the values back to parent(modify parent's env) from child.
and through out this process you are always in parent process.

pipe timely commands to ssh

I am trying to pipe commands to an opened SSH session. The commands will be generated by a script, analyzing the results, and sending the next commands in accordance.
I do not want to put all the commands in a script on the remote host, and just run that script, because I am interested also in the status of the SSH process: sending locally the commands allow to "test" whether the SSH connection is alive or not, and get the appropriate return code from the SSH process.
I tried using something along these lines:
$ mkfifo /tpm/commands
$ ssh -t remote </tmp/commands
And from another term:
$ echo "command" >> /tmp/commands
Problem: SSH tells me that no pseudo-tty will be opened for stdin, and closes the connection as soon as "command" terminates.
I tried another approach:
$ ssh -t remote <<EOF
$(echo "command"; while true; do sleep 10; echo "command"; done)
EOF
But then, nothing is flushed to ssh until EOF is reached (in my case, never).
Do any of you have a solution ?
Stop closing /tmp/commands before you're done with it. When you close the pipe, ssh stops reading from it.
exec 7> /tmp/commands. # open once
echo foo >&7 # write multiple times
echo bar >&7
exec 7>&- # close once
You can additionally use ssh -tt to force ssh to open a tty on the remote.

Loop until connected to SSH

Sometimes when connecting to a remote SSH server I get Connection Closed By *IP*; Couldn't read packet: Connection reset by peer. But after trying one or two more times it connects properly.
This presents a problem with a few bash scripts I use to automatically upload my archived backups to the SSH server, like so;
export SSHPASS=$sshpassword
sshpass -e sftp -oBatchMode=no -b - root#$sshaddress << !
cd $remotefolder
put $backupfolder/Qt_$date.sql.gz
bye
!
How can I have this part loop until it actually properly connects?
UPDATE: (Solution)
RETVAL=1
while [ $RETVAL -ne 0 ]
do
export SSHPASS=$sshpassword
sshpass -e sftp -oBatchMode=no -b - root#$sshaddress << !
cd $remotefolder
put $backupfolder/Qt_$date.tgz
bye
!
RETVAL=$?
[ $RETVAL -eq 0 ] && echo Success
[ $RETVAL -ne 0 ] && echo Failure
done
Try something like this :
export SSHPASS=$sshpassword
sshpassFunc() {
sshpass -e sftp -oBatchMode=no -b - root#$sshaddress << !
cd $remotefolder
put $backupfolder/Qt_$date.sql.gz
bye
!
}
until sshpassFunc; do
sleep 1
done
(not tested)
I am not a shell scripting expert, but I would check the return value of sshpass when it exits.
From man ssh:
ssh exits with the exit status of the remote command or
with 255 if an error occurred.
From man sshpath:
Return Values
As with any other program, sshpass returns 0 on success. In case of
failure, the following return codes are used:
Invalid command line argument
Conflicting arguments given
General runtime error
Unrecognized response from ssh (parse error)
Invalid/incorrect password
Host public key is unknown. sshpass exits without confirming the new key.
In addition, ssh might be complaining about a man in the middle
attack. This complaint does not go to the tty. In other words, even
with sshpass, the error message from ssh is printed to standard error.
In such a case ssh's return code is reported back. This is typically
an unimaginative (and non-informative) "255" for all error cases.
So try to run the command, and check its return value. If the return value was not 0 (for SUCCESS) then try again. Repeat using a while loop until you succeed.
Sidenote: why are you using sshpass instead of public-key (passwordless) authentication? It is more secure (you don't have to write down your password) and makes logging in via regular ssh as easy as ssh username#host.
There's even an easy tool to set it up: ssh-copy-id.

Resources