From 476a20baf518a8fedcc0372c0ee699e7d60d27c4 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 20 Mar 2010 23:56:14 +0000 Subject: epstopdf 2.15 git-svn-id: svn://tug.org/texlive/trunk@17516 c570f23f-e606-0410-a88d-b1316a301751 --- .../texlive/linked_scripts/epstopdf/epstopdf.pl | 187 +++++++++++---------- 1 file changed, 102 insertions(+), 85 deletions(-) (limited to 'Build/source') diff --git a/Build/source/texk/texlive/linked_scripts/epstopdf/epstopdf.pl b/Build/source/texk/texlive/linked_scripts/epstopdf/epstopdf.pl index a312a9b7f90..d7662c96a88 100755 --- a/Build/source/texk/texlive/linked_scripts/epstopdf/epstopdf.pl +++ b/Build/source/texk/texlive/linked_scripts/epstopdf/epstopdf.pl @@ -2,7 +2,7 @@ eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $ if 0; use strict; -# $Id: epstopdf.pl 16244 2009-11-30 01:36:08Z karl $ +# $Id: epstopdf.pl 17496 2010-03-18 17:57:31Z karl $ # (Copyright lines below.) # # Redistribution and use in source and binary forms, with or without @@ -39,14 +39,27 @@ use strict; # c) the result is piped to Ghostscript and a PDF version written. # # It needs a Level 2 PS interpreter. -# If the bounding box is not right, of course, there will be problems. +# If the input bounding box is not right, of course there will be problems. # -# One thing not allowed for is the case of +# One thing not allowed for: the case of # "%%BoundingBox: (atend)" when input is not seekable (e.g., from a pipe), -# which is more complicated. # # emacs-page # History +# 2010/03/19 v2.15 (Karl Berry) +# * let --outfile override --filter again. +# * recognize MSWin64 as well as MSWin32, just in case. +# 2010/03/08 v2.14 (Manuel P\'egouri\'e-Gonnard) +# * In restricted mode, forbid --gscmd (all platforms) and call GS with full +# path relative to self location (Windows). +# 2010/02/26 v2.13 (Karl Berry) +# * New release. +# 2010/02/23 (Manuel P\'egouri\'e-Gonnard) +# * Use kpsewhich for filename validation in restricted mode, both input and +# output. Requires kpathsea 5.1.0 (TL2010), rejects the name with earlier +# versions of kpsewhich. +# * Call external programs with full path on win32 in order to avoid obvious +# attacks with rogue versions of these programs in the current directory. # 2009/11/27 v2.12 (Karl Berry) # * Make --filter work again # 2009/11/25 (Manuel P\'egouri\'e-Gonnard) @@ -133,9 +146,9 @@ use strict; ### program identification my $program = "epstopdf"; -my $ident = '($Id: epstopdf.pl 16244 2009-11-30 01:36:08Z karl $) 2.12'; +my $ident = '($Id: epstopdf.pl 17496 2010-03-18 17:57:31Z karl $) 2.15'; my $copyright = < @@ -144,26 +157,28 @@ There is NO WARRANTY, to the extent permitted by law. END_COPYRIGHT my $title = "$program $ident\n"; +my $on_windows = $^O =~ /^MSWin/; +my $on_windows_or_cygwin = $on_windows || $^O eq "cygwin"; + ### ghostscript command name -my $GS = "gs"; -$GS = "gswin32c" if $^O eq 'MSWin32'; +my $GS = $on_windows ? "gswin32c" : "gs"; ### restricted mode my $restricted = 0; $restricted = 1 if $0 =~ /repstopdf/; ### options -$::opt_outfile=""; -$::opt_compress=1; -$::opt_debug=0; -$::opt_embed=1; -$::opt_exact=0; -$::opt_filter=0; -$::opt_gs=1; -$::opt_hires=0; -$::opt_gscmd=""; -$::opt_res=0; -$::opt_autorotate="None"; +$::opt_autorotate = "None"; +$::opt_compress = 1; +$::opt_debug = 0; +$::opt_embed = 1; +$::opt_exact = 0; +$::opt_filter = 0; +$::opt_gs = 1; +$::opt_gscmd = ""; +$::opt_hires = 0; +$::opt_outfile = ""; +$::opt_res = 0; ### usage my @bool = ("false", "true"); @@ -193,7 +208,7 @@ Options: For EPS files, PageByPage is equivalent to All --restricted use restricted mode (default: $bool[$restricted]) -Examples for producing 'test.pdf': +Examples producing test.pdf: * $program test.eps * produce postscript | $program --filter >test.pdf * produce postscript | $program -f -d -o=test.pdf @@ -211,40 +226,57 @@ END_OF_USAGE ### process options use Getopt::Long; GetOptions ( - "help", - "version", - "outfile=s", # \ref{openout_any} + "autorotate=s", # \ref{val_autorotate} "compress!", "debug!", "embed!", "exact!", "filter!", "gs!", - "hires!", "gscmd=s", # \ref{val_gscmd} - "res=i", # validated by Getopt ('i' specifier) - "autorotate=s", # \ref{val_autorotate} + "help", + "hires!", + "outfile=s", # \ref{openout_any} + "res=i", # validated by getopt ('i' specifier) "restricted", + "version", ) or die $usage; ### help functions -sub debug { - print STDERR "* @_\n" if $::opt_debug; -} -sub warning { - print STDERR "==> Warning: @_\n"; -} -sub error { - die "$title!!! Error: @_\n"; -} -sub errorUsage { - die "$usage\n!!! Error: @_\n"; -} +sub debug { print STDERR "* @_\n" if $::opt_debug; } +sub warning { print STDERR "==> Warning: @_\n"; } +sub error { die "$title!!! Error: @_\n"; } +sub errorUsage { die "Error: @_ (try --help for more information)\n"; } ### restricted option $restricted = 1 if $::opt_restricted; debug "Restricted mode activated" if $restricted; +### safer external commands for Windows in restricted mode +my $kpsewhich = 'kpsewhich'; +if ($restricted && $on_windows) { + use File::Basename; + my $mydirname = dirname $0; + # $mydirname is the location of the Perl script + $kpsewhich = "$mydirname/../../../bin/win32/$kpsewhich"; + $GS = "$mydirname/../../../tlpkg/tlgs/bin/$GS"; +} +debug "kpsewhich command: $kpsewhich"; + +### check if a name is "safe" according to kpse's open(in|out)_any +# return true if name is ok, false otherwise +sub safe_name +{ + my ($mode, $name) = @_; + my $option = ""; + $option = '-safe-in-name' if $mode eq 'in'; + $option = '-safe-out-name' if $mode eq 'out'; + error "Unknown check mode in safe_name(): $mode" unless $option; + my @args = ($kpsewhich, '-progname', 'repstopdf', $option, $name); + my $bad = system {$args[0]} @args; + return ! $bad; +} + ### help, version options. if ($::opt_help) { print $usage; @@ -257,29 +289,28 @@ if ($::opt_version) { exit (0); } -### get input filename +### get input filename (\ref{openin_any} for validation) my $InputFilename = ""; if ($::opt_filter) { @ARGV == 0 or - die errorUsage "Input file cannot be used with filter option"; + errorUsage "Input file cannot be used with filter option"; debug "Filtering: will read standard input"; } else { - @ARGV > 0 or die errorUsage "Input filename missing"; - @ARGV < 2 or die errorUsage "Unknown option or too many input files"; + @ARGV > 0 or errorUsage "Input filename missing"; + @ARGV < 2 or errorUsage "Unknown option or too many input files"; $InputFilename = $ARGV[0]; #-r $InputFilename or error "\"$InputFilename\" not readable"; debug "Input filename:", $InputFilename; } +### emacs-page ### option gscmd if ($::opt_gscmd) { - debug "Switching from $GS to $::opt_gscmd"; - $GS = $::opt_gscmd; - # validate GS \label{val_gscmd} - if ($restricted) { - $GS =~ /^(gs|mgs|gswin32c|gs386|gsos2)\z/ - or $GS =~ /^gs[\-_]?(\d|\d[\.-_]?\d\d)c?\z/ - or die error "Value of gscmd '$GS' not allowed in restricted mode."; + if ($restricted) { # \label{val_gscmd} + error "Option forbidden in restricted mode: --gscmd"; + } else { + debug "Switching from $GS to $::opt_gscmd"; + $GS = $::opt_gscmd; } } @@ -289,24 +320,24 @@ push @GS, qw(-q -dNOPAUSE -dSAFER -sDEVICE=pdfwrite); ### option outfile my $OutputFilename = $::opt_outfile; -if ($OutputFilename eq "") { +if (! $OutputFilename) { if ($::opt_gs) { - $OutputFilename = $InputFilename; - if (!$::opt_filter) { - my $ds = ($^O eq "MSWin32" || $^O eq "cygwin") ? '\\/' : '/'; + if ($::opt_filter) { + debug "Filtering: will write standard output"; + $OutputFilename = "-"; + } else { + # Ghostscript, no filter: replace input extension with .pdf. + $OutputFilename = $InputFilename; + my $ds = $on_windows_or_cygwin ? '\\/' : '/'; $OutputFilename =~ s/\.[^\.$ds]*$//; $OutputFilename .= ".pdf"; } } else { + debug "No Ghostscript: will write standard output"; $OutputFilename = "-"; # no ghostscript, write to standard output } } -if ($::opt_filter) { - debug "Filtering: will write standard output"; - $OutputFilename = "-"; -} else { - debug "Output filename:", $OutputFilename; -} +debug "Output filename:", $OutputFilename; push @GS, "-sOutputFile=$OutputFilename"; ### options compress, embed, res, autorotate @@ -321,7 +352,7 @@ $rotmsg = $::opt_autorotate ? $::opt_autorotate : "[use gs default]"; error "Invalid value for autorotate: '$::opt_autorotate' " . "(use 'All', 'None' or 'PageByPage')." if ($::opt_autorotate and - not $::opt_autorotate =~ /^(None|All|PageByPage)\z/); + not $::opt_autorotate =~ /^(None|All|PageByPage)$/); ### option BoundingBox types my $BBName = "%%BoundingBox:"; @@ -331,31 +362,15 @@ $BBName = "%%HiResBoundingBox:" if $::opt_hires; $BBName = "%%ExactBoundingBox:" if $::opt_exact; debug "BoundingBox comment:", $BBName; +### validate input file name in restricted mode \label{openin_any} +if ($restricted and not $::opt_filter + and not safe_name('in', $InputFilename)) { + error "Input filename '$InputFilename' not allowed in restricted mode."; +} + ### validate output file name in restricted mode \label{openout_any} -use File::Spec::Functions qw(splitpath file_name_is_absolute); -if ($restricted) { - # use the equivalent of openout_any = p - # (see opennameok() web2c/lib/texmfmp.c) - # Well, for now, be even more paranoid: don't allow absolute path at all - my $ok = 1; - # disallow opening dot-files on Unix - unless ($^O eq "MSWin32") { - my ($drive, $path, $basename) = splitpath($OutputFilename); - $ok = 0 if $basename =~ /^\./; - } - # disallow absolute path - $ok = 0 if file_name_is_absolute($OutputFilename); - # disallow colon on Windows. It could be used either after a drive - # (like "a:dir\file") or for an alternate data stream (like - # "file:ads"). - if ($^O eq "MSWin32" || $^O eq "cygwin") { - $ok = 0 if $OutputFilename =~ /:/; - } - # disallow going to parent directory - my $ds = ($^O eq "MSWin32" || $^O eq "cygwin") ? qr([\\/]) : qr(/); - $ok = 0 if $OutputFilename =~ /^\.\.$ds|$ds\.\.$ds/; - # we passed all tests - die error "Output filename '$OutputFilename' not allowed in restricted mode." unless $ok; +if ($restricted and not safe_name('out', $OutputFilename)) { + error "Output filename '$OutputFilename' not allowed in restricted mode."; } ### option gs @@ -382,7 +397,7 @@ my $tmp_filename; # temporary file for windows my $OUT; # filehandle for output (GS pipe or temporary file) use File::Temp 'tempfile'; if ($::opt_gs) { - unless ($^O eq 'MSWin32' || $^O eq 'cygwin') { # list piped open works + if (! $on_windows_or_cygwin) { # list piped open works push @GS, qw(- -c quit); debug "Ghostscript pipe:", join(' ', @GS); open($OUT, '|-', @GS) or error "Cannot open Ghostscript for piped input"; @@ -584,3 +599,5 @@ if ($? & 127) { warning "BoundingBox not found" unless $BBCorrected; debug "Done."; + +# vim: ts=8 sw=2 expandtab: -- cgit v1.2.3