I am using this code to add server to the known_hosts:
subprocess.Popen(['sshpass', '-p', password, 'ssh', '-o', 'StrictHostKeyChecking=no', add_key], stdout=subprocess.PIPE).communicate()[0]
This adds hostname to the known_hosts but the server hangs as it tries to enter into the host. I just want add hostname to the known_hosts and continue with my other codes. How can I do that? Thanks
This should do the job. This solution use the pexpect library which is a great way to automate commands. You basically call add_known_hosts with the host, user, password that you want added. it will try to ssh to that host and either enters the password or responds to the add to known hosts connection with a yes and then enters the password. Finally it cleanly exits the connection by sending the exit command. You can modify this and not require a username and password and just answer yes to the continue connecting question and then end the ssh process instead of continuing with the password prompt.
import pexpect, time
def add_known_hosts(host, user, password):
child = pexpect.spawn('ssh %s#%s' % (user, host))
i = child.expect(['.* password:', '.* continue connecting (yes/no)?'])
if i == 1:
child.sendline('yes')
child.expect('.* password:')
child.sendline(password)
child.expect('%s#%s' % (user, host))
time.sleep(1)
child.sendline('exit')
add_known_hosts('myhost', 'myusername', 'mypassword')
debugging
from the comments below it seems you are facing issues using pexpect on your system. A good way to just to do a simple test to confirm pexpect is working correctly with ssh is to run the code below. Fill in host, user with your appropriate settings and then run the code, you should be able to interact with the ssh session. At this point you can build up from here and see exactly what text you are expecting to get from ssh and what text you want to send in response.
import pexpect
host, user = 'myhost', 'myusername'
child = pexpect.spawn('ssh %s#%s' % (user, host))
child.interact()
Never mind, Solved it myself. Here's what I did:
test = subprocess.Popen(['sshpass', '-p', password, 'ssh', '-o', 'StrictHostKeyChecking=no', add_key])
time.sleep(5.0)
test.kill()
Thanks!
Related
I'm modifying a script in python to run in securecrt 8.5.2 in order to backup the running-config of some cisco ASR9K equipment I have in charge, but the script seems to end abruptly after the second sucessful ssh2 hop (2nd tab) and does not send the commands I scripted (the exit in this specifical example), here's the code I have, as I'd said it's a modified version of the one's in vandyke page for opening ssh2.
One important thing is that I have to tab each session of each individual routers, because it doesn't permit doing an ssh direct from the active cli, so I had to improvise and implement this "connect in TAB", I'm suspecting that the secureCRT doesn't know if it is in the new tab I've opened so, it doesn't know where to send the commands.
I was playing with the line 30, but it doesn't seem to have any effect. I was changing the expected text, but it doesn't seem to recognize the correct tab or doesn't read the correct one.
Personal Background: A complete beginner in the python language.
# $language = "python"
# $interface = "1.0"
# Connect to an SSH server using the SSH2 protocol. Specify the
# username and password and hostname on the command line as well as
# some SSH2 protocol specific options.
host = "X.X.X.a"
host2 = "X.X.X.b"
def main():
crt.Screen.Synchronous = True
# Prompt for a username and password instead of embedding it in a script...
#
usr = crt.Dialog.Prompt("Enter the user name for" + host, "Username", "", True)
passwd = crt.Dialog.Prompt("Enter TACACS+ for" + host, "Login", "", True)
# Build a command-line string to pass to the Connect method.
cmd = "/SSH2 /L %s /PASSWORD %s /C AES-128-CTR /M SHA1 %s" % (usr, passwd, host)
crt.Session.Connect(cmd)
crt.Screen.WaitForString("X.X.X.a#")
crt.Screen.Send("copy running-config tftp:\r")
crt.Screen.WaitForString("Host name or IP address (control-c to abort): []?")
crt.Screen.Send("tftpserver.com\r")
crt.Screen.WaitForString("Destination file name (control-c to abort): [running-config]?")
crt.Screen.Send("X.X.X.a_running_config\r")
crt.Screen.WaitForString("X.X.X.a")
cmd2 = "/SSH2 /L %s /PASSWORD %s /C AES-128 /M SHA1 %s" % (usr, passwd, host2)
crt.Session.ConnectInTab(cmd2)
crt.Screen.WaitForString("X.X.X.b#")
crt.Screen.Send("exit\r")
main()
crt.Session.ConnectInTab(cmd2)
It connects to the equipment in a new tab, but what I expect is that the script will keep doing the same it did for the host1 (X.X.X.a) and send the same boring stuff to the host2 (X.X.X.b) via ssh2 tab, and continue the itterative process until I do this for all the equipments I need.
Thanks for reading me.
Well it's not even funny easy was to solve this very sub-optimal code or script but it was not much of a problem, the only thing is that I had to dissconect to the previous session when I inyected all the commands, so in order to put the cursor on the new tab, the previous session must be dissconected first.
The solution?
crt.Session.Disconnect()
I'm using a python script to manage ssh fingerprint problems after a workstation(s) is reimaged.
I attempt to connect with ssh, and if I get a any warnings I deal with them.
However, if there are no errors, then I am asked for a password to connect. At this point I want to terminate the process. However, the script hangs on the password request.
Here's the method:
def ssh_fingerprint_changed(node):
"""
Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
It does this by attempting to connect via ssh and inspecting stdout for an error message.
:param node: the ip or hostname of the node
:return: True if the node's fingerprint doesn't match the client's records. Else False.
"""
changed = False
cmd = ["ssh", "-q", ADMIN_USER + "#" + node, "exit"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
print("Checking for fingerprint changes")
for line in proc.stdout: # loop on lines
print("in for loop") # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
if b"Offending key" in line:
print("Offending key found.")
proc.stdin.write(b"no\n") # don't connect
changed = True
elif b"REMOTE HOST IDENTIFICATION HAS CHANGED!" in line:
print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
changed = True
print(changed) # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
if not changed: # then everything's good, but it will be waiting for a password to connect
print("Good to go, terminating ssh test.")
rc = proc.terminate()
else:
rc = proc.wait()
return changed
If I run this from the terminal ./my_python_script.py, I have the problems. Oddly, if I run in PyCharm, it doesn't hang on the password request and terminates shh, continuing with the script as expected.
The easy answer is simply to tell ssh that you don't want to support password authentication at all; you'll still get the messages you want if the host key is changed, but you won't ever have the process hanging waiting for a password to be entered.
cmd = ['ssh',
'-o', 'PasswordAuthentication no', ### <-- THIS LINE HERE
'-o', 'StrictHostKeyChecking yes', ### also, never modify known_hosts
'-q',
'%s#%s' % (ADMIN_USER, + node),
'exit']
If you did not want to process other prompts, I would suggest setting stdin=subprocess.DEVNULL (in Python 3) or passing the -n argument to ssh to prevent stdin from being passed to the process at all.
I am using this code for executing command on remote server.
import subprocess
import sys
COMMAND="ls"
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
When I try to execute this script, I get prompt for password. Is there any way I could avoid it, for example, can I enter password in script somehow? Also, password should be encrypted somehow so that people who have access to the script cannot see it.
Why make it so complicated? Here's what I suggest:
1) Create a ssh config section in your ~/.ssh/config file:
Host myserver
HostName 50.50.50.12 (fill in with your server's ip)
Port xxxx (optional)
User me (your username for server)
2) If you have generated your ssh keypair do it now (with ssh-keygen). Then upload with:
$ ssh-copy-id myserver
3) Now you can use subprocess with ssh. For example, to capture output, I call:
result = subprocess.check_output(['ssh', 'myserver', 'cat', 'somefile'])
Simple, robust, and the only time a password is needed is when you copy the public key to the server.
BTW, you code will probably work just fine as well using these steps.
One way is to create a public key, put it on the server, and do ssh -i /path/to/pub/key user#host or use paramiko like this:
import paramiko
import getpass
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
p = getpass.getpass()
ssh.connect('hostname', username='user', password=p)
stdin, stdout, stderr = ssh.exec_command('ls')
print stdout.readlines()
ssh.close()
You should use pexpect or paramiko to connect to remote machine,then spawn a child ,and then run subprocess to achieve what you want.
Here's what I did when encountering this issue before:
Set up your ssh keys for access to the server.
Set up an alias for the server you're accessing. Below I'll call it remote_server.
Put the following two lines at the end of ~/.bash_profile.
eval $(ssh-agent -s)
ssh-add
Now every time you start your shell, you will be prompted for a passphrase. By entering it, you will authenticate your ssh keys and put them 'in hand' at the start of your bash session. For the remainder of your session you will be able to run commands like
ssh remote_server ls
without being prompted for a passphrase. Here ls will run on the remote server and return the results to you. Likewise your python script should run without password prompt interruption if you execute it from the shell.
You'll also be able to ssh to the server just by typing ssh remote_server without having to enter your username or password every time.
The upside to doing it this way is that you should be doing this anyway to avoid password annoyances and remembering funky server names :) Also you don't have to worry about having passwords saved anywhere in your script. The only potential downside is that if you want to share the python script with others, they'll have to do this configuring as well (which they should anyway).
You don't really need something like pexpect to handle this. SSH keys already provide a very good and secure solution to this sort of issue.
The simplest way to get the results you want would probably be to generate an ssh key and place it in the .ssh folder of your device. I believe github has a pretty good guide to doing that, if you look into it. Once you set up the keys correctly on both systems, you won't actually have to add a single line to your code. When you don't specify a password it will automatically use the key to authenticate you.
While subprocess.Popen might work for wrapping ssh access, this is not the preferred way to do so.
I recommend using paramiko.
import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(server, username=user,password=password)
...
ssh_client.close()
And If you want to simulate a terminal, as if a user was typing:
chan=ssh_client.invoke_shell()
def exec_cmd(cmd):
"""Gets ssh command(s), execute them, and returns the output"""
prompt='bash $' # the command line prompt in the ssh terminal
buff=''
chan.send(str(cmd)+'\n')
while not chan.recv_ready():
time.sleep(1)
while not buff.endswith(prompt):
buff+=ssh_client.chan.recv(1024)
return buff[:len(prompt)]
Example usage: exec_cmd('pwd')
If you don't know the prompt in advance, you can set it with:
chan.send('PS1="python-ssh:"\n')
You could use following.
import subprocess
import sys
COMMAND="ls"
ssh = subprocess.Popen("powershell putty.exe user#HOST -pw "password", stdout=PIPE, stdin=PIPE, stderr=STDOUT)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
I'm trying to use the pexpect module pxssh to log in into my one of my server. I get password refused. I think I know what it is the problem, but can't figure out how to fix it. The issue is that there is a welcome banner when I log in into the server(Changing the banner is not an option) and the pexpect get confuse. Here is my code:
import pxssh
ssh = pxssh.pxssh()
ssh.login('192.168.1.10', 'username', 'password')
I'm expecting a 'password:', but pxssh is expecting original_prompt='[#$]'and those are symbols and in the banner the are couple of '.'
Any help, I will appreciate. Thanks
This error came for ssh is lock.so open the terminals and execute that command
xxxx#toad:~$ rm .ssh/known_hosts
remove the known_hosts
another options is you login in windows means check command prompt.
if you try to login in windows means use for pexpect
child = pexpect.spawn('ssh tiger#172.16.0.190 -p 8888')
child.logfile = open("/tmp/mylog", "w")
print child.before
child.expect('.*Are you sure you want to continue connecting (yes/no)?')
child.sendline("yes")
child.expect(".*assword:")
child.sendline("tiger\r")
child.expect('Press any key to continue...')
child.send('\r')
child.expect('C:\Users\.*>')
child.sendline('dir')
child.prompt('C:\Users\.*>')
pxssh uses the shell prompt to synchronize output from the remote host.
In order to make this more robust it sets the shell prompt to something more
unique than just $ or #. This should work on most Borne/Bash or Csh style
shells.
Refer
http://www.pythonforbeginners.com/code-snippets-source-code/ssh-connection-with-python/
I don't know if you are right on your diagnostic, I don't think the banner can cause that but a wrong prompt can do it for sure. Look at the code to be sure.
http://www.opensource.apple.com/source/lldb/lldb-69/test/pexpect-2.4/pxssh.py
Especially that part:
elif i==2: # password prompt again
# For incorrect passwords, some ssh servers will
# ask for the password again, others return 'denied' right away.
# If we get the password prompt again then this means
# we didn't get the password right the first time.
self.close()
raise ExceptionPxssh ('password refused')
Disclaimer: this is not my code but Pxssh code.
Why not using paramiko (http://www.lag.net/paramiko/) or pexpect directly?
I'm trying to run an scp (secure copy) command using subprocess.Popen. The login requires that I send a password:
from subprocess import Popen, PIPE
proc = Popen(['scp', "user#10.0.1.12:/foo/bar/somefile.txt", "."], stdin = PIPE)
proc.stdin.write(b'mypassword')
proc.stdin.flush()
This immediately returns an error:
user#10.0.1.12's password:
Permission denied, please try again.
I'm certain the password is correct. I easily verify it by manually invoking scp on the shell. So why doesn't this work?
Note, there are many similar questions to this, asking about subprocess.Popen and sending a password for automated SSH or FTP login:
How can I set a users password in linux from a python script?
Use subprocess to send a password
The answer(s) to these questions don't work and/or don't apply because I am using Python 3.
Here's a function to ssh with a password using pexpect:
import pexpect
import tempfile
def ssh(host, cmd, user, password, timeout=30, bg_run=False):
"""SSH'es to a host using the supplied credentials and executes a command.
Throws an exception if the command doesn't return 0.
bgrun: run command in the background"""
fname = tempfile.mktemp()
fout = open(fname, 'w')
options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'
if bg_run:
options += ' -f'
ssh_cmd = 'ssh %s#%s %s "%s"' % (user, host, options, cmd)
child = pexpect.spawn(ssh_cmd, timeout=timeout) #spawnu for Python 3
child.expect(['[pP]assword: '])
child.sendline(password)
child.logfile = fout
child.expect(pexpect.EOF)
child.close()
fout.close()
fin = open(fname, 'r')
stdout = fin.read()
fin.close()
if 0 != child.exitstatus:
raise Exception(stdout)
return stdout
Something similar should be possible using scp.
The OpenSSH scp utility invokes the ssh program to make the SSH connection to the remote host, and the ssh process handles authentication. The ssh utility doesn't accept a password on the command line or on its standard input. I believe this is a deliberate decision on the part of the OpenSSH developers, because they feel that people should be using more secure mechanisms like key-based authentication. Any solution for invoking ssh is going to follow one of these approaches:
Use an SSH key for authentication, instead of a password.
Use sshpass, expect, or a similar tool to automate responding to the password prompt.
Use (abuse) the SSH_ASKPASS feature to get ssh to get the password by invoking another command, described here or here, or in some of the answers here.
Get the SSH server administrator to enable host-based authentication and use that. Note that host-based authentication is only suitable for certain network environments. See additional notes here and here.
Write your own ssh client using perl, python, java, or your favorite language. There are ssh client libraries available for most modern programming languages, and you'd have full control over how the client gets the password.
Download the ssh source code and build a modified version of ssh that works the way you want.
Use a different ssh client. There are other ssh clients available, both free and commercial. One of them might suit your needs better than the OpenSSH client.
In this particular case, given that you're already invoking scp from a python script, it seems that one of these would be the most reasonable approach:
Use pexpect, the python expect module, to invoke scp and feed the password to it.
Use paramiko, the python ssh implementation, to do this ssh task instead of invoking an outside program.
The second answer you linked suggests you use Pexpect (which is usually the right way to go about interacting with command line programs that expect input).
Pexpect has a library for exactly this: pxssh
http://pexpect.readthedocs.org/en/stable/api/pxssh.html
import pxssh
import getpass
try:
s = pxssh.pxssh()
hostname = raw_input('hostname: ')
username = raw_input('username: ')
password = getpass.getpass('password: ')
s.login(hostname, username, password)
s.sendline('uptime') # run a command
s.prompt() # match the prompt
print(s.before) # print everything before the prompt.
s.logout()
except pxssh.ExceptionPxssh as e:
print("pxssh failed on login.")
print(e)
I guess some applications interact with the user using stdin and some applications interact using terminal. In this case when we write the password using PIPE we are writing to stdin. But SCP application reads the password from terminal. As subprocess cannot interact with user using terminal but can only interact using stdin we cannot use the subprocess module and we must use pexpect for copying the file using scp.
Feel free for corrections.
Here is my scp function based on pexpect. It can handle wildcards (i.e. multiple file transfer), in addition to the password.
To handle multiple file transfer (i.e. wildcards), we need to issue a command via a shell. Refer to pexpect FAQ.
import pexpect
def scp(src,user2,host2,tgt,pwd,opts='',timeout=30):
''' Performs the scp command. Transfers file(s) from local host to remote host '''
cmd = f'''/bin/bash -c "scp {opts} {src} {user2}#{host2}:{tgt}"'''
print("Executing the following cmd:",cmd,sep='\n')
tmpFl = '/tmp/scp.log'
fp = open(tmpFl,'wb')
childP = pexpect.spawn(cmd,timeout=timeout)
try:
childP.sendline(cmd)
childP.expect([f"{user2}#{host2}'s password:"])
childP.sendline(pwd)
childP.logfile = fp
childP.expect(pexpect.EOF)
childP.close()
fp.close()
fp = open(tmpFl,'r')
stdout = fp.read()
fp.close()
if childP.exitstatus != 0:
raise Exception(stdout)
except KeyboardInterrupt:
childP.close()
fp.close()
return
print(stdout)
It can be used this way:
params = {
'src': '/home/src/*.txt',
'user2': 'userName',
'host2': '192.168.1.300',
'tgt': '/home/userName/',
'pwd': myPwd(),
'opts': '',
}
scp(**params)
This is a rewrite I did from the code posted by #Kobayashi and #sjbx but for the purposes of doing scp requests, so credit to those two.
def scp(host, user, password, from_dir, to_dir, timeout=300, recursive=False):
fname = tempfile.mktemp()
fout = open(fname, 'w')
scp_cmd = 'scp'
if recursive:
scp_cmd += ' -r'
scp_cmd += f' {user}#{host}:{from_dir} {to_dir}'
child = pexpect.spawnu(scp_cmd, timeout=timeout)
child.expect(['[pP]assword: '])
child.sendline(str(password))
child.logfile = fout
child.expect(pexpect.EOF)
child.close()
fout.close()
fin = open(fname, 'r')
stdout = fin.read()
fin.close()
if 0 != child.exitstatus:
raise Exception(stdout)
return stdout