Expect script not working and terminal closes immediately - authentication

I don't know what's wrong with the script. I set up a new profile on Iterm terminal to run the script, but it never works and closes immediately. Here's the script:
#!/usr/bin/expect -f
set timeout 120
set secret mysecret
set username asdf
set host {123.456.789.010}
set password password123
log_user 0
spawn oathtool --totp --base32 $secret
expect -re \\d+
sleep 400
set otp $expect_out(0,string)
spawn ssh -2 $username#$host
expect "*assword:*"
send "$password\n"
expect "Enter Google Authenticator code:"
send "$otp\n"
interact

First, test you ssh connection with:
ssh -v <auser>#<apassword>
That will validate the SSH session works.
Make sure to not use ssh -T ..., since you might need a terminal for expect commands to work.
Second, add at least an echo at the beginning of the script, to see if it is called:
puts "Script running\r"
Third, see if a bash script, with part of it using expect as in here, would work better in this case

Related

How do you pass serveral passwords in SCP using expect?

My purpose is control transferring files between two remote machines. If I could use key-pair it would be much easier but I can't choose the options but passing passwords.
Environments : Local(Mac), Remote_source(Linux), Remote_target(Linux)
Here it is my expect.sh. When I run it, source#source's password: pops up, then target#target's password: and nothing else. No files transferred, no stdout, no error message, just disconnected.
#!/usr/bin/expect
set timeout -1
spawn scp -3 scp://remote_source_user#host:port/home/source/test.txt scp://remote_target_user#host:port/home/target/
expect "remote_source_user#host's password:"
send "SOURCE_PASSWORD\r"
expect "remote_target_user#host's password:"
send "TARGET_PASSWORD\r"
expect eof
When I change the sequence the password (meaning send target password first rather than sending source password first.) it occurs error, so I guess it is working but I have got no idea what is going on internally.
I have tried sshpass but it is not working with several passwords.
I debugged it with -v flag and found out that Connection works perfectly but the problem is the directory.
# in debugging mode
Sink: scp: home/username/test.txt: No such file or directory
It seems not recognizing /home/username/test.txt at the beginning.
so the code should be like below:
#!/usr/bin/expect
set timeout -1
spawn scp -3 scp://remote_source_user#host:port/~/test.txt scp://remote_target_user#host:port/~/
expect "remote_source_user#host's password:"
send "SOURCE_PASSWORD\r"
expect "remote_target_user#host's password:"
send "TARGET_PASSWORD\r"
expect eof
Do not explicitly write your home directory /home/username/ but use /~/.
# The Result
debug1: Sending command: scp -v -r -f ~/test.txt
Sending file modes: C0000 00 test.txt
Sink: C0000 00 test.txt

How to check SSH credentials are working or not

I have a large number of devices around 300
I have different creds to them
SSH CREDS, API CREDS
So as I cannot manually SSH to all those devices and check the creds are working or not
I am thinking of writing a script and pass the device IP's to the script and which gives me as yes as a result if the SSH creds are working and NO if not working.
I am new to all this stuff! details will be appreciated!
I will run this script on a server from where I can ssh to all the devices.
Your question isn't clear as to what sort of credentials you use for connecting to each host: do all hosts have the same connection method, for instance?
Let's assume that you use ssh's authorised keys method to log in to each host (i.e. you have a public key on each host within the ~/.ssh/authorized_keys file). You can run ssh with a do nothing command against each host and look at the exit code to see if the connection was successful.
HOST=1.2.3.4
ssh -i /path/to/my/private.key user#${HOST} true > /dev/null 2>&1
if [ $? -ne 0]; then echo "Error, could not connect to ${HOST}"; fi
Now it's just a case of wrapping this in some form of loop where you cycle through each host (and choose the right key for each host, perhaps you could name each private key after the name or IP address of the target host). The script will go out all those hosts for which a connection was not possible. Note that this script assumes that true is available on the target host, otherwise you could use ls or similar. We pipe all output to /dev/null/ as we're only interested in the ability to connect.
EDIT IN RESPONSE TO OP CLARIFICATION:
I'd strongly recommend not using username/password for login, as the username and password will likely be held in your script somewhere, or even in your shell history, if you run the command from the command line. If you must do this, then you could use expect or sshpass, as detailed here: https://srvfail.com/how-to-provide-ssh-password-inside-a-script-or-oneliner/
The ssh command shown does not spawn a shell, it literally logs in to the remote server, executes the command true (or ls, etc), then exits. You can use the return code ($? in bash) to check whether the command executed correctly. My example shows it printing out an error message for non-zero return codes, but to print out YES on successful connection, you could do this:
if [ $? -eq 0]; then echo "${HOST}: YES"; fi

Expect echo password in clear text

Automating psftp with bash/expect in cygwin.
I have a very minimal script file yftp.exp with code:
#!/usr/bin/expect -f
spawn psftp unixftpsrvr
expect "login as: "
send "myID\r"
expect "Password:"
send "Passw0rd\r"
expect "psftp>"
the output:
$ ./yftp.exp
spawn psftp unixftpsrvr
login as: myID
Using keyboard-interactive authentication.
Enter your UDS
Password: Passw0rd
Remote working directory is /home/myID
psftp>
The password is printed out as clear text!!!
if I run the command directly with psftp. here are the output:
$ psftp unixftpsrvr
login as: myID
Enter your UDS Password:
Remote working directory is /home/myID
psftp>
The password is not displayed at all.
This seems to be more an issue on the expect side.
I am not concerned the password in clear text in my expect script file, I am concerned the password in clear text in the output!
how can I supress the display of password in clear text?
The password may be sent too early before ECHO is turned off. So try adding sleep 1 after expect "Password:".
If that does not work then try like this:
expect "Password:"
log_user 0; # disable logging to stdout
send "password\r"
log_user 1

Using expect script to do an ssh from a remote machine

I am new to expect scripts and have a use case in which I need to do an ssh from a machine in which I have already done an ssh using expect script. This is my code snippet
#!/usr/bin/expect -f
set timeout 60
spawn ssh username#machine1.domain.com
expect "Password: "
send "Password\r"
send "\r" # This is successful. I am able to login successfully to the first machine
set timeout 60
spawn ssh username#machine2.domain.com #This fails
This takes a some amount of time and fails saying
ssh: connect to host machine2.domain.com port 22: Operation timed out. I understand that 22 is the default port on which ssh runs and I can manually override it by giving a -p option to ssh.
If I try to ssh independently without the expect script I get a prompt that asks me to enter (yes/no). From where is the correct port being picked up if I execute ssh directly without the expect script. If I do not need to enter the port number on shell why would it be needed to enter a port number if I am using an expect script.
That that point, you don't spawn a new ssh: spawn creates a new process on your local machine. You just send a command to the remote server
#!/usr/bin/expect -f
set timeout 60
spawn ssh username#machine1.domain.com
expect "Password: "
send "Password\r"
send "\r" # This is successful. I am able to login successfully to the first machine
# at this point, carry on scripting the first ssh session:
send "ssh username#machine2.domain.com\r"
expect ...

How to do remote ssh non-interactively

I am trying to connect to a remote host from my local host through the below command.But there was a setting in the remote host that soon after we login it will prompt to enter a badge ID,password and reason for logging in, because it was coded like that in profile file on remote-host How can I overcome those steps and login directly non-interactively, without disturbing the code in profile.
jsmith#local-host$ ssh -t -t generic_userID#remote-host
Enter your badgeID, < exit > to abort:
Enter your password for <badgeID> :
Enter a one line justification for your interactive login to generic_userID
Small amendment: to overcome remote server expect approach is required, but in case local script connects to bunch of remote servers, which configuration may be broken, just use SSH options:
ssh -f -q -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null USER#TARGETSYSTEM
This will omit ask for password in case there is no ssh_key setup, exit silently and continue with script/other hosts.
Puts ssh to background with -f, which is required when calling ssh command from sh (batch) file to remove local console redirect to remote input (implies -n).
Look into setting up a wrapper script around expect. This should do exactly what you're looking for.
Here are a few examples you can work from.
I have upvoted Marvin Pinto's answer because there is every reason to script this, in case there are other features in the profile that you need, such as Message of the Day motd.
However, there is a quick and dirty alternative if you don't want to make a script and you don't want other features from the profile. Depending on your preferred shell on the remote host, you can insist that the shell bypasses the profile files. For example, if bash is available on the remote host, you can invoke it with:
ssh -t -t generic_userID#remote-host bash --noprofile
I tested the above on the macOS 10.13 version of OpenSSH. Normally the command at the end of the ssh invocation is run non-interactively, but the -t flag allows bash to start an interactive shell.
Details are in the Start-up files section of the Bash Reference Manual.