From 29ec7859f44a2529fadc71ff08f2fd6bfbc7531d Mon Sep 17 00:00:00 2001 From: James Kasten Date: Thu, 16 Aug 2012 16:25:26 -0400 Subject: [PATCH] Added recovery code for configurator in case of error or incomplete program execution --- trustify/client/CONFIG.py | 4 ++ trustify/client/client.py | 8 ++-- trustify/client/configurator.py | 66 ++++++++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/trustify/client/CONFIG.py b/trustify/client/CONFIG.py index 2e10c9939..7a7da8705 100644 --- a/trustify/client/CONFIG.py +++ b/trustify/client/CONFIG.py @@ -4,6 +4,8 @@ SERVER_ROOT = "/etc/apache2/" CONFIG_DIR = "/etc/trustify/" # Working directory for trustify WORK_DIR = "/var/lib/trustify/" +# Directory where configuration backups are stored +BACKUP_DIR = WORK_DIR + "backups/" # Used by openssl to sign challenge certificate with trustify extension CHOC_CERT_CONF = CONFIG_DIR + "choc_cert_extensions.cnf" @@ -11,6 +13,8 @@ CHOC_CERT_CONF = CONFIG_DIR + "choc_cert_extensions.cnf" OPTIONS_SSL_CONF = CONFIG_DIR + "options-ssl.conf" # Temporary file for challenge virtual hosts APACHE_CHALLENGE_CONF = CONFIG_DIR + "choc_sni_cert_challenge.conf" +# Modified files intended to be reset (for challenges/tmp config changes) +MODIFIED_FILES = BACKUP_DIR + "modified_files" # Byte size of S and Nonce S_SIZE = 32 NONCE_SIZE = 32 diff --git a/trustify/client/client.py b/trustify/client/client.py index b4758444a..bad6b4355 100644 --- a/trustify/client/client.py +++ b/trustify/client/client.py @@ -195,9 +195,11 @@ def save_key_csr(key, csr): directory. """ # Create directories if they do not exist - # TODO: Lookup what permissions cert files/directory should have... + # This should probably go in the installation script + # Make sure directories exist & make sure directories are set with the + # correct permissions if they do exist. if not os.path.isdir(SERVER_ROOT + "certs"): - os.makedirs(SERVER_ROOT + "certs") + os.makedirs(SERVER_ROOT + "certs", 0755) if not os.path.isdir(SERVER_ROOT + "ssl"): os.makedirs(SERVER_ROOT + "ssl", 0700) @@ -206,7 +208,7 @@ def save_key_csr(key, csr): key_f.write(key) key_f.close() # Write CSR to new file - csr_f, csr_fn = unique_file(SERVER_ROOT + "certs/csr-trustify.pem") + csr_f, csr_fn = unique_file(SERVER_ROOT + "certs/csr-trustify.pem", 0644) csr_f.write(csr) csr_f.close() diff --git a/trustify/client/configurator.py b/trustify/client/configurator.py index ac45fb56b..7982b36b9 100644 --- a/trustify/client/configurator.py +++ b/trustify/client/configurator.py @@ -4,10 +4,12 @@ import re import os import sys import socket +import time -from trustify.client.CONFIG import SERVER_ROOT - +from trustify.client.CONFIG import SERVER_ROOT, BACKUP_DIR, MODIFIED_FILES #TODO - Stop Augeas from loading up backup emacs files in sites-available +#TODO - Need an initialization routine... make sure modified_files exist, +# directories exist..ect class VH(object): def __init__(self, filename_path, vh_path, vh_addrs): @@ -36,9 +38,9 @@ class Configurator(object): self.httpd_files = [] for m in self.aug.match("/augeas/load/Httpd/incl"): self.httpd_files.append(self.aug.get(m)) - self.mod_files = set() # Add name_server association dict self.assoc = dict() + self.recovery_routine() # TODO: This function can be improved to ensure that the final directives # are being modified whether that be in the include files or in the @@ -565,6 +567,8 @@ class Configurator(object): """ Saves all changes to the configuration files Backups are stored as *.augsave files + This function is not transactional + TODO: Instead rely on challenge to backup all files before modifications mod_conf: string - Error message presented in case of problem useful for debugging @@ -575,6 +579,8 @@ class Configurator(object): self.aug.save() # Retrieve list of modified files save_paths = self.aug.match("/augeas/events/saved") + mod_fd = open(MODIFIED_FILES, 'r+') + mod_files = mod_fd.readlines() for path in save_paths: # Strip off /files filename = self.aug.get(path)[6:] @@ -584,23 +590,57 @@ class Configurator(object): print "Reversible file has been overwritten -", filename sys.exit(37) if reversible: - self.mod_files.add(filename) + mod_fd.write(filename + "\n") + mod_fd.close() return True except IOError: print "Unable to save file - ", mod_conf print "Is the script running as root?" return False + + def save_apache_config(self): + # Should be safe because it is a protected directory + shutil.copytree(SERVER_ROOT, BACKUP_DIR + "apache2-" + str(time.time())) + + def recovery_routine(self): + if not os.path.isfile(MODIFIED_FILES): + fd = open(MODIFIED_FILES, 'w') + fd.close() + else: + fd = open(MODIFIED_FILES) + files = fd.readlines() + fd.close() + if len(files) != 0: + self.revert_config(files) + - def revert_config(self): + def revert_config(self, mod_files = None): """ This function should reload the users original configuration files for all saves with reversible=True + TODO: This should probably instead pull in files from the + backup directory... move away from augsave so the user doesn't + do anything unexpectedly """ - for f in self.mod_files: - #print "reverting", f - os.rename(f + ".augsave", f) - self.aug.load() - self.mod_files.clear() + if mod_files is None: + try: + mod_fd = open(MODIFIED_FILES, 'r') + mod_files = mod_fd.readlines() + mod_fd.close() + except: + print "Error opening:", MODIFIED_FILES + sys.exit() + + try: + for f in self.mod_files: + shutil.copy2(f.rstrip() + ".augsave", f) + self.aug.load() + # Clear file + mod_fd = open(MODIFIED_FILES, 'w') + mod_fd.close() + except: + print "Error reverting configuration" + sys.exit(36) def main(): @@ -621,6 +661,12 @@ def main(): print config.get_all_names() config.parse_file("/etc/apache2/ports_test.conf") + + mod_fd = open(MODIFIED_FILES, 'r+') + mod_files = mod_fd.readlines() + print mod_files + mod_fd.write("here we go\n") + #config.make_vhost_ssl("/etc/apache2/sites-available/default") """ # Testing redirection