duplicity-talk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Duplicity-talk] Unnecessarily asking for passphrase on incremental


From: Kenneth Loafman
Subject: Re: [Duplicity-talk] Unnecessarily asking for passphrase on incremental backup
Date: Wed, 15 Apr 2009 09:47:31 -0500
User-agent: Thunderbird 2.0.0.21 (X11/20090318)

Kenneth Loafman wrote:
> Georg Lutz wrote:
>> On 2009-04-07 15:55, Kenneth Loafman wrote:
>>> Duplicity needs the key to decrypt the remote manifest file, which it
>>> then compares to the local manifest to guarantee that the two are in
>>> sync.  If you are running a recent release of duplicity, --use-agent is
>>> available to allow gpg to query a gpg-agent instead of the user.
>>>
>> Hi Ken,
>>
>> Ok, I understand that this make the data handling much more robust and
>> probably fixes another severe bug.
>>
>> However this breaks the nice feature that duplicity didn't need access
>> to a secret key just for doing backups up to version 0.5.12 . I liked
>> it, because the backup should work fully unattended - the concerning
>> workstations/servers just had to be switched on at a certain time. Now I
>> have to make sure to manually unlock the secret key on every machine to
>> let the backup happen. The same issue was recently reported as bug
>> #26112.
>>
>> Couldn't the data integrity check been done without decrypting the
>> remote manifest? The archive-dir could hold e.g. an additional file with
>> a checksum for the encrypted remote manifest. What do you think? Would
>> this be feasible?
> 
> This is a good idea.  If the archive dir had the name and a hash of the
> latest manifest gpg file that could be checked and all would be OK.
> 
> Taking it a step further, hashes for all of the remote files could be
> saved in the archive.  During a restore, it would be nice to know that
> the downloaded file had been corrupted.
> 
> I'll keep this in mind and get it fixed, at least the first part.

It's going to be a while before the fix for this is available, so I put
together a patch that restores the old behavior.  This will still allow
you to "screw up" the archive if you forget to use the --archive-dir
option every time, but my tests show that duplicity will complain enough
that you'll be able to spot the problem if you do.  The worst case is
that an incremental will be repeated because we just threw away the now
extra copy on the remote.

I had to edit the patch file to remove some other changes, so there may
be some fuzz warnings when you apply the patch.

...Ken

Index: duplicity-bin
===================================================================
RCS file: /sources/duplicity/duplicity/duplicity-bin,v
retrieving revision 1.71
diff -u -r1.71 duplicity-bin
--- duplicity-bin    9 Apr 2009 16:32:15 -0000    1.71
+++ duplicity-bin    15 Apr 2009 14:35:21 -0000
@@ -109,6 +109,15 @@
           and not globals.gpg_profile.sign_key):
         return ""

+    # for an inc backup, we don't need a password if
+    # there is no sign_key and there are recipients
+    # and there is an archive-dir specified
+    elif (action == "inc"
+          and globals.gpg_profile.recipients
+          and not globals.gpg_profile.sign_key
+          and globals.archive_dir):
+        return ""
+
     # Finally, ask the user for the passphrase
     else:
         log.Info("PASSPHRASE variable not set, asking user.")
@@ -695,6 +710,7 @@
         log.Notice(_("Last full backup date:") + " " + 
dup_time.timetopretty(last_full_time))
     else:
         log.Notice(_("Last full backup date: none"))
+        action = "full"
     if action == "inc" and last_full_time < globals.full_force_time:
         log.Notice(_("Last full backup is too old, forcing full backup"))
         action = "full"
@@ -765,6 +781,15 @@
         # No traceback, just get out
         sys.exit(e)

+    except gpg.GPGError, e:
+        # For user errors, don't show an ugly stack trace by
+        # default. But do with sufficient verbosity.
+        log.Info(_("GPG error detail: %s")
+                 % (''.join(traceback.format_exception(*sys.exc_info()))))
+        log.FatalError("%s: %s" % (e.__class__.__name__, e.args[0]),
+                       log.ErrorCode.gpg_failed,
+                       e.__class__.__name__)
+
     except duplicity.errors.UserError, e:
         # For user errors, don't show an ugly stack trace by
         # default. But do with sufficient verbosity.
Index: duplicity/collections.py
===================================================================
RCS file: /sources/duplicity/duplicity/duplicity/collections.py,v
retrieving revision 1.41
diff -u -r1.41 collections.py
--- duplicity/collections.py    2 Apr 2009 14:47:16 -0000    1.41
+++ duplicity/collections.py    15 Apr 2009 14:35:22 -0000
@@ -30,6 +30,7 @@
 from duplicity import dup_time
 from duplicity import globals
 from duplicity import manifest
+from duplicity.gpg import GPGError

 class CollectionsError(Exception):
     pass
@@ -164,8 +165,8 @@
         # public key w/o secret key
         try:
             manifest_buffer = self.backend.get_data(self.remote_manifest_name)
-        except IOError, message:
-            if message.args[0] == "GnuPG exited non-zero, with code 2":
+        except GPGError, message:
+            if "secret key not available" in message.args[0]:
                 return None
             else:
                 raise
Index: duplicity/gpg.py
===================================================================
RCS file: /sources/duplicity/duplicity/duplicity/gpg.py,v
retrieving revision 1.28
diff -u -r1.28 gpg.py
--- duplicity/gpg.py    2 Apr 2009 14:47:15 -0000    1.28
+++ duplicity/gpg.py    15 Apr 2009 14:35:22 -0000
@@ -147,15 +147,13 @@
         return res

     def gpg_failed(self):
-        self.print_log(0)
-        log.FatalError("GPG Failed, see log above", log.ErrorCode.gpg_failed)
-
-    def print_log(self, level):
-        log.Log("===== Begin GnuPG log =====", level)
+        msg = "GPG Failed, see log below:\n"
+        msg += "===== Begin GnuPG log =====\n"
         self.logger_fp.seek(0)
         for line in self.logger_fp:
-            log.Log(line.strip(), level)
-        log.Log("===== End GnuPG log =====", level)
+            msg += line.strip() + "\n"
+        msg += "===== End GnuPG log =====\n"
+        raise GPGError, msg

     def close(self):
         if self.encrypt:
@@ -187,7 +185,6 @@
                 self.gpg_process.wait()
             except:
                 self.gpg_failed()
-        self.print_log(5)
         self.logger_fp.close()
         self.closed = 1

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]