diff options
-rw-r--r-- | Bugzilla/Auth/Login/Cookie.pm | 6 | ||||
-rw-r--r-- | Bugzilla/Constants.pm | 2 | ||||
-rw-r--r-- | Bugzilla/Token.pm | 22 | ||||
-rwxr-xr-x | attachment.cgi | 19 | ||||
-rw-r--r-- | docs/en/xml/Bugzilla-Guide.xml | 4 | ||||
-rw-r--r-- | template/en/default/admin/flag-type/edit.html.tmpl | 6 | ||||
-rw-r--r-- | template/en/default/filterexceptions.pl | 2 | ||||
-rw-r--r-- | template/en/default/global/code-error.html.tmpl | 3 | ||||
-rw-r--r-- | template/en/default/pages/release-notes.html.tmpl | 30 | ||||
-rw-r--r-- | template/en/default/reports/report-table.html.tmpl | 38 | ||||
-rwxr-xr-x | token.cgi | 7 |
11 files changed, 98 insertions, 41 deletions
diff --git a/Bugzilla/Auth/Login/Cookie.pm b/Bugzilla/Auth/Login/Cookie.pm index 88c48e236..4db486a8f 100644 --- a/Bugzilla/Auth/Login/Cookie.pm +++ b/Bugzilla/Auth/Login/Cookie.pm @@ -72,8 +72,8 @@ sub get_login_info { trick_taint($login_cookie); detaint_natural($user_id); - my $is_valid = - $dbh->selectrow_array('SELECT 1 + my $db_cookie = + $dbh->selectrow_array('SELECT cookie FROM logincookies WHERE cookie = ? AND userid = ? @@ -81,7 +81,7 @@ sub get_login_info { undef, ($login_cookie, $user_id, $ip_addr)); # If the cookie is valid, return a valid username. - if ($is_valid) { + if (defined $db_cookie && $login_cookie eq $db_cookie) { # If we logged in successfully, then update the lastused # time on the login cookie $dbh->do("UPDATE logincookies SET lastused = NOW() diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 1f712f25d..ef3afeccb 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -209,7 +209,7 @@ use Memoize; # CONSTANTS # # Bugzilla version -use constant BUGZILLA_VERSION => "4.2.6+"; +use constant BUGZILLA_VERSION => "4.2.7"; # Location of the remote and local XML files to track new releases. use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml'; diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index 4804851bb..24df470ac 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -277,13 +277,18 @@ sub Cancel { # Get information about the token being canceled. trick_taint($token); - my ($issuedate, $tokentype, $eventdata, $userid) = - $dbh->selectrow_array('SELECT ' . $dbh->sql_date_format('issuedate') . ', + my ($db_token, $issuedate, $tokentype, $eventdata, $userid) = + $dbh->selectrow_array('SELECT token, ' . $dbh->sql_date_format('issuedate') . ', tokentype, eventdata, userid FROM tokens WHERE token = ?', undef, $token); + # Some DBs such as MySQL are case-insensitive by default so we do + # a quick comparison to make sure the tokens are indeed the same. + (defined $db_token && $db_token eq $token) + || ThrowCodeError("cancel_token_does_not_exist"); + # If we are canceling the creation of a new user account, then there # is no entry in the 'profiles' table. my $user = new Bugzilla::User($userid); @@ -348,10 +353,17 @@ sub GetTokenData { $token = clean_text($token); trick_taint($token); - return $dbh->selectrow_array( - "SELECT userid, " . $dbh->sql_date_format('issuedate') . ", eventdata - FROM tokens + my @token_data = $dbh->selectrow_array( + "SELECT token, userid, " . $dbh->sql_date_format('issuedate') . ", eventdata + FROM tokens WHERE token = ?", undef, $token); + + # Some DBs such as MySQL are case-insensitive by default so we do + # a quick comparison to make sure the tokens are indeed the same. + my $db_token = shift @token_data; + return undef if (!defined $db_token || $db_token ne $token); + + return @token_data; } # Deletes specified token diff --git a/attachment.cgi b/attachment.cgi index 95d793e75..57706d5e0 100755 --- a/attachment.cgi +++ b/attachment.cgi @@ -680,20 +680,23 @@ sub update { $attachment->set_filename(scalar $cgi->param('filename')); # Now make sure the attachment has not been edited since we loaded the page. - if (defined $cgi->param('delta_ts') - && $cgi->param('delta_ts') ne $attachment->modification_time) - { - ($vars->{'operations'}) = - Bugzilla::Bug::GetBugActivity($bug->id, $attachment->id, $cgi->param('delta_ts')); + my $delta_ts = $cgi->param('delta_ts'); + my $modification_time = $attachment->modification_time; - # The token contains the old modification_time. We need a new one. - $cgi->param('token', issue_hash_token([$attachment->id, $attachment->modification_time])); + if ($delta_ts && $delta_ts ne $modification_time) { + datetime_from($delta_ts) + or ThrowCodeError('invalid_timestamp', { timestamp => $delta_ts }); + ($vars->{'operations'}) = + Bugzilla::Bug::GetBugActivity($bug->id, $attachment->id, $delta_ts); # If the modification date changed but there is no entry in # the activity table, this means someone commented only. # In this case, there is no reason to midair. if (scalar(@{$vars->{'operations'}})) { - $cgi->param('delta_ts', $attachment->modification_time); + $cgi->param('delta_ts', $modification_time); + # The token contains the old modification_time. We need a new one. + $cgi->param('token', issue_hash_token([$attachment->id, $modification_time])); + $vars->{'attachment'} = $attachment; print $cgi->header(); diff --git a/docs/en/xml/Bugzilla-Guide.xml b/docs/en/xml/Bugzilla-Guide.xml index 045a426ee..d2079630f 100644 --- a/docs/en/xml/Bugzilla-Guide.xml +++ b/docs/en/xml/Bugzilla-Guide.xml @@ -32,9 +32,9 @@ For a devel release, simple bump bz-ver and bz-date --> -<!ENTITY bz-ver "4.2.6"> +<!ENTITY bz-ver "4.2.7"> <!ENTITY bz-nextver "4.4"> -<!ENTITY bz-date "2013-05-22"> +<!ENTITY bz-date "2013-10-16"> <!ENTITY current-year "2013"> <!ENTITY landfillbase "http://landfill.bugzilla.org/bugzilla-4.2-branch/"> diff --git a/template/en/default/admin/flag-type/edit.html.tmpl b/template/en/default/admin/flag-type/edit.html.tmpl index 46346d2ea..69dc05bd3 100644 --- a/template/en/default/admin/flag-type/edit.html.tmpl +++ b/template/en/default/admin/flag-type/edit.html.tmpl @@ -52,7 +52,7 @@ <form id="flagtype_properties" method="post" action="editflagtypes.cgi"> <input type="hidden" name="action" value="[% action FILTER html %]"> <input type="hidden" name="can_fully_edit" value="[% can_fully_edit FILTER html %]"> - <input type="hidden" name="id" value="[% type.id %]"> + <input type="hidden" name="id" value="[% type.id FILTER html %]"> <input type="hidden" name="token" value="[% token FILTER html %]"> <input type="hidden" name="target_type" value="[% type.target_type FILTER html %]"> <input type="hidden" name="check_clusions" value="[% check_clusions FILTER none %]"> @@ -149,8 +149,8 @@ this type will be sorted when displayed to users in a list; ignore if you don't care what order the types appear in or if you want them to appear in alphabetical order.<br> - <input type="text" name="sortkey" value="[% type.sortkey || 1 %]" size="5" maxlength="5" - [%- ' disabled="disabled"' UNLESS can_fully_edit %]> + <input type="text" name="sortkey" value="[% type.sortkey || 1 FILTER html %]" size="5" + maxlength="5" [% ' disabled="disabled"' UNLESS can_fully_edit %]> </td> </tr> diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index 08757cfe7..16a3220e2 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -406,8 +406,6 @@ ], 'admin/flag-type/edit.html.tmpl' => [ - 'type.id', - 'type.sortkey || 1', 'selname', ], diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl index d98f2578c..62442c268 100644 --- a/template/en/default/global/code-error.html.tmpl +++ b/template/en/default/global/code-error.html.tmpl @@ -438,6 +438,9 @@ [% ELSIF error == "token_generation_error" %] Something is seriously wrong with the token generation system. + [% ELSIF error == "cancel_token_does_not_exist" %] + The token to be cancelled does not exist. + [% ELSIF error == "template_error" %] [% template_error_msg FILTER html %] diff --git a/template/en/default/pages/release-notes.html.tmpl b/template/en/default/pages/release-notes.html.tmpl index 3d5b36b45..ebc08afb1 100644 --- a/template/en/default/pages/release-notes.html.tmpl +++ b/template/en/default/pages/release-notes.html.tmpl @@ -53,6 +53,36 @@ <h2 id="v42_point">Updates in this 4.2.x Release</h2> +<h3>4.2.7</h3> + +<p>This release fixes several security issues. See the + <a href="http://www.bugzilla.org/security/4.0.10/">Security Advisory</a> + for details.</p> + +<p>In addition, the following [% terms.bugs %] have been fixed in this release:</p> + +<ul> + <li>Internet Explorer 11 and KHTML-based browsers such as Konqueror can now + display buglists correctly. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=902515">[% terms.Bug %] 902515</a> and + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=914262">[% terms.bug %] 914262</a>)</li> + <li>When the <kbd>password_complexity</kbd> parameter was set to + 'letters_numbers_specialchars', passwords containing numbers and special + characters only were accepted. Now it makes sure that a letter is also present. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=897264">[% terms.Bug %] 897264</a>)</li> + <li>With DB servers doing case-insensitive comparisons, such as MySQL, tokens + and login cookies were not correctly validated as the case was ignored. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=906745">[% terms.Bug %] 906745</a> and + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=907438">[% terms.bug %] 907438</a>)</li> + <li>All security headers (such as X-Frame-Options) are now returned when using XML-RPC. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=787328">[% terms.Bug %] 787328</a>)</li> + <li>Oracle crashed when reporting a new [% terms.bug %] if a custom free-text field + was non-mandatory and left empty. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=919475">[% terms.Bug %] 919475</a>)</li> + <li>It was not possible to import [% terms.bugs %] using <kbd>importxml.pl</kbd> with Oracle. + (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=848063">[% terms.Bug %] 848063</a>)</li> +</ul> + <h3>4.2.6</h3> <p>The following important fixes/changes have been made in this release:</p> diff --git a/template/en/default/reports/report-table.html.tmpl b/template/en/default/reports/report-table.html.tmpl index b41753550..cef47c2d9 100644 --- a/template/en/default/reports/report-table.html.tmpl +++ b/template/en/default/reports/report-table.html.tmpl @@ -47,32 +47,42 @@ [% END %] <script type="text/javascript"> +function bz_encode (str, decode) { + // First decode HTML entities, if requested. + if (decode) + str = str.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"') + .replace(/ /g, " ").replace(/&/g, "&").replace(/\s+$/,""); + + // encodeURIComponent() doesn't escape single quotes. + return encodeURIComponent(str).replace(/'/g, escape); +}; + YAHOO.util.Event.addListener(window, "load", function() { this.Linkify = function(elLiner, oRecord, oColumn, oData) { if (oData == 0) elLiner.innerHTML = "."; else if (oRecord.getData("row_title") == "Total") - elLiner.innerHTML = "<a href='[% urlbase %]&[% col_field FILTER js %]=" - + oColumn.field + "[% '&' _ row_vals IF row_vals %]'>" - + oData + "</a>"; + elLiner.innerHTML = '<a href="[% urlbase FILTER js %]&[% col_field FILTER uri FILTER js %]=' + + bz_encode(oColumn.field) + + '[% "&" _ row_vals IF row_vals %]">' + oData + '</a>'; else - elLiner.innerHTML = "<a href='[% urlbase %]&[% row_field FILTER js %]=" - + oRecord.getData("row_title").replace(/\s+$/,"") - + "&[% col_field FILTER js %]=" + oColumn.field - + "'>" + oData + "</a>"; + elLiner.innerHTML = '<a href="[% urlbase FILTER js %]&[% row_field FILTER uri FILTER js %]=' + + bz_encode(oRecord.getData("row_title"), 1) + + '&[% col_field FILTER uri FILTER js %]=' + + bz_encode(oColumn.field) + '">' + oData + '</a>'; }; this.LinkifyTotal = function(elLiner, oRecord, oColumn, oData) { if (oData == 0) elLiner.innerHTML = "."; else if (oRecord.getData("row_title") == "Total") - elLiner.innerHTML = "<a href='[% urlbase %][% '&' _ row_vals IF row_vals %] - [%~ '&' _ col_vals IF col_vals %]'>" - + oData + "</a>"; + elLiner.innerHTML = '<a href="[% urlbase FILTER js %][% "&" _ row_vals IF row_vals %] + [%~ "&" _ col_vals IF col_vals %]">' + + oData + '</a>'; else - elLiner.innerHTML = "<a href='[% urlbase %]&[% row_field FILTER js %]=" - + oRecord.getData("row_title").replace(/\s+$/,"") - + "[% '&' _ col_vals IF col_vals %]'>" + oData + "</a>"; + elLiner.innerHTML = '<a href="[% urlbase FILTER js %]&[% row_field FILTER uri FILTER js %]=' + + bz_encode(oRecord.getData("row_title"), 1) + + '[% "&" _ col_vals IF col_vals %]">' + oData + '</a>'; YAHOO.util.Dom.addClass(elLiner.parentNode, "ttotal"); }; @@ -164,7 +174,7 @@ YAHOO.util.Event.addListener(window, "load", function() { [% col_idx = 0 %] [% row_idx = 0 %] [% grand_total = 0 %] -<div id="tabular_report_container_[% tbl FILTER js %]"> +<div id="tabular_report_container_[% tbl FILTER html %]"> <table id="tabular_report" border="1"> [% IF col_field %] <thead> @@ -67,9 +67,10 @@ if ($token) { trick_taint($token); # Make sure the token exists in the database. - my ($tokentype) = $dbh->selectrow_array('SELECT tokentype FROM tokens - WHERE token = ?', undef, $token); - $tokentype || ThrowUserError("token_does_not_exist"); + my ($db_token, $tokentype) = $dbh->selectrow_array('SELECT token, tokentype FROM tokens + WHERE token = ?', undef, $token); + (defined $db_token && $db_token eq $token) + || ThrowUserError("token_does_not_exist"); # Make sure the token is the correct type for the action being taken. if ( grep($action eq $_ , qw(cfmpw cxlpw chgpw)) && $tokentype ne 'password' ) { |