Bug#696072: unblock: request-tracker4/4.0.7-4
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package request-tracker4
This contains fixes for important bugs only. debdiff against 4.0.7-2
(the version currently in testing) attached.
unblock request-tracker4/4.0.7-4
-- System Information:
Debian Release: wheezy/sid
APT prefers testing
APT policy: (500, 'testing')
Architecture: i386 (i686)
Kernel: Linux 3.2.0-4-686-pae (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
diff -Nru request-tracker4-4.0.7/debian/changelog request-tracker4-4.0.7/debian/changelog
--- request-tracker4-4.0.7/debian/changelog 2012-10-23 10:59:00.000000000 +0100
+++ request-tracker4-4.0.7/debian/changelog 2012-12-16 14:08:32.000000000 +0000
@@ -1,3 +1,18 @@
+request-tracker4 (4.0.7-4) unstable; urgency=low
+
+ * Add extra robustness to hostname handling (Closes: 685502)
+
+ -- Dominic Hargreaves <dom@earth.li> Sun, 16 Dec 2012 14:08:31 +0000
+
+request-tracker4 (4.0.7-3) unstable; urgency=low
+
+ * Cherry-pick fix from 4.0.8 fixing duplicate transaction creation
+ bug (Closes: #691701)
+ * Remove unused code which uses Digest::SHA1 which in turn has been
+ removed from Debian (Closes: #694484)
+
+ -- Dominic Hargreaves <dom@earth.li> Mon, 10 Dec 2012 14:13:24 +0000
+
request-tracker4 (4.0.7-2) unstable; urgency=high
* Multiple security fixes for:
diff -Nru request-tracker4-4.0.7/debian/config request-tracker4-4.0.7/debian/config
--- request-tracker4-4.0.7/debian/config 2012-10-15 17:50:27.000000000 +0100
+++ request-tracker4-4.0.7/debian/config 2012-12-16 14:01:42.000000000 +0000
@@ -112,7 +112,7 @@
db_version 2.0
db_capb backup
-hostname="$(hostname -f)"
+hostname="$(hostname -f || true)"
hostname="${hostname:-$(hostname)}"
# sane startup defaults
diff -Nru request-tracker4-4.0.7/debian/patches/68_lock_transaction_updates request-tracker4-4.0.7/debian/patches/68_lock_transaction_updates
--- request-tracker4-4.0.7/debian/patches/68_lock_transaction_updates 1970-01-01 01:00:00.000000000 +0100
+++ request-tracker4-4.0.7/debian/patches/68_lock_transaction_updates 2012-11-20 18:01:28.000000000 +0000
@@ -0,0 +1,185 @@
+From b99af56fa6fed07f2ea055e0abed393ce3c6fb4a Mon Sep 17 00:00:00 2001
+From: Alex Vandiver <alexmv@bestpractical.com>
+Date: Fri, 16 Mar 2012 16:57:07 -0400
+Subject: [PATCH] Lock transaction updates so scrips get a consistent snapshot
+
+Previously, nothing prevented multiple transactions from being run on
+the system concurrently, and making identical changes. This could lead
+to multiple Corrrespondences, followed by multiple "Status changed from
+new to open" transactions. Prevent this by always running
+->_NewTransaction in a database transaction, and ensuring that it takes
+a write lock on the row before running scrips and purges the cache.
+This ensures a coherent and serial execution of scrips.
+---
+ lib/RT/Record.pm | 35 +++++++++++++++++++++++++++++++++++
+ lib/RT/Ticket.pm | 10 +++++++---
+ t/ticket/race.t | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 93 insertions(+), 3 deletions(-)
+ create mode 100644 t/ticket/race.t
+
+diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
+index 29cff47..c116ee8 100644
+--- a/lib/RT/Record.pm
++++ b/lib/RT/Record.pm
+@@ -1413,8 +1413,35 @@ sub _DeleteLink {
+ }
+
+
++=head1 LockForUpdate
+
++In a database transaction, gains an exclusive lock on the row, to
++prevent race conditions. On SQLite, this is a "RESERVED" lock on the
++entire database.
+
++=cut
++
++sub LockForUpdate {
++ my $self = shift;
++
++ my $pk = $self->_PrimaryKey;
++ my $id = @_ ? $_[0] : $self->$pk;
++ $self->_expire if $self->isa("DBIx::SearchBuilder::Record::Cachable");
++ if (RT->Config->Get('DatabaseType') eq "SQLite") {
++ # SQLite does DB-level locking, upgrading the transaction to
++ # "RESERVED" on the first UPDATE/INSERT/DELETE. Do a no-op
++ # UPDATE to force the upgade.
++ return RT->DatabaseHandle->dbh->do(
++ "UPDATE " .$self->Table.
++ " SET $pk = $pk WHERE 1 = 0");
++ } else {
++ return $self->_LoadFromSQL(
++ "SELECT * FROM ".$self->Table
++ ." WHERE $pk = ? FOR UPDATE",
++ $id,
++ );
++ }
++}
+
+ =head2 _NewTransaction PARAMHASH
+
+@@ -1441,6 +1468,11 @@ sub _NewTransaction {
+ @_
+ );
+
++ my $in_txn = RT->DatabaseHandle->TransactionDepth;
++ RT->DatabaseHandle->BeginTransaction unless $in_txn;
++
++ $self->LockForUpdate;
++
+ my $old_ref = $args{'OldReference'};
+ my $new_ref = $args{'NewReference'};
+ my $ref_type = $args{'ReferenceType'};
+@@ -1487,6 +1519,9 @@ sub _NewTransaction {
+ if ( RT->Config->Get('UseTransactionBatch') and $transaction ) {
+ push @{$self->{_TransactionBatch}}, $trans if $args{'CommitScrips'};
+ }
++
++ RT->DatabaseHandle->Commit unless $in_txn;
++
+ return ( $transaction, $msg, $trans );
+ }
+
+diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
+index 3f2e94c..79fa036 100644
+--- a/lib/RT/Ticket.pm
++++ b/lib/RT/Ticket.pm
+@@ -2095,14 +2095,16 @@ sub Comment {
+ }
+ $args{'NoteType'} = 'Comment';
+
++ $RT::Handle->BeginTransaction();
+ if ($args{'DryRun'}) {
+- $RT::Handle->BeginTransaction();
+ $args{'CommitScrips'} = 0;
+ }
+
+ my @results = $self->_RecordNote(%args);
+ if ($args{'DryRun'}) {
+ $RT::Handle->Rollback();
++ } else {
++ $RT::Handle->Commit();
+ }
+
+ return(@results);
+@@ -2141,10 +2143,10 @@ sub Correspond {
+ or ( $self->CurrentUserHasRight('ModifyTicket') ) ) {
+ return ( 0, $self->loc("Permission Denied"), undef );
+ }
++ $args{'NoteType'} = 'Correspond';
+
+- $args{'NoteType'} = 'Correspond';
++ $RT::Handle->BeginTransaction();
+ if ($args{'DryRun'}) {
+- $RT::Handle->BeginTransaction();
+ $args{'CommitScrips'} = 0;
+ }
+
+@@ -2161,6 +2163,8 @@ sub Correspond {
+
+ if ($args{'DryRun'}) {
+ $RT::Handle->Rollback();
++ } else {
++ $RT::Handle->Commit();
+ }
+
+ return (@results);
+diff --git a/t/ticket/race.t b/t/ticket/race.t
+new file mode 100644
+index 0000000..aa1150e
+--- /dev/null
++++ b/t/ticket/race.t
+@@ -0,0 +1,51 @@
++use strict;
++use warnings;
++
++use RT::Test tests => 2;
++
++use constant KIDS => 50;
++
++my $id;
++
++{
++ my $t = RT::Ticket->new( RT->SystemUser );
++ ($id) = $t->Create(
++ Queue => "General",
++ Subject => "Race $$",
++ );
++}
++
++diag "Created ticket $id";
++RT->DatabaseHandle->Disconnect;
++
++my @kids;
++for (1..KIDS) {
++ if (my $pid = fork()) {
++ push @kids, $pid;
++ next;
++ }
++
++ # In the kid, load up the ticket and correspond
++ RT->ConnectToDatabase;
++ my $t = RT::Ticket->new( RT->SystemUser );
++ $t->Load( $id );
++ $t->Correspond( Content => "Correspondence from PID $$" );
++ undef $t;
++ exit 0;
++}
++
++
++diag "Forked @kids";
++waitpid $_, 0 for @kids;
++diag "All kids finished corresponding";
++
++RT->ConnectToDatabase;
++my $t = RT::Ticket->new( RT->SystemUser );
++$t->Load($id);
++my $txns = $t->Transactions;
++$txns->Limit( FIELD => 'Type', VALUE => 'Status' );
++is($txns->Count, 1, "Only one transaction change recorded" );
++
++$txns = $t->Transactions;
++$txns->Limit( FIELD => 'Type', VALUE => 'Correspond' );
++is($txns->Count, KIDS, "But all correspondences were recorded" );
+--
+1.7.10.4
+
diff -Nru request-tracker4-4.0.7/debian/patches/69_remove_unused_authenticate_method request-tracker4-4.0.7/debian/patches/69_remove_unused_authenticate_method
--- request-tracker4-4.0.7/debian/patches/69_remove_unused_authenticate_method 1970-01-01 01:00:00.000000000 +0100
+++ request-tracker4-4.0.7/debian/patches/69_remove_unused_authenticate_method 2012-12-10 14:10:38.000000000 +0000
@@ -0,0 +1,66 @@
+From ddd207807fff9e373ea665636b7363b03903982c Mon Sep 17 00:00:00 2001
+From: Alex Vandiver <alexmv@bestpractical.com>
+Date: Mon, 20 Jun 2011 14:02:44 -0400
+Subject: [PATCH] Remove the unused Authenticate method
+
+This method was added as part of an Atom feature, the functionality of
+which was removed from core in ec3af9f and made into RTx-Atom, which
+rolls its own version of this method.
+---
+ lib/RT/CurrentUser.pm | 40 ----------------------------------------
+ 1 file changed, 40 deletions(-)
+
+diff --git a/lib/RT/CurrentUser.pm b/lib/RT/CurrentUser.pm
+index 57ee1eb..6b04e46 100644
+--- a/lib/RT/CurrentUser.pm
++++ b/lib/RT/CurrentUser.pm
+@@ -268,46 +268,6 @@ sub CurrentUser {
+ return shift;
+ }
+
+-=head2 Authenticate
+-
+-Takes $password, $created and $nonce, and returns a boolean value
+-representing whether the authentication succeeded.
+-
+-If both $nonce and $created are specified, validate $password against:
+-
+- encode_base64(sha1(
+- $nonce .
+- $created .
+- sha1_hex( "$username:$realm:$server_pass" )
+- ))
+-
+-where $server_pass is the md5_hex(password) digest stored in the
+-database, $created is in ISO time format, and $nonce is a random
+-string no longer than 32 bytes.
+-
+-=cut
+-
+-sub Authenticate {
+- my ($self, $password, $created, $nonce, $realm) = @_;
+-
+- require Digest::MD5;
+- require Digest::SHA1;
+- require MIME::Base64;
+-
+- my $username = $self->UserObj->Name or return;
+- my $server_pass = $self->UserObj->__Value('Password') or return;
+- my $auth_digest = MIME::Base64::encode_base64(Digest::SHA1::sha1(
+- $nonce .
+- $created .
+- Digest::MD5::md5_hex("$username:$realm:$server_pass")
+- ));
+-
+- chomp($password);
+- chomp($auth_digest);
+-
+- return ($password eq $auth_digest);
+-}
+-
+ RT::Base->_ImportOverlays();
+
+ 1;
+--
+1.7.10.4
+
diff -Nru request-tracker4-4.0.7/debian/patches/series request-tracker4-4.0.7/debian/patches/series
--- request-tracker4-4.0.7/debian/patches/series 2012-10-23 10:50:16.000000000 +0100
+++ request-tracker4-4.0.7/debian/patches/series 2012-12-10 14:11:33.000000000 +0000
@@ -8,3 +8,5 @@
65_rt_setup_fulltext_index_no_dba_preset
66_sanity-check-stylesheets_shebang
67_patchset-2012-10-10
+68_lock_transaction_updates
+69_remove_unused_authenticate_method
Reply to: