X-Git-Url: https://code.grnet.gr/git/ncclient/blobdiff_plain/030b950d0e31f73141d6c8791c19316f6679d18a..c15671aa73d6c3d4824cbd5dfa5dc754dc727430:/ncclient/transport/ssh.py diff --git a/ncclient/transport/ssh.py b/ncclient/transport/ssh.py index ac32e45..3e2be10 100644 --- a/ncclient/transport/ssh.py +++ b/ncclient/transport/ssh.py @@ -14,6 +14,7 @@ import os import socket +import getpass from binascii import hexlify from cStringIO import StringIO from select import select @@ -24,27 +25,22 @@ from errors import AuthenticationError, SessionCloseError, SSHError, SSHUnknownH from session import Session import logging -logger = logging.getLogger('ncclient.transport.ssh') +logger = logging.getLogger("ncclient.transport.ssh") BUF_SIZE = 4096 MSG_DELIM = "]]>]]>" TICK = 0.1 def default_unknown_host_cb(host, fingerprint): - """An `unknown host callback` returns :const:`True` if it finds the key - acceptable, and :const:`False` if not. + """An unknown host callback returns `True` if it finds the key acceptable, and `False` if not. - This default callback always returns :const:`False`, which would lead to - :meth:`connect` raising a :exc:`SSHUnknownHost` exception. - - Supply another valid callback if you need to verify the host key - programatically. + This default callback always returns `False`, which would lead to :meth:`connect` raising a :exc:`SSHUnknownHost` exception. + + Supply another valid callback if you need to verify the host key programatically. - :arg host: the hostname that needs to be verified - :type host: string + *host* is the hostname that needs to be verified - :arg fingerprint: a hex string representing the host key fingerprint - :type fingerprint: string + *fingerprint* is a hex string representing the host key fingerprint, colon-delimited e.g. `"4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"` """ return False @@ -70,10 +66,7 @@ class SSHSession(Session): self._parsing_pos = 0 def _parse(self): - '''Messages ae delimited by MSG_DELIM. The buffer could have grown by a - maximum of BUF_SIZE bytes everytime this method is called. Retains state - across method calls and if a byte has been read it will not be - considered again. ''' + "Messages ae delimited by MSG_DELIM. The buffer could have grown by a maximum of BUF_SIZE bytes everytime this method is called. Retains state across method calls and if a byte has been read it will not be considered again." delim = MSG_DELIM n = len(delim) - 1 expect = self._parsing_state @@ -114,11 +107,9 @@ class SSHSession(Session): self._parsing_pos = self._buffer.tell() def load_known_hosts(self, filename=None): - """Load host keys from a :file:`known_hosts`-style file. Can be called multiple - times. + """Load host keys from an openssh :file:`known_hosts`-style file. Can be called multiple times. - If *filename* is not specified, looks in the default locations i.e. - :file:`~/.ssh/known_hosts` and :file:`~/ssh/known_hosts` for Windows. + If *filename* is not specified, looks in the default locations i.e. :file:`~/.ssh/known_hosts` and :file:`~/ssh/known_hosts` for Windows. """ if filename is None: filename = os.path.expanduser('~/.ssh/known_hosts') @@ -139,49 +130,34 @@ class SSHSession(Session): self._transport.close() self._connected = False - def connect(self, host, port=830, timeout=None, - unknown_host_cb=default_unknown_host_cb, - username=None, password=None, - key_filename=None, allow_agent=True, look_for_keys=True): - """Connect via SSH and initialize the NETCONF session. First attempts - the publickey authentication method and then password authentication. + # REMEMBER to update transport.rst if sig. changes, since it is hardcoded there + def connect(self, host, port=830, timeout=None, unknown_host_cb=default_unknown_host_cb, + username=None, password=None, key_filename=None, allow_agent=True, look_for_keys=True): + """Connect via SSH and initialize the NETCONF session. First attempts the publickey authentication method and then password authentication. - To disable attemting publickey authentication altogether, call with - *allow_agent* and *look_for_keys* as :const:`False`. This may be needed - for Cisco devices which immediately disconnect on an incorrect - authentication attempt. + To disable attempting publickey authentication altogether, call with *allow_agent* and *look_for_keys* as `False`. - :arg host: the hostname or IP address to connect to - :type host: `string` + *host* is the hostname or IP address to connect to - :arg port: by default 830, but some devices use the default SSH port of 22 so this may need to be specified - :type port: `int` + *port* is by default 830, but some devices use the default SSH port of 22 so this may need to be specified - :arg timeout: an optional timeout for the TCP handshake - :type timeout: `int` + *timeout* is an optional timeout for socket connect - :arg unknown_host_cb: called when a host key is not recognized - :type unknown_host_cb: see :meth:`signature ` + *unknown_host_cb* is called when the server host key is not recognized. It takes two arguments, the hostname and the fingerprint (see the signature of :func:`default_unknown_host_cb`) - :arg username: the username to use for SSH authentication - :type username: `string` + *username* is the username to use for SSH authentication - :arg password: the password used if using password authentication, or the passphrase to use for unlocking keys that require it - :type password: `string` + *password* is the password used if using password authentication, or the passphrase to use for unlocking keys that require it - :arg key_filename: a filename where a the private key to be used can be found - :type key_filename: `string` + *key_filename* is a filename where a the private key to be used can be found - :arg allow_agent: enables querying SSH agent (if found) for keys - :type allow_agent: `bool` + *allow_agent* enables querying SSH agent (if found) for keys - :arg look_for_keys: enables looking in the usual locations for ssh keys (e.g. :file:`~/.ssh/id_*`) - :type look_for_keys: `bool` + *look_for_keys* enables looking in the usual locations for ssh keys (e.g. :file:`~/.ssh/id_*`) """ - if username is None: - raise SSHError("No username specified") - + username = getpass.getuser() + sock = None for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res @@ -197,7 +173,7 @@ class SSHSession(Session): continue break else: - raise SSHError("Could not open socket") + raise SSHError("Could not open socket to %s:%s" % (host, port)) t = self._transport = paramiko.Transport(sock) t.set_log_channel(logger.name) @@ -308,13 +284,9 @@ class SSHSession(Session): q = self._q try: while True: - # select on a paramiko ssh channel object does not ever return - # it in the writable list, so it channel's don't exactly emulate - # the socket api + # select on a paramiko ssh channel object does not ever return it in the writable list, so channels don't exactly emulate the socket api r, w, e = select([chan], [], [], TICK) - # will wakeup evey TICK seconds to check if something - # to send, more if something to read (due to select returning - # chan in readable list) + # will wakeup evey TICK seconds to check if something to send, more if something to read (due to select returning chan in readable list) if r: data = chan.recv(BUF_SIZE) if data: @@ -337,9 +309,5 @@ class SSHSession(Session): @property def transport(self): - """Underlying `paramiko.Transport - `_ - object. This makes it possible to call methods like set_keepalive on it. - """ + "Underlying `paramiko.Transport `_ object. This makes it possible to call methods like :meth:`~paramiko.Transport.set_keepalive` on it." return self._transport -