Blob Blame History Raw
# HG changeset patch
# User Yann Leboulanger <asterix@lagaule.org>
# Date 1334652355 -7200
# Node ID f046e4aaf7d49b2934622db66da1667ddddb1703
# Parent  0a8585330ccaa26f97ead998c29427d31c5d395b
more secure tmp file creation for latex

diff --git a/src/common/latex.py b/src/common/latex.py
--- a/src/common/latex.py
+++ b/src/common/latex.py
@@ -29,7 +29,7 @@
 
 import os
 import random
-from tempfile import gettempdir
+from tempfile import mkstemp, mkdtemp
 from subprocess import Popen, PIPE
 
 import logging
@@ -57,24 +57,6 @@
             return True
     return False
 
-def get_tmpfile_name():
-    random.seed()
-    nb = 0
-    while(nb < 100):
-        int_ = random.randint(0, 10000)
-        filename = os.path.join(gettempdir(), 'gajimtex_' + int_.__str__())
-        # Check if a file to not overwrite it
-        ok = True
-        extensions = ['.tex', '.log', '.aux', '.dvi']
-        for ext in extensions:
-            if os.path.exists(filename + ext):
-                ok = False
-                break
-        if ok:
-            return filename
-        nb += 1
-    return filename
-
 def write_latex(filename, str_):
     texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
     texstr += '\\usepackage{amsmath}\\usepackage{amssymb}'
@@ -91,12 +73,13 @@
 # a wrapper for Popen so that no window gets opened on Windows
 # (i think this is the reason we're using Popen rather than just system())
 # stdout goes to a pipe so that it can be read
-def popen_nt_friendly(command):
+def popen_nt_friendly(command, directory):
     if os.name == 'nt':
         # CREATE_NO_WINDOW
-        return Popen(command, creationflags=0x08000000, cwd=gettempdir(), stdout=PIPE)
+        return Popen(command, creationflags=0x08000000, cwd=directory,
+            stdout=PIPE)
     else:
-        return Popen(command, cwd=gettempdir(), stdout=PIPE)
+        return Popen(command, cwd=directory, stdout=PIPE)
 
 def check_for_latex_support():
     """
@@ -112,16 +95,16 @@
     except LatexError:
         return False
 
-def try_run(argv):
+def try_run(argv, directory):
     try:
-        p = popen_nt_friendly(argv)
+        p = popen_nt_friendly(argv, directory)
         out = p.communicate()[0]
         log.info(out)
         return p.wait()
     except Exception, e:
         return _('Error executing "%(command)s": %(error)s') % {
-                'command': " ".join(argv),
-                'error': helpers.decode_string(str(e))}
+            'command': " ".join(argv),
+            'error': helpers.decode_string(str(e))}
 
 
 def latex_to_image(str_):
@@ -137,32 +120,41 @@
             return []
         except AttributeError:
             # interface may not be available when we test latext at startup
-            return ['-fg', 'rgb 0.0 0.0 0.0']
+            return {'hex': ['+level-colors', '0x000000'],
+                'tex': ['-fg', 'rgb 0.0 0.0 0.0']}[fmt]
 
     # filter latex code with bad commands
     if check_blacklist(str_):
         # we triggered the blacklist, immediately return None
         return None
 
-    tmpfile = get_tmpfile_name()
+    try:
+        tmpdir = mkdtemp(prefix='gajimtex')
+        tmppng = mkstemp(prefix='gajim_tex', suffix='.png')[1]
+    except Exception:
+        raise LatexError('could not securely create one or more temporary files'
+            ' for LaTeX conversion')
+
+    tmpfile = os.path.join(tmpdir, 'gajim_tex')
 
     # build latex string
-    write_latex(os.path.join(tmpfile + '.tex'), str_)
+    write_latex(tmpfile + '.tex', str_)
 
     # convert TeX to dvi
-    exitcode = try_run(['latex', '--interaction=nonstopmode',
-                      tmpfile + '.tex'])
+    exitcode = try_run(['latex', '--interaction=nonstopmode', tmpfile + '.tex'],
+        tmpdir)
 
     if exitcode == 0:
         # convert dvi to png
         latex_png_dpi = gajim.config.get('latex_png_dpi')
         exitcode = try_run(['dvipng'] + fg_str('tex') + ['-T', 'tight', '-D',
-            latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png'])
+            latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png'], tmpdir)
 
         if exitcode:
             # dvipng failed, try convert
             exitcode = try_run(['convert'] + fg_str('hex') + ['-trim',
-                '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png'])
+                '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png'],
+                tmpdir)
 
     # remove temp files created by us and TeX
     extensions = ['.tex', '.log', '.aux', '.dvi']
@@ -172,10 +164,15 @@
         except Exception:
             pass
 
+    if exitcode == 0:
+        os.rename(tmpfile + '.png', tmppng)
+
+    os.rmdir(tmpdir)
+
     if isinstance(exitcode, (unicode, str)):
         raise LatexError(exitcode)
 
     if exitcode == 0:
-        result = tmpfile + '.png'
+        result = tmppng
 
     return result