From 138291d78ab8fbf63f3a5a299afcc186641e45ba Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 18 Aug 2002 17:43:20 +0000 Subject: Fixed the remote destination restore and no increment restore bugs. git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@184 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109 --- rdiff-backup/rdiff_backup/Main.py | 5 +++-- rdiff-backup/rdiff_backup/Security.py | 13 +++++++---- rdiff-backup/rdiff_backup/restore.py | 1 + rdiff-backup/rdiff_backup/rpath.py | 42 +++++++++++++++++++++++++++++------ rdiff-backup/src/Main.py | 5 +++-- rdiff-backup/src/Security.py | 13 +++++++---- rdiff-backup/src/restore.py | 1 + rdiff-backup/src/rpath.py | 42 +++++++++++++++++++++++++++++------ 8 files changed, 96 insertions(+), 26 deletions(-) diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py index a7c9ecf..76c652a 100644 --- a/rdiff-backup/rdiff_backup/Main.py +++ b/rdiff-backup/rdiff_backup/Main.py @@ -509,7 +509,8 @@ def RemoveOlderThan(rootrp): "\nIf you want to delete multiple increments in this way, " "use the --force." % (len(times_in_secs), inc_pretty_time)) - Log("Deleting increment%sat times:\n%s" % - (len(times_in_secs) == 1 and " " or "s ", inc_pretty_time), 3) + if len(times_in_secs) == 1: + Log("Deleting increment at time:\n" + inc_pretty_time, 3) + else: Log("Deleting increments at times:\n" + inc_pretty_time, 3) Manage.delete_earlier_than(datadir, time) diff --git a/rdiff-backup/rdiff_backup/Security.py b/rdiff-backup/rdiff_backup/Security.py index 7f193aa..95b8296 100644 --- a/rdiff-backup/rdiff_backup/Security.py +++ b/rdiff-backup/rdiff_backup/Security.py @@ -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 @@ def set_security_level(action, cmdpairs): 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 @@ def set_security_level(action, cmdpairs): 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 @@ def set_allowed_requests(sec_level): "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 --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py index 4d57b4d..432f9cc 100644 --- a/rdiff-backup/rdiff_backup/restore.py +++ b/rdiff-backup/rdiff_backup/restore.py @@ -79,6 +79,7 @@ class Restore: """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 --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py index 4fffcfb..7365f14 100644 --- a/rdiff-backup/rdiff_backup/rpath.py +++ b/rdiff-backup/rdiff_backup/rpath.py @@ -200,10 +200,26 @@ class RPathStatic: 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 @@ class RPath(RORPath): 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 @@ class RPath(RORPath): """Return open file. Supports modes "w" and "r". If compress is true, data written/read will be gzip - compressed/decompressed on the fly. + 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 compress: return self.conn.gzip.GzipFile(self.path, mode) - else: return self.conn.open(self.path, mode) + 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 diff --git a/rdiff-backup/src/Main.py b/rdiff-backup/src/Main.py index a7c9ecf..76c652a 100644 --- a/rdiff-backup/src/Main.py +++ b/rdiff-backup/src/Main.py @@ -509,7 +509,8 @@ def RemoveOlderThan(rootrp): "\nIf you want to delete multiple increments in this way, " "use the --force." % (len(times_in_secs), inc_pretty_time)) - Log("Deleting increment%sat times:\n%s" % - (len(times_in_secs) == 1 and " " or "s ", inc_pretty_time), 3) + if len(times_in_secs) == 1: + Log("Deleting increment at time:\n" + inc_pretty_time, 3) + else: Log("Deleting increments at times:\n" + inc_pretty_time, 3) Manage.delete_earlier_than(datadir, time) diff --git a/rdiff-backup/src/Security.py b/rdiff-backup/src/Security.py index 7f193aa..95b8296 100644 --- a/rdiff-backup/src/Security.py +++ b/rdiff-backup/src/Security.py @@ -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 @@ def set_security_level(action, cmdpairs): 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 @@ def set_security_level(action, cmdpairs): 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 @@ def set_allowed_requests(sec_level): "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 --git a/rdiff-backup/src/restore.py b/rdiff-backup/src/restore.py index 4d57b4d..432f9cc 100644 --- a/rdiff-backup/src/restore.py +++ b/rdiff-backup/src/restore.py @@ -79,6 +79,7 @@ class Restore: """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 --git a/rdiff-backup/src/rpath.py b/rdiff-backup/src/rpath.py index 4fffcfb..7365f14 100644 --- a/rdiff-backup/src/rpath.py +++ b/rdiff-backup/src/rpath.py @@ -200,10 +200,26 @@ class RPathStatic: 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 @@ class RPath(RORPath): 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 @@ class RPath(RORPath): """Return open file. Supports modes "w" and "r". If compress is true, data written/read will be gzip - compressed/decompressed on the fly. + 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 compress: return self.conn.gzip.GzipFile(self.path, mode) - else: return self.conn.open(self.path, mode) + 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 -- cgit v1.2.1