#!/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 form0 { '
'; } 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: