Use DBI placeholders to avoid SQL injection issues.

Bug #260894 r=timeless,justdave
This commit is contained in:
cls%seawood.org 2004-12-01 08:28:06 +00:00
Родитель 8d09f98fb4
Коммит 47cb389e36
5 изменённых файлов: 153 добавлений и 116 удалений

Просмотреть файл

@ -41,25 +41,36 @@ validateRepository($CVS_ROOT);
my $CVS_REPOS_SUFIX = $CVS_ROOT;
$CVS_REPOS_SUFIX =~ s/\//_/g;
ConnectToDatabase();
&ConnectToDatabase();
my $f = SqlQuote($file);
my $qstring = "select distinct dirs.dir from checkins,dirs,files,repositories where dirs.id=dirid and files.id=fileid and repositories.id=repositoryid and repositories.repository='$CVS_ROOT' and files.file=$f order by dirs.dir";
my @bind_values = ( $CVS_ROOT, $file );
my $qstring = "SELECT DISTINCT dirs.dir FROM checkins,dirs,files," .
"repositories WHERE dirs.id=dirid AND files.id=fileid AND " .
"repositories.id=repositoryid AND repositories.repository=? AND " .
"files.file=? ORDER BY dirs.dir";
if ($debug) {
print "<pre wrap>$qstring</pre>\n";
print "<pre wrap>\n";
print &html_quote($qstring) . "\n";
print "With values:\n";
foreach my $v (@bind_values) {
print "\t" . &html_quote($v) . "\n";
}
print "</pre>\n";
}
my (@row, $d, @fl, $s);
SendSQL($qstring);
while(@row = FetchSQLData()){
&SendSQL($qstring, @bind_values);
while(@row = &FetchSQLData()){
$d = $row[0];
push @fl, "$d/$file";
}
&DisconnectFromDatabase();
if( @fl == 0 ){
print "<h3>No files matched this file name. It may have been added recently.</h3>";
print "<h3>No files matched this file name: " . &html_quote($file) .
". It may have been added recently.</h3>";
}
elsif( @fl == 1 ){
$s = &url_quote($fl[0]);
@ -73,6 +84,6 @@ else {
print "<h3>Pick the file that best matches the one you are looking for:</h3>\n";
for $s (@fl) {
print "<dt><a href=cvsblame.cgi?file=" . &url_quote($s) .
"&rev=$rev&mark=$mark#$ln>$s</a>";
"&rev=$rev&mark=$mark#$ln>" . &html_quote($s) . "</a>";
}
}

Просмотреть файл

@ -85,6 +85,7 @@ sub query_checkins {
my (%mod_map) = @_;
my ($ci,$result,$lastlog,$rev,$begin_tag,$end_tag);
my $have_mod_map;
my @bind_values;
$::query_module = 'all' unless defined $::query_module;
if( $::query_module ne 'all' && $::query_module ne 'allrepositories' && @::query_dirs == 0 ){
@ -121,82 +122,96 @@ sub query_checkins {
$result = [];
ConnectToDatabase();
&ConnectToDatabase();
my $qstring = "select type, UNIX_TIMESTAMP(ci_when), people.who, repositories.repository, dirs.dir, files.file, revision, stickytag, branches.branch, addedlines, removedlines, descs.description from checkins,people,repositories,dirs,files,branches,descs where people.id=whoid and repositories.id=repositoryid and dirs.id=dirid and files.id=fileid and branches.id=branchid and descs.id=descid";
my $qstring = "SELECT type, UNIX_TIMESTAMP(ci_when), people.who, " .
"repositories.repository, dirs.dir, files.file, revision, " .
"stickytag, branches.branch, addedlines, removedlines, " .
"descs.description FROM checkins,people,repositories,dirs,files," .
"branches,descs WHERE people.id=whoid AND " .
"repositories.id=repositoryid AND dirs.id=dirid AND " .
"files.id=fileid AND branches.id=branchid AND descs.id=descid";
if( $::query_module ne 'allrepositories' ){
$qstring .= " and repositories.repository = '$::CVS_ROOT'";
$qstring .= " AND repositories.repository = ?";
push(@bind_values, $::CVS_ROOT);
}
if ($::query_date_min) {
my $t = formatSqlTime($::query_date_min);
$qstring .= " and ci_when >= '$t'";
$qstring .= " AND ci_when >= ?";
push(@bind_values, &formatSqlTime($::query_date_min));
}
if ($::query_date_max) {
my $t = formatSqlTime($::query_date_max);
$qstring .= " and ci_when <= '$t'";
$qstring .= " AND ci_when <= ?";
push(@bind_values, &formatSqlTime($::query_date_max));
}
if ($::query_branch_head) {
$qstring .= " and branches.branch = ''";
$qstring .= " AND branches.branch = ''";
} elsif ($::query_branch ne '') {
my $q = SqlQuote($::query_branch);
if ($::query_branchtype eq 'regexp') {
$qstring .=
" and branches.branch regexp $q";
$qstring .= " AND branches.branch REGEXP ?";
push(@bind_values, $::query_branch);
} elsif ($::query_branchtype eq 'notregexp') {
if ($::query_branch eq 'HEAD') {
$qstring .= " and branches.branch != ''";
$qstring .= " AND branches.branch != ''";
} else {
$qstring .= " and not (branches.branch regexp $q) ";
$qstring .= " and not (branches.branch REGEXP ?)";
push(@bind_values, $::query_branch);
}
} else {
$qstring .=
" and (branches.branch = $q or branches.branch = ";
$qstring .= SqlQuote("T$::query_branch") . ")";
" AND (branches.branch = ? OR branches.branch = ?)";
push(@bind_values, $::query_branch);
push(@bind_values, "T$::query_branch");
}
}
if (0 < @::query_dirs) {
my @list;
foreach my $i (@::query_dirs) {
push(@list, "dirs.dir like " . SqlQuote("$i%"));
push(@list, "dirs.dir LIKE ?");
push(@bind_values, "$i%");
}
$qstring .= "and (" . join(" or ", @list) . ")";
$qstring .= "AND (" . join(" OR ", @list) . ")";
}
if (defined $::query_file && $::query_file ne '') {
my $q = SqlQuote($::query_file);
$::query_filetype ||= "exact";
if ($::query_filetype eq 'regexp') {
$qstring .= " and files.file regexp $q";
} elsif ($::query_filetype eq 'notregexp') {
$qstring .= " and not (files.file regexp $q)";
$qstring .= " AND files.file REGEXP ?";
} elsif ($::query_filetype eq 'notregexp') {
$qstring .= " AND NOT (files.file REGEXP ?)";
} else {
$qstring .= " and files.file = $q";
$qstring .= " AND files.file = ?";
}
push(@bind_values, $::query_file);
}
if (defined $::query_who && $::query_who ne '') {
my $q = SqlQuote($::query_who);
$::query_whotype ||= "exact";
if ($::query_whotype eq 'regexp') {
$qstring .= " and people.who regexp $q";
$qstring .= " AND people.who REGEXP ?";
}
elsif ($::query_whotype eq 'notregexp') {
$qstring .= " and not (people.who regexp $q)";
$qstring .= " AND NOT (people.who REGEXP ?)";
} else {
$qstring .= " and people.who = $q";
$qstring .= " AND people.who = ?";
}
push(@bind_values, $::query_who);
}
if (defined($::query_logexpr) && $::query_logexpr ne '') {
my $q = SqlQuote($::query_logexpr);
$qstring .= " and descs.description regexp $q";
$qstring .= " AND descs.description regexp ?";
push(@bind_values, $::query_logexpr);
}
if ($::query_debug) {
print "<pre wrap> Query: $qstring\nTreeID is $::TreeID\n";
print "<pre wrap> Query: " . &html_quote($qstring) . "\n";
print "With values:\n";
foreach my $v (@bind_values) {
print "\t" . &html_quote($v) . "\n";
}
print "\nTreeID is $::TreeID\n";
if ($have_mod_map) {
print "Dump of module map:\n";
foreach my $k (sort(keys %mod_map)) {
@ -211,7 +226,7 @@ sub query_checkins {
print "</pre>\n";
}
SendSQL($qstring);
&SendSQL($qstring, @bind_values);
$lastlog = 0;
my @row;

Просмотреть файл

@ -337,11 +337,11 @@ sub refigureStartDateIfNecessary {
return;
}
ConnectToDatabase();
SendSQL("select min(ci_when)
from checkins,repositories
where repositories.id = repositoryid and
repository = '$::CVS_ROOT'");
&ConnectToDatabase();
&SendSQL("SELECT MIN(ci_when)
FROM checkins,repositories
WHERE repositories.id = repositoryid and
repository = ?", $::CVS_ROOT);
my $startdate = FetchOneColumn();
if ($startdate eq "") {

Просмотреть файл

@ -125,13 +125,28 @@ sub DisconnectFromDatabase {
}
sub SendSQL {
my ($str) = (@_);
my ($rows);
my ($str, @bind_values) = (@_);
my $status = 0;
$::currentquery = $::db->prepare($str)
|| die "'$str': ". $::db->errstr;
$rows = $::currentquery->execute
|| die "'$str': Can't execute the query: " . $::currentquery->errstr;
$::currentquery = $::db->prepare($str) || $status++;
if ($status) {
print STDERR "SendSQL prepare error: '$str' with values (";
foreach my $v (@bind_values) {
print STDERR "'" . &shell_escape($v) . "', ";
}
print STDERR ") :: " . $::db->errstr . "\n";
die "Cannot prepare SQL query. Please contact system administrator.\n";
}
$::currentquery->execute(@bind_values) || $status++;
if ($status) {
print STDERR "SendSQL execute error: '$str' with values (";
foreach my $v (@bind_values) {
print STDERR "'" . &shell_escape($v) . "', ";
}
print STDERR ") :: " . $::currentquery->errstr . "\n";
die "Cannot execute SQL query. Please contact system administrator.\n";
}
}
sub MoreSQLData {
@ -150,7 +165,7 @@ sub FetchSQLData {
undef @::fetchahead;
return @result;
}
return $::currentquery->fetchrow();
return $::currentquery->fetchrow_array();
}
@ -160,19 +175,6 @@ sub FetchOneColumn {
}
# This routine is largely copied from Mysql.pm.
sub SqlQuote {
my ($str) = (@_);
# if (!defined $str) {
# confess("Undefined passed to SqlQuote");
# }
$str =~ s/([\\\'])/\\$1/g;
$str =~ s/\0/\\0/g;
return "'$str'";
}
# Fills in a hashtable with info about the columns for the given table in the
# database. The hashtable has the following entries:
@ -182,10 +184,10 @@ sub SqlQuote {
sub LearnAboutColumns {
my ($table) = (@_);
my %a;
SendSQL("show columns from $table");
&SendSQL("SHOW columns FROM $table");
my @list = ();
my @row;
while (@row = FetchSQLData()) {
while (@row = &FetchSQLData()) {
my ($name,$type) = (@row);
$a{"$name,type"} = $type;
push @list, $name;
@ -224,9 +226,9 @@ sub SplitEnumType {
sub PerlQuote {
my ($str) = (@_);
$str = SqlQuote($str);
return $str;
$str =~ s/([\\\'])/\\$1/g;
$str =~ s/\0/\\0/g;
return "'$str'";
}
sub GenerateArrayCode {
@ -328,20 +330,19 @@ undef %lastidcache;
sub GetId {
my ($table, $field, $value) = @_;
my ($index, $qvalue, $id);
my ($index, $id);
$index = "$table|$field|$value";
return ($lastidcache{$index})
if (exists $lastidcache{$index});
$qvalue = SqlQuote($value);
SendSQL("select id from $table where $field = $qvalue");
($id) = FetchSQLData();
&SendSQL("SELECT id FROM $table WHERE $field = ?", $value);
($id) = &FetchSQLData();
unless ($id) {
SendSQL("insert into $table ($field) values ($qvalue)");
SendSQL("select LAST_INSERT_ID()");
($id) = FetchSQLData();
&SendSQL("INSERT INTO $table ($field) VALUES (?)", $value);
&SendSQL("SELECT LAST_INSERT_ID()");
($id) = &FetchSQLData();
}
return ($lastidcache{$index} = $id);
@ -350,16 +351,15 @@ sub GetId {
sub GetId_NoCache {
my ($table, $field, $value) = @_;
my ($qvalue, $id);
my ($id);
$qvalue = SqlQuote($value);
SendSQL("select id from $table where $field = $qvalue");
($id) = FetchSQLData();
&SendSQL("SELECT id FROM $table WHERE $field = ?", $value);
($id) = &FetchSQLData();
unless ($id) {
SendSQL("insert into $table ($field) values ($qvalue)");
SendSQL("select LAST_INSERT_ID()");
($id) = FetchSQLData();
&SendSQL("INSERT INTO $table ($field) values (?)", $value);
&SendSQL("SELECT LAST_INSERT_ID()");
($id) = &FetchSQLData();
}
return $id;
@ -386,17 +386,18 @@ sub MakeValueHash {
sub GetHashedId {
my ($table, $field, $value) = @_;
my ($qvalue, $id, $hash);
my (@bind_values, $id);
$hash = MakeValueHash($value);
$qvalue = SqlQuote($value);
SendSQL("select id from $table where hash = $hash and $field = $qvalue");
($id) = FetchSQLData();
@bind_values = (&MakeValueHash($value), $value);
&SendSQL("SELECT id FROM $table WHERE hash = ? AND $field = ?",
@bind_values);
($id) = &FetchSQLData();
unless ($id) {
SendSQL("insert into $table (hash, $field) values ($hash, $qvalue)");
SendSQL("select LAST_INSERT_ID()");
($id) = FetchSQLData();
&SendSQL("INSERT INTO $table (hash, $field) values (?, ?)",
@bind_values);
&SendSQL("SELECT LAST_INSERT_ID()");
($id) = &FetchSQLData();
}
return $id;
@ -410,7 +411,7 @@ undef $lastdescription;
sub AddToDatabase {
my ($lines, $desc) = @_;
my ($descid, $basequery, $query, $line, $quoted);
my ($descid, $basequery, $query, $line, @bind_values);
my ($chtype, $date, $name, $repository, $dir);
my ($file, $version, $sticky, $branch, $addlines, $removelines);
@ -426,12 +427,12 @@ sub AddToDatabase {
}
# Build the query...
$basequery = "replace into
$basequery = "REPLACE INTO
checkins(
type, ci_when, whoid, repositoryid, dirid,
fileid, revision, stickytag, branchid, addedlines,
removedlines, descid)
values (";
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
foreach $line (split(/\n/, $lines)) {
next if ($line =~ /^\s*$/);
@ -455,8 +456,7 @@ sub AddToDatabase {
# Find the description id, if it isn't already set
if (!defined($descid)) {
$descid = GetHashedId('descs', 'description', $desc);
$quoted = SqlQuote($desc);
$descid = &GetHashedId('descs', 'description', $desc);
$lastdescriptionid = $descid;
$lastdescription = $desc;
}
@ -464,28 +464,27 @@ sub AddToDatabase {
# Build the final query
$query = $basequery;
if ($chtype eq "C") {
$query .= "'Change'";
$chtype = 'Change';
} elsif ($chtype eq "A") {
$query .= "'Append'";
$chtype = 'Append';
} elsif ($chtype eq "R") {
$query .= "'Remove'";
$chtype = 'Remove';
} else {
$query .= "NULL";
$chtype = "NULL";
}
$query .= ", '$date'";
$query .= ", " . GetId("people", "who", $name);
$query .= ", " . GetId("repositories", "repository", $repository);
$query .= ", " . GetId("dirs", "dir", $dir);
$query .= ", " . GetId("files", "file", $file);
$query .= ", " . SqlQuote($version);
$query .= ", " . SqlQuote($sticky);
$query .= ", " . GetId("branches", "branch", $branch);
$query .= ", $addlines";
$query .= ", $removelines";
$query .= ", $descid)";
SendSQL($query);
@bind_values = ($chtype,
$date,
&GetId("people", "who", $name),
&GetId("repositories", "repository", $repository),
&GetId("dirs", "dir", $dir),
&GetId("files", "file", $file),
$version,
$sticky,
&GetId("branches", "branch", $branch),
$addlines,
$removelines,
$descid);
&SendSQL($query, @bind_values);
}
}

Просмотреть файл

@ -67,9 +67,21 @@ Searching for first checkin after " . SqlFmtClock($startfrom) . "...<p>\n";
my $inbranch = $::TreeInfo{$::TreeID}->{'branch'};
print "<p> $inbranch <p> \n";
my $sqlstring = "select type, UNIX_TIMESTAMP(ci_when), people.who, repositories.repository, dirs.dir, files.file, revision, stickytag, branches.branch, addedlines, removedlines, descs.description from checkins,people,repositories,dirs,files,branches,descs where people.id=whoid and repositories.id=repositoryid and dirs.id=dirid and files.id=fileid and branches.id=branchid and descs.id=descid and branches.branch='$inbranch' and ci_when>='" . SqlFmtClock($startfrom) . "' order by ci_when;";
print "<p> $sqlstring <p>\n";
SendSQL("$sqlstring");
my $sqlstring = "SELECT type, UNIX_TIMESTAMP(ci_when), people.who, " .
"repositories.repository, dirs.dir, files.file, revision, stickytag, " .
"branches.branch, addedlines, removedlines, descs.description FROM " .
"checkins,people,repositories,dirs,files,branches,descs WHERE " .
"people.id=whoid AND repositories.id=repositoryid AND dirs.id=dirid " .
"AND files.id=fileid AND branches.id=branchid AND descs.id=descid AND " .
"branches.branch=? AND ci_when>=? ORDER BY ci_when;";
my @bind_values = ($inbranch, &SqlFmtClock($startfrom));
print "<p> " . &html_quote($sqlstring) . " <br>\n";
print "With values:<br>\n";
foreach my $v (@bind_values) {
print "\t" . &html_quote($v) . "<br>\n";
}
print "<p>\n";
&SendSQL($sqlstring, @bind_values);
my ($change, $date, $who, $repos, $dir, $file, $rev, $sticky, $branch, $linesa, $linesr, $log);
my ($lastchange, $lastdate, $lastwho, $lastrepos, $lastdir, $lastrev, $laststicky, $lastbranch, $lastlinesa, $lastlinesr, $lastlog);