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