[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Be a bit more reasonable about shredding files



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.seul.org:/tmp/cvs-serv2459/lib/mixminion

Modified Files:
	Common.py 
Log Message:
Be a bit more reasonable about shredding files

Index: Common.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Common.py,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- Common.py	2 Dec 2002 03:21:54 -0000	1.26
+++ Common.py	2 Dec 2002 20:18:08 -0000	1.27
@@ -14,6 +14,7 @@
 import sys
 import time
 import stat
+import statvfs
 import traceback
 import calendar
 from types import StringType
@@ -127,6 +128,7 @@
 # Secure filesystem operations.
 #
 
+
 _SHRED_CMD = "---"
 _SHRED_OPTS = None
     
@@ -143,13 +145,37 @@
 
     if cmd is None:
         if os.path.exists("/usr/bin/shred"):
-            cmd, opts = "/usr/bin/shred", ["-uz"]
+            cmd, opts = "/usr/bin/shred", ["-uz", "-n0"]
         else:
             getLog().warn("Files will not be securely deleted.")
             cmd, opts = None, None
 
     _SHRED_CMD, _SHRED_OPTS = cmd, opts
 
+
+# Size of a block on the filesystem we're overwriting on
+_BLKSIZE = 0
+# A string of _BLKSIZE zeros
+_NILSTR = None
+def _overwriteFile(f):
+    """Overwrite f with zeros, rounding up to the nearest block.  This is
+       used as the default implementation of secureDelete."""
+    global _BLKSIZE
+    global _NILSTR
+    if not _BLKSIZE:
+	#???? this assumes that all filesystems we are using have the same
+	#??? block size.
+	_BLKSIZE = os.statvfs(f)[statvfs.F_BSIZE]
+	_NILSTR = '\x00' * _BLKSIZE
+    fd = os.open(f, os.O_WRONLY)
+    try:
+	size = os.fstat(fd)[stat.ST_SIZE]
+	blocks = ceilDiv(size, _BLKSIZE)
+	for _ in xrange(blocks):
+	    os.write(fd, _NILSTR)
+    finally:
+	os.close(fd)
+
 def secureDelete(fnames, blocking=0):
     """Given a list of filenames, removes the contents of all of those
        files, from the disk, 'securely'.  If blocking=1, does not
@@ -158,11 +184,24 @@
        files.  (Returns None if this process unlinked the files
        itself.) 
 
-       XXXX Securely deleting files only does so much good.  Metadata on
-       XXXX the file system, such as atime and dtime, can still be used
-       XXXX to reconstruct information about message timings.  To be
-       XXXX really safe, we should use a loopback device and shred _that_
-       XXXX from time to time.
+       Securely deleting files only does so much good.  Metadata on
+       the file system, such as atime and dtime, can still be used to
+       reconstruct information about message timings.  To be more
+       safe, we could use a loopback device and shred _that_ from time
+       to time.  But since many filesystems relocate data underneath
+       you, you can't trust loopback devices: a separate shreddable
+       partition is necessary.  But even then, HD controllers and
+       drives sometimes relocate blocks to avoid bad blocks: then
+       there's no way to overwrite the old locations!  The only
+       heavy-duty solution is to use an encrypted filesystem and swap
+       partition from the get-go... or to physically destroy and
+       replace your hard drive every so often.)
+
+       So we don't even bother trying to make the data 'physcially
+       irretrievable.'  We just zero it out, which should be good
+       enough to stymie root for most purposes, and totally inadequate
+       against a well-funded adversary with access to your hard drive
+       and a bunch of sensitive magnetic equipment.
 
        XXXX Currently, we use shred from GNU fileutils.  Shred's 'unlink'
        XXXX operation has the regrettable property that two shred commands
@@ -178,18 +217,19 @@
     
     if isinstance(fnames, StringType):
         fnames = [fnames]
+
+    if not _SHRED_CMD:
+        for f in fnames:
+	    _overwriteFile(f)
+            os.unlink(f)
+        return None
+	
     if blocking:
         mode = os.P_WAIT
     else:
         mode = os.P_NOWAIT
 
-    if _SHRED_CMD:
-        code = os.spawnl(mode, _SHRED_CMD, _SHRED_CMD, *(_SHRED_OPTS+fnames))
-	return code
-    else:
-        for f in fnames:
-            os.unlink(f)
-        return None
+    return os.spawnl(mode, _SHRED_CMD, _SHRED_CMD, *(_SHRED_OPTS+fnames))
 
 #----------------------------------------------------------------------
 # Logging