Ruby scripting - Telnet Hangs During Login - ruby

I am trying to do some basic scripting using ruby to log in to a windows machine via telnet and pull some files over using the dos command line ftp. When I do this manually everything goes swimmingly but when I try it via ruby I'm getting an error in the login call.
Here is my test program in its entirety:
require 'net/telnet'
tn = Net::Telnet::new("Host"=>"xxx.xxx.xxx.xxx", "Timeout"=>25, "Output_log"=>"output_log.log", "Dump_log"=> "dump_log.log", "Prompt"=>"C:.*>")
tn.login("administrator", "xxxxxxx") {}
tn.cmd('dir')
exit
The contents of output_log don't betray anything as being wrong:
Trying 208.10.202.187...
Connected to 208.10.202.187.
Welcome to Microsoft Telnet Service
login: administrator
password:
*===============================================================
Welcome to Microsoft Telnet Server.
*===============================================================
C:\Documents and Settings\Administrator>
Same for the dump_log which has very similar but awkwardly formatted contents. When I run the program it sits around for a while and then outputs the following error:
PS C:\code\tools\deployment> ruby test.rb
C:/Ruby/lib/ruby/1.8/net/telnet.rb:551:in `waitfor': timed out while waiting for more data (Timeout::Error)
from C:/Ruby/lib/ruby/1.8/net/telnet.rb:685:in `cmd'
from C:/Ruby/lib/ruby/1.8/net/telnet.rb:730:in `login'
from test.rb:3
Which leads me to suspect that the telnet class is not recognizing the command prompt. I've tried several different regex strings for the Prompt parameter, including the default and nothing seems to help.

I think the prompt field needs to be a regexp, not a string
Try
tn = Net::Telnet::new("Host"=>"xxx.xxx.xxx.xxx", "Timeout"=>25,
"Output_log"=>"output_log.log", "Dump_log"=> "dump_log.log",
"Prompt"=> /C:.*>/)

Related

Windows cmd simulate console input a command

I need to write a batch script which connects to a vpn automatically when username and password is saved somewhere (Ex: in a file). VPN client is openconnect which provides a CLI but the problem is user input needs to be provided interactively to the command in order for it to complete.
See the output below when I run :
openconnect <serverhostname>
OUTPUT
POST https://<serverhostname>/
Connected to <serverhostname>:443
SSL negotiation with <serverhostname>
Server certificate verify failed: signer not found
Certificate from VPN server "<serverhostname>" failed verification.
Reason: signer not found
To trust this server in future, perhaps add this to your command line:
--servercert pin-sha256:<somesha>
Enter 'yes' to accept, 'no' to abort; anything else to view:
So I basically have to type yes manually and press Enter (it also prompts for further input), this needs to be automated in a script. Also, it's worth noting that the output is suggesting to provide --server-cert option and I could do that but when it asks the password, there's no option for it.
I tried putting the input lines in a file and redirecting that to the stdin of the command (which did not work but same the method worked on zsh on linux)
openconnect <serverhostname> < inputfile.txt
I also tried piping to stdin of the command which also didn't work.
I think the particular command doesn't read from stdin but directly from the console somehow which I really don't know how, but I could find a bit of information about something called "CON" on cmd.
Any solution is highly appreciated.

Redirect input to a Java application inside a bash script

I am using the ftm cli by Oracle. When I run a command, it asks for a password by saying "Enter a password". I am writing a script which uses this command and so I want to enter the password programatically.
Here's what I have tried -
echo "password" | java -jar ftmcli.jar list
But this doesn't work. Any idea what to do to make it work?
Without being able to look into the source code of ftmcli, I presume that Oracle is using Console.readPassword() from the java.io.Console class. However, there is a snag with this function:
public final class Console
Methods to access the character-based console device, if any,
associated with the current Java virtual machine.
Whether a virtual machine has a console is dependent upon the
underlying platform and also upon the manner in which the virtual
machine is invoked. If the virtual machine is started from an
interactive command line without redirecting the standard input and
output streams then its console will exist and will typically be
connected to the keyboard and display from which the virtual machine
was launched. If the virtual machine is started automatically, for
example by a background job scheduler, then it will typically not have
a console.
If this virtual machine has a console then it is represented by a
unique instance of this class which can be obtained by invoking the
System.console() method. If no console device is available then an
invocation of that method will return null.
By piping/redirecting the stdout of echo to the JVM, the Java method System.console() will return null and hence not read anything from your redirection.
Look at the following questions which handle the same problem, but on Java side: "How to handle java passwd reading when System.console() returns null?" or How to pipe input to Java program with bash
On your side, there is more or less nothing you can really do. Executing echo $password | java -jar ftmcli.jar list or java -jar ftmcli.jar list <<< $password will always fail as long Oracle doesn't change the way how ftmcli reads the password from stdin.
If you are ready for a one time password setup, then follow the below steps.
run java -jar ftmcli.jar --save-auth-key
You will be prompted for teh password and once it is given, the file will be uploaded and a ftmclikeystore file is created under ftmcli folder.
Now as long as if you don't change the user, then ftmcli will take the password from this file.
Found this little but fantastic tool called expect does the magic:
$ ./expect.script
spawn java -cp /tmp/brm-test/oraclepki.jar:/tmp/brm-test/BRMActions.jar com.oracle.installer.brm.BRMInstallHelper 7 /tmp/brm-test/client upgC
Enter Password for the wallet:
$
Perhaps it's not very much visible in the snippet above, but it is working:
$ cat /tmp/brm-test/client/.wp
upgC=MyMag1cPa$$word#
What is in the expect.script?
$ cat expect.script
#!/usr/bin/expect
stty -echo
spawn java -cp /tmp/brm-test/oraclepki.jar:/tmp/brm-test/BRMActions.jar com.oracle.installer.brm.BRMInstallHelper 7 /tmp/brm-test/client upgC
expect "Enter Password for the wallet:"
send "MyMag1cPa$$word#\r"
interact
Seems this can be used also in Chef, see this cookbook.
I hope it will help,
Jarek

cygwin ssh via windows cmd removes double quotes

I've got two windows machines running the latest version of cygwin. I have OpenSSH configured on both of them, and password-less authentication has been set up for the remote machine. I can ssh into either machine without problems. All commands below are executed in cmd.exe.
System Specification (identical for both machines):
Cygwin version 1.7.32
Windows 7
ver from cmd returns "Microsoft Windows [Version 6.1.7601]"
R 2.14.1
The basic form of my problem is this. I have to start an executable on my remote machine. I must start this executable via ssh through windows command line, not cygwin. That executable has a couple parameters. One of these parameters needs to be encapsulated within double quotes (Because I am working with a third party package in R, which makes a call to system(), and one parameter expects a string). The actual parameter is -e "parallel:::.slaveRSOCK()"
The script.exe called below is the file Rscript.exe. This comes with any (to my knowledge) installation of R. I did not create it, compile it, or anything. It is just utilized by the package I am trying to debug, as it allows you to execute R commands outside of the R console gui. The package I am trying to debug is "parallel", which I am using to run parallel processes on remote machines. I also did not have any hand in creating or compiling this code.
Maybe needless additional info, but the portion of the package I'm trying to debug is the function that spins up a process on a remote machine. This function develops a command, given some parameters, and executes this command in cmd.exe. I'm trying to replicate the command and manually execute, as when running through the actual package the process simply hangs.
If I were starting the executable on my machine, I would do the following, in windows cmd.
C:\Path\script.exe -e "parallel:::.slaveRSOCK()"
And this works fine. Establishing an ssh connection to the remote machine and subsequently running this command (changing C to c) also works.
But, when I make the following call for starting this script on the remote machine from my machine
ssh remoteHost c:/Path/script.exe -e "parallel:::.slaveRSOCK()"
I get the following error
bash: -c: line 0: syntax error near unexpected token '('
bash: -c: line 0: 'c:/Path/script.exe -e parallel:::.slaveRSOCK()'
So I've lost the double quotes, obviously I'm not escaping them correctly. I've tried the following call. which was close
ssh remoteHost c:/Path/script.exe -e \"parallel:::.slaveRSOCK()\"
but the second line of the error gave me
bash: -c: line 0: 'c:/Path/script.exe -e \parallel:::.slaveRSOCK()"'
Doesn't make a whole lot of sense to me, as I managed to escape the second quote but the first disappears, and I'm left with a \ before parallel.
EDIT
This one, as suggested in one of the answers
ssh remoteHost "c:/Path/script.exe -e \"parallel:::.slaveRSOCK()\""
gave me the following error
bash: -c: line 0: 'c:/Path/script.exe -e \parallel:::.slaveRSOCK()\'
Also quite an odd result, we lose both double quotes but keep the escapes
I've also tried various combinations of double quotes (single quotes) around the whole command after ssh remoteHost, and using the ^ to escape , but now it has pretty much turned into taking shots in the dark, so I thought it may be a good idea to turn to people more knowledgeable than me.
Any help or insight that can be provided is much appreciated. If there are any questions let me know.
EDIT 2
Here are some simple examples of the odd escaping that's going on.
Call:
ssh otherhost echo \"hello()\"
Returns:
bash: -c: line 0: unexpected EOF while looking for matching '"'
bash: -c: line 0: syntax error: unexpected end of file
Call:
ssh otherhost echo \"hello()"
Returns:
hello()
Call:
ssh otherhost echo '\"hello()\" '
Returns:
"hello()"
Call:
ssh otherhost echo "\"hello()\""
Returns:
hello\(\)
Alternatively, an explanation of this behavior would be appreciated.
I think you want:
ssh remoteHost "c:/Path/script.exe -e \"parallel:::.slaveRSOCK()\""
I honestly can't fully explain the reasoning behind the quoting (or what's screwing it up if it's a bug), but I think this will work for you:
ssh remoteHost "c:/Path/script.exe -e \"parallel:::.slaveRSOCK\(\)\""
The complication seems to be the following sequence of things parsing the command line(s):
Windows cmd.exe on the local machine gets and parses the whole thing
ssh sends the "c:/Path/script.exe -e \"parallel:::.slaveRSOCK()\"" portion to sshd on the remote Windows host. I'm not sure in what form sshd gets this command line, or exactly what transformations it might do to it.
sshd apparently invokes bash to run the command (thorough some cygwin mechanism?). Again, I'm not sure of the exact form the command line that gets to bash.
bash gets confused unless the parens are escaped, and the backslashes seem to get far enough through this assembly line of processes to make bash on the remote windows-with-cygwin machine happy.

Execute multiple commands via SSH and PowerShell

I successfully managed to connect to a Cisco IE-2000-L switch via SSH. I used the Renci SSH.NET library.
Starting guide: http://vwiki.co.uk/SSH_Client_(PowerShell)
My working code is
# Load SSH library (for .NET 4.0 and PowerShell 3)
$DllPath = "D:\temp\Renci.SshNet.dll"
[void][reflection.assembly]::LoadFrom( (Resolve-Path $DllPath) )
# Connect to switch (Cisco IE2000-L) with IP, port, username, password
$SshClient = New-Object Renci.SshNet.SshClient('172.20.91.30', 22, 'admin', 'mypassword')
$SshClient.Connect()
# execute one command on Cisco switch
$SshCommand = $SshClient.RunCommand('show arp')
# show result
$SshCommand.Result
# close SSH connection
$SshCommand.Dispose()
$SshClient.Disconnect()
$SshClient.Dispose()
My problem is
The above code sends just one command. But I want to execute several commands consecutively without closing and reopening a session.
If I add a second command right after the first one
# execute one command on Cisco switch
$SshCommand = $SshClient.RunCommand('show arp')
$SshCommand = $SshClient.RunCommand('show start')
...the script hangs and never finishes. What am I doing wrong?
Minor relevant information
My main goal is to send multiple commands at once to a Cisco switch
I already tried Plink together with batch cmd input. It's not reliable enough. It works sometimes and sometimes not.
I already tried telnet scripting. Too awkward.

How to enter a password into another process prompt from Ruby

I am writing an application that needs to run command on a remote Raspberry PI using a revssh script. revssh is a custom script that implements to some level the Revssh protocol concepts. it uses ssh reverse tunneling to send commands from the server to the clients.
I am using Ruby 2.1, I tried to do this using IO.popen but it does not work, so I tried the following:
# revssh (short for reverse ssh ) enables the execution of remote commands
# from the server on connected clients, like the 'psu_pi_analytics' here. but it requires
# to enter a root password each time you want to run a command using 'revssh -c'
IO.popen('revssh -c psu_pi_analytics uname -a', 'w+') do|io|
io.puts 'password' # enter the password when prompted
puts io.gets
end
this code work if the command to execute run on the local machine, but not in my case.
So any thoughts, or suggestions.
What important here is how to deal with the new connection created by the revssh script using ssh, which is managed in the terminal if the script is run directly from the terminal.
Edit:
By not work I mean it still prompts for the password, even if I puts the password to the io.
You can use an Expect-like library (e.g. RExpect, Expect4r) for interacting with other processes.
Another question related to this: Is there an Expect equivalent gem for Ruby?

Resources