Commit 4287f054 authored by Alain Takoudjou's avatar Alain Takoudjou

add securedelete script used to securely wipe files

parent 9c64cf45
......@@ -106,6 +106,7 @@ setup(name=name,
'pubsubserver = slapos.pubsub:main',
'qemu-qmp-client = slapos.qemuqmpclient:main',
'rdiffbackup.genstatrss = slapos.resilient.rdiffBackupStat2RSS:main',
'securedelete = slapos.securedelete:main',
'slapos-kill = slapos.systool:kill',
'slaprunnertest = slapos.runner.runnertest:main',
'slaprunnerteststandalone = slapos.runner.runnertest:runStandaloneUnitTest',
......
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import argparse
import subprocess
import psutil
import glob
def getAgumentParser():
"""
Return argument parser for secure delete script.
"""
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--iterations', default=1, type=int,
help='overwrite N times instead of the default (1)')
parser.add_argument('-u', '--remove', action='store_true',
help='truncate and remove file after overwriting.')
parser.add_argument('-z', '--zero', action='store_true',
help='add a final overwrite with zeros to hide shredding.')
parser.add_argument('-s', '--skip-non-exist', action='store_true',
default=False,
help='If a file don\'t exists, skip instead of raise.')
parser.add_argument('--file', dest='file_list',
required=True, nargs='+', metavar='FILE',
help='File(s) to overwrite and remove if -u is used.')
parser.add_argument('-p', '--check-pid', type=int, metavar="PID",
help='If process is running with PID, abort command. ' \
'This is to prevent delete files used by a process.')
parser.add_argument('--check-pid-file', metavar="PID_FILE",
help='Same as "check-pid" option but read PID from PID_FILE')
return parser
def getFileList(source_file_list, check_exists):
file_list = []
for file_path in source_file_list:
for file in glob.glob(file_path):
if check_exists and not os.path.exists(file):
continue
file_list.append(os.path.realpath(file))
assert len(file_list) > 0, file_list
return file_list
def shred(options):
# Overwrite the specified FILE(s) repeatedly, in order to make it harder
# for even very expensive hardware probing to recover the data.
# using Linux `shred` utility
check_pid = None
if options.check_pid_file:
with open(options.check_pid_file, 'r') as fpid:
check_pid = int(fpid.read())
else:
check_pid = options.check_pid
if check_pid and psutil.pid_exists(check_pid):
raise Exception("check-pid is enabled and process with pid %s is running. "\
  • This Exception seems not the right one, better pick a more appropriated one.

Please register or sign in to reply
"Cannot wipe file(s) while the process is running." % check_pid)
arg_list = ['/usr/bin/shred', '-n', str(options.iterations), '-v']
  • This seems not good, as the path is hardcoded. It is better use whatever is available on PATH instead (or pass as parameter)

    Edited by Rafael Monnerat
Please register or sign in to reply
if options.remove:
arg_list.append('-u')
if options.zero:
arg_list.append('-z')
arg_list.extend(getFileList(options.file_list, options.skip_non_exist))
pshred = subprocess.Popen(arg_list, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
result = pshred.communicate()[0]
  • I think here you ignore and discard the stderr, it is probably better print nicely the stdout no?

Please register or sign in to reply
if pshred.returncode is None:
pshred.kill()
if pshred.returncode != 0:
raise RuntimeError('Command %r failed, with output:\n%s' % (
' '.join(arg_list), result))
return result
def main():
arg_parser = getAgumentParser()
output = shred(arg_parser.parse_args())
print output
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2017 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import unittest
import os.path
import tempfile
import shutil
from datetime import date
from slapos.securedelete import getAgumentParser, shred
class TestSecureDelete(unittest.TestCase):
def setUp(self):
_, self.remove_file = tempfile.mkstemp()
_, self.remove_file2 = tempfile.mkstemp()
with open(self.remove_file, 'w') as f:
f.write("Skjsds@ßdjierhjzlalaa...")
with open(self.remove_file2, 'w') as f:
f.write("Skjsds@ßdjiesdsdrhjzlalaa...")
def tearDown(self):
if os.path.exists(self.remove_file):
os.remove(self.remove_file)
if os.path.exists(self.remove_file2):
os.remove(self.remove_file2)
def test_secure_remove_file(self):
options = getAgumentParser().parse_args(['-n', '2', '-u', '-z', '--file', self.remove_file])
passes = 2 + 1 # Option -z is used, plus one more pass
result = shred(options)
self.assertFalse(os.path.exists(self.remove_file))
self.assertTrue("pass %s/%s" % (passes, passes) in result)
self.assertTrue("%s: removed" % os.path.basename(self.remove_file) in result)
def test_secure_remove_file_keep_file(self):
options = getAgumentParser().parse_args(['-n', '2', '-z', '--file', self.remove_file])
passes = 2 + 1 # Option -z is used, plus one more pass
result = shred(options)
self.assertTrue(os.path.exists(self.remove_file))
self.assertTrue("pass %s/%s" % (passes, passes) in result)
self.assertFalse("%s: removed" % os.path.basename(self.remove_file) in result)
def test_secure_remove_file_non_zero(self):
options = getAgumentParser().parse_args(['-n', '2', '-u', '--file', self.remove_file])
passes = 2
result = shred(options)
self.assertFalse(os.path.exists(self.remove_file))
self.assertTrue("pass %s/%s" % (passes, passes) in result)
self.assertTrue("%s: removed" % os.path.basename(self.remove_file) in result)
def test_secure_remove_file_multiple_files(self):
options = getAgumentParser().parse_args(['-n', '2', '-u', '-z', '--file', self.remove_file, self.remove_file2])
passes = 2 + 1 # Option -z is used, plus one more pass
result = shred(options)
self.assertFalse(os.path.exists(self.remove_file))
self.assertTrue("pass %s/%s" % (passes, passes) in result)
self.assertTrue("%s: removed" % os.path.basename(self.remove_file) in result)
self.assertFalse(os.path.exists(self.remove_file2))
self.assertTrue("%s: removed" % os.path.basename(self.remove_file2) in result)
if __name__ == '__main__':
unittest.main()
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