# This source code file is part of the "mod_survey" package.
#
# Copyright (C) 2004 Joel Palmius
#
# 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.
#
# 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. 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 (probably in a file named "LICENSE.txt" or the like);
# if not, write to:
#
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#!/usr/bin/perl
package Survey::System;
use strict;
use Survey::Language;
if ($ENV{"_SURVEY_USEDBI"})
{
require DBI;
}
sub new
{
my ($crap, $doc, $arg) = @_;
my $self = {};
$self->{ERROR} = 0;
$self->{ERRORCODE} = 0;
$self->{DOCUMENT} = $doc;
$self->{ARGUMENT} = $arg;
bless($self);
if (($arg->ArgByName("action") eq "submit") && (!$arg->Error()))
{
if ($doc->GetOption("ASCIIFILE"))
{
$self->CheckAscii();
}
if ($doc->GetOption("DBITABLE"))
{
$self->CheckDbi();
}
}
return ($self);
}
sub CheckAscii
{
my ($self) = shift;
my ($doc) = $self->{DOCUMENT};
my ($file) = $doc->GetOption("ASCIIFILE");
my (@statarr, $outown);
if (!(-e $file))
{
$self->{ERROR} =
lprint("The export file (") . $file . lprint(") does not exist. I cowardly refuse to create it myself.");
$self->{ERRORCODE} = 3;
}
else
{
if (!(-w $file))
{
$self->{ERROR} = lprint("The export file (") . $file . lprint(") is not writable by the web user.");
$self->{ERRORCODE} = 4;
}
else
{
@statarr = stat($doc->GetOption("FILE"));
$outown = $statarr[4];
@statarr = stat($file);
if (($outown ne $statarr[4]) && (!$doc->GetOption("ISAUTO")))
{
$self->{ERROR} =
lprint("The export file (")
. $file
. lprint(") and the survey file (")
. $doc->GetOption("FILE")
. lprint(") are not owned by the same user.");
$self->{ERRORCODE} = 5;
}
}
}
1;
}
sub CheckDbi
{
my ($self) = shift;
my ($doc) = $self->{DOCUMENT};
my ($table) = $doc->GetOption("DBITABLE");
my ($dsn) = $doc->GetOption("DBIDSN");
$dsn =~ s/\x08/\;/g;
my ($usr) = $doc->GetOption("DBIUSER");
my ($psw) = $doc->GetOption("DBIPASSWD");
my ($cre) = $doc->GetOption("DBICREATE");
my ($dbh, $sth);
if (!$ENV{"_SURVEY_USEDBI"})
{
$self->{ERROR} = lprint("DBI is switched off");
$self->{ERRORCODE} = 10;
return 1;
}
my ($exec) = "\$dbh = DBI->connect(\$dsn,\$usr,\$psw,{ PrintError => 0, AutoCommit => 1, RaiseError => 0})";
eval $exec;
if (!$dbh)
{
my ($errstr) = lprint("Malformed DSN. No such DBD driver ?");
eval "\$errstr = \$DBI::errstr;";
if (!$errstr) { $errstr = lprint("Malformed DSN. No such DBD driver ?"); }
$self->{ERROR} = lprint("Could not do a DBI connect. Error was : ") . $errstr;
$self->{ERRORCODE} = 6;
}
else
{
if (!($sth = $dbh->prepare("SELECT * FROM " . $table)))
{
$self->{ERROR} = lprint("Could not prepare a select. Error was : ") . $DBI::errstr;
$self->{ERRORCODE} = 7;
}
else
{
if (!($sth->execute()))
{
$self->{ERROR} = lprint("Could not execute a select. Error was : ") . $DBI::errstr;
$self->{ERRORCODE} = 8;
}
else
{
$sth->finish;
}
}
$dbh->disconnect;
}
1;
}
sub GetKey
{
my ($self) = shift;
return $self->{KEY};
}
sub CheckSetUser
{
my ($self) = shift;
my ($doc) = $self->{DOCUMENT};
my ($sb) = $doc->GetOption("SYSBASE");
if ( ($doc->GetOption("REQAUTH") ne "no")
&& (($doc->GetOption("UNIQUE") eq "yes") || ($doc->GetOption("UNIQUE") eq "auth")))
{
$sb .= $ENV{REMOTE_USER};
open(FIL, ">" . $sb);
close(FIL);
}
if ($doc->GetOption("UNIQUE") eq "ip")
{
$sb .= $ENV{REMOTE_ADDR};
open(FIL, ">" . $sb);
close(FIL);
}
}
sub CreateKey
{
my ($self) = shift;
my ($i);
my ($key);
my ($doc) = $self->{DOCUMENT};
my ($sb) = $doc->GetOption("SYSBASE");
umask 0077;
my (@timecodes) = localtime(time);
for ($i = 0 ; $i < @timecodes ; $i++)
{
if ($timecodes[$i] < 10)
{
$timecodes[$i] = "0" . $timecodes[$i];
}
}
$timecodes[4]++;
$key = 1900 + $timecodes[5];
$key = $key . $timecodes[4];
$key = $key . $timecodes[3] . "_";
$key = $key . $timecodes[2];
$key = $key . $timecodes[1];
$key = $key . $timecodes[0];
$key = $key . "_" . $$;
$self->{KEY} = $key;
# -- Start fix for avoiding key clash.
# That a key clash would occur even without this is extremely
# unlikely, but it doesn't really cost anything to have it
# here, so why not?
if (-e $sb . $key)
{
$i = int(rand(27)) + 65;
my ($c) = chr($i);
$key .= $c;
}
# -- end key clash fix
open(FIL, ">" . $sb . $key);
close(FIL);
if (!(-e $sb . $key))
{
$self->{ERROR} = lprint("Could not generate system key");
$self->{ERRORCODE} = 2;
}
1;
}
sub CheckKey
{
my ($self) = shift;
my ($arg) = $self->{ARGUMENT};
my ($key) = $arg->ArgByName("key");
my ($doc) = $self->{DOCUMENT};
my ($sb) = $doc->GetOption("SYSBASE");
my ($dat, $tim, $prc) = split("_", $key, $3);
if ((length($dat) != 8) || (length($tim) != 6) || ($prc < 1))
{
$self->{ERROR} = lprint("Malformed key");
$self->{ERRORCODE} = 9;
}
else
{
if (-e $sb . $key)
{
unlink $sb . $key;
}
else
{
$self->{ERROR} = lprint("Invalid key");
$self->{ERRORCODE} = 1;
}
}
1;
}
sub Error
{
my ($self) = shift;
return $self->{ERROR};
}
sub PrintErrorDescription
{
my $self = shift;
my ($e) = $self->{ERRORCODE};
my ($found) = 0;
my ($lb) = "\<\;";
my ($rb) = "\>\;";
print "
\n ";
if ($e)
{
if ($e eq 1)
{
print "[" . lprint("SYSTEM ERROR 1, INVALID KEY") . "] ";
print lprint("The key for the submitted document was not valid. ");
print lprint("A system key is generated each time a survey is viewed. ");
print lprint("This key has to be the same when the survey is submitted. ");
print lprint("This is a security measure aimed at attempts of overloading the system with junk data. ");
print lprint(
'The sollution is to press "back" in your browser and reload the page containing the survey in order to generate a new system key. '
);
print lprint("If the problem persists, contact the system administrator.");
$found = 1;
}
if ($e eq 2)
{
print "[" . lprint("SYSTEM ERROR 2, COULD NOT GENERATE KEY") . "] ";
print lprint("The system key could not be written to the key database. ");
print lprint("A system key is generated each time a survey is viewed. ");
print lprint("This key has to be the same when the survey is submitted. ");
print lprint("This is a security measure aimed at attempts of overloading the system with junk data. ");
print lprint(
"The probable reason for the error is that the web user does not have permission to write where the key database is stored (by default in /tmp). "
);
$found = 1;
}
if ($e eq 3)
{
print "[" . lprint("SYSTEM ERROR 3, EXPORT FILE DOES NOT EXIST") . "] ";
print lprint(
"The ASCIIFILE parameter is set in the survey file, but the location it points to does not exist. ");
print lprint(
"Since allowing the web user too generous write permissions might be a security hazard, the program will not attempt to create the file. "
);
print lprint(
"You can create an empty file in the appropriate location by issuing the command touch \<\; filename\>\;. ");
print lprint("You will also have to permit the web user write access to that file. ");
print lprint(
"The quick and dirty way to do this is by issuing the command chmod 777 \<\;filename\>\;.");
$found = 1;
}
if ($e eq 4)
{
print "[" . lprint("SYSTEM ERROR 4, EXPORT FILE IS NOT WRITABLE") . "] ";
print lprint(
"The ASCIIFILE parameter is set but points to a file to which the web user do not have write persmissions. ");
print lprint(
"The quick and dirty way to correct this is by issuing the command chmod 777 \<\;filename\>\;. "
);
print lprint("(Where filename is the location that ASCIIFILE points to)");
$found = 1;
}
if ($e eq 5)
{
print "[" . lprint("SYSTEM ERROR 5, NOT OWNED BY SAME USER") . "] ";
print lprint(
"As a security measure, the program will refuse to write to an ASCIIFILE which is not owned by the same user as the surveyfile that pointed to the ASCIIFILE. "
);
print lprint("This in order to prevent users from overwriting each other\'s files. ");
print lprint(
"To solve this problem, set the same UID on both files, or create a new ASCIIFILE with the correct ownership.");
$found = 1;
}
if ($e eq 6)
{
print "[" . lprint("SYSTEM ERROR 6, COULD NOT CONNECT DBI DATABASE") . "] ";
print lprint("When connecting DBI databases, quite a lot of things might be wrong. ");
print lprint("You will have to try to interpret the error description printed above.");
$found = 1;
}
if ($e eq 7)
{
print "[" . lprint("SYSTEM ERROR 7, COULD NOT PREPARE A DBI SELECT") . "] ";
print lprint("When using DBI databases, quite a lot of things might be wrong. ");
print lprint("You will have to try to interpret the error description printed above.");
$found = 1;
}
if ($e eq 8)
{
print "[" . lprint("SYSTEM ERROR 8, COULD NOT EXECUTE A DBI SELECT") . "] ";
print lprint("When using DBI databases, quite a lot of things might be wrong. ");
print lprint("You will have to try to interpret the error description printed above.");
$found = 1;
}
if ($e eq 9)
{
print "[" . lprint("SYSTEM ERROR 9, MALFORMED KEY") . "] ";
print lprint(
"The key handling routine expects the key to be formatted approximately YYYYMMDD_HHMMSS_PPPP (date, time and process number when the key was created. "
);
print lprint("For some reason the input key was malformed.");
$found = 1;
}
if ($e eq 10)
{
print "[" . lprint("SYSTEM ERROR 10, DBI IS SWITCHED OFF") . "] ";
print lprint(
"In the global configuration file, the flag which controls the use of DBI is set to zero, meaning that Mod_Survey should not try to access the DBI modules. "
);
print lprint("Therefore, it is not possible to use the DBITABLE export method.");
$found = 1;
}
if (!$found)
{
print lprint("This error is not in the knowledge base, so I guess the programmer has made a mistake.");
}
}
else
{
print "[" . lprint("SYSTEM ERROR 0, NO ERROR") . "] ";
print lprint(
"No error has occured, but the programmer has for some reason called PrintErrorDescription() anyway. ");
print lprint("I guess the programmer has again made a mistake, something that is a very common event indeed.");
}
print "\n
\n";
1;
}
1;