paramiko.util

Package paramiko :: Module util |
[frames] | no frames]

# Source Code for Module paramiko.util

      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  """
     20  Useful functions used by the rest of paramiko.
     21  """
     22
     23  from __future__ import generators
     24
     25  import array
     26  from binascii import hexlify, unhexlify
     27  import errno
     28  import sys
     29  import struct
     30  import traceback
     31  import threading
     32
     33  from paramiko.common import *
     34  from paramiko.config import SSHConfig
     35
     36
     37  # Change by RogerB - python < 2.3 doesn't have enumerate so we implement it
     38  if sys.version_info < (2,3):
     39 -    class enumerate:
     40 -        def __init__ (self, sequence):
     41              self.sequence = sequence
     42 -        def __iter__ (self):
     43              count = 0
     44              for item in self.sequence:
     45                  yield (count, item)
     46                  count += 1
     47
     48
     49 -def inflate_long(s, always_positive=False):
     50      "turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"
     51      out = 0L
     52      negative = 0
     53      if not always_positive and (len(s) > 0) and (ord(s[0]) >= 0x80):
     54          negative = 1
     55      if len(s) % 4:
     56          filler = '\x00'
     57          if negative:
     58              filler = '\xff'
     59          s = filler * (4 - len(s) % 4) + s
     60      for i in range(0, len(s), 4):
     61          out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
     62      if negative:
     63          out -= (1L << (8 * len(s)))
     64      return out
     65
     66 -def deflate_long(n, add_sign_padding=True):
     67      "turns a long-int into a normalized byte string (adapted from Crypto.Util.number)"
     68      # after much testing, this algorithm was deemed to be the fastest
     69      s = ''
     70      n = long(n)
     71      while (n != 0) and (n != -1):
     72          s = struct.pack('>I', n & 0xffffffffL) + s
     73          n = n >> 32
     74      # strip off leading zeros, FFs
     75      for i in enumerate(s):
     76          if (n == 0) and (i[1] != '\000'):
     77              break
     78          if (n == -1) and (i[1] != '\xff'):
     79              break
     80      else:
     81          # degenerate case, n was either 0 or -1
     82          i = (0,)
     83          if n == 0:
     84              s = '\000'
     85          else:
     86              s = '\xff'
     87      s = s[i[0]:]
     88      if add_sign_padding:
     89          if (n == 0) and (ord(s[0]) >= 0x80):
     90              s = '\x00' + s
     91          if (n == -1) and (ord(s[0]) < 0x80):
     92              s = '\xff' + s
     93      return s
     94
     95 -def format_binary_weird(data):
     96      out = ''
     97      for i in enumerate(data):
     98          out += '%02X' % ord(i[1])
     99          if i[0] % 2:
    100              out += ' '
    101          if i[0] % 16 == 15:
    102              out += '\n'
    103      return out
    104
    105 -def format_binary(data, prefix=''):
    106      x = 0
    107      out = []
    108      while len(data) > x + 16:
    109          out.append(format_binary_line(data[x:x+16]))
    110          x += 16
    111      if x < len(data):
    112          out.append(format_binary_line(data[x:]))
    113      return [prefix + x for x in out]
    114
    115 -def format_binary_line(data):
    116      left = ' '.join(['%02X' % ord(c) for c in data])
    117      right = ''.join([('.%c..' % c)[(ord(c)+63)//95] for c in data])
    118      return '%-50s %s' % (left, right)
    119
    120 -def hexify(s):
    121      return hexlify(s).upper()
    122
    123 -def unhexify(s):
    124      return unhexlify(s)
    125
    126 -def safe_string(s):
    127      out = ''
    128      for c in s:
    129          if (ord(c) >= 32) and (ord(c) <= 127):
    130              out += c
    131          else:
    132              out += '%%%02X' % ord(c)
    133      return out
    134
    135  # ''.join([['%%%02X' % ord(c), c][(ord(c) >= 32) and (ord(c) <= 127)] for c in s])
    136
    137 -def bit_length(n):
    138      norm = deflate_long(n, 0)
    139      hbyte = ord(norm[0])
    140      if hbyte == 0:
    141          return 1
    142      bitlen = len(norm) * 8
    143      while not (hbyte & 0x80):
    144          hbyte <<= 1
    145          bitlen -= 1
    146      return bitlen
    147
    148 -def tb_strings():
    149      return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
    150
    151 -def generate_key_bytes(hashclass, salt, key, nbytes):
    152      """
    153      Given a password, passphrase, or other human-source key, scramble it
    154      through a secure hash into some keyworthy bytes.  This specific algorithm
    155      is used for encrypting/decrypting private key files.
    156
    157      @param hashclass: class from L{Crypto.Hash} that can be used as a secure
    158          hashing function (like C{MD5} or C{SHA}).
    159      @type hashclass: L{Crypto.Hash}
    160      @param salt: data to salt the hash with.
    161      @type salt: string
    162      @param key: human-entered password or passphrase.
    163      @type key: string
    164      @param nbytes: number of bytes to generate.
    165      @type nbytes: int
    166      @return: key data
    167      @rtype: string
    168      """
    169      keydata = ''
    170      digest = ''
    171      if len(salt) > 8:
    172          salt = salt[:8]
    173      while nbytes > 0:
    174          hash_obj = hashclass.new()
    175          if len(digest) > 0:
    176              hash_obj.update(digest)
    177          hash_obj.update(key)
    178          hash_obj.update(salt)
    179          digest = hash_obj.digest()
    180          size = min(nbytes, len(digest))
    181          keydata += digest[:size]
    182          nbytes -= size
    183      return keydata
    184
    185 -def load_host_keys(filename):
    186      """
    187      Read a file of known SSH host keys, in the format used by openssh, and
    188      return a compound dict of C{hostname -> keytype ->} L{PKey <paramiko.pkey.PKey>}.
    189      The hostname may be an IP address or DNS name.  The keytype will be either
    190      C{"ssh-rsa"} or C{"ssh-dss"}.
    191
    192      This type of file unfortunately doesn't exist on Windows, but on posix,
    193      it will usually be stored in C{os.path.expanduser("~/.ssh/known_hosts")}.
    194
    195      Since 1.5.3, this is just a wrapper around L{HostKeys}.
    196
    197      @param filename: name of the file to read host keys from
    198      @type filename: str
    199      @return: dict of host keys, indexed by hostname and then keytype
    200      @rtype: dict(hostname, dict(keytype, L{PKey <paramiko.pkey.PKey>}))
    201      """
    202      from paramiko.hostkeys import HostKeys
    203      return HostKeys(filename)
    204
    205 -def parse_ssh_config(file_obj):
    206      """
    207      Provided only as a backward-compatible wrapper around L{SSHConfig}.
    208      """
    209      config = SSHConfig()
    210      config.parse(file_obj)
    211      return config
    212
    213 -def lookup_ssh_host_config(hostname, config):
    214      """
    215      Provided only as a backward-compatible wrapper around L{SSHConfig}.
    216      """
    217      return config.lookup(hostname)
    218
    219 -def mod_inverse(x, m):
    220      # it's crazy how small python can make this function.
    221      u1, u2, u3 = 1, 0, m
    222      v1, v2, v3 = 0, 1, x
    223
    224      while v3 > 0:
    225          q = u3 // v3
    226          u1, v1 = v1, u1 - v1 * q
    227          u2, v2 = v2, u2 - v2 * q
    228          u3, v3 = v3, u3 - v3 * q
    229      if u2 < 0:
    230          u2 += m
    231      return u2
    232
    233  _g_thread_ids = {}
    234  _g_thread_counter = 0
    235  _g_thread_lock = threading.Lock()
    236 -def get_thread_id():
    237      global _g_thread_ids, _g_thread_counter, _g_thread_lock
    238      tid = id(threading.currentThread())
    239      try:
    240          return _g_thread_ids[tid]
    241      except KeyError:
    242          _g_thread_lock.acquire()
    243          try:
    244              _g_thread_counter += 1
    245              ret = _g_thread_ids[tid] = _g_thread_counter
    246          finally:
    247              _g_thread_lock.release()
    248          return ret
    249
    250 -def log_to_file(filename, level=DEBUG):
    251      "send paramiko logs to a logfile, if they're not already going somewhere"
    252      l = logging.getLogger("paramiko")
    253      if len(l.handlers) > 0:
    254          return
    255      l.setLevel(level)
    256      f = open(filename, 'w')
    257      lh = logging.StreamHandler(f)
    258      lh.setFormatter(logging.Formatter('%(levelname)-.3s [%(asctime)s.%(msecs)03d] thr=%(_threadid)-3d %(name)s: %(message)s',
    259                                        '%Y%m%d-%H:%M:%S'))
    260      l.addHandler(lh)
    261
    262  # make only one filter object, so it doesn't get applied more than once
    263 -class PFilter (object):
    264 -    def filter(self, record):
    265          record._threadid = get_thread_id()
    266          return True
    267  _pfilter = PFilter()
    268
    269 -def get_logger(name):
    270      l = logging.getLogger(name)
    271      l.addFilter(_pfilter)
    272      return l
    273
    274 -def retry_on_signal(function):
    275      """Retries function until it doesn't raise an EINTR error"""
    276      while True:
    277          try:
    278              return function()
    279          except EnvironmentError, e:
    280              if e.errno != errno.EINTR:
    281                  raise
    282
    283 -class Counter (object):
    284      """Stateful counter for CTR mode crypto"""
    285 -    def __init__(self, nbits, initial_value=1L, overflow=0L):
    286          self.blocksize = nbits / 8
    287          self.overflow = overflow
    288          # start with value - 1 so we don't have to store intermediate values when counting
    289          # could the iv be 0?
    290          if initial_value == 0:
    291              self.value = array.array('c', '\xFF' * self.blocksize)
    292          else:
    293              x = deflate_long(initial_value - 1, add_sign_padding=False)
    294              self.value = array.array('c', '\x00' * (self.blocksize - len(x)) + x)
    295
    296 -    def __call__(self):
    297          """Increament the counter and return the new value"""
    298          i = self.blocksize - 1
    299          while i > -1:
    300              c = self.value[i] = chr((ord(self.value[i]) + 1) % 256)
    301              if c != '\x00':
    302                  return self.value.tostring()
    303              i -= 1
    304          # counter reset
    305          x = deflate_long(self.overflow, add_sign_padding=False)
    306          self.value = array.array('c', '\x00' * (self.blocksize - len(x)) + x)
    307          return self.value.tostring()
    308
    309 -    def new(cls, nbits, initial_value=1L, overflow=0L):
    310          return cls(nbits, initial_value=initial_value, overflow=overflow)
    311      new = classmethod(new)
    312