PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/create_conn.py

https://gitlab.com/pineiden/gnc
Python | 329 lines | 271 code | 36 blank | 22 comment | 12 complexity | 0d4b565ad9b251545a98485ea5cfa15c MD5 | raw file
  1. import asyncio
  2. import getpass
  3. import io
  4. import os
  5. import socket
  6. import sys
  7. import time
  8. from collections import OrderedDict
  9. from .agent import connect_agent
  10. from .auth import lookup_client_auth
  11. from .auth import get_server_auth_methods, lookup_server_auth
  12. from .auth_keys import read_authorized_keys
  13. from .channel import SSHClientChannel, SSHServerChannel
  14. from .channel import SSHTCPChannel, SSHUNIXChannel, SSHAgentChannel
  15. from .cipher import get_encryption_algs, get_encryption_params, get_cipher
  16. from .client import SSHClient
  17. from .compression import get_compression_algs, get_compression_params
  18. from .compression import get_compressor, get_decompressor
  19. from .constants import DEFAULT_LANG
  20. from .constants import DISC_BY_APPLICATION, DISC_CONNECTION_LOST
  21. from .constants import DISC_KEY_EXCHANGE_FAILED, DISC_HOST_KEY_NOT_VERIFYABLE
  22. from .constants import DISC_MAC_ERROR, DISC_NO_MORE_AUTH_METHODS_AVAILABLE
  23. from .constants import DISC_PROTOCOL_ERROR, DISC_SERVICE_NOT_AVAILABLE
  24. from .constants import EXTENDED_DATA_STDERR
  25. from .constants import MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG
  26. from .constants import MSG_SERVICE_REQUEST, MSG_SERVICE_ACCEPT, MSG_EXT_INFO
  27. from .constants import MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_CONFIRMATION
  28. from .constants import MSG_CHANNEL_OPEN_FAILURE, MSG_CHANNEL_WINDOW_ADJUST
  29. from .constants import MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA
  30. from .constants import MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST
  31. from .constants import MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE
  32. from .constants import MSG_KEXINIT, MSG_NEWKEYS, MSG_KEX_FIRST, MSG_KEX_LAST
  33. from .constants import MSG_USERAUTH_REQUEST, MSG_USERAUTH_FAILURE
  34. from .constants import MSG_USERAUTH_SUCCESS, MSG_USERAUTH_BANNER
  35. from .constants import MSG_USERAUTH_FIRST, MSG_USERAUTH_LAST
  36. from .constants import MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS
  37. from .constants import MSG_REQUEST_FAILURE
  38. from .constants import OPEN_ADMINISTRATIVELY_PROHIBITED, OPEN_CONNECT_FAILED
  39. from .constants import OPEN_UNKNOWN_CHANNEL_TYPE
  40. from .forward import SSHForwarder
  41. from .kex import get_kex_algs, get_kex
  42. from .known_hosts import match_known_hosts
  43. from .listener import SSHTCPClientListener, create_tcp_forward_listener
  44. from .listener import SSHUNIXClientListener, create_unix_forward_listener
  45. from .logging import logger
  46. from .mac import get_mac_algs, get_mac_params, get_mac
  47. from .misc import ChannelOpenError, DisconnectError, PasswordChangeRequired
  48. from .misc import async_context_manager, ensure_future, ip_address
  49. from .misc import load_default_keypairs, map_handler_name
  50. from .packet import Boolean, Byte, NameList, String, UInt32, UInt64
  51. from .packet import PacketDecodeError, SSHPacket, SSHPacketHandler
  52. from .process import PIPE, SSHClientProcess
  53. from .public_key import CERT_TYPE_HOST, CERT_TYPE_USER, KeyImportError
  54. from .public_key import get_public_key_algs, get_certificate_algs
  55. from .public_key import decode_ssh_public_key, decode_ssh_certificate
  56. from .public_key import load_keypairs, load_public_keys
  57. from .saslprep import saslprep, SASLPrepError
  58. from .server import SSHServer
  59. from .sftp import SFTPClient, SFTPServer, SFTPClientHandler
  60. from .stream import SSHClientStreamSession, SSHServerStreamSession
  61. from .stream import SSHTCPStreamSession, SSHUNIXStreamSession
  62. from .stream import SSHReader, SSHWriter
  63. # SSH default port
  64. _DEFAULT_PORT = 22
  65. # SSH service names
  66. _USERAUTH_SERVICE = b'ssh-userauth'
  67. _CONNECTION_SERVICE = b'ssh-connection'
  68. # Default rekey parameters
  69. _DEFAULT_REKEY_BYTES = 1 << 30 # 1 GiB
  70. _DEFAULT_REKEY_SECONDS = 3600 # 1 hour
  71. # Default login timeout
  72. _DEFAULT_LOGIN_TIMEOUT = 120 # 2 minutes
  73. # Default channel parameters
  74. _DEFAULT_WINDOW = 2 * 1024 * 1024 # 2 MiB
  75. _DEFAULT_MAX_PKTSIZE = 32768 # 32 kiB
  76. # Default line editor parameters
  77. _DEFAULT_LINE_HISTORY = 1000 # 1000 lines
  78. async def create_connection(client_factory, host, port=_DEFAULT_PORT, *,
  79. loop=None, tunnel=None, family=0, flags=0,
  80. local_addr=None, known_hosts=(), username=None,
  81. password=None, client_keys=(), passphrase=None,
  82. agent_path=(), agent_forwarding=False,
  83. client_version=(), kex_algs=(), encryption_algs=(),
  84. mac_algs=(), compression_algs=(), signature_algs=(),
  85. rekey_bytes=_DEFAULT_REKEY_BYTES,
  86. rekey_seconds=_DEFAULT_REKEY_SECONDS):
  87. """Create an SSH client connection
  88. This function is a coroutine which can be run to create an outbound SSH
  89. client connection to the specified host and port.
  90. When successful, the following steps occur:
  91. 1. The connection is established and an :class:`SSHClientConnection`
  92. object is created to represent it.
  93. 2. The ``client_factory`` is called without arguments and should
  94. return an :class:`SSHClient` object.
  95. 3. The client object is tied to the connection and its
  96. :meth:`connection_made() <SSHClient.connection_made>` method
  97. is called.
  98. 4. The SSH handshake and authentication process is initiated,
  99. calling methods on the client object if needed.
  100. 5. When authentication completes successfully, the client's
  101. :meth:`auth_completed() <SSHClient.auth_completed>` method is
  102. called.
  103. 6. The coroutine returns the ``(connection, client)`` pair. At
  104. this point, the connection is ready for sessions to be opened
  105. or port forwarding to be set up.
  106. If an error occurs, it will be raised as an exception and the partially
  107. open connection and client objects will be cleaned up.
  108. .. note:: Unlike :func:`socket.create_connection`, asyncio calls
  109. to create a connection do not support a ``timeout``
  110. parameter. However, asyncio calls can be wrapped in a
  111. call to :func:`asyncio.wait_for` or :func:`asyncio.wait`
  112. which takes a timeout and provides equivalent functionality.
  113. :param callable client_factory:
  114. A callable which returns an :class:`SSHClient` object that will
  115. be tied to the connection
  116. :param str host:
  117. The hostname or address to connect to
  118. :param int port: (optional)
  119. The port number to connect to. If not specified, the default
  120. SSH port is used.
  121. :param loop: (optional)
  122. The event loop to use when creating the connection. If not
  123. specified, the default event loop is used.
  124. :param tunnel: (optional)
  125. An existing SSH client connection that this new connection should
  126. be tunneled over. If set, a direct TCP/IP tunnel will be opened
  127. over this connection to the requested host and port rather than
  128. connecting directly via TCP.
  129. :param family: (optional)
  130. The address family to use when creating the socket. By default,
  131. the address family is automatically selected based on the host.
  132. :param flags: (optional)
  133. The flags to pass to getaddrinfo() when looking up the host address
  134. :param local_addr: (optional)
  135. The host and port to bind the socket to before connecting
  136. :param known_hosts: (optional)
  137. The list of keys which will be used to validate the server host
  138. key presented during the SSH handshake. If this is not specified,
  139. the keys will be looked up in the file :file:`.ssh/known_hosts`.
  140. If this is explicitly set to ``None``, server host key validation
  141. will be disabled.
  142. :param str username: (optional)
  143. Username to authenticate as on the server. If not specified,
  144. the currently logged in user on the local machine will be used.
  145. :param str password: (optional)
  146. The password to use for client password authentication or
  147. keyboard-interactive authentication which prompts for a password.
  148. If this is not specified, client password authentication will
  149. not be performed.
  150. :param client_keys: (optional)
  151. A list of keys which will be used to authenticate this client
  152. via public key authentication. If no client keys are specified,
  153. an attempt will be made to get them from an ssh-agent process.
  154. If that is not available, an attempt will be made to load them
  155. from the files :file:`.ssh/id_ed25519`, :file:`.ssh/id_ecdsa`,
  156. :file:`.ssh/id_rsa`, and :file:`.ssh/id_dsa` in the user's home
  157. directory, with optional certificates loaded from the files
  158. :file:`.ssh/id_ed25519-cert.pub`, :file:`.ssh/id_ecdsa-cert.pub`,
  159. :file:`.ssh/id_rsa-cert.pub`, and :file:`.ssh/id_dsa-cert.pub`.
  160. If this argument is explicitly set to ``None``, client public
  161. key authentication will not be performed.
  162. :param str passphrase: (optional)
  163. The passphrase to use to decrypt client keys when loading them,
  164. if they are encrypted. If this is not specified, only unencrypted
  165. client keys can be loaded. If the keys passed into client_keys
  166. are already loaded, this argument is ignored.
  167. :param agent_path: (optional)
  168. The path of a UNIX domain socket to use to contact an ssh-agent
  169. process which will perform the operations needed for client
  170. public key authentication, or the :class:`SSHServerConnection`
  171. to use to forward ssh-agent requests over. If this is not
  172. specified and the environment variable ``SSH_AUTH_SOCK`` is
  173. set, its value will be used as the path. If ``client_keys``
  174. is specified or this argument is explicitly set to ``None``,
  175. an ssh-agent will not be used.
  176. :param bool agent_forwarding: (optional)
  177. Whether or not to allow forwarding of ssh-agent requests from
  178. processes running on the server. By default, ssh-agent forwarding
  179. requests from the server are not allowed.
  180. :param str client_version: (optional)
  181. An ASCII string to advertise to the SSH server as the version of
  182. this client, defaulting to ``AsyncSSH`` and its version number.
  183. :param kex_algs: (optional)
  184. A list of allowed key exchange algorithms in the SSH handshake,
  185. taken from :ref:`key exchange algorithms <KexAlgs>`
  186. :param encryption_algs: (optional)
  187. A list of encryption algorithms to use during the SSH handshake,
  188. taken from :ref:`encryption algorithms <EncryptionAlgs>`
  189. :param mac_algs: (optional)
  190. A list of MAC algorithms to use during the SSH handshake, taken
  191. from :ref:`MAC algorithms <MACAlgs>`
  192. :param compression_algs: (optional)
  193. A list of compression algorithms to use during the SSH handshake,
  194. taken from :ref:`compression algorithms <CompressionAlgs>`, or
  195. ``None`` to disable compression
  196. :param signature_algs: (optional)
  197. A list of public key signature algorithms to use during the SSH
  198. handshake, taken from :ref:`signature algorithms <SignatureAlgs>`
  199. :param int rekey_bytes: (optional)
  200. The number of bytes which can be sent before the SSH session
  201. key is renegotiated. This defaults to 1 GB.
  202. :param int rekey_seconds: (optional)
  203. The maximum time in seconds before the SSH session key is
  204. renegotiated. This defaults to 1 hour.
  205. :type tunnel: :class:`SSHClientConnection`
  206. :type family: ``socket.AF_UNSPEC``, ``socket.AF_INET``, or
  207. ``socket.AF_INET6``
  208. :type flags: flags to pass to :meth:`getaddrinfo() <socket.getaddrinfo>`
  209. :type local_addr: tuple of str and int
  210. :type known_hosts: *see* :ref:`SpecifyingKnownHosts`
  211. :type client_keys: *see* :ref:`SpecifyingPrivateKeys`
  212. :type agent_path: str or :class:`SSHServerConnection`
  213. :type kex_algs: list of str
  214. :type encryption_algs: list of str
  215. :type mac_algs: list of str
  216. :type compression_algs: list of str
  217. :type signature_algs: list of str
  218. :returns: An :class:`SSHClientConnection` and :class:`SSHClient`
  219. """
  220. def conn_factory():
  221. """Return an SSH client connection handler"""
  222. return SSHClientConnection(client_factory, loop, client_version,
  223. kex_algs, encryption_algs, mac_algs,
  224. compression_algs, signature_algs,
  225. rekey_bytes, rekey_seconds, host, port,
  226. known_hosts, username, password,
  227. client_keys, agent, agent_path, auth_waiter)
  228. if not client_factory:
  229. client_factory = SSHClient
  230. if not loop:
  231. loop = asyncio.get_event_loop()
  232. client_version = _validate_version(client_version)
  233. kex_algs, encryption_algs, mac_algs, compression_algs, signature_algs = \
  234. _validate_algs(kex_algs, encryption_algs, mac_algs,
  235. compression_algs, signature_algs)
  236. if username is None:
  237. username = getpass.getuser()
  238. agent = None
  239. if agent_path is ():
  240. agent_path = os.environ.get('SSH_AUTH_SOCK', None)
  241. if client_keys:
  242. client_keys = load_keypairs(client_keys, passphrase)
  243. elif client_keys is ():
  244. if agent_path:
  245. agent = await connect_agent(agent_path)
  246. if agent:
  247. client_keys = await agent.get_keys()
  248. else:
  249. agent_path = None
  250. if not client_keys:
  251. client_keys = load_default_keypairs()
  252. if not agent_forwarding:
  253. agent_path = None
  254. auth_waiter = asyncio.Future(loop=loop)
  255. # pylint: disable=broad-except
  256. try:
  257. if tunnel:
  258. _, conn = await tunnel.create_connection(conn_factory, host,
  259. port)
  260. else:
  261. _, conn = await loop.create_connection(conn_factory, host,
  262. port, family=family,
  263. flags=flags,
  264. local_addr=local_addr)
  265. except Exception:
  266. if agent:
  267. agent.close()
  268. raise
  269. await auth_waiter
  270. return conn, conn.get_owner()