You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
8.3 KiB

7 years ago
  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. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  18. """
  19. Useful functions used by the rest of paramiko.
  20. """
  21. from __future__ import generators
  22. import errno
  23. import sys
  24. import struct
  25. import traceback
  26. import threading
  27. import logging
  28. from paramiko.common import DEBUG, zero_byte, xffffffff, max_byte
  29. from paramiko.py3compat import PY2, long, byte_chr, byte_ord, b
  30. from paramiko.config import SSHConfig
  31. def inflate_long(s, always_positive=False):
  32. """turns a normalized byte string into a long-int
  33. (adapted from Crypto.Util.number)"""
  34. out = long(0)
  35. negative = 0
  36. if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80):
  37. negative = 1
  38. if len(s) % 4:
  39. filler = zero_byte
  40. if negative:
  41. filler = max_byte
  42. # never convert this to ``s +=`` because this is a string, not a number
  43. # noinspection PyAugmentAssignment
  44. s = filler * (4 - len(s) % 4) + s
  45. for i in range(0, len(s), 4):
  46. out = (out << 32) + struct.unpack('>I', s[i:i + 4])[0]
  47. if negative:
  48. out -= (long(1) << (8 * len(s)))
  49. return out
  50. deflate_zero = zero_byte if PY2 else 0
  51. deflate_ff = max_byte if PY2 else 0xff
  52. def deflate_long(n, add_sign_padding=True):
  53. """turns a long-int into a normalized byte string
  54. (adapted from Crypto.Util.number)"""
  55. # after much testing, this algorithm was deemed to be the fastest
  56. s = bytes()
  57. n = long(n)
  58. while (n != 0) and (n != -1):
  59. s = struct.pack('>I', n & xffffffff) + s
  60. n >>= 32
  61. # strip off leading zeros, FFs
  62. for i in enumerate(s):
  63. if (n == 0) and (i[1] != deflate_zero):
  64. break
  65. if (n == -1) and (i[1] != deflate_ff):
  66. break
  67. else:
  68. # degenerate case, n was either 0 or -1
  69. i = (0,)
  70. if n == 0:
  71. s = zero_byte
  72. else:
  73. s = max_byte
  74. s = s[i[0]:]
  75. if add_sign_padding:
  76. if (n == 0) and (byte_ord(s[0]) >= 0x80):
  77. s = zero_byte + s
  78. if (n == -1) and (byte_ord(s[0]) < 0x80):
  79. s = max_byte + s
  80. return s
  81. def format_binary(data, prefix=''):
  82. x = 0
  83. out = []
  84. while len(data) > x + 16:
  85. out.append(format_binary_line(data[x:x + 16]))
  86. x += 16
  87. if x < len(data):
  88. out.append(format_binary_line(data[x:]))
  89. return [prefix + line for line in out]
  90. def format_binary_line(data):
  91. left = ' '.join(['{:02X}'.format(byte_ord(c)) for c in data])
  92. right = ''.join([
  93. '.{:c}..'.format(byte_ord(c))[(byte_ord(c) + 63) // 95]
  94. for c in data
  95. ])
  96. return '{:50s} {}'.format(left, right)
  97. def safe_string(s):
  98. out = b''
  99. for c in s:
  100. i = byte_ord(c)
  101. if 32 <= i <= 127:
  102. out += byte_chr(i)
  103. else:
  104. out += b('%{:02X}'.format(i))
  105. return out
  106. def bit_length(n):
  107. try:
  108. return n.bit_length()
  109. except AttributeError:
  110. norm = deflate_long(n, False)
  111. hbyte = byte_ord(norm[0])
  112. if hbyte == 0:
  113. return 1
  114. bitlen = len(norm) * 8
  115. while not (hbyte & 0x80):
  116. hbyte <<= 1
  117. bitlen -= 1
  118. return bitlen
  119. def tb_strings():
  120. return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
  121. def generate_key_bytes(hash_alg, salt, key, nbytes):
  122. """
  123. Given a password, passphrase, or other human-source key, scramble it
  124. through a secure hash into some keyworthy bytes. This specific algorithm
  125. is used for encrypting/decrypting private key files.
  126. :param function hash_alg: A function which creates a new hash object, such
  127. as ``hashlib.sha256``.
  128. :param salt: data to salt the hash with.
  129. :type salt: byte string
  130. :param str key: human-entered password or passphrase.
  131. :param int nbytes: number of bytes to generate.
  132. :return: Key data `str`
  133. """
  134. keydata = bytes()
  135. digest = bytes()
  136. if len(salt) > 8:
  137. salt = salt[:8]
  138. while nbytes > 0:
  139. hash_obj = hash_alg()
  140. if len(digest) > 0:
  141. hash_obj.update(digest)
  142. hash_obj.update(b(key))
  143. hash_obj.update(salt)
  144. digest = hash_obj.digest()
  145. size = min(nbytes, len(digest))
  146. keydata += digest[:size]
  147. nbytes -= size
  148. return keydata
  149. def load_host_keys(filename):
  150. """
  151. Read a file of known SSH host keys, in the format used by openssh, and
  152. return a compound dict of ``hostname -> keytype ->`` `PKey
  153. <paramiko.pkey.PKey>`. The hostname may be an IP address or DNS name. The
  154. keytype will be either ``"ssh-rsa"`` or ``"ssh-dss"``.
  155. This type of file unfortunately doesn't exist on Windows, but on posix,
  156. it will usually be stored in ``os.path.expanduser("~/.ssh/known_hosts")``.
  157. Since 1.5.3, this is just a wrapper around `.HostKeys`.
  158. :param str filename: name of the file to read host keys from
  159. :return:
  160. nested dict of `.PKey` objects, indexed by hostname and then keytype
  161. """
  162. from paramiko.hostkeys import HostKeys
  163. return HostKeys(filename)
  164. def parse_ssh_config(file_obj):
  165. """
  166. Provided only as a backward-compatible wrapper around `.SSHConfig`.
  167. """
  168. config = SSHConfig()
  169. config.parse(file_obj)
  170. return config
  171. def lookup_ssh_host_config(hostname, config):
  172. """
  173. Provided only as a backward-compatible wrapper around `.SSHConfig`.
  174. """
  175. return config.lookup(hostname)
  176. def mod_inverse(x, m):
  177. # it's crazy how small Python can make this function.
  178. u1, u2, u3 = 1, 0, m
  179. v1, v2, v3 = 0, 1, x
  180. while v3 > 0:
  181. q = u3 // v3
  182. u1, v1 = v1, u1 - v1 * q
  183. u2, v2 = v2, u2 - v2 * q
  184. u3, v3 = v3, u3 - v3 * q
  185. if u2 < 0:
  186. u2 += m
  187. return u2
  188. _g_thread_ids = {}
  189. _g_thread_counter = 0
  190. _g_thread_lock = threading.Lock()
  191. def get_thread_id():
  192. global _g_thread_ids, _g_thread_counter, _g_thread_lock
  193. tid = id(threading.currentThread())
  194. try:
  195. return _g_thread_ids[tid]
  196. except KeyError:
  197. _g_thread_lock.acquire()
  198. try:
  199. _g_thread_counter += 1
  200. ret = _g_thread_ids[tid] = _g_thread_counter
  201. finally:
  202. _g_thread_lock.release()
  203. return ret
  204. def log_to_file(filename, level=DEBUG):
  205. """send paramiko logs to a logfile,
  206. if they're not already going somewhere"""
  207. l = logging.getLogger("paramiko")
  208. if len(l.handlers) > 0:
  209. return
  210. l.setLevel(level)
  211. f = open(filename, 'a')
  212. lh = logging.StreamHandler(f)
  213. frm = '%(levelname)-.3s [%(asctime)s.%(msecs)03d] thr=%(_threadid)-3d %(name)s: %(message)s' # noqa
  214. lh.setFormatter(logging.Formatter(frm, '%Y%m%d-%H:%M:%S'))
  215. l.addHandler(lh)
  216. # make only one filter object, so it doesn't get applied more than once
  217. class PFilter (object):
  218. def filter(self, record):
  219. record._threadid = get_thread_id()
  220. return True
  221. _pfilter = PFilter()
  222. def get_logger(name):
  223. l = logging.getLogger(name)
  224. l.addFilter(_pfilter)
  225. return l
  226. def retry_on_signal(function):
  227. """Retries function until it doesn't raise an EINTR error"""
  228. while True:
  229. try:
  230. return function()
  231. except EnvironmentError as e:
  232. if e.errno != errno.EINTR:
  233. raise
  234. def constant_time_bytes_eq(a, b):
  235. if len(a) != len(b):
  236. return False
  237. res = 0
  238. # noinspection PyUnresolvedReferences
  239. for i in (xrange if PY2 else range)(len(a)): # noqa: F821
  240. res |= byte_ord(a[i]) ^ byte_ord(b[i])
  241. return res == 0
  242. class ClosingContextManager(object):
  243. def __enter__(self):
  244. return self
  245. def __exit__(self, type, value, traceback):
  246. self.close()
  247. def clamp_value(minimum, val, maximum):
  248. return max(minimum, min(val, maximum))

Powered by TurnKey Linux.