Skip to content

Commit

Permalink
Item12189: Add better control of temp files
Browse files Browse the repository at this point in the history
Clarify documentation, add a configuration variable, and ensure
that the %ENV entries for temporary files is untainted.

git-svn-id: http://svn.foswiki.org/trunk@15705 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
GeorgeClark authored and GeorgeClark committed Oct 25, 2012
1 parent 59fe5bc commit c4d05e6
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 81 deletions.
22 changes: 19 additions & 3 deletions core/lib/Foswiki.pm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use strict;
use warnings;
use Assert;
use Error qw( :try );
use File::Spec ();
use Monitor ();
use CGI (); # Always required to get html generation tags;
use Digest::MD5 (); # For passthru and validation
Expand Down Expand Up @@ -1668,9 +1669,24 @@ sub new {
ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) )
if DEBUG;

# Compatibility; not used except maybe in plugins
$Foswiki::cfg{TempfileDir} = "$Foswiki::cfg{WorkingDir}/tmp"
unless defined( $Foswiki::cfg{TempfileDir} );
unless ( defined $Foswiki::cfg{TempfileDir} ) {

# Give it a sane default.
if ( $^O eq 'MSWin32' ) {

# Windows default tmpdir is the C: root use something sane.
# Configure does a better job, it should be run.
$Foswiki::cfg{TempfileDir} = $Foswiki::cfg{WorkingDir};
}
else {
$Foswiki::cfg{TempfileDir} = File::Spec->tmpdir();
}
}

# Cover all the possibilities
$ENV{TMPDIR} = $Foswiki::cfg{TempfileDir};
$ENV{TEMP} = $Foswiki::cfg{TempfileDir};
$ENV{TMP} = $Foswiki::cfg{TempfileDir};

if ( defined $Foswiki::cfg{WarningFileName}
&& $Foswiki::cfg{Log}{Implementation} eq 'Foswiki::Logger::PlainFile' )
Expand Down
12 changes: 11 additions & 1 deletion core/lib/Foswiki.spec
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,24 @@ $Foswiki::cfg{PathCheckLimit} = 5000;
# For obvious reasons, these files must <b>not</b> be browseable from the web!
# Additionally you are recommended to restrict access rights to this directory
# so only the web server user can create files.</li>
# <li>{WorkngDir}<tt>/requestTmp</tt> - used as an alternate location for the
# system <tt>/tmp</tt> directory. This is only used if <tt>{TempfileDir}</tt>
# is configured.</li>
# <li>{WorkingDir}<tt>/work_areas</tt> - these are work areas used by
# extensions that need to store data on the disc </li>
# extensions that need to store persistent data across sessions. </li>
# <li>{WorkingDir}<tt>/registration_approvals</tt> - this is used by the
# default Foswiki registration process to store registrations that are pending
# verification.</li>
# </ul>
# $Foswiki::cfg{WorkingDir} = '/home/httpd/foswiki/working';

# **PATH**
# This is used to override the default system temporary file location.
# Set this if you wish to have control over where working tmp files are
# created. It substitutes as the environment <tt>TempfileDir</tt> setting which
# will not be used by perl for security reasons.
#$Foswiki::cfg{TempfileDir} = '/tmp';

# **STRING**
# If your host has aliases (such as both www.mywiki.net and mywiki.net
# and some IP addresses) you need to tell Foswiki that redirecting to them
Expand Down
127 changes: 127 additions & 0 deletions core/lib/Foswiki/Configure/Checkers/TempfileDir.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# See bottom of file for license and copyright information
package Foswiki::Configure::Checkers::TempfileDir;

use strict;
use warnings;

use Foswiki::Configure::Checker ();
our @ISA = ('Foswiki::Configure::Checker');

sub check {
my $this = shift;
my $e;

my $tmpdir = $Foswiki::cfg{TempfileDir} || File::Spec->tmpdir();
Foswiki::Configure::Load::expandValue($tmpdir);

$e .= $this->NOTE("Temporary files will be written to: <tt>$tmpdir</tt>");

my $msg;
$msg .= "<li>Environment TMPDIR setting: <tt>$ENV{TMPDIR}</tt></li>"
if $ENV{TMPDIR};
$msg .= "<li>Environment TEMP setting: <tt>$ENV{TEMP}</tt></li>"
if $ENV{TEMP};
$msg .= "<li>Environment TMP setting: <tt>$ENV{TMP}</tt></li>"
if $ENV{TMP};
$msg .=
'<li>Alternate Foswiki suggested location: <tt>$Foswiki::cfg{WorkingDir}/requestTmp</tt></li>';
$msg .=
"<li>Perl detected temporary file location: <tt>"
. File::Spec->tmpdir()
. "</tt></li></ul>";
$e .= $this->NOTE("Other possible alternatives:<ul>$msg");

if ( $tmpdir =~ /^[\/\\]$/ ) {
$e .= $this->ERROR( <<MSG);
Temporary files will be written to system root directory, do you really want this?<br/>
I've updated the setting with a suggested alternative.<br/>
Save your configuration to make this active.
MSG
$Foswiki::cfg{TempfileDir} = '$Foswiki::cfg{WorkingDir}/requestTmp';
}

$e .= $this->_checkTmpDir($tmpdir);

return $e;
}

sub untaint {
$_[0] =~ m/^(.*)$/;
return $1;
}

sub _checkTmpDir {
my ( $this, $dir ) = @_;
my $mess = '';

unless ( -d "$dir" ) {
if ( -e "$dir" ) {
print "NOT A DIRECTORY $dir <br/>";
return $this->ERROR("$dir already exists, but is not a directory");
}
elsif ( !mkdir( untaint("$dir"), oct(1777) ) ) {
print "DIDNT MAKE DIRECTORY $dir <br/>";
return $this->ERROR("Could not create $dir");
}
else {
print "CREATED DIRECTORY " . untaint("$dir") . " <br/>";
$mess .= $this->NOTE("Created $dir");
}
}

my $D;
if ( !opendir( $D, $dir ) ) {
return $this->ERROR(<<HERE);
Cannot open '$dir' for read ($!) - check that permissions are correct.
HERE
}
closedir($D);

my $tmp = time();
my $F;
while ( -e "$dir/$tmp" ) {
$tmp++;
}
$tmp = "$dir/$tmp";
$tmp =~ /^(.*)$/;
$tmp = $1;
if ( !open( $F, '>', $tmp ) ) {
return $this->ERROR(<<HERE);
Cannot create a file in '$dir' ($!) - check the directory exists, and that permissions are correct, and the filesystem is not full.
HERE
}
close($F);
if ( !unlink($tmp) ) {
return $this->ERROR(<<HERE);
Cannot unlink '$tmp' ($!) - check that permissions are correct on the directory.
HERE
}
return $mess;
}

1;
__END__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2008-2010 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
Additional copyrights apply to some or all of the code in this
file as follows:
Copyright (C) 2000-2006 TWiki Contributors. All Rights Reserved.
TWiki Contributors are listed in the AUTHORS file in the root
of this distribution. NOTE: Please extend that file, not this notice.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. For
more details read LICENSE in the root of this distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As per the GPL, removal of this notice is prohibited.
8 changes: 0 additions & 8 deletions core/lib/Foswiki/Configure/Load.pm
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,6 @@ CODE

$Foswiki::cfg{ConfigurationFinished} = 1;

#on Windows, File::Spec returns a really useless empty string for tempdir under apache
#(in its unix code, it assumes /tmp - but at least thats standard..)
#so defaulting $ENV{TMP} can get us limping along (and can over-ride using TMPDIR or TEMP env
if ( $^O eq 'MSWin32' ) {

#force paths to use '/'
Expand All @@ -151,11 +148,6 @@ CODE
$Foswiki::cfg{TemplateDir} =~ s|\\|/|g;
$Foswiki::cfg{LocalesDir} =~ s|\\|/|g;
$Foswiki::cfg{WorkingDir} =~ s|\\|/|g;

#$ENV{TMPDIR}
#$ENV{TEMP}
#$ENV{TMP}
$ENV{TMP} = $Foswiki::cfg{WorkingDir};
}

# Alias TWiki cfg to Foswiki cfg for plugins and contribs
Expand Down
63 changes: 0 additions & 63 deletions core/lib/Foswiki/Configure/UIs/CGISetup.pm
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,6 @@ This is the Perl library path, used to load Foswiki modules,
third-party modules used by some plugins, and Perl built-in modules.
HERE

$contents .= $this->setting( 'System temporary directory',
$this->_checkTmpDir( \$erk ) );

$contents .= $this->setting( 'CGI bin directory', $this->_getBinDir() );

# Turn off fatalsToBrowser while checking module loads, to avoid
Expand Down Expand Up @@ -294,66 +291,6 @@ sub _getBinDir {
return $dir;
}

sub _checkTmpDir {
my ( $this, $rerk ) = @_;
my $dir = File::Spec->tmpdir();

if ( ( $dir =~ /^[\/\\]$/ ) and ( $^O eq 'MSWin32' ) ) {

#on windows, don't make a big old mess of c:\
$dir = $ENV{TEMP};
if ( defined($dir) and ( $dir =~ /(.*)/ ) ) {
$dir = $1;
}
else {
$dir = '.';
}
}

if ( $dir eq '.' ) {
$dir = '';
my $newCfg = '';
$newCfg =
"Please save your initial path settings and recheck that the guessed defaults are good."
if ($Foswiki::badLSC);
return $this->ERROR(<<HERE);
No writable system temporary directory. $newCfg
HERE
}
my $D;
if ( !opendir( $D, $dir ) ) {
$$rerk++;
return $this->ERROR(<<HERE);
Cannot open '$dir' for read ($!) - check that permissions are correct.
HERE
}
closedir($D);

my $tmp = time();
my $F;
while ( -e "$dir/$tmp" ) {
$tmp++;
}
$tmp = "$dir/$tmp";
$tmp =~ /^(.*)$/;
$tmp = $1;
if ( !open( $F, '>', $tmp ) ) {
$$rerk++;
return $this->ERROR(<<HERE);
Cannot create a file in '$dir' ($!) - check the directory exists, and that permissions are correct, and the filesystem is not full.
HERE
}
close($F);
if ( !unlink($tmp) ) {
$$rerk++;
return $this->ERROR(<<HERE);
Cannot unlink '$tmp' ($!) - check that permissions are correct on the directory.
HERE
}

return $dir;
}

# The perl modules that are required by Foswiki.
sub _loadDEPENDENCIES {
my $this = shift;
Expand Down
1 change: 1 addition & 0 deletions core/lib/Foswiki/Contrib/core/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ lib/Foswiki/Configure/Checkers/Store/EgrepCmd.pm 0444
lib/Foswiki/Configure/Checkers/Store/FgrepCmd.pm 0444
lib/Foswiki/Configure/Checkers/Store/Implementation.pm 0444
lib/Foswiki/Configure/Checkers/Store/SearchAlgorithm.pm 0444
lib/Foswiki/Configure/Checkers/TempfileDir.pm 0444
lib/Foswiki/Configure/Checkers/TemplateDir.pm 0444
lib/Foswiki/Configure/Checkers/TemplatePath.pm 0444
lib/Foswiki/Configure/Checkers/ToolsDir.pm 0444
Expand Down
3 changes: 3 additions & 0 deletions core/lib/Foswiki/Func.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2741,6 +2741,9 @@ user. By default it will *not* be web accessible.
The directory and its contents are permanent, so Plugins must be careful
to keep their areas tidy.
For temporary file storage that only exists for the life of the transaction,
use the Perl =File::Temp= or related =File::Spec= functions.
=cut

sub getWorkArea {
Expand Down
6 changes: 1 addition & 5 deletions core/lib/Foswiki/Sandbox.pm
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,7 @@ sub sysCommand {

# Note: Use of the file handle $fh returned here would be safer than
# using the file name. But it is less portable, so filename wil have to do.
my ( $fh, $stderrCache ) = tempfile(
"STDERR.$$.XXXXXXXXXX",
DIR => "$Foswiki::cfg{WorkingDir}/tmp",
UNLINK => 0
);
my ( $fh, $stderrCache ) = tempfile( "STDERR.$$.XXXXXXXXXX", UNLINK => 0 );
close $fh;

# Item5449: A random key known by both parent and child.
Expand Down
2 changes: 1 addition & 1 deletion core/working/tmp/README
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This is the directory where Foswiki stores session files and passthrough files.
These are security-sensitive temporary files, and should *not* be browseable
from the web, or accessible to anyone on the server except the webserver
user.
user. This directory is not intended for general tmpfile use.

0 comments on commit c4d05e6

Please sign in to comment.