summaryrefslogtreecommitdiffstats
path: root/third_party/pexpect/pxssh.py
diff options
context:
space:
mode:
authorbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 16:35:15 +0000
committerbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 16:35:15 +0000
commit2dbd513b86a1105f684c1fe2b031e5e937c53c52 (patch)
tree3947ef34c3b48b8b9795e087907fdd7137923861 /third_party/pexpect/pxssh.py
parent7d489649a0912884680165e9705848fae5ba33e0 (diff)
downloadchromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.zip
chromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.tar.gz
chromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.tar.bz2
Roll third_party/pexpect 509:533
The author kindly updated the license headers as requested by nduca. One of the files requires more context for the license to be detected, so increase it to 100 (instead of the default 60). BUG=156113 TEST=tools/checklicenses/checklicenses.py --root . -vv third_party/pexpect Review URL: https://chromiumcodereview.appspot.com/11360098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167398 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/pexpect/pxssh.py')
-rw-r--r--third_party/pexpect/pxssh.py86
1 files changed, 63 insertions, 23 deletions
diff --git a/third_party/pexpect/pxssh.py b/third_party/pexpect/pxssh.py
index d3f46ab..b1354b4 100644
--- a/third_party/pexpect/pxssh.py
+++ b/third_party/pexpect/pxssh.py
@@ -1,12 +1,29 @@
"""This class extends pexpect.spawn to specialize setting up SSH connections.
This adds methods for login, logout, and expecting the shell prompt.
-$Id: pxssh.py 487 2007-08-29 22:33:29Z noah $
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
"""
from pexpect import *
import pexpect
import time
+import os
__all__ = ['ExceptionPxssh', 'pxssh']
@@ -30,10 +47,10 @@ class pxssh (spawn):
shells.
Example that runs a few commands on a remote server and prints the result::
-
+
import pxssh
import getpass
- try:
+ try:
s = pxssh.pxssh()
hostname = raw_input('hostname: ')
username = raw_input('username: ')
@@ -71,11 +88,12 @@ class pxssh (spawn):
"""
def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None):
+
spawn.__init__(self, None, timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
self.name = '<pxssh>'
-
- #SUBTLE HACK ALERT! Note that the command to set the prompt uses a
+
+ #SUBTLE HACK ALERT! Note that the command that SETS the prompt uses a
#slightly different string than the regular expression to match it. This
#is because when you set the prompt the command will echo back, but we
#don't want to match the echoed command. So if we make the set command
@@ -91,14 +109,18 @@ class pxssh (spawn):
# used to set shell command-line prompt to UNIQUE_PROMPT.
self.PROMPT_SET_SH = "PS1='[PEXPECT]\$ '"
self.PROMPT_SET_CSH = "set prompt='[PEXPECT]\$ '"
- self.SSH_OPTS = "-o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
+ self.SSH_OPTS = ("-o'RSAAuthentication=no'"
+ + " -o 'PubkeyAuthentication=no'")
+# Disabling host key checking, makes you vulnerable to MITM attacks.
+# + " -o 'StrictHostKeyChecking=no'"
+# + " -o 'UserKnownHostsFile /dev/null' ")
# Disabling X11 forwarding gets rid of the annoying SSH_ASKPASS from
# displaying a GUI password dialog. I have not figured out how to
# disable only SSH_ASKPASS without also disabling X11 forwarding.
# Unsetting SSH_ASKPASS on the remote side doesn't disable it! Annoying!
#self.SSH_OPTS = "-x -o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
self.force_password = False
- self.auto_prompt_reset = True
+ self.auto_prompt_reset = True
def levenshtein_distance(self, a,b):
@@ -120,18 +142,25 @@ class pxssh (spawn):
current[j] = min(add, delete, change)
return current[n]
- def synch_original_prompt (self):
+ def sync_original_prompt (self):
"""This attempts to find the prompt. Basically, press enter and record
the response; press enter again and record the response; if the two
- responses are similar then assume we are at the original prompt. """
+ responses are similar then assume we are at the original prompt. This
+ is a slow function. It can take over 10 seconds. """
# All of these timing pace values are magic.
# I came up with these based on what seemed reliable for
# connecting to a heavily loaded machine I have.
+ self.sendline()
+ time.sleep(0.1)
# If latency is worse than these values then this will fail.
- self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
+ try:
+ # Clear the buffer before getting the prompt.
+ self.read_nonblocking(size=10000,timeout=1)
+ except TIMEOUT:
+ pass
time.sleep(0.1)
self.sendline()
time.sleep(0.5)
@@ -154,7 +183,7 @@ class pxssh (spawn):
### TODO: This is getting messy and I'm pretty sure this isn't perfect.
### TODO: I need to draw a flow chart for this.
- def login (self,server,username,password='',terminal_type='ansi',original_prompt=r"[#$]",login_timeout=10,port=None,auto_prompt_reset=True):
+ def login (self,server,username,password='',terminal_type='ansi',original_prompt=r"[#$]",login_timeout=10,port=None,auto_prompt_reset=True,ssh_key=None):
"""This logs the user into the given server. It uses the
'original_prompt' to try to find the prompt right after login. When it
@@ -171,7 +200,7 @@ class pxssh (spawn):
to guess when we have reached the prompt. Then we hope for the best and
blindly try to reset the prompt to something more unique. If that fails
then login() raises an ExceptionPxssh exception.
-
+
In some situations it is not possible or desirable to reset the
original prompt. In this case, set 'auto_prompt_reset' to False to
inhibit setting the prompt to the UNIQUE_PROMPT. Remember that pxssh
@@ -184,6 +213,12 @@ class pxssh (spawn):
ssh_options = ssh_options + ' ' + self.SSH_OPTS
if port is not None:
ssh_options = ssh_options + ' -p %s'%(str(port))
+ if ssh_key is not None:
+ try:
+ os.path.isfile(ssh_key)
+ except:
+ raise ExceptionPxssh ('private ssh key does not exist')
+ ssh_options = ssh_options + ' -i %s' % (ssh_key)
cmd = "ssh %s -l %s %s" % (ssh_options, username, server)
# This does not distinguish between a remote server 'password' prompt
@@ -192,7 +227,7 @@ class pxssh (spawn):
i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT, "(?i)connection closed by remote host"], timeout=login_timeout)
# First phase
- if i==0:
+ if i==0:
# New certificate -- always accept it.
# This is what you get if SSH does not have the remote host's
# public key stored in the 'known_hosts' cache.
@@ -210,14 +245,14 @@ class pxssh (spawn):
# This is weird. This should not happen twice in a row.
self.close()
raise ExceptionPxssh ('Weird error. Got "are you sure" prompt twice.')
- elif i==1: # can occur if you have a public key pair set to authenticate.
+ elif i==1: # can occur if you have a public key pair set to authenticate.
### TODO: May NOT be OK if expect() got tricked and matched a false prompt.
pass
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.
+ # we didn't get the password right the first time.
self.close()
raise ExceptionPxssh ('password refused')
elif i==3: # permission denied -- password was bad.
@@ -237,10 +272,10 @@ class pxssh (spawn):
elif i==6: # Connection closed by remote host
self.close()
raise ExceptionPxssh ('connection closed')
- else: # Unexpected
+ else: # Unexpected
self.close()
raise ExceptionPxssh ('unexpected login response')
- if not self.synch_original_prompt():
+ if not self.sync_original_prompt():
self.close()
raise ExceptionPxssh ('could not synchronize with original prompt')
# We appear to be in.
@@ -263,20 +298,25 @@ class pxssh (spawn):
self.expect(EOF)
self.close()
- def prompt (self, timeout=20):
+ def prompt (self, timeout=-1):
"""This matches the shell prompt. This is little more than a short-cut
to the expect() method. This returns True if the shell prompt was
- matched. This returns False if there was a timeout. Note that if you
- called login() with auto_prompt_reset set to False then you should have
- manually set the PROMPT attribute to a regex pattern for matching the
- prompt. """
+ matched. This returns False if a timeout was raised. Note that if you
+ called login() with auto_prompt_reset set to False then before calling
+ prompt() you must set the PROMPT attribute to a regex that prompt()
+ will use for matching the prompt. Calling prompt() will erase the
+ contents of the 'before' attribute even if no prompt is ever matched.
+ If timeout is not given or it is set to -1 then self.timeout is used.
+ """
+ if timeout == -1:
+ timeout = self.timeout
i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
if i==1:
return False
return True
-
+
def set_unique_prompt (self):
"""This sets the remote prompt to something more unique than # or $.