def __initialize_filestore(self): """ Initialize the filestore """ if not os.path.exists(self.__filestore_path): self.__create_empty_filestore() try: file_obj = open(self.__filestore_path, 'r') except: msg = 'FATAL ERROR: error opening filestore' self.__logger.log_err('Filestore engine error: ' + msg) raise tcs_utils.ActionError(msg) try: object = pickle.loads(zlib.decompress(file_obj.read())) file_obj.close() except: # Corrupted datastore, recreating msg = 'ERROR: corrupted filestore detected, creating new filestore' self.__logger.log_err('Filestore engine error: ' + msg) self.__create_empty_filestore() object = {} return object
def __initialize_modules(self, list): """ Returns a list of modules on which you can invoke analyze, apply and undo functions """ instantiated_module_list = [] for module in list: try: if module['ModuleType'] == 'generic': exec ('from sb_utils.generic_modules import %s' % \ module['ModuleFilename']) elif module['ModuleType'] == 'specific': exec ('from security_modules import %s' % \ module['ModuleFilename']) else: msg = 'FATAL ERROR, invalid module type: %s' % \ module['ModuleType'] self.logger.log_err('Module init error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) except ImportError: msg = 'Error Importing: %s' % module['ModuleFilename'] self.logger.log_err(self.module_name, msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) paramList = module['ModuleParams'].values() paramList.reverse() paramString = str(paramList).lstrip('[').rstrip(']') try: # TODO: add some regex here to make this safer exec ('instantiated_module_list.append(%s.%s (%s))' % \ (module['ModuleFilename'], \ module['ModuleName'], \ paramString)) except: msg = 'Error Initializing: %s' % module['ModuleFilename'] self.logger.log_err(self.module_name, msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) return instantiated_module_list
def revert_to_diff(diff, target_file): """ Helper function to revert file to previous state. """ try: # TODO: find more elegant way of doing this tmp_file = open("trash", 'w') tmp_file.write(diff) tmp_file.close() except Exception, err: msg = "Cannot create tempory undo file (" + str(err) + ")." raise tcs_utils.ActionError(msg)
def generate_diff_record(fromfilename, tofilename, calling_ident=None): """ Generate a string containing a unified diff between the specified files. """ diff_string = "" cmd = "/usr/bin/diff -Nur " + fromfilename + ' ' + tofilename out = tcs_utils.tcs_run_cmd(cmd, True) if out[0] == 2: msg = "ERROR: Unable to generate diff record." raise tcs_utils.ActionError(msg) elif out[0] == 1: diff_string = out[1] return diff_string
def move_file_over(tmp_file, target_file): """ Copy temp file over to target file, ensuring target's permissions are not changed """ try: shutil.copymode(target_file, tmp_file) shutil.copy2(tmp_file, target_file) shutil.copymode(tmp_file, target_file) sb_utils.SELinux.restoreSecurityContext(target_file) os.unlink(tmp_file) except Exception, err: msg = "Unexpected error replacing original file (" + str(err) + ")." raise tcs_utils.ActionError(msg)
def __create_empty_filestore(self): """ Create an empty filestore """ #Ensure our filestore has the correct permissions os.umask(077) if os.path.exists(self.__filestore_path): os.unlink(self.__filestore_path) try: file_obj = open(self.__filestore_path, 'w') except: msg = 'FATAL ERROR: error creating template filestore' self.__logger.log_err('TemplateStore ', msg) raise tcs_utils.ActionError(msg) emptyDict = {} objectStr = zlib.compress(pickle.dumps(emptyDict)) file_obj.truncate() file_obj.write(objectStr) file_obj.close()
# TODO: find more elegant way of doing this tmp_file = open("trash", 'w') tmp_file.write(diff) tmp_file.close() except Exception, err: msg = "Cannot create tempory undo file (" + str(err) + ")." raise tcs_utils.ActionError(msg) cmd = "/usr/bin/patch -p0 -s -t < trash" ret = tcs_utils.tcs_run_cmd(cmd, True) os.unlink('trash') if ret[0] != 0: msg = "Unable to revert file: (%s)." % ret[1].rstrip('\n') raise tcs_utils.ActionError(msg) return (True, '') ############################################################################## def move_file_over(tmp_file, target_file): """ Copy temp file over to target file, ensuring target's permissions are not changed """ try: shutil.copymode(target_file, tmp_file) shutil.copy2(tmp_file, target_file) shutil.copymode(tmp_file, target_file)
def undo(self, action_record=None): """Undo previous change application.""" self.logger.log_debug(self.module_name, 'Initiating undo change.') # NOTE: not running analyze system in undo due to the ability to pass # in custom parameters #result = self.scan()[0] #if result == 'Fail': # return 0 # Unpack action_record object action_record = tcs_utils.extractFromString(action_record) # set the current system value cmd = '%s -w %s=%s' % (self.__sysctl_path, self.__kernel_parameter, \ action_record[0]) output_tuple = tcs_utils.tcs_run_cmd(cmd) if output_tuple[0] != 0: msg = "Unexpected return value (%s)" % output_tuple[0] self.logger.log_info(self.module_name, 'Undo Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) # # Modify the sysctl.conf file so the parameter is set on reboot # if os.access(self.__target_file, os.R_OK): origfile = open(self.__target_file, 'r') else: msg = "Cannot open source file (" + self.__target_file + ")." self.logger.log_err(self.module_name, 'Undo Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) try: workfile = open(self.__tmp_file, 'w') except OSError: msg = "Unable to create temporary file (" + self.__tmp_file + ")." self.logger.log_err(self.module_name, 'Undo Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) found = False # Search for corrected line regex = re.compile('^\s*%s\s*$' % action_record[1]) for line in origfile: # NOTE: we ignore commented out lines if (not found and regex.match(line)): workfile.write(action_record[2]) found = True # Strip out all other duplicate lines elif regex.match(line): pass else: workfile.write(line) origfile.close() workfile.close() # Ensure we replicate permissions off of original file (if exists) try: shutil.copymode(self.__target_file, self.__tmp_file) shutil.copy2(self.__tmp_file, self.__target_file) sb_utils.SELinux.restoreSecurityContext(self.__target_file) os.unlink(self.__tmp_file) except Exception, err: msg = "Unexpected error replacing original file (" + str( err) + ")." self.logger.log_err(self.module_name, 'Undo Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg))
def apply(self, option=None): """ Set kernel parameter to predefined setting """ if not option: option = self.__value else: option = int(option) self.logger.log_debug(self.module_name, 'Initiating apply change.') result = self.scan(option)[0] if result == 'Pass': return 0, str(option) # Protect file tcs_utils.protect_file(self.__target_file) # make sure we have the original values from the system before we # start modifying them, so we can save them for the change record # (note: we don't bother checking to see whether the command # succeeded - it won't fail now if it didn't fail in the call # to scan() above) # NOTE: In order for undo to succeed, the parameter value in memory has # to be the same as the parameter value stored in /etc/sysctl.conf # This might be something TODO in the future. if not self.__analysis_results: cmd = '%s -n %s' % (self.__sysctl_path, self.__kernel_parameter) output_tuple = tcs_utils.tcs_run_cmd(cmd) self.__analysis_results = output_tuple[1].strip() # set the current system value cmd = '%s -w %s=%s' % (self.__sysctl_path, self.__kernel_parameter, \ option) self.logger.log_notice(self.module_name, 'Executing: ' + cmd) output_tuple = tcs_utils.tcs_run_cmd(cmd) if output_tuple[0] != 0: msg = "Unexpected return value (%s): %s" % (output_tuple[0], output_tuple[2]) self.logger.log_info(self.module_name, 'Apply Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) # # Modify the sysctl.conf file so the parameter is set on reboot # if os.access(self.__target_file, os.R_OK): origfile = open(self.__target_file, 'r') # Create /etc/sysctl.conf file if doesn't exist # NOTE: we do not undo this action elif not os.path.exists(self.__target_file): # Create the configuration file from sb_utils.file import TemplateStore store = TemplateStore.TemplateStore() if store.has_key(self.__target_file): store.write_to_path(self.__target_file) else: msg = "Error creating file (" + self.__target_file + ")." self.logger.log_err(self.module_name, 'Apply Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) # Clean up after ourselves del store del TemplateStore origfile = open(self.__target_file, 'r') else: msg = "Cannot open source file (" + self.__target_file + ")." self.logger.log_err(self.module_name, 'Apply Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) try: workfile = open(self.__tmp_file, 'w') except OSError: msg = "Unable to create temporary file (" + self.__tmp_file + ")." self.logger.log_err(self.module_name, 'Apply Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg)) found = False regex = re.compile('\s*%s\s*=\s*\d+' % self.__kernel_parameter) correct_line = ' %s = %s\n' % (self.__kernel_parameter, option) old_match = '' for line in origfile: # NOTE: we ignore commented out lines if (not found and regex.match(line)): old_match = line workfile.write(correct_line) found = True # Strip out all other duplicate lines elif regex.match(line): pass else: workfile.write(line) # Stick the lines in if we didn't find them if not found: workfile.write(correct_line) origfile.close() workfile.close() # Ensure we replicate permissions off of original file (if exists) try: shutil.copymode(self.__target_file, self.__tmp_file) shutil.copy2(self.__tmp_file, self.__target_file) sb_utils.SELinux.restoreSecurityContext(self.__target_file) os.unlink(self.__tmp_file) except Exception, err: msg = "Unexpected error replacing original file (" + str( err) + ")." self.logger.log_err(self.module_name, 'Apply Error: ' + msg) raise tcs_utils.ActionError('%s %s' % (self.module_name, msg))