From 518654df61488d454c051951a18c7793b935a7d4 Mon Sep 17 00:00:00 2001 From: Paul Rodger Date: Mon, 20 May 2002 06:14:54 +0000 Subject: [PATCH] We now call mkdir() to create a temporary directory to store any generated tempfiles. This should be a lot more secure. --- CHANGELOG | 3 +++ Makefile | 2 +- TODO | 1 + archivemail.py | 49 ++++++++++++++++++--------------------------- setup.py | 2 +- test_archivemail.py | 37 ---------------------------------- 6 files changed, 26 insertions(+), 68 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 51a040c..3b48b20 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 0.4.8 - 20 May 2002 + * Call mkdir() to create a container directory in which we can place any + created tempfiles Version 0.4.7 - 9 May 2002 * Fixed a bug where archivemail would abort if it received a date header diff --git a/Makefile b/Makefile index 8979dee..288089a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -VERSION=0.4.7 +VERSION=0.4.8 VERSION_TAG=v$(subst .,_,$(VERSION)) TARFILE=archivemail-$(VERSION).tar.gz diff --git a/TODO b/TODO index f11f40c..77013d6 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ Goals for next minor release (0.4.8): ------------------------------------- +* When you get a file-not-found in the 6th mailbox of 10, it aborts * Think about the best way to specify the names of archives created with possibly an --archive-name option. * Add more tests (see top of test_archivemail.py) diff --git a/archivemail.py b/archivemail.py index dd19e0d..d82892e 100755 --- a/archivemail.py +++ b/archivemail.py @@ -22,7 +22,7 @@ Website: http://archivemail.sourceforge.net/ """ # global administrivia -__version__ = "archivemail v0.4.7" +__version__ = "archivemail v0.4.8" __cvs_id__ = "$Id$" __copyright__ = """Copyright (C) 2002 Paul Rodger This is free software; see the source for copying conditions. There is NO @@ -112,6 +112,7 @@ class StaleFiles: archive = None # tempfile for messages to be archived procmail_lock = None # original_mailbox.lock retain = None # tempfile for messages to be retained + temp_dir = None # our tempfile directory container def clean(self): """Delete any temporary files or lockfiles that exist""" @@ -127,6 +128,10 @@ class StaleFiles: vprint("removing stale archive file '%s'" % self.archive) try: os.remove(self.archive) except (IOError, OSError): pass + if self.temp_dir: + vprint("removing stale tempfile directory '%s'" % self.temp_dir) + try: os.rmdir(self.temp_dir) + except (IOError, OSError): pass class Options: @@ -418,7 +423,7 @@ class RetainMbox(Mbox): """ assert(final_name) - temp_name = tempfile.mktemp("archivemail_retain") + temp_name = tempfile.mktemp("retain") self.mbox_file = open(temp_name, "w") self.mbox_file_name = temp_name _stale.retain = temp_name @@ -490,7 +495,7 @@ class ArchiveMbox(Mbox): unexpected_error("""There is already a file named '%s'! Have you been previously compressing this archive? You probably should uncompress it manually, and try running me again.""" % compressed_archive) - temp_name = tempfile.mktemp("archivemail_archive") + temp_name = tempfile.mktemp("archive") if os.path.isfile(final_name): vprint("file already exists that is named: %s" % final_name) shutil.copy2(final_name, temp_name) @@ -507,7 +512,7 @@ uncompress it manually, and try running me again.""" % compressed_archive) Have you been reading this archive? You probably should re-compress it manually, and try running me again.""" % final_name) - temp_name = tempfile.mktemp("archivemail_archive.gz") + temp_name = tempfile.mktemp("archive.gz") if os.path.isfile(compressed_filename): vprint("file already exists that is named: %s" % \ compressed_filename) @@ -923,10 +928,16 @@ def archive(mailbox_name): os.path.basename(final_archive_name)) vprint("archiving '%s' to '%s' ..." % (mailbox_name, final_archive_name)) + # create a temporary directory for us to work in securely old_temp_dir = tempfile.tempdir - tempfile.tempdir = choose_temp_dir(mailbox_name) - assert(tempfile.tempdir) - vprint("set tempfile directory to '%s'" % tempfile.tempdir) + tempfile.tempdir = None + new_temp_dir = tempfile.mktemp('archivemail') + assert(new_temp_dir) + os.mkdir(new_temp_dir) + _stale.temp_dir = new_temp_dir + tempfile.tempdir = new_temp_dir + + vprint("set tempfile directory to '%s'" % new_temp_dir) # check to see if we are running as root -- if so, change our effective # userid and groupid to that of the original mailbox @@ -961,6 +972,8 @@ def archive(mailbox_name): vprint("changing effective groupid and userid back to root") os.setegid(0) os.seteuid(0) + os.rmdir(new_temp_dir) + _stale.temp_dir = None tempfile.tempdir = old_temp_dir @@ -1103,28 +1116,6 @@ def _archive_dir(mailbox_name, final_archive_name, type): ############### misc functions ############### -def choose_temp_dir(mailbox_name): - """Return a suitable temporary directory to use for a given mailbox name""" - assert(mailbox_name) - mailbox_dirname = os.path.dirname(mailbox_name) - temp_dir = None - - if options.output_dir: - temp_dir = options.output_dir - elif mailbox_dirname: - temp_dir = mailbox_dirname - else: - temp_dir = os.curdir - assert(temp_dir) - if is_world_writable(temp_dir): - unexpected_error(("temporary directory is world-writable: " + \ - "%s -- I feel nervous!") % temp_dir) - if not os.access(temp_dir, os.W_OK): - user_error("no write permission on temporary directory: '%s'" % \ - temp_dir) - return temp_dir - - def set_signal_handlers(): """set signal handlers to clean up temporary files on unexpected exit""" # Make sure we clean up nicely - we don't want to leave stale procmail diff --git a/setup.py b/setup.py index 43743ec..9e79173 100755 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ check_python_version() # define & run this early - 'distutils.core' is new from distutils.core import setup setup(name="archivemail", - version="0.4.7", + version="0.4.8", description="archive and compress old email", license="GNU GPL", url="http://archivemail.sourceforge.net/", diff --git a/test_archivemail.py b/test_archivemail.py index 0af5f7a..96f0cf6 100755 --- a/test_archivemail.py +++ b/test_archivemail.py @@ -300,43 +300,6 @@ class TestIsTooOld(unittest.TestCase): assert(not archivemail.is_older_than_days(time_message=time_msg, max_days=1)) -################ archivemail.choose_temp_dir() unit testing ############# - -class TestChooseTempDir(unittest.TestCase): - def setUp(self): - self.output_dir = tempfile.mktemp() - os.mkdir(self.output_dir) - self.sub_dir = tempfile.mktemp() - os.mkdir(self.sub_dir) - - def testCurrentDir(self): - """use the current directory as a temp directory with no output dir""" - archivemail.options.output_dir = None - dir = archivemail.choose_temp_dir("dummy") - self.assertEqual(dir, os.curdir) - - def testSubDir(self): - """use the mailbox parent directory as a temp directory""" - archivemail.options.output_dir = None - dir = archivemail.choose_temp_dir(os.path.join(self.sub_dir, "dummy")) - self.assertEqual(dir, self.sub_dir) - - def testOutputDir(self): - """use the output dir as a temp directory when specified""" - archivemail.options.output_dir = self.output_dir - dir = archivemail.choose_temp_dir("dummy") - self.assertEqual(dir, self.output_dir) - - def testSubDirOutputDir(self): - """use the output dir as temp when given a mailbox directory""" - archivemail.options.output_dir = self.output_dir - dir = archivemail.choose_temp_dir(os.path.join(self.sub_dir, "dummy")) - self.assertEqual(dir, self.output_dir) - - def tearDown(self): - os.rmdir(self.output_dir) - os.rmdir(self.sub_dir) - ########## acceptance testing ###########