diff options
-rw-r--r-- | globals.pl | 280 |
1 files changed, 63 insertions, 217 deletions
diff --git a/globals.pl b/globals.pl index 0da5ec895..91bed7794 100644 --- a/globals.pl +++ b/globals.pl @@ -20,7 +20,6 @@ # Contributor(s): Terry Weissman <terry@mozilla.org> # Dan Mosedale <dmose@mozilla.org> # Jake <jake@acutex.net> -# Bradley Baetz <bbaetz@cs.mcgill.ca> # Contains some global variables and routines used throughout bugzilla. @@ -51,7 +50,6 @@ sub globals_pl_sillyness { $zz = @main::milestoneurl; $zz = @main::prodmaxvotes; $zz = $main::superusergroupset; - $zz = $main::userid; } # @@ -73,11 +71,11 @@ use Date::Parse; # For str2time(). #use Carp; # for confess use RelationSet; -# Some environment variables are not taint safe -delete $ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; +# $ENV{PATH} is not taint safe +delete $ENV{PATH}; # Contains the version string for the current running Bugzilla. -$::param{'version'} = '2.15'; +$::param{'version'} = '2.14.1'; $::dontchange = "--do_not_change--"; $::chooseone = "--Choose_one:--"; @@ -104,8 +102,8 @@ sub ConnectToDatabase { $name = Param("shadowdb"); $::dbwritesallowed = 0; } - $::db = DBI->connect("DBI:mysql:host=$::db_host;database=$name", $::db_user, $::db_pass) - || die "Bugzilla is currently broken. Please try again later. " . + $::db = DBI->connect("DBI:mysql:host=$::db_host;database=$name", $::db_user, $::db_pass) + || die "Bugzilla is currently broken. Please try again later. " . "If the problem persists, please contact " . Param("maintainer") . ". The error you should quote is: " . $DBI::errstr; } @@ -213,13 +211,8 @@ sub SendSQL { } SqlLog($str); $::currentquery = $::db->prepare($str); - if (!$::currentquery->execute) { - my $errstr = $::db->errstr; - # Cut down the error string to a reasonable.size - $errstr = substr($errstr, 0, 2000) . ' ... ' . substr($errstr, -2000) - if length($errstr) > 4000; - die "$str: " . $errstr; - } + $::currentquery->execute + || die "$str: " . $::db->errstr; SqlLog("Done"); if (!$dontshadow && $iswrite && Param("shadowdb")) { my $q = SqlQuote($str); @@ -242,10 +235,10 @@ sub MoreSQLData { return 0; } if (defined @::fetchahead) { - return 1; + return 1; } if (@::fetchahead = $::currentquery->fetchrow_array) { - return 1; + return 1; } return 0; } @@ -256,9 +249,9 @@ sub FetchSQLData { return; } if (defined @::fetchahead) { - my @result = @::fetchahead; - undef @::fetchahead; - return @result; + my @result = @::fetchahead; + undef @::fetchahead; + return @result; } return $::currentquery->fetchrow_array; } @@ -416,7 +409,7 @@ sub GenerateCode { $result = ""; foreach my $k (sort { uc($a) cmp uc($b)} eval("keys $name")) { $result .= GenerateCode("\$" . substr($name, 1) . - "{" . PerlQuote($k) . "}"); + "{'" . $k . "'}"); } return $result; } else { @@ -530,13 +523,6 @@ sub GenerateVersionTable { my $tmpname = "data/versioncache.$$"; open(FID, ">$tmpname") || die "Can't create $tmpname"; - print FID "#\n"; - print FID "# DO NOT EDIT!\n"; - print FID "# This file is automatically generated at least once every\n"; - print FID "# hour by the GenerateVersionTable() sub in globals.pl.\n"; - print FID "# Any changes you make will be overwritten.\n"; - print FID "#\n"; - print FID GenerateCode('@::log_columns'); print FID GenerateCode('%::versions'); @@ -706,98 +692,6 @@ sub GenerateRandomPassword { return $password; } -sub SelectVisible { - my ($query, $userid, $usergroupset) = @_; - - # Run the SQL $query with the additional restriction that - # the bugs can be seen by $userid. $usergroupset is provided - # as an optimisation when this is already known, eg from CGI.pl - # If not present, it will be obtained from the db. - # Assumes that 'bugs' is mentioned as a table name. You should - # also make sure that bug_id is qualified bugs.bug_id! - # Your query must have a WHERE clause. This is unlikely to be a problem. - - # Also, note that mySQL requires aliases for tables to be locked, as well - # This means that if you change the name from selectVisible_cc (or add - # additional tables), you will need to update anywhere which does a - # LOCK TABLE, and then calls routines which call this - - $usergroupset = 0 unless $userid; - - unless (defined($usergroupset)) { - PushGlobalSQLState(); - SendSQL("SELECT groupset FROM profiles WHERE userid = $userid"); - $usergroupset = FetchOneColumn(); - PopGlobalSQLState(); - } - - # Users are authorized to access bugs if they are a member of all - # groups to which the bug is restricted. User group membership and - # bug restrictions are stored as bits within bitsets, so authorization - # can be determined by comparing the intersection of the user's - # bitset with the bug's bitset. If the result matches the bug's bitset - # the user is a member of all groups to which the bug is restricted - # and is authorized to access the bug. - - # A user is also authorized to access a bug if she is the reporter, - # assignee, QA contact, or member of the cc: list of the bug and the bug - # allows users in those roles to see the bug. The boolean fields - # reporter_accessible, assignee_accessible, qacontact_accessible, and - # cclist_accessible identify whether or not those roles can see the bug. - - # Bit arithmetic is performed by MySQL instead of Perl because bitset - # fields in the database are 64 bits wide (BIGINT), and Perl installations - # may or may not support integers larger than 32 bits. Using bitsets - # and doing bitset arithmetic is probably not cross-database compatible, - # however, so these mechanisms are likely to change in the future. - - my $replace = " "; - - if ($userid) { - $replace .= "LEFT JOIN cc selectVisible_cc ON - bugs.bug_id = selectVisible_cc.bug_id AND - selectVisible_cc.who = $userid " - } - - $replace .= "WHERE ((bugs.groupset & $usergroupset) = bugs.groupset "; - - if ($userid) { - # There is a mysql bug affecting v3.22 and 3.23 (at least), where this will - # cause all rows to be returned! We work arround this by adding an not isnull - # test to the JOINed cc table. See http://lists.mysql.com/cgi-ez/ezmlm-cgi?9:mss:11417 - # Its needed, even though it shouldn't be - $replace .= "OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid) - OR (bugs.assignee_accessible = 1 AND bugs.assigned_to = $userid) - OR (bugs.qacontact_accessible = 1 AND bugs.qa_contact = $userid) - OR (bugs.cclist_accessible = 1 AND selectVisible_cc.who = $userid AND not isnull(selectVisible_cc.who))"; - } - - $replace .= ") AND "; - - $query =~ s/\sWHERE\s/$replace/i; - - return $query; -} - -sub CanSeeBug { - # Note that we pass in the usergroupset, since this is known - # in most cases (ie viewing bugs). Maybe make this an optional - # parameter? - - my ($id, $userid, $usergroupset) = @_; - - # Query the database for the bug, retrieving a boolean value that - # represents whether or not the user is authorized to access the bug. - - PushGlobalSQLState(); - SendSQL(SelectVisible("SELECT bugs.bug_id FROM bugs WHERE bugs.bug_id = $id", - $userid, $usergroupset)); - - my $ret = defined(FetchSQLData()); - PopGlobalSQLState(); - - return $ret; -} sub ValidatePassword { # Determines whether or not a password is valid (i.e. meets Bugzilla's @@ -929,22 +823,16 @@ sub DBNameToIdAndCheck { exit(0); } -# Use trick_taint() when you know that there is no way that the data +# Use detaint_string() when you know that there is no way that the data # in a scalar can be tainted, but taint mode still bails on it. # WARNING!! Using this routine on data that really could be tainted # defeats the purpose of taint mode. It should only be # used on variables that cannot be touched by users. -sub trick_taint { - $_[0] =~ /^(.*)$/s; - $_[0] = $1; - return (defined($_[0])); -} - -sub detaint_natural { - $_[0] =~ /^(\d+)$/; - $_[0] = $1; - return (defined($_[0])); +sub detaint_string { + my ($str) = @_; + $str =~ m/^(.*)$/s; + $str = $1; } # This routine quoteUrls contains inspirations from the HTML::FromText CPAN @@ -991,22 +879,6 @@ sub quoteUrls { $things[$count++] = $item; } - # Either a comment string or no comma and a compulsory #. - while ($text =~ s/\bbug(\s|%\#)*(\d+),?\s*comment\s*(\s|%\#)(\d+)/"##$count##"/ei) { - my $item = $&; - my $bugnum = $2; - my $comnum = $4; - $item = GetBugLink($bugnum, $item); - $item =~ s/(id=\d+)/$1#c$comnum/; - $things[$count++] = $item; - } - while ($text =~ s/\bcomment(\s|%\#)*(\d+)/"##$count##"/ei) { - my $item = $&; - my $num = $2; - $item = value_quote($item); - $item = qq{<A HREF="#c$num">$item</A>}; - $things[$count++] = $item; - } while ($text =~ s/\bbug(\s|%\#)*(\d+)/"##$count##"/ei) { my $item = $&; my $num = $2; @@ -1039,7 +911,7 @@ sub quoteUrls { } $text = value_quote($text); - $text =~ s/\
/\n/g; + $text =~ s/\
/\n/g; # Stuff everything back from the array. for (my $i=0 ; $i<$count ; $i++) { @@ -1059,61 +931,40 @@ sub quoteUrls { sub GetBugLink { my ($bug_num, $link_text) = (@_); - detaint_natural($bug_num) || die "GetBugLink() called with non-integer bug number"; - - # If we've run GetBugLink() for this bug number before, %::buglink - # will contain an anonymous array ref of relevent values, if not - # we need to get the information from the database. - if (! defined $::buglink{$bug_num}) { - # Make sure any unfetched data from a currently running query - # is saved off rather than overwritten - PushGlobalSQLState(); + my ($link_return) = ""; - SendSQL("SELECT bugs.bug_status, resolution, short_desc, groupset " . - "FROM bugs WHERE bugs.bug_id = $bug_num"); - - # If the bug exists, save its data off for use later in the sub - if (MoreSQLData()) { - my ($bug_state, $bug_res, $bug_desc, $bug_grp) = FetchSQLData(); - # Initialize these variables to be "" so that we don't get warnings - # if we don't change them below (which is highly likely). - my ($pre, $title, $post) = ("", "", ""); + # TODO - Add caching capabilites... possibly use a global variable in the form + # of $buglink{$bug_num} that contains the text returned by this sub. If that + # variable is defined, simply return it's value rather than running the SQL + # query. This would cut down on the number of SQL calls when the same bug is + # referenced multiple times. + + # Make sure any unfetched data from a currently running query + # is saved off rather than overwritten + PushGlobalSQLState(); + + # Get this bug's info from the SQL Database + SendSQL("select bugs.bug_status, resolution, short_desc, groupset + from bugs where bugs.bug_id = $bug_num"); + my ($bug_stat, $bug_res, $bug_desc, $bug_grp) = (FetchSQLData()); + + # Format the retrieved information into a link + if ($bug_stat eq "UNCONFIRMED") { $link_return .= "<i>" } + if ($bug_res ne "") { $link_return .= "<strike>" } + $bug_desc = value_quote($bug_desc); + $link_text = value_quote($link_text); + $link_return .= qq{<a href="show_bug.cgi?id=$bug_num" title="$bug_stat}; + if ($bug_res ne "") {$link_return .= " $bug_res"} + if ($bug_grp == 0) { $link_return .= " - $bug_desc" } + $link_return .= qq{">$link_text</a>}; + if ($bug_res ne "") { $link_return .= "</strike>" } + if ($bug_stat eq "UNCONFIRMED") { $link_return .= "</i>"} + + # Put back any query in progress + PopGlobalSQLState(); - $title = $bug_state; - if ($bug_state eq $::unconfirmedstate) { - $pre = "<i>"; - $post = "</i>"; - } - elsif (! IsOpenedState($bug_state)) { - $pre = "<strike>"; - $title .= " $bug_res"; - $post = "</strike>"; - } - if ($bug_grp == 0 || CanSeeBug($bug_num, $::userid, $::usergroupset)) { - $title .= " - $bug_desc"; - } - $::buglink{$bug_num} = [$pre, value_quote($title), $post]; - } - else { - # Even if there's nothing in the database, we want to save a blank - # anonymous array in the %::buglink hash so the query doesn't get - # run again next time we're called for this bug number. - $::buglink{$bug_num} = []; - } - # All done with this sidetrip - PopGlobalSQLState(); - } + return $link_return; - # Now that we know we've got all the information we're gonna get, let's - # return the link (which is the whole reason we were called :) - my ($pre, $title, $post) = @{$::buglink{$bug_num}}; - # $title will be undefined if the bug didn't exist in the database. - if (defined $title) { - return qq{$pre<a href="show_bug.cgi?id=$bug_num" title="$title">$link_text</a>$post}; - } - else { - return qq{$link_text}; - } } sub GetLongDescriptionAsText { @@ -1184,14 +1035,16 @@ sub GetLongDescriptionAsHTML { my ($who, $email, $when, $text) = (FetchSQLData()); $email .= Param('emailsuffix'); if ($count) { - $result .= qq|<BR><BR><I>------- Additional Comment <a name="c$count" href="#c$count">#$count</a> From |; - if ($who) { - $result .= qq{<A HREF="mailto:$email">$who</A> }; - } else { - $result .= qq{<A HREF="mailto:$email">$email</A> }; - } - - $result .= time2str("%Y-%m-%d %H:%M", str2time($when)) . " -------</I><BR>\n"; + $result .= "<BR><BR><I>------- Additional Comments From "; + if ($who) { + $result .= qq{<A HREF="mailto:$email">$who</A> } . + time2str("%Y-%m-%d %H:%M", str2time($when)) . + " -------</I><BR>\n"; + } else { + $result .= qq{<A HREF="mailto:$email">$email</A> } . + time2str("%Y-%m-%d %H:%M", str2time($when)) . + " -------</I><BR>\n"; + } } $result .= "<PRE>" . quoteUrls(\%knownattachments, $text) . "</PRE>\n"; $count++; @@ -1233,7 +1086,7 @@ sub SplitEnumType { while ($guts =~ /^\'([^\']*)\',(.*)$/) { push @result, $1; $guts = $2; - } + } } return @result; } @@ -1249,7 +1102,7 @@ sub SqlQuote { $str =~ s/([\\\'])/\\$1/g; $str =~ s/\0/\\0/g; # If it's been SqlQuote()ed, then it's safe, so we tell -T that. - trick_taint($str); + $str = detaint_string($str); return "'$str'"; } @@ -1318,19 +1171,12 @@ sub GroupIsActive { sub IsOpenedState { my ($state) = (@_); - if (grep($_ eq $state, OpenStates())) { + if ($state =~ /^(NEW|REOPENED|ASSIGNED)$/ || $state eq $::unconfirmedstate) { return 1; } return 0; } -# This sub will return an array containing any status that -# is considered an open bug. - -sub OpenStates { - return ('NEW', 'REOPENED', 'ASSIGNED', $::unconfirmedstate); -} - sub RemoveVotes { my ($id, $who, $reason) = (@_); |