Commit f8acd7ac authored by Marco Mariani's avatar Marco Mariani

backported security fix, hardcoded version #

parent 08f63135
...@@ -14,7 +14,7 @@ import re, os ...@@ -14,7 +14,7 @@ import re, os
# The current version of rdiff-backup # The current version of rdiff-backup
version = "$version" version = "0.11.0-dev"
# If this is set, use this value in seconds as the current time # If this is set, use this value in seconds as the current time
# instead of reading it from the clock. # instead of reading it from the clock.
......
# Copyright 2002 Ben Escoto # Copyright 2002 Ben Escoto
# vim: set nolist noet ts=4:
# #
# This file is part of rdiff-backup. # This file is part of rdiff-backup.
# #
...@@ -10,8 +11,9 @@ ...@@ -10,8 +11,9 @@
"""Functions to make sure remote requests are kosher""" """Functions to make sure remote requests are kosher"""
import sys, tempfile import sys, tempfile, types
import Globals, Main import Globals, Main
import rpath
from rpath import * from rpath import *
class Violation(Exception): class Violation(Exception):
...@@ -27,6 +29,23 @@ allowed_requests = None ...@@ -27,6 +29,23 @@ allowed_requests = None
# set on the server. # set on the server.
disallowed_server_globals = ["server", "security_level", "restrict_path"] disallowed_server_globals = ["server", "security_level", "restrict_path"]
# Some common file commands we may want to check to make sure they are
# in the right directory. Any commands accessing files that could be
# added to allowed_requests must be here. A few others have also been
# added---this is not a intended to be a complete list of course, just
# some support for the depreciated --restrict option when the
# security_level is "all" so you don't accidentally step out of the
# directory.
#
# The keys are files request, the value is the index of the argument
# taking a file.
file_requests = {'os.listdir':0, 'C.make_file_dict':0, 'os.chmod':0,
'os.chown':0, 'os.remove':0, 'os.removedirs':0,
'os.rename':0, 'os.renames':0, 'os.rmdir':0, 'os.unlink':0,
'os.utime':0, 'os.lchown':0, 'os.link':1, 'os.symlink':1,
'os.mkdir':0, 'os.lchown':0, 'os.getcwd': 0}
def initialize(action, cmdpairs): def initialize(action, cmdpairs):
"""Initialize allowable request list and chroot""" """Initialize allowable request list and chroot"""
global allowed_requests global allowed_requests
...@@ -97,30 +116,33 @@ def set_security_level(action, cmdpairs): ...@@ -97,30 +116,33 @@ def set_security_level(action, cmdpairs):
def set_allowed_requests(sec_level): def set_allowed_requests(sec_level):
"""Set the allowed requests list using the security level""" """Set the allowed requests list using the security level"""
global allowed_requests global allowed_requests
if sec_level == "all": return
allowed_requests = ["VirtualFile.readfromid", "VirtualFile.closebyid", l = ["VirtualFile.readfromid", "VirtualFile.closebyid",
"Globals.get", "Globals.is_not_None", "Globals.get", "Globals.is_not_None", "Globals.get_dict_val",
"Globals.get_dict_val", "Log.open_logfile_allconn", "Log.close_logfile_allconn",
"Log.open_logfile_allconn", "Log.log_to_file", "FilenameMapping.set_init_quote_vals_local",
"Log.close_logfile_allconn", "SetConnections.add_redirected_conn", "RedirectedRun",
"SetConnections.add_redirected_conn", "sys.stdout.write", "robust.install_signal_handlers"]
"RedirectedRun", if (sec_level == "read-only" or sec_level == "update-only" or
"sys.stdout.write"] sec_level == "all"):
if sec_level == "minimal": pass l.extend(["C.make_file_dict",
elif sec_level == "read-only" or sec_level == "update-only": "rpath.ea_get",
allowed_requests.extend(["C.make_file_dict", "rpath.acl_get",
"rpath.setdata_local",
"Log.log_to_file",
"os.getuid", "os.getuid",
"os.listdir", "os.listdir",
"Time.setcurtime_local", "os.getcwd",
"Resume.ResumeCheck",
"HLSourceStruct.split_initial_dsiter", "HLSourceStruct.split_initial_dsiter",
"HLSourceStruct.get_diffs_and_finalize", "HLSourceStruct.get_diffs_and_finalize",
"RPathStatic.gzip_open_local_read", "RPathStatic.gzip_open_local_read",
"RPathStatic.open_local_read"]) "RPathStatic.open_local_read",
if sec_level == "update-only": "Time.setcurtime_local",
allowed_requests. \ "rpath.gzip_open_local_read",
extend(["Log.open_logfile_local", "Log.close_logfile_local", "rpath.open_local_read",
"Log.close_logfile_allconn", "Log.log_to_file", "Hardlink.initialize_dictionaries",
"user_group.uid2uname",
"user_group.gid2gname",
"SaveState.init_filenames", "SaveState.init_filenames",
"SaveState.touch_last_file", "SaveState.touch_last_file",
"HLDestinationStruct.get_sigs", "HLDestinationStruct.get_sigs",
...@@ -129,8 +151,43 @@ def set_allowed_requests(sec_level): ...@@ -129,8 +151,43 @@ def set_allowed_requests(sec_level):
"HLDestinationStruct.patch_increment_and_finalize", "HLDestinationStruct.patch_increment_and_finalize",
"Main.backup_touch_curmirror_local", "Main.backup_touch_curmirror_local",
"Globals.ITRB.increment_stat"]) "Globals.ITRB.increment_stat"])
if sec_level == "read-only" or sec_level == "all":
l.extend(["fs_abilities.get_fsabilities_readonly",
"fs_abilities.get_fsabilities_restoresource",
"restore.MirrorStruct.set_mirror_and_rest_times",
"restore.MirrorStruct.initialize_rf_cache",
"restore.MirrorStruct.close_rf_cache",
"restore.MirrorStruct.get_diffs",
"Resume.ResumeCheck",
"backup.SourceStruct.get_source_select",
"backup.SourceStruct.set_source_select",
"backup.SourceStruct.get_diffs"])
if sec_level == "update-only" or sec_level == "all":
l.extend(["Log.open_logfile_local", "Log.close_logfile_local",
"log.ErrorLog.open", "log.ErrorLog.isopen",
"log.ErrorLog.close",
"backup.DestinationStruct.set_rorp_cache",
"backup.DestinationStruct.get_sigs",
"backup.DestinationStruct.patch_and_increment",
"Main.backup_touch_curmirror_local",
"Main.backup_remove_curmirror_local",
"Globals.ITRB.increment_stat",
"statistics.record_error",
"log.ErrorLog.write_if_open",
"Resume.ResumeCheck",
"fs_abilities.get_fsabilities_readwrite"])
if sec_level == "all":
l.extend(["os.mkdir", "os.chown", "os.lchown", "os.rename",
"os.unlink", "os.remove", "os.chmod",
"backup.DestinationStruct.patch",
"restore.TargetStruct.get_initial_iter",
"restore.TargetStruct.patch",
"restore.TargetStruct.set_target_select",
"regress.Regress", "manage.delete_earlier_than_local"
])
if Globals.server: if Globals.server:
allowed_requests.extend(["SetConnections.init_connection_remote", l.extend(["SetConnections.init_connection_remote",
"Log.setverbosity", "Log.setverbosity",
"Log.setterm_verbosity", "Log.setterm_verbosity",
"Time.setprevtime_local", "Time.setprevtime_local",
...@@ -139,6 +196,17 @@ def set_allowed_requests(sec_level): ...@@ -139,6 +196,17 @@ def set_allowed_requests(sec_level):
"Globals.set_select", "Globals.set_select",
"HLSourceStruct.set_session_info", "HLSourceStruct.set_session_info",
"HLDestinationStruct.set_session_info"]) "HLDestinationStruct.set_session_info"])
allowed_requests = {}
for req in l: allowed_requests[req] = None
def raise_violation(request, arglist):
"""Raise a security violation about given request"""
raise Violation("\nWarning Security Violation!\n"
"Bad request for function: %s\n"
"with arguments: %s\n" % (request.function_string,
arglist))
def vet_request(request, arglist): def vet_request(request, arglist):
"""Examine request for security violations""" """Examine request for security violations"""
...@@ -147,15 +215,14 @@ def vet_request(request, arglist): ...@@ -147,15 +215,14 @@ def vet_request(request, arglist):
if Globals.restrict_path: if Globals.restrict_path:
for arg in arglist: for arg in arglist:
if isinstance(arg, RPath): vet_rpath(arg) if isinstance(arg, RPath): vet_rpath(arg)
if security_level == "all": return if request.function_string in file_requests:
vet_filename(request, arglist)
if security_level == "override": return
if request.function_string in allowed_requests: return if request.function_string in allowed_requests: return
if request.function_string == "Globals.set": if request.function_string == "Globals.set":
if Globals.server and arglist[0] not in disallowed_server_globals: if Globals.server and arglist[0] not in disallowed_server_globals:
return return
raise Violation("\nWarning Security Violation!\n" raise_violation(request, arglist)
"Bad request for function: %s\n"
"with arguments: %s\n" % (request.function_string,
arglist))
def vet_rpath(rpath): def vet_rpath(rpath):
"""Require rpath not to step outside retricted directory""" """Require rpath not to step outside retricted directory"""
...@@ -173,5 +240,13 @@ def vet_rpath(rpath): ...@@ -173,5 +240,13 @@ def vet_rpath(rpath):
"restrict path %s.\n" % (normalized, restrict)) "restrict path %s.\n" % (normalized, restrict))
def vet_filename(request, arglist):
"""Check to see if file operation is within the restrict_path"""
i = file_requests[request.function_string]
if len(arglist) <= i: raise_violation(request, arglist)
filename = arglist[i]
if type(filename) is not types.StringType:
raise_violation(request, arglist)
vet_rpath(rpath.RPath(Globals.local_connection, filename))
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
from __future__ import generators from __future__ import generators
import types, os, tempfile, cPickle, shutil, traceback, pickle, socket import types, os, tempfile, cPickle, shutil, traceback, pickle, socket
import rpath
class ConnectionError(Exception): pass class ConnectionError(Exception): pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment