paramiko.util

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

# Source Code for Module paramiko.util

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