Error (and fix) restoring to a non-local directory
Ben Escoto
bescoto@stanford.edu
Sun, 18 Aug 2002 10:57:34 -0700
--==_Exmh_968037334P
Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
Content-Id: <2153.1029693431.0@folly.Stanford.EDU>
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <2153.1029693431.1@folly.Stanford.EDU>
>>>>> "PJE" == Phillip J Eby <pje@telecommunity.com>
>>>>> wrote the following on Sun, 18 Aug 2002 11:12:17 -0400
PJE> I got the following error trying to do a restore from a local
PJE> drive to a drive over an SSH connection, using 0.9.5:
...
PJE> To fix it, I looked at the code and fixed up the "else" branch
PJE> that was being executed for a restore from a local to a
PJE> non-local drive, so that it set 'rdir=getpath(cp2)', since that
PJE> seemed consistent with branches for other operations. Restore
PJE> then seemed to work okay.
Are you sure this works? The fix seems more complicated than that to
me (see bottom).
PJE> Apparently, it's not possible to restore a new backup that has
PJE> no increments yet. I didn't try to trace this one down,
PJE> however, since my simple workaround at this point is to always
PJE> run rdiff-backup *twice* when I first create a backup. ;)
Thanks for reporting these two bugs. I'm almost relieved since I've
gotten a variety of backup bug reports but very few restore
reports... Makes me wonder if no one is restoring anything...
Anyway, here are the changes which make rdiff-backup pass my
(newly added) tests.
--
Ben Escoto
------- =_aaaaaaaaaa0
Content-Type: text/patches; charset="us-ascii"
Content-ID: <2153.1029693431.2@folly.Stanford.EDU>
diff -u -r1.3 -r1.4
--- Security.py 25 Jul 2002 06:34:48 -0000 1.3
+++ Security.py 18 Aug 2002 17:43:20 -0000 1.4
@@ -10,8 +10,8 @@
"""Functions to make sure remote requests are kosher"""
-import sys
-import Globals, tempfile
+import sys, tempfile
+import Globals, Main
from rpath import *
class Violation(Exception):
@@ -67,6 +67,8 @@
rdir = tempfile.gettempdir()
elif islocal(cp1):
sec_level = "read-only"
+ rdir = Main.restore_get_root(RPath(Globals.local_connection,
+ getpath(cp1)))[0].path
else:
assert islocal(cp2)
sec_level = "all"
@@ -89,7 +91,8 @@
else: assert 0, "Unknown action %s" % action
Globals.security_level = sec_level
- Globals.restrict_path = rdir
+ Globals.restrict_path = RPath(Globals.local_connection,
+ rdir).normalize().path
def set_allowed_requests(sec_level):
"""Set the allowed requests list using the security level"""
@@ -111,7 +114,9 @@
"Time.setcurtime_local",
"Resume.ResumeCheck",
"HLSourceStruct.split_initial_dsiter",
- "HLSourceStruct.get_diffs_and_finalize"])
+ "HLSourceStruct.get_diffs_and_finalize",
+ "RPathStatic.gzip_open_local_read",
+ "RPathStatic.open_local_read"])
if sec_level == "update-only":
allowed_requests. \
extend(["Log.open_logfile_local", "Log.close_logfile_local",
diff -u -r1.12 -r1.13
--- restore.py 25 Jun 2002 18:04:08 -0000 1.12
+++ restore.py 18 Aug 2002 17:43:20 -0000 1.13
@@ -79,6 +79,7 @@
"""Returns increments with given base"""
dirname, basename = inc_rpath.dirsplit()
parent_dir = RPath(inc_rpath.conn, dirname, ())
+ if not parent_dir.isdir(): return [] # inc directory not created yet
index = inc_rpath.index
if index:
diff -u -r1.21 -r1.22
--- rpath.py 10 Aug 2002 00:43:04 -0000 1.21
+++ rpath.py 18 Aug 2002 17:43:20 -0000 1.22
@@ -200,10 +200,26 @@
try: return tuple(os.lstat(filename))
except os.error: return None
- def make_socket(path):
- """Make a local socket at the given path"""
+ def make_socket_local(rpath):
+ """Make a local socket at the given path
+
+ This takes an rpath so that it will be checked by Security.
+ (Miscellaneous strings will not be.)
+
+ """
+ assert rpath.conn is Globals.local_connection
s = socket.socket(socket.AF_UNIX)
- s.bind(path)
+ s.bind(rpath.path)
+
+ def gzip_open_local_read(rpath):
+ """Return open GzipFile. See security note directly above"""
+ assert rpath.conn is Globals.local_connection
+ return gzip.GzipFile(rpath.path, "rb")
+
+ def open_local_read(rpath):
+ """Return open file (provided for security reasons)"""
+ assert rpath.conn is Globals.local_connection
+ return open(rpath.path, "rb")
MakeStatic(RPathStatic)
@@ -587,7 +603,7 @@
def mksock(self):
"""Make a socket at self.path"""
- self.conn.RPathStatic.make_socket(self.path)
+ self.conn.RPathStatic.make_socket_local(self)
self.setdata()
assert self.issock()
@@ -700,11 +716,23 @@
"""Return open file. Supports modes "w" and "r".
If compress is true, data written/read will be gzip
- compressed/decompressed on the fly.
-
- """
- if compress: return self.conn.gzip.GzipFile(self.path, mode)
- else: return self.conn.open(self.path, mode)
+ compressed/decompressed on the fly. The extra complications
+ below are for security reasons - try to make the extent of the
+ risk apparent from the remote call.
+
+ """
+ if self.conn is Globals.local_connection:
+ if compress: return gzip.GzipFile(self.path, mode)
+ else: return open(self.path, mode)
+
+ if compress:
+ if mode == "r" or mode == "rb":
+ return self.conn.RPathStatic.gzip_open_local_read(self)
+ else: return self.conn.gzip.GzipFile(self.path, mode)
+ else:
+ if mode == "r" or mode == "rb":
+ return self.conn.RPathStatic.open_local_read(self)
+ else: return self.conn.open(self.path, mode)
def write_from_fileobj(self, fp, compress = None):
"""Reads fp and writes to self.path. Closes both when done
------- =_aaaaaaaaaa0--
--==_Exmh_968037334P
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)
Comment: Exmh version 2.5 01/15/2001
iD8DBQE9X+AK+owuOvknOnURAi23AKCANlcvGvVr+E79JvYOIjvTFLO+dACdG5Pl
obeFoc0LUoMuNqaTMXJ09Hk=
=FbPi
-----END PGP SIGNATURE-----
--==_Exmh_968037334P--