1
# Copyright (C) 2010 Stanislav Sinyagin
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18
# Stanislav Sinyagin <ssinyagin@yahoo.com>
20
# Universal CGI handler for Apache mod_perl and FastCGI
29
# This modue is not a part of mod_perl
30
use Apache::Session::File;
35
use Torrus::SiteConfig;
38
## Torrus::CGI->process($q)
39
## Expects a CGI object as input
40
## In case of an error, the DB environment would
41
## be uncleaned after do_process().
42
## Here we explicitly clean it up
46
$class->do_process($q);
47
&Torrus::DB::cleanupEnvironment();
54
my $path_info = $q->url(-path => 1);
56
# quickly give plaintext file contents
58
my $pos = index( $path_info, $Torrus::Renderer::plainURL );
61
my $fname = $Torrus::Global::webPlainDir . '/' .
63
$pos + length($Torrus::Renderer::plainURL) );
68
if( $path_info =~ /\.css$/o )
79
my $fh = new IO::File( $fname );
82
print $q->header('-type' => $type,
87
while( $fh->read( $buffer, 65536 ) )
98
print $q->header(-status=>400),
99
$q->start_html('Error'),
101
$q->strong('Cannot retrieve file: ' . $fname);
108
my @paramNames = $q->param();
110
if( $q->param('DEBUG') and not $Torrus::Renderer::globalDebug )
112
&Torrus::Log::setLevel('debug');
116
foreach my $name ( @paramNames )
118
if( $name =~ /^[A-Z]/ and $name ne 'SESSION_ID' )
120
$options{'variables'}->{$name} = $q->param($name);
124
my( $fname, $mimetype, $expires );
127
my $renderer = new Torrus::Renderer();
128
if( not defined( $renderer ) )
130
return report_error($q, 'Error initializing Renderer');
133
my $tree = $path_info;
134
$tree =~ s/^.*\/(.*)$/$1/;
136
if( $Torrus::CGI::authorizeUsers )
138
$options{'acl'} = new Torrus::ACL;
140
my $hostauth = $q->param('hostauth');
141
if( defined( $hostauth ) )
143
my $uid = $q->remote_addr();
145
my $password = $uid . '//' . $hostauth;
147
Debug('Host-based authentication for ' . $uid);
149
if( not $options{'acl'}->authenticateUser( $uid, $password ) )
151
print $q->header(-status=>'403 Forbidden',
152
'-type' => 'text/plain');
153
print('Host-based authentication failed for ' . $uid);
154
Info('Host-based authentication failed for ' . $uid);
158
Info('Host authenticated: ' . $uid);
159
$options{'uid'} = $uid;
164
my $ses_id = $q->cookie('SESSION_ID');
166
my $needs_new_session = 1;
171
# create a session object based on the cookie we got from the
172
# browser, or a new session if we got no cookie
175
tie %session, 'Apache::Session::File', $ses_id, {
176
Directory => $Torrus::Global::sesStoreDir,
177
LockDirectory => $Torrus::Global::sesLockDir }
181
if( $options{'variables'}->{'LOGOUT'} )
183
tied( %session )->delete();
187
$needs_new_session = 0;
192
if( $needs_new_session )
194
tie %session, 'Apache::Session::File', undef, {
195
Directory => $Torrus::Global::sesStoreDir,
196
LockDirectory => $Torrus::Global::sesLockDir };
199
# might be a new session, so lets give them their cookie back
201
my %cookie = (-name => 'SESSION_ID',
202
-value => $session{'_session_id'});
204
if( $session{'uid'} )
206
$options{'uid'} = $session{'uid'};
207
if( $session{'remember_login'} )
209
$cookie{'-expires'} = '+60d';
216
# POST form parameters
218
my $uid = $q->param('uid');
219
my $password = $q->param('password');
220
if( defined( $uid ) and defined( $password ) )
222
if( $options{'acl'}->authenticateUser( $uid, $password ) )
224
$session{'uid'} = $options{'uid'} = $uid;
226
Info('User logged in: ' . $uid);
228
if( $q->param('remember') )
230
$cookie{'-expires'} = '+60d';
231
$session{'remember_login'} = 1;
236
$options{'authFailed'} = 1;
242
$options{'urlPassTree'} = $tree;
243
foreach my $param ( 'token', 'path', 'nodeid',
246
my $val = $q->param( $param );
247
if( defined( $val ) and length( $val ) > 0 )
249
$options{'urlPassParams'}{$param} = $val;
253
( $fname, $mimetype, $expires ) =
254
$renderer->renderUserLogin( %options );
256
die('renderUserLogin returned undef') unless $fname;
261
push(@cookies, $q->cookie(%cookie));
267
if( not $tree or not Torrus::SiteConfig::treeExists( $tree ) )
269
( $fname, $mimetype, $expires ) =
270
$renderer->renderTreeChooser( %options );
274
if( $Torrus::CGI::authorizeUsers and
275
not $options{'acl'}->hasPrivilege( $options{'uid'}, $tree,
278
return report_error($q, 'Permission denied');
281
if( $Torrus::Renderer::displayReports and
282
defined( $q->param('htmlreport') ) )
284
if( $Torrus::CGI::authorizeUsers and
285
not $options{'acl'}->hasPrivilege( $options{'uid'}, $tree,
288
return report_error($q, 'Permission denied');
291
my $reportfname = $q->param('htmlreport');
292
# strip off leading slashes for security
293
$reportfname =~ s/^.*\///o;
295
$fname = $Torrus::Global::reportsDir . '/' . $tree .
296
'/html/' . $reportfname;
299
return report_error($q, 'No such file: ' . $reportfname);
302
$mimetype = 'text/html';
307
my $config_tree = new Torrus::ConfigTree( -TreeName => $tree );
308
if( not defined($config_tree) )
310
return report_error($q, 'Configuration is not ready');
313
my $token = $q->param('token');
314
if( not defined($token) )
316
my $path = $q->param('path');
317
if( not defined($path) )
319
my $nodeid = $q->param('nodeid');
320
if( defined($nodeid) )
322
$token = $config_tree->getNodeByNodeid( $nodeid );
323
if( not defined($token) )
326
($q, 'Cannot find nodeid: ' . $nodeid);
331
$token = $config_tree->token('/');
336
$token = $config_tree->token($path);
337
if( not defined($token) )
339
return report_error($q, 'Invalid path');
343
elsif( $token !~ /^S/ and
344
not defined( $config_tree->path( $token ) ) )
346
return report_error($q, 'Invalid token');
349
my $view = $q->param('view');
350
if( not defined($view) )
352
$view = $q->param('v');
355
if( defined($view) and
356
not $config_tree->viewExists($view) )
358
return report_error($q, 'Invalid view name: ' . $view);
361
( $fname, $mimetype, $expires ) =
362
$renderer->render( $config_tree, $token, $view, %options );
370
&Torrus::DB::cleanupEnvironment();
372
if( defined( $options{'acl'} ) )
374
undef $options{'acl'};
377
if( defined($fname) )
381
return report_error($q, 'No such file or directory: ' . $fname);
384
Debug("Render returned $fname $mimetype $expires");
386
my $fh = new IO::File( $fname );
389
print $q->header('-type' => $mimetype,
390
'-expires' => '+'.$expires.'s',
391
'-cookie' => \@cookies);
393
$fh->binmode(':raw');
395
while( $fh->read( $buffer, 65536 ) )
403
return report_error($q, 'Cannot open file ' . $fname . ': ' . $!);
408
return report_error($q, "Renderer returned error.\n" .
409
"Probably wrong directory permissions or " .
410
"directory missing:\n" .
411
$Torrus::Global::cacheDir);
414
if( not $Torrus::Renderer::globalDebug )
416
&Torrus::Log::setLevel('info');
427
my $v = $q->param('view');
428
if( defined($v) and $v eq 'rpc' )
433
print $q->header('-type' => 'application/json', '-expires' => 'now');
434
print $json->encode({'success' => 0, 'error' => $msg});
438
print $q->header('-type' => 'text/plain', '-expires' => 'now');
439
print('Error: ' . $msg);
448
# indent-tabs-mode: nil
449
# perl-indent-level: 4