ssh_exception.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
  2. #
  3. # This file is part of paramiko.
  4. #
  5. # Paramiko is free software; you can redistribute it and/or modify it under the
  6. # terms of the GNU Lesser General Public License as published by the Free
  7. # Software Foundation; either version 2.1 of the License, or (at your option)
  8. # any later version.
  9. #
  10. # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  13. # details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
  17. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. import socket
  19. class SSHException(Exception):
  20. """
  21. Exception raised by failures in SSH2 protocol negotiation or logic errors.
  22. """
  23. pass
  24. class AuthenticationException(SSHException):
  25. """
  26. Exception raised when authentication failed for some reason. It may be
  27. possible to retry with different credentials. (Other classes specify more
  28. specific reasons.)
  29. .. versionadded:: 1.6
  30. """
  31. pass
  32. class PasswordRequiredException(AuthenticationException):
  33. """
  34. Exception raised when a password is needed to unlock a private key file.
  35. """
  36. pass
  37. class BadAuthenticationType(AuthenticationException):
  38. """
  39. Exception raised when an authentication type (like password) is used, but
  40. the server isn't allowing that type. (It may only allow public-key, for
  41. example.)
  42. .. versionadded:: 1.1
  43. """
  44. allowed_types = []
  45. # TODO 3.0: remove explanation kwarg
  46. def __init__(self, explanation, types):
  47. # TODO 3.0: remove this supercall unless it's actually required for
  48. # pickling (after fixing pickling)
  49. AuthenticationException.__init__(self, explanation, types)
  50. self.explanation = explanation
  51. self.allowed_types = types
  52. def __str__(self):
  53. return "{}; allowed types: {!r}".format(
  54. self.explanation, self.allowed_types
  55. )
  56. class PartialAuthentication(AuthenticationException):
  57. """
  58. An internal exception thrown in the case of partial authentication.
  59. """
  60. allowed_types = []
  61. def __init__(self, types):
  62. AuthenticationException.__init__(self, types)
  63. self.allowed_types = types
  64. def __str__(self):
  65. return "Partial authentication; allowed types: {!r}".format(
  66. self.allowed_types
  67. )
  68. class ChannelException(SSHException):
  69. """
  70. Exception raised when an attempt to open a new `.Channel` fails.
  71. :param int code: the error code returned by the server
  72. .. versionadded:: 1.6
  73. """
  74. def __init__(self, code, text):
  75. SSHException.__init__(self, code, text)
  76. self.code = code
  77. self.text = text
  78. def __str__(self):
  79. return "ChannelException({!r}, {!r})".format(self.code, self.text)
  80. class BadHostKeyException(SSHException):
  81. """
  82. The host key given by the SSH server did not match what we were expecting.
  83. :param str hostname: the hostname of the SSH server
  84. :param PKey got_key: the host key presented by the server
  85. :param PKey expected_key: the host key expected
  86. .. versionadded:: 1.6
  87. """
  88. def __init__(self, hostname, got_key, expected_key):
  89. SSHException.__init__(self, hostname, got_key, expected_key)
  90. self.hostname = hostname
  91. self.key = got_key
  92. self.expected_key = expected_key
  93. def __str__(self):
  94. msg = (
  95. "Host key for server '{}' does not match: got '{}', expected '{}'"
  96. ) # noqa
  97. return msg.format(
  98. self.hostname,
  99. self.key.get_base64(),
  100. self.expected_key.get_base64(),
  101. )
  102. class IncompatiblePeer(SSHException):
  103. """
  104. A disagreement arose regarding an algorithm required for key exchange.
  105. .. versionadded:: 2.9
  106. """
  107. # TODO 3.0: consider making this annotate w/ 1..N 'missing' algorithms,
  108. # either just the first one that would halt kex, or even updating the
  109. # Transport logic so we record /all/ that /could/ halt kex.
  110. # TODO: update docstrings where this may end up raised so they are more
  111. # specific.
  112. pass
  113. class ProxyCommandFailure(SSHException):
  114. """
  115. The "ProxyCommand" found in the .ssh/config file returned an error.
  116. :param str command: The command line that is generating this exception.
  117. :param str error: The error captured from the proxy command output.
  118. """
  119. def __init__(self, command, error):
  120. SSHException.__init__(self, command, error)
  121. self.command = command
  122. self.error = error
  123. def __str__(self):
  124. return 'ProxyCommand("{}") returned nonzero exit status: {}'.format(
  125. self.command, self.error
  126. )
  127. class NoValidConnectionsError(socket.error):
  128. """
  129. Multiple connection attempts were made and no families succeeded.
  130. This exception class wraps multiple "real" underlying connection errors,
  131. all of which represent failed connection attempts. Because these errors are
  132. not guaranteed to all be of the same error type (i.e. different errno,
  133. `socket.error` subclass, message, etc) we expose a single unified error
  134. message and a ``None`` errno so that instances of this class match most
  135. normal handling of `socket.error` objects.
  136. To see the wrapped exception objects, access the ``errors`` attribute.
  137. ``errors`` is a dict whose keys are address tuples (e.g. ``('127.0.0.1',
  138. 22)``) and whose values are the exception encountered trying to connect to
  139. that address.
  140. It is implied/assumed that all the errors given to a single instance of
  141. this class are from connecting to the same hostname + port (and thus that
  142. the differences are in the resolution of the hostname - e.g. IPv4 vs v6).
  143. .. versionadded:: 1.16
  144. """
  145. def __init__(self, errors):
  146. """
  147. :param dict errors:
  148. The errors dict to store, as described by class docstring.
  149. """
  150. addrs = sorted(errors.keys())
  151. body = ", ".join([x[0] for x in addrs[:-1]])
  152. tail = addrs[-1][0]
  153. if body:
  154. msg = "Unable to connect to port {0} on {1} or {2}"
  155. else:
  156. msg = "Unable to connect to port {0} on {2}"
  157. super(NoValidConnectionsError, self).__init__(
  158. None, msg.format(addrs[0][1], body, tail) # stand-in for errno
  159. )
  160. self.errors = errors
  161. def __reduce__(self):
  162. return (self.__class__, (self.errors,))
  163. class CouldNotCanonicalize(SSHException):
  164. """
  165. Raised when hostname canonicalization fails & fallback is disabled.
  166. .. versionadded:: 2.7
  167. """
  168. pass
  169. class ConfigParseError(SSHException):
  170. """
  171. A fatal error was encountered trying to parse SSH config data.
  172. Typically this means a config file violated the ``ssh_config``
  173. specification in a manner that requires exiting immediately, such as not
  174. matching ``key = value`` syntax or misusing certain ``Match`` keywords.
  175. .. versionadded:: 2.7
  176. """
  177. pass