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. "\
"Cannot wipe file(s) while the process is running." % check_pid)
arg_list = ['/usr/bin/shred', '-n', str(options.iterations), '-v']
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]
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