X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Fbin%2Fwebmux.pl;h=8ce68ca142507ee1714c43a95bb6de7954584163;hb=ed1f84b4e8f626245995ecda5afcf83092c153b2;hp=6e1ae06de1bb44d74e9793adc188dfb920966192;hpb=c0567c688084e89fcd11bf82348b6c418f1254ac;p=freeside.git diff --git a/rt/bin/webmux.pl b/rt/bin/webmux.pl old mode 100755 new mode 100644 index 6e1ae06de..8ce68ca14 --- a/rt/bin/webmux.pl +++ b/rt/bin/webmux.pl @@ -1,177 +1,205 @@ -# $Header: /home/cvs/cvsroot/freeside/rt/bin/Attic/webmux.pl,v 1.1 2002-08-12 06:17:07 ivan Exp $ -# RT is (c) 1996-2000 Jesse Vincent (jesse@fsck.com); - +#!/usr/bin/perl +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} use strict; -$ENV{'PATH'} = '/bin:/usr/bin'; # or whatever you need -$ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; -$ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; -$ENV{'ENV'} = '' if defined $ENV{'ENV'}; -$ENV{'IFS'} = '' if defined $ENV{'IFS'}; +local $ENV{'PATH'} = '/bin:/usr/bin'; # or whatever you need +local $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; +local $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; +local $ENV{'ENV'} = '' if defined $ENV{'ENV'}; +local $ENV{'IFS'} = '' if defined $ENV{'IFS'}; +package HTML::Mason::Commands; +our %session; -# We really don't want apache to try to eat all vm -# see http://perl.apache.org/guide/control.html#Preventing_mod_perl_Processes_Fr +package RT::Mason; +our ($Nobody, $SystemUser, $Handler, $r); -package RT::Mason; +my $protect_fd; -use CGI qw(-private_tempfiles); #bring this in before mason, to make sure we - #set private_tempfiles -use HTML::Mason::ApacheHandler (args_method => 'CGI'); -use HTML::Mason; # brings in subpackages: Parser, Interp, etc. - -use vars qw($VERSION %session $Nobody $SystemUser $r $m); - -# List of modules that you want to use from components (see Admin -# manual for details) - -#Clean up our umask...so that the session files aren't world readable, writable or executable -umask(0077); - - - -$VERSION="!!RT_VERSION!!"; - -use lib "!!RT_LIB_PATH!!"; -use lib "!!RT_ETC_PATH!!"; - -#This drags in RT's config.pm -use config; -use Carp; - -{ - package HTML::Mason::Commands; - use vars qw(%session $m); - - use RT; - use RT::Ticket; - use RT::Tickets; - use RT::Transaction; - use RT::Transactions; - use RT::User; - use RT::Users; - use RT::CurrentUser; - use RT::Template; - use RT::Templates; - use RT::Queue; - use RT::Queues; - use RT::ScripAction; - use RT::ScripActions; - use RT::ScripCondition; - use RT::ScripConditions; - use RT::Scrip; - use RT::Scrips; - use RT::Group; - use RT::Groups; - use RT::Keyword; - use RT::Keywords; - use RT::ObjectKeyword; - use RT::ObjectKeywords; - use RT::KeywordSelect; - use RT::KeywordSelects; - use RT::GroupMember; - use RT::GroupMembers; - use RT::Watcher; - use RT::Watchers; - use RT::Handle; - use RT::Interface::Web; - use MIME::Entity; - use Text::Wrapper; - use Apache::Cookie; - use Date::Parse; - use HTML::Entities; - - #TODO: make this use DBI - use Apache::Session::File; - - # Set this page's content type to whatever we are called with - sub SetContentType { - my $type = shift; - $RT::Mason::r->content_type($type); - } - - sub CGIObject { - $m->cgi_object(); - } - - } -my ($parser, $interp, $ah); -if ($HTML::Mason::VERSION < 1.0902) { - $parser = &RT::Interface::Web::NewParser(allow_globals => [%session]); - - $interp = &RT::Interface::Web::NewInterp(parser=>$parser, - allow_recursive_autohandlers => 1, - ); - - $ah = &RT::Interface::Web::NewApacheHandler($interp); -} else { - $ah = &RT::Interface::Web::NewMason11ApacheHandler(); -} -# Activate the following if running httpd as root (the normal case). -# Resets ownership of all files created by Mason at startup. -# -chown (Apache->server->uid, Apache->server->gid, - [$RT::MasonSessionDir]); +sub handler { + ($r) = @_; + if ( !$protect_fd && $ENV{'MOD_PERL'} && exists $ENV{'MOD_PERL_API_VERSION'} + && $ENV{'MOD_PERL_API_VERSION'} >= 2 && fileno(STDOUT) != 1 + ) { + # under mod_perl2, STDOUT gets closed and re-opened, however new STDOUT + # is not on FD #1. In this case next IO operation will occupy this FD + # and make all system() and open "|-" dangerouse, for example DBI + # can get this FD for DB connection and system() call will close + # by putting grabage into the socket + open( $protect_fd, '>', '/dev/null' ) + or die "Couldn't open /dev/null: $!"; + unless ( fileno($protect_fd) == 1 ) { + warn "We opened /dev/null to protect FD #1, but descriptor #1 is already occupied"; + } + } -chown (Apache->server->uid, Apache->server->gid, - $ah->interp->files_written); + local $SIG{__WARN__}; + local $SIG{__DIE__}; + RT::InitSignalHandlers(); -# Die if WebSessionDir doesn't exist or we can't write to it + if ($r->content_type =~ m/^httpd\b.*\bdirectory/i) { + use File::Spec::Unix; + # Our DirectoryIndex is always index.html, regardless of httpd settings + $r->filename( File::Spec::Unix->catfile( $r->filename, 'index.html' ) ); + } -stat ($RT::MasonSessionDir); -die "Can't read and write $RT::MasonSessionDir" - unless (( -d _ ) and ( -r _ ) and ( -w _ )); + Module::Refresh->refresh if RT->Config->Get('DevelMode'); + RT::ConnectToDatabase(); -sub handler { - ($r) = @_; - - RT::Init(); - - # We don't need to handle non-text items - return -1 if defined($r->content_type) && $r->content_type !~ m|^text/|io; - - #This is all largely cut and pasted from mason's session_handler.pl - - my %cookies = Apache::Cookie::parse($r->header_in('Cookie')); - - eval { - tie %HTML::Mason::Commands::session, 'Apache::Session::File', - ( $cookies{'AF_SID'} ? $cookies{'AF_SID'}->value() : undef ), - { Directory => $RT::MasonSessionDir, - LockDirectory => $RT::MasonSessionDir, - } ; - }; - - if ( $@ ) { - # If the session is invalid, create a new session. - if ( $@ =~ m#^Object does not exist in the data store# ) { - tie %HTML::Mason::Commands::session, 'Apache::Session::File', undef, - { Directory => $RT::MasonSessionDir, - LockDirectory => $RT::MasonSessionDir, - }; - undef $cookies{'AF_SID'}; - } - else { - die "RT Couldn't write to session directory '$RT::MasonSessionDir'. Check that this directory's permissions are correct."; - } + # none of the methods in $r gives us the information we want (most + # canonicalize /foo/../bar to /bar which is exactly what we want to avoid) + my (undef, $requested) = split ' ', $r->the_request, 3; + my $uri = URI->new("http://".$r->hostname.$requested); + my $path = URI::Escape::uri_unescape($uri->path); + + ## Each environment has its own way of handling .. and so on in paths, + ## so RT consistently forbids such paths. + if ( $path =~ m{/\.} ) { + $RT::Logger->crit("Invalid request for ".$path." aborting"); + RT::Interface::Web::Handler->CleanupRequest(); + return 400; } - - if ( !$cookies{'AF_SID'} ) { - my $cookie = new Apache::Cookie - ($r, - -name=>'AF_SID', - -value=>$HTML::Mason::Commands::session{_session_id}, - -path => '/',); - $cookie->bake; + my (%session, $status); + { + local $@; + $status = eval { $Handler->handle_request($r) }; + $RT::Logger->crit( $@ ) if $@; } - my $status = $ah->handle_request($r); - untie %HTML::Mason::Commands::session; - + undef %session; + + RT::Interface::Web::Handler->CleanupRequest(); + return $status; +} + +package main; + +# check mod_perl version if it's mod_perl +BEGIN { + die "RT does not support mod_perl 1.99. Please upgrade to mod_perl 2.0" + if $ENV{'MOD_PERL'} + and $ENV{'MOD_PERL'} =~ m{mod_perl/(?:1\.9)}; +} + +require CGI; +CGI->import(qw(-private_tempfiles)); + +# fix lib paths, some may be relative +BEGIN { + require File::Spec; + my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); + my $bin_path; + + for my $lib (@libs) { + unless ( File::Spec->file_name_is_absolute($lib) ) { + unless ($bin_path) { + if ( File::Spec->file_name_is_absolute(__FILE__) ) { + $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; + } + else { + require FindBin; + no warnings "once"; + $bin_path = $FindBin::Bin; + } + } + $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); + } + unshift @INC, $lib; + } + +} + +require RT; +die "Wrong version of RT $RT::Version found; need 3.8.*" + unless $RT::VERSION =~ /^3\.8\./; +RT::LoadConfig(); +if ( RT->Config->Get('DevelMode') ) { + require Module::Refresh; +} +RT::Init(); + +# check compatibility of the DB +{ + my $dbh = $RT::Handle->dbh; + if ( $dbh ) { + my ($status, $msg) = $RT::Handle->CheckCompatibility( $dbh, 'post' ); + die $msg unless $status; + } +} + +require RT::Interface::Web::Handler; +$RT::Mason::Handler = RT::Interface::Web::Handler->new( + RT->Config->Get('MasonParameters') +); + +# load more for mod_perl before forking +RT::InitClasses( Heavy => 1 ) if $ENV{'MOD_PERL'} || $ENV{RT_WEBMUX_HEAVY_LOAD}; + +# we must disconnect DB before fork +$RT::Handle->dbh(undef); +undef $RT::Handle; + +if ( $ENV{'MOD_PERL'} && !RT->Config->Get('DevelMode')) { + # Under static_source, we need to purge the component cache + # each time we restart, so newer components may be reloaded. + # + # We can't do this in FastCGI or we'll blow away the component + # root _every_ time a new server starts which happens every few + # hits. - } -1; + require File::Path; + require File::Glob; + my @files = File::Glob::bsd_glob("$RT::MasonDataDir/obj/*"); + File::Path::rmtree([ @files ], 0, 1) if @files; +} +1;