Your message dated Wed, 30 Aug 2006 14:54:19 -0400
with message-id <[EMAIL PROTECTED]>
and subject line fixed..
has caused the attached Bug report to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what I am
talking about this indicates a serious mail system misconfiguration
somewhere.  Please contact me immediately.)

Debian bug tracking system administrator
(administrator, Debian Bugs database)

--- Begin Message ---
Package: archivemail
Version: 0.6.2-1
Severity: grave
Tags: security

tempfile.mktemp in python has this comment:

    User-callable function to return a unique temporary file name.  The
    file is not created.

    Arguments are as for mkstemp, except that the 'text' argument is
    not accepted.

    This function is unsafe and should not be used.  The file name
    refers to a file that did not exist at some point, but by the time
    you get around to creating it, someone else may have beaten you to
    the punch.

While I was looking over archivemail's source due to bug #385249, I
noticed that it creates temporary files insecurely. 

        temp_name = tempfile.mktemp("retain")
        self.mbox_file = open(temp_name, "w")

So this seems raceable. Here's another one:

        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)
        _stale.archive = temp_name
        self.mbox_file = open(temp_name, "a")

There are a few more like that.

There are also a lot of other uses of mktemp in the test suite, which
could lead to security problems at build time.

I've attached the patch that I came up with after this little audit. I'll be
releasing to unstable, but thought I should file the bug so this can be hadled
for stable and in case someone wants to get a CVE and such. Upstream
maintainers are CC'd.

Oh, one other funny thing, the TODO has this in it:
"Check for symlink attacks for tempfiles (although we don't use /var/tmp)"

-- 
see shy jo
Index: debian/changelog
===================================================================
--- debian/changelog    (revision 12604)
+++ debian/changelog    (working copy)
@@ -1,3 +1,10 @@
+archivemail (0.6.2-2) unstable; urgency=HIGH
+
+  * Fix a number of temporary file security holes in archivemail and its
+    test suite.
+
+ -- Joey Hess <[EMAIL PROTECTED]>  Wed, 30 Aug 2006 00:09:13 -0400
+
 archivemail (0.6.2-1) unstable; urgency=low
 
   * New upstream release.
Index: test_archivemail.py
===================================================================
--- test_archivemail.py (revision 12604)
+++ test_archivemail.py (working copy)
@@ -318,7 +318,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -346,7 +346,7 @@
 From is on this line
 This is after the ^From line"""
         self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), body=body)
-        self.copy_name = tempfile.mktemp()
+        fd, self.copy_name = tempfile.mkstemp()
         shutil.copyfile(self.mbox_name, self.copy_name)
         archivemail.archive(self.mbox_name)
         assert(os.path.exists(self.mbox_name))
@@ -384,7 +384,7 @@
             for option in ('--date=2000-07-29', '-D2000-07-29', 
                 '--date="29 Jul 2000"', '--date="29 July 2000"'):
                 self.mbox_name = make_mbox(messages=3, headers=headers)
-                self.copy_name = tempfile.mktemp()
+                fd, self.copy_name = tempfile.mkstemp()
                 shutil.copyfile(self.mbox_name, self.copy_name)
                 run = "./archivemail.py -q %s %s" % (option, self.mbox_name)
                 self.assertEqual(os.system(run), 0)
@@ -400,7 +400,7 @@
             for option in ('--date=2000-07-27', '-D2000-07-27', 
                 '--date="27 Jul 2000"', '--date="27 July 2000"'):
                 self.mbox_name = make_mbox(messages=3, headers=headers)
-                self.copy_name = tempfile.mktemp()
+                fd, self.copy_name = tempfile.mkstemp()
                 shutil.copyfile(self.mbox_name, self.copy_name)
                 run = "./archivemail.py -q %s %s" % (option, self.mbox_name)
                 self.assertEqual(os.system(run), 0)
@@ -415,7 +415,7 @@
         for execute in ("package", "system"):
             self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
             self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
-            self.mbox_name = tempfile.mktemp()
+            fd, self.mbox_name = tempfile.mkstemp()
             shutil.copyfile(self.new_mbox, self.mbox_name)
             append_file(self.old_mbox, self.mbox_name)
             if execute == "package":
@@ -441,7 +441,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -465,7 +465,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             archive_name = self.mbox_name + "_archive"
             shutil.copyfile(self.mbox_name, self.copy_name) 
             shutil.copyfile(self.mbox_name, archive_name) # archive has 3 msgs
@@ -535,7 +535,7 @@
         for headers in weird_headers:
             self.setUp()
             self.mbox_name = make_mbox(messages=3, headers=headers)
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             archivemail.archive(self.mbox_name)
             assert(os.path.exists(self.mbox_name))
@@ -641,7 +641,7 @@
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
                 headers={"Status":"RO"})
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -670,7 +670,7 @@
         """archiving an unread mailbox should not create an archive"""
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -707,7 +707,7 @@
         for suffix in ("_static_", "_%B_%Y", "-%Y-%m-%d"):
             for execute in ("system_long", "system_short", "package"):
                 self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
-                self.copy_name = tempfile.mktemp()
+                fd, self.copy_name = tempfile.mkstemp()
                 shutil.copyfile(self.mbox_name, self.copy_name)
                 if execute == "system_long":
                     run = "./archivemail.py --quiet --suffix='%s' %s" % \
@@ -750,7 +750,7 @@
         """archiving an old mailbox with the 'dry-run' option"""
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -785,7 +785,7 @@
         """specifying the 'days' option on an older mailbox"""
         for execute in ("package", "system", "system_long"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 12))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -813,7 +813,7 @@
         """specifying the 'days' option on a newer mailbox"""
         for execute in ("package", "system", "system_long"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 10))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -853,7 +853,7 @@
         """archiving a new mailbox with the 'delete' option"""
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -875,7 +875,7 @@
         for execute in ("package", "system"):
             self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
             self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
-            self.mbox_name = tempfile.mktemp()
+            fd, self.mbox_name = tempfile.mkstemp()
             shutil.copyfile(self.new_mbox, self.mbox_name)
             append_file(self.old_mbox, self.mbox_name)
             if execute == "package":
@@ -897,7 +897,7 @@
         """archiving an old mailbox with the 'delete' option"""
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -931,7 +931,7 @@
         for execute in ("system", "package"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
                 headers={"X-Status":"F"})
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -953,7 +953,7 @@
         for execute in ("system", "package"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179), \
                 headers={"X-Status":"F"})
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -976,7 +976,7 @@
         for execute in ("system", "package"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
                 headers={"X-Status":"F"})
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -1013,7 +1013,7 @@
         """archiving an old mailbox with a sepecified output dir"""
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             self.dir_name = tempfile.mktemp()
             os.mkdir(self.dir_name)
@@ -1070,7 +1070,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.no_compress = 1
@@ -1097,7 +1097,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.no_compress = 1
@@ -1123,7 +1123,7 @@
         for execute in ("package", "system"):
             self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
             self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
-            self.mbox_name = tempfile.mktemp()
+            fd, self.mbox_name = tempfile.mkstemp()
             shutil.copyfile(self.new_mbox, self.mbox_name)
             append_file(self.old_mbox, self.mbox_name)
             if execute == "package":
@@ -1149,7 +1149,7 @@
         for execute in ("package", "system"):
             self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
             self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             archive_name = self.mbox_name + "_archive"
             shutil.copyfile(self.mbox_name, self.copy_name) 
             shutil.copyfile(self.mbox_name, archive_name) # archive has 3 msgs
@@ -1191,7 +1191,7 @@
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181))
             size_arg = os.path.getsize(self.mbox_name) - 1
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -1222,7 +1222,7 @@
         for execute in ("package", "system_long", "system_short"):
             self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181))
             size_arg = os.path.getsize(self.mbox_name) + 1
-            self.copy_name = tempfile.mktemp()
+            fd, self.copy_name = tempfile.mkstemp()
             shutil.copyfile(self.mbox_name, self.copy_name)
             if execute == "package":
                 archivemail.options.quiet = 1
@@ -1351,7 +1351,7 @@
 
 
 def make_mbox(body=None, headers=None, hours_old=0, messages=1):
-    name = tempfile.mktemp()
+    fd, name = tempfile.mkstemp()
     file = open(name, "w")
     for count in range(messages):
         msg = make_message(body=body, default_headers=headers, 
Index: archivemail.py
===================================================================
--- archivemail.py      (revision 12604)
+++ archivemail.py      (working copy)
@@ -439,7 +439,7 @@
 
         """
         assert(final_name)
-        temp_name = tempfile.mktemp("retain")
+        temp_fd, temp_name = tempfile.mkstemp("retain")
         self.mbox_file = open(temp_name, "w")
         self.mbox_file_name = temp_name
         _stale.retain = temp_name
@@ -511,7 +511,7 @@
             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("archive")
+        temp_fd, temp_name = tempfile.mkstemp("archive")
         if os.path.isfile(final_name):
             vprint("file already exists that is named: %s" % final_name)
             shutil.copy2(final_name, temp_name)
@@ -528,7 +528,7 @@
 Have you been reading this archive? You probably should re-compress it
 manually, and try running me again.""" % final_name)
 
-        temp_name = tempfile.mktemp("archive.gz")
+        temp_fd, temp_name = tempfile.mkstemp("archive.gz")
         if os.path.isfile(compressed_filename):
             vprint("file already exists that is named: %s" %  \
                 compressed_filename)

Attachment: signature.asc
Description: Digital signature


--- End Message ---
--- Begin Message ---
Version: 0.6.2-2

Fixed in -2

-- 
see shy jo

Attachment: signature.asc
Description: Digital signature


--- End Message ---

Reply via email to