#!/usr/bin/perl -Tw
# -*- perl -*-
# $Id: BoreWiki.cgi 1333 2007-04-09 10:57:15Z too $
#
# Author: Tomi Ollila -- too ät iki piste fi
#
# Created: Thu Apr 27 10:40:22 EEST 2006 too
# Last Modified: Mon Apr 09 13:35:01 EEST 2007 too
#
# Licensed under GPL v2 (until v3 is ready and if good enough).
use 5.8.0;
use strict;
use Fcntl;
use Digest::MD5 qw(md5_hex);
# cgi support self-implemented (for fun).
#use Data::Dumper; # for testing.
# Begin shared variables (keep syntax sh-compatible, when lines catenated...)
my $version = '0.981';
my $bwdotdir = "/var/tmp/.borewiki";
my $cnf_passwd = "$bwdotdir/passwd.conf";
my $cnf_cookies = "$bwdotdir/cookies.conf";
my $logfile = "$bwdotdir/log";
my $savelogfile = "$bwdotdir/savelog";
my $errfile = "$bwdotdir/stderr";
my $tmpdir = "$bwdotdir/tmp";
# End shared variables
my $https_required_with_port = 0;
my $prestdir = "prest-0.003016";
# Tune this implementation if required.
sub randombytes($)
{
openI('/dev/urandom');
my $x;
read(I, $x, $_[0], 0);
close I;
return $x;
}
my $request_method = $ENV{'REQUEST_METHOD'};
if (defined $request_method) { open STDERR, '>>', $errfile; }
my $https = $ENV{'HTTPS'};
$\ = "\n";
my $cookie_expiretime_in_hours = 5;
my $pagecss = 'borewiki.css';
$ENV{'PATH'} = '/bin:/usr/bin';
die "Opening log file $logfile failed: $!\n" unless open LOG, '>>', $logfile;
#select((select(LOG), $| = 1)[0]);
use subs qw(log);
sub log(@)
{
local $" = ' ';
my $t = localtime; # Does not show TZ.
syswrite LOG, "$t [$$]: @_\n";
}
sub stderr(@)
{
local $" = ' ';
my $t = localtime; # Does not show TZ.
syswrite STDERR, "$t [$$]: @_\n";
}
log "BoreWiki connection from $ENV{'REMOTE_ADDR'}:$ENV{'REMOTE_PORT'}";
sub nl() { "\n"; }
sub ilog($) { log('I:', $_[0]); }
sub _info(@)
{
ilog(shift @_); header(shift @_);
local $" = nl; print "@_"; _tailer();
}
sub nlog($) { log('N:', $_[0]); }
sub _notice(@)
{
nlog(shift @_); header(shift @_);
local $" = nl; print "@_"; _tailer();
}
sub elog($) { log('E:', $_[0]); }
sub _error(@)
{
elog(shift @_); header(shift @_);
local $" = nl; print "@_"; _tailer();
}
sub _internal_error($)
{
local $" = nl;
log("Internal Error: $_[0]");
header('Internal Error');
print 'Error in BoreWiki operation. See log for more information.';
_tailer();
}
sub makeurlprefix($$)
{
if (defined $_[1]) {
if ($_[0] != 443) { return "https://$ENV{'HTTP_HOST'}:$_[0]" }
else { return "https://$ENV{'HTTP_HOST'}"; }
} else {
if ($_[0] != 80) { return "http://$ENV{'HTTP_HOST'}:$_[0]"; }
else { return "http://$ENV{'HTTP_HOST'}"; }
}
}
if (! defined $https && $https_required_with_port)
{
_error('HTTP POST when HTTPS required',
'HTTPS Required',
'HTTP POST request was made when HTTPS protocol was required.')
if $request_method != 'GET';
my $urlprefix = makeurlprefix($https_required_with_port, 1);
log('prefix+location', $urlprefix, $ENV{'REQUEST_URI'});
print "Location: " . $urlprefix . $ENV{'REQUEST_URI'};
print ;
exit 0;
}
sub h1($) { '
' . $_[0] . '
'; }
sub h3($) { '
' . $_[0] . '
'; }
sub h4($) { '
' . $_[0] . ''; }
sub form(@) { qq(
'; }
sub p () { '
'; } sub p0 () { '
'; } sub p7 () { ''; }
sub pre () { '
'; } sub pre0 () { '
'; }
sub table () { '
'; } sub table0 () { '
'; }
#use subs qw(tr);
sub tr_ () { '
'; } sub tr0 () { '
'; }
sub td($) { '
' . $_[0] . '
'; }
sub b($) { '' . $_[0] . ''; }
sub i($) { '' . $_[0] . ''; }
sub br7() { ' '; }
sub hr7() { ''; }
sub hidden($$) { qq(); }
sub submit($$) {
qq(); }
# XXX wrap="..." is not really xhtml (especially not strict...)
sub textarea($$) {
qq('; }
sub openI($)
{
_internal_error("Opening file $_[0] for reading failed: $!")
unless ( open(I, '<', $_[0]) );
}
sub openO($)
{
stderr('openO:', $_[0]);
_internal_error("Opening file $_[0] for writing failed: $!")
unless ( open(O, '>', $_[0]) );
}
sub start_proc(@)
{
my $pid = fork;
_internal_error("fork() failed: $!") unless defined $pid;
return $pid if $pid;
# child -- close-on exec flag (see $^F on perlvar) is in action.
my $listref = shift @_;
stderr('exec:', @_);
if (defined $listref) {
while (1) {
my $new = shift @{$listref};
my $old = shift @{$listref};
last unless defined $old;
open($new, "<& $old");
}}
exec { $_[0] } @_;
exit 1;
}
sub run_proc(@) { waitpid(start_proc(@_), 0); return $?; }
my $copenpid;
sub copenI(@)
{
stderr('copenI:', @_);
_internal_error("Creating pipe: $!") unless pipe(I, WH);
$copenpid = start_proc([*STDOUT, *WH], @_);
close WH;
}
sub ccloseI()
{
close I;
waitpid($copenpid, 0);
}
sub getpasswd($)
{
if (-f $cnf_passwd) {
openI($cnf_passwd);
while () {
chomp;
# line format: passwd: path [path...]
if (s/^passwd:\s+(\S+)\s+//) {
if ($1 eq $_[0]) {
my @a = split(/\s+/);
close I, return @a if (@a >= 4);
}}}
close I;
}
return undef;
}
my $username;
my @useraccess;
sub findcookie($)
{
if (-f $cnf_cookies) {
my $now = time;
openI($cnf_cookies);
while () {
chomp;
# line format: cookie: