~gregretkowski/duplicity/cf-retry-delete

« back to all changes in this revision

Viewing changes to duplicity/backends/sshbackend.py

  • Committer: Kenneth Loafman
  • Date: 2012-03-13 11:38:58 UTC
  • mfrom: (847.2.2 trunk)
  • Revision ID: kenneth@loafman.com-20120313113858-locfmgxtsj69tjc6
Merged in lp:~ed.so/duplicity/0.6-ssh_add_missinghostkey

add missing_host_key prompt to new sshbackend similar to ssh procedure

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
import errno
30
30
import sys
31
31
import getpass
 
32
from binascii import hexlify
32
33
 
33
34
# debian squeeze's paramiko is a bit old, so we silence randompool depreciation warning
34
35
# note also: passphrased private keys work with squeeze's paramiko only if done with DES, not AES
70
71
            self.remote_dir = '.'
71
72
 
72
73
        self.client = paramiko.SSHClient()
 
74
        self.client.set_missing_host_key_policy(AgreedAddPolicy())
73
75
        # load known_hosts files
74
76
        # paramiko is very picky wrt format and bails out on any problem...
75
77
        try:
78
80
        except Exception, e:
79
81
            raise BackendException("could not load /etc/ssh/ssh_known_hosts, maybe corrupt?")
80
82
        try:
81
 
            self.client.load_system_host_keys()
 
83
            # use load_host_keys() to signal it's writable to paramiko
 
84
            # load if file exists or add filename to create it if needed
 
85
            file = os.path.expanduser('~/.ssh/known_hosts')
 
86
            if os.path.isfile(file):
 
87
                self.client.load_host_keys(file)
 
88
            else:
 
89
                self.client._host_keys_filename = file
82
90
        except Exception, e:
83
91
            raise BackendException("could not load ~/.ssh/known_hosts, maybe corrupt?")
84
92
 
319
327
        
320
328
        return sshconfig.lookup(host)
321
329
 
 
330
class AgreedAddPolicy (paramiko.AutoAddPolicy):
 
331
    """
 
332
    Policy for showing a yes/no prompt and adding the hostname and new 
 
333
    host key to the known host file accordingly.
 
334
    
 
335
    This class simply extends the AutoAddPolicy class with a yes/no prompt.
 
336
    """
 
337
    def missing_host_key(self, client, hostname, key):
 
338
        fp = hexlify(key.get_fingerprint())
 
339
        fingerprint = ':'.join(a+b for a,b in zip(fp[::2], fp[1::2]))
 
340
        question = """The authenticity of host '%s' can't be established.
 
341
%s key fingerprint is %s.
 
342
Are you sure you want to continue connecting (yes/no)? """ % (hostname, key.get_name().upper(), fingerprint)
 
343
        while True:
 
344
            sys.stdout.write(question)
 
345
            choice = raw_input().lower()
 
346
            if choice in ['yes','y']:
 
347
                super(AgreedAddPolicy, self).missing_host_key(client, hostname, key)
 
348
                return
 
349
            elif choice in ['no','n']:
 
350
                raise AuthenticityException( hostname )
 
351
            else:
 
352
                question = "Please type 'yes' or 'no': "
 
353
 
 
354
class AuthenticityException (paramiko.SSHException):
 
355
    def __init__(self, hostname):
 
356
        paramiko.SSHException.__init__(self, 'Host key verification for server %s failed.' % hostname)
322
357
 
323
358
 
324
359
duplicity.backend.register_backend("sftp", SftpBackend)