How to use CVS in expect through SSH? - remote-access

I can't find a way to pass CVS the password to run it automatically on the test server. I am trying to make a expect script.
I have a ssh alias, for which I made an ssh-copy-id, so the pasword handeling of ssh is no problems.
I would like to emulate :
ssh name;
run_remote_script.sh
#(which triggers cvs update at the good place. Nb, the server has a MOTD)
expect "Password:"
send "${CVS_REMOTE_PASSWORD}\n" #enter the password
I made that :
#!/bin/bash
SOFT=$(basename $0)
if [ -z ${CVS_REMOTE_PASSWORD+x} ];then
echo "$SOFT : Undefined variable \$CVS_REMOTE_PASSWORD"
fi
hostname="company"
/usr/bin/expect <<EOD
spawn ssh $hostname
cvs_company.sh
expect "Password:"
send "$CVS_REMOTE_PASSWORD\n"
interact
EOD
I would like to point out that typing ssh company, though 'company' is a placeholder, in my console works perfectly fine.
What is wrong with my script ? It yields "Invalid command name cvs_company.sh while executing cvs_company.sh"
Is there a proper way of doing that ?

Sounds like you need something like this:
expect << EOD
spawn ssh $hostname
expect "YOUR-SHELL-PROMPT"
send "cvs_company.sh\r"
expect "Password:"
send "$CVS_REMOTE_PASSWORD\r"
interact
EOD

I'm not sure about how CVS authentication works, but see if you can do this:
ssh $hostname "echo '$CVS_REMOTE_PASSWORD' | cvs_company.sh"
This assumes your password does not contain single quotes. If it does, there are simple-but-ugly workarounds.
Expect is a fantastic tool, but in many cases you don't need to use it.

Related

sending an output to another comand

I'm making a script that reads passwords from pass to ssh, I want to stop the script if the hostname is not found but I don't know how to read the output of ssh
I've tried this
test=$(ssh user#nonvalidip)
check="ssh: Could not resolve hostname nonvalidip: Name or service not known"
if [ $test = $check ]; then
echo "Please enter a valid ip"
fi
but $test is empty, how can I read the output of ssh and make that the test variable?
Assuming that you are trying to run a shell script to gain access through a system through SSH then if that connection is successful to run a command. To do this there are multiple things you could do that are much simpler than trying to make an interpret less language work. What I would strongly suggest is that to solve the first issue is to make a smaller script within the script. Such as doing something like this:
ssh user#known_address << EOF - This will start the session and keep everything running beneath it until it reaches the term EOF
Using this may help you later if you are in the Linux industry as well. The script should look something like this:
ssh user#known_address << EOF
scp /etc/passwd USER#your_address/Path
EOF - keep note that this is an example of what you can do but it is not very wise to keep extra copies of the password file laying around on other systems.
Then instead of using exact copies of what the system outputs you can simply use exit codes. This can be WAY more helpful along the way. You can receive the error codes of the last command you ran with echo $?
I cannot guarantee that this script will work but here's an example of what you can do
session() {ssh user#add << EOF; command1; command2; command3; EOF}; session; if $? == 1; echo "test failed".
Sources
https://www.shellhacks.com/ssh-execute-remote-command-script-linux/
Meaning of exit status 1 returned by linux command
https://www.shellscript.sh/functions.html

Embedded expect script return success or failure to bash

Im embedding an expect script inside of a bash script in order to place some ftp files on a server.
Im trying to have the expect script return an output value of success or failure to the bash process so I can act on it, but I am failing miserably.
The script looks like this:
sftper()
{
local filename="$1"
local user="user"
local password="password"
local host="ftpserver"
local in=1
IFS= read -r -d '' expect_commands <<EOD >echo_log
spawn /usr/bin/sftp $user#$host
expect "*assword:"
send "$password\r"
expect "sftp>"
send "put $filename\r"
expect "sftp>"
send "bye\r"
interact
EOD
expect -c "${expect_commands//
/;}"
in="$?"
return "$in"
}
`
Please, what am I doing wrong, and how can I fix this?
The single most surprising thing in your script is that you call interact, which is an Expect command to allow the user to be connected directly to the spawned program. However, it's unlikely to be useful after you have sent a bye command to sftp; a close; exit sequence would be much more expected (to shut down the controlling virtual terminal and quit the Expect script).
Thus, I'd expect something more like:
IFS= read -r -d '' expect_commands <<EOD >echo_log
spawn /usr/bin/sftp $user#$host
expect "*assword:"
send "$password\r"
expect "sftp>"
send "put $filename\r"
expect "sftp>"
send "bye\r"
close
exit
EOD
More generally, you ought to think about what happens if a problem occurs (e.g., if the password has been expired), and it is probably easier to write a full expect script instead of running the gauntlet of all that shell quoting. I've added a few small explanatory comments…
# Assuming this is in a file called do_sftp_put.exp
# set up the variables; first line is how to get a command line argument
set filename [lindex $argv 0]
set user "user"
set password "password"
set host "ftpserver"
# launch sftp
spawn /usr/bin/sftp $user#$host
# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"
# send the file
send "put $filename\r"
expect "sftp>"
# Shut down
send "bye\r"
close
exit
Then your shell script wrapper becomes much simpler:
sftper()
{
expect /path/to/do_sftp_put.exp "$1"
return $?
}
Not much fancy quoting is required here; this is how everything is designed to work. Yes, the expect script needs careful protection so that only you can read it as it contains live credentials, but you had that problem before in your shell code so that's nothing new.
[EDIT]: Of course, this still doesn't detect errors. For that, you need a more complex script. One of the most common errors is for the password to be wrong (or to not match the user). To solve that one, we take this bit:
# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"
and upgrade it to something like:
# login sequence
expect "*assword:"
send "$password\r"
expect {
"password" {
# It's asking for the password *again*; must be wrong!
# Kill the sftp program and exit with an error code
close
exit 1
}
"sftp>"
}
Working out how to detect an error isn't always trivial (you can use regular expressions and so on, and you need to understand exactly what you are working against), and in some cases it's actually better to back up and try another approach entirely. For sftp specifically, I would be trying to get an SSH identity configured so that I could use key-based auth instead of password-based auth, as that's significantly more secure in practice in several ways. However, that's a substantial change to your operations so it is definitely out of the scope of the question.

How to store a string into a variable that includes a $ using linux bash

I am attempting to send a password to a remote server using a bash script. This worked fine until we were required to change the passwords to more complex passwords and one of the new passwords included a $ character (i.e. P#$sw0rd).
I have included the snippet that is no longer working:
password="'P#$sw0rd'"
spawn ssh "$deviceType#$device"
expect {
"*no)?" {send "yes\r"}
"*assword:" {send "$password\r"}
"*assword:" {send "$password\r"}
}
Every time it sends the password, the remote system attempts to find the variable $sw0rd.
I know the problem is with the $ character in the password itself, but is there a way to do this without changing this one password on all of our remote servers to one that does not include the $ character?
I have tried different ways to store the $ character:
password='P#$sw0rd'
password=P#$sw0rd
password="'P#\$sw0rd'"
password="P#\$sw0rd"
password='P#\$sw0rd'
password=P#\$sw0rd
None of these have worked.
Please, help.
As you use spawn command there is a chance that you actually have expect script and not bash script. This should work in expect:
set password P#\$sw0rd
Of course you also have to use expect to run that script, either by adding #!/usr/bin/env expect at the top or using expect directly in the terminal: expect <SCRIPT>
#ArkadiuszDrabczyk has your answer.
You need to use exp_continue to get your login to work though:
spawn ssh "$deviceType#$device"
expect {
"*no)?" {send "yes\r"; exp_continue}
"*assword:" {send "$password\r"; exp_continue}
"*your prompt pattern here"
}
# ... carry on with the script
exp_continue allows you to stay in the current expect command and continue to look for other patterns. You do need something else to expect to allow you to break out.

Using ssh through an expect script on cygwin

I'm trying to execute commands remotely over ssh using an expect script that will log in with a password. So far I have the following script (details changed of course):
#!/usr/bin/expect
spawn ssh user1#cpu3.lab.ie
expect "password:"
send "psw123\r"
expect "$"
send "mkdir pswdtest\r"
I name this script testpswd.sh and then runchmod +x testpswd.sh, d2u testpswd.sh and ./testpswd.sh.
Apparently the script manages to login because I get the Last login:... prompt. However, after this the script seems to wait for a bit and then exit back out of ssh, without making a directory called pswdtest (as I can check afterwards).
I have tried looking up tutorials etc and changing the script above in all ways I could think of, e.g. expect "user1#cpu3:~$"instead of expect "$" and so on.
I'm running windows and use cygwin (hence the d2u), and the network I'm logging into uses Linux.
Any ideas?
While developing an expect script, always add exp_internal 1 at the top of the script: expect will show you what it's matching (or not).
Perhaps you could match the prompt with this: expect -re {\$\s*$}
After you send something, you should expect something
exp_internal 1
set prompt {\$\s*$}
spawn ssh user1#cpu3.lab.ie
expect "password:"
send "psw123\r"
expect -re $prompt
send "mkdir pswdtest\r"
expect -re $prompt
send "exit\r"
expect eof

Linux Expect SFTP + put file

I just got some help in automating my password input during an SFTP connection by using Expect.
I then tried to issue a put command and things got complicated again. I'm using the following code:
#!/usr/bin/expect
#!/bin/sh
expect -c "
spawn sftp remoteuser#*.*.*.*
expect \"remoteuser#*.*.*.*'s password:\"
send \"passwrd\r\"
interact "
echo "put output/data.xml\r"
echo "quit\r"
My password input and connection to the remote server works just fine but I am struggling to get the put output/data.xml command to display and execute at the SFTP prompt.
My echo "put output/data.xml\r" and echo "quit\r" lines just print as text which is not entirely surprising but I really don't know what else might work.
I understand you need some help, but you should at least try doing some reading. When you say expect -c 'some stuff ...', you are specifying the entire expect script as the parameter to the -c option. The Expect session will not exist afterward.
Also, try to understand what the interact command does instead of blindly applying what someone advises.
Anyway, the solution:
expect <<'END_EXPECT'
set timeout -1
spawn sftp remoteuser#1.2.3.4
expect "[Pp]assword:"
send "passwrd\r"
expect "whatever the sftp prompt looks like"
send "put output/data.xml\r"
expect "whatever the sftp prompt looks like"
send "quit\r"
expect eof
END_EXPECT
Note that the here-doc delimiter is quoted when you first see it. That way, you will not be subjected to any shell expansions. It's like the entire here-doc is single-quoted.

Resources