Bug#773700: unblock: otrs2/3.3.9-3
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package otrs2. -security also ACKed this upload.
diff -Naur '--exclude=.svn' 3.3.9-2/debian/changelog 3.3.9-3/debian/changelog
--- 3.3.9-2/debian/changelog 2014-10-29 09:32:47.224286362 +0100
+++ 3.3.9-3/debian/changelog 2014-12-18 19:57:30.862192259 +0100
@@ -1,3 +1,13 @@
+otrs2 (3.3.9-3) unstable; urgency=medium
+
+ * Add patch 16-CVE-2014-9324.diff which fixes CVE-2014-9324, also known as
+ OSA-2014-06:
+ An attacker with valid OTRS credentials could access and manipulate ticket
+ data of other users via the GenericInterface, if a ticket webservice is
+ configured and not additionally secured.
+
+ -- Patrick Matthäi <pmatthaei@debian.org> Thu, 18 Dec 2014 19:02:56 +0100
+
otrs2 (3.3.9-2) unstable; urgency=low
* Drop libjs-jquery dependency and use the emebedded version again to avoid
diff -Naur '--exclude=.svn' 3.3.9-2/debian/patches/16-CVE-2014-9324.diff 3.3.9-3/debian/patches/16-CVE-2014-9324.diff
--- 3.3.9-2/debian/patches/16-CVE-2014-9324.diff 1970-01-01 01:00:00.000000000 +0100
+++ 3.3.9-3/debian/patches/16-CVE-2014-9324.diff 2014-12-18 19:57:30.874192201 +0100
@@ -0,0 +1,1528 @@
+# Upstream patch to fix CVE-2014-9324, also known as OSA-2014-06:
+# An attacker with valid OTRS credentials could access and manipulate ticket
+# data of other users via the GenericInterface, if a ticket webservice is
+# configured and not additionally secured.
+# URL:
+# https://www.otrs.com/security-advisory-2014-06-incomplete-access-control/
+
+diff -Naur otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/Common.pm otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/Common.pm
+--- otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/Common.pm 2014-09-03 15:15:41.000000000 +0200
++++ otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/Common.pm 2014-12-18 18:54:26.386869907 +0100
+@@ -1369,6 +1369,17 @@
+
+ =item CheckCreatePermissions ()
+
++Tests if the user have the permissions to create a ticket on a determined queue
++
++ my $Result = $CommonObject->CheckCreatePermissions(
++ Ticket => $TicketHashReference,
++ UserID => 123, # or 'CustomerLogin'
++ UserType => 'Agent', # or 'Customer'
++ );
++
++returns:
++ $Success = 1 # if everything is OK
++
+ =cut
+
+ sub CheckCreatePermissions {
+@@ -1413,6 +1424,45 @@
+ return 1;
+ }
+
++=item CheckAccessPermissions()
++
++Tests if the user have access permissions over a ticket
++
++ my $Result = $CommonObject->CheckAccessPermissions(
++ TicketID => 123,
++ UserID => 123, # or 'CustomerLogin'
++ UserType => 'Agent', # or 'Customer'
++ );
++
++returns:
++ $Success = 1 # if everything is OK
++
++=cut
++
++sub CheckAccessPermissions {
++ my ( $Self, %Param ) = @_;
++
++ # check needed stuff
++ for my $Needed (qw(TicketID UserID UserType)) {
++ if ( !$Param{$Needed} ) {
++ return;
++ }
++ }
++
++ my $TicketPermissionFunction = 'TicketPermission';
++ if ( $Param{UserType} eq 'Customer' ) {
++ $TicketPermissionFunction = 'TicketCustomerPermission';
++ }
++
++ my $Access = $Self->{TicketObject}->$TicketPermissionFunction(
++ Type => 'ro',
++ TicketID => $Param{TicketID},
++ UserID => $Param{UserID},
++ );
++
++ return $Access;
++}
++
+ =begin Internal:
+
+ =item _ValidateUser()
+diff -Naur otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketCreate.pm otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketCreate.pm
+--- otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketCreate.pm 2014-09-03 15:15:41.000000000 +0200
++++ otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketCreate.pm 2014-12-18 18:54:26.390869876 +0100
+@@ -238,6 +238,7 @@
+ );
+ }
+
++ my $PermissionUserID = $UserID;
+ if ( $UserType eq 'Customer' ) {
+ $UserID = $Self->{ConfigObject}->Get('CustomerPanelUserID')
+ }
+@@ -304,7 +305,7 @@
+ # check create permissions
+ my $Permission = $Self->{TicketCommonObject}->CheckCreatePermissions(
+ Ticket => $Ticket,
+- UserID => $UserID,
++ UserID => $PermissionUserID,
+ UserType => $UserType,
+ );
+
+diff -Naur otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketGet.pm otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketGet.pm
+--- otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketGet.pm 2014-09-03 15:15:41.000000000 +0200
++++ otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketGet.pm 2014-12-18 18:54:26.390869876 +0100
+@@ -271,6 +271,24 @@
+ ErrorMessage => "TicketGet: Structure for TicketID is not correct!",
+ );
+ }
++
++ TICKET:
++ for my $TicketID (@TicketIDs) {
++
++ my $Access = $Self->{TicketCommonObject}->CheckAccessPermissions(
++ TicketID => $TicketID,
++ UserID => $UserID,
++ UserType => $UserType,
++ );
++
++ next TICKET if $Access;
++
++ return $Self->{TicketCommonObject}->ReturnError(
++ ErrorCode => 'TicketGet.AccessDenied',
++ ErrorMessage => 'TicketGet: User does not have access to the ticket!',
++ );
++ }
++
+ my $DynamicFields = $Param{Data}->{DynamicFields} || 0;
+ my $Extended = $Param{Data}->{Extended} || 0;
+ my $AllArticles = $Param{Data}->{AllArticles} || 0;
+diff -Naur otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketUpdate.pm otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketUpdate.pm
+--- otrs2-3.3.9.orig/Kernel/GenericInterface/Operation/Ticket/TicketUpdate.pm 2014-09-03 15:15:41.000000000 +0200
++++ otrs2-3.3.9/Kernel/GenericInterface/Operation/Ticket/TicketUpdate.pm 2014-12-18 18:54:26.390869876 +0100
+@@ -251,8 +251,10 @@
+ );
+ }
+
++ my $PermissionUserID = $UserID;
++
+ if ( $UserType eq 'Customer' ) {
+- $UserID = $Self->{ConfigObject}->Get('CustomerPanelUserID')
++ $UserID = $Self->{ConfigObject}->Get('CustomerPanelUserID');
+ }
+
+ # check TicketID
+@@ -289,10 +291,10 @@
+ }
+
+ # check basic needed permissions
+- my $Access = $Self->{TicketObject}->TicketPermission(
+- Type => 'ro',
++ my $Access = $Self->{TicketCommonObject}->CheckAccessPermissions(
+ TicketID => $TicketID,
+- UserID => $UserID
++ UserID => $PermissionUserID,
++ UserType => $UserType,
+ );
+
+ if ( !$Access ) {
+diff -Naur otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketCreate.t otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketCreate.t
+--- otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketCreate.t 2014-09-03 15:15:43.000000000 +0200
++++ otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketCreate.t 2014-12-18 18:54:26.394869808 +0100
+@@ -199,6 +199,32 @@
+ "QueueGet() - for testing queue",
+ );
+
++# create new queue (Admin)
++my $QueueID2 = $QueueObject->QueueAdd(
++ Name => 'TestQueue2' . $RandomID,
++ ValidID => 1,
++ GroupID => 2,
++ SystemAddressID => 1,
++ SalutationID => 1,
++ SignatureID => 1,
++ Comment => 'Some comment',
++ UserID => 1,
++);
++
++# sanity check
++$Self->True(
++ $QueueID2,
++ "QueueAdd() - create testing queue2",
++);
++
++my %QueueData2 = $QueueObject->QueueGet( ID => $QueueID2 );
++
++# sanity check
++$Self->True(
++ IsHashRefWithData( \%QueueData2 ),
++ "QueueGet() - for testing queue2",
++);
++
+ # create new type
+ my $TypeID = $TypeObject->TypeAdd(
+ Name => 'TestType' . $RandomID,
+@@ -498,6 +524,18 @@
+ );
+ my $Password = $UserLogin;
+
++# create a new user without permissions for current test
++my $UserLogin2 = $HelperObject->TestUserCreate();
++my $Password2 = $UserLogin2;
++
++# create a customer where a ticket will use and will have permissions
++my $CustomerUserLogin = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword = $CustomerUserLogin;
++
++# create a customer that will not have permissions
++my $CustomerUserLogin2 = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword2 = $CustomerUserLogin2;
++
+ # start requester with our webservice
+ my $RequesterSessionResult = $RequesterSessionObject->Run(
+ WebserviceID => $WebserviceID,
+@@ -3053,6 +3091,61 @@
+ Operation => 'TicketCreate',
+ },
+ {
++ Name => 'Ticket with IDs (Using Session)',
++ SuccessRequest => 1,
++ SuccessCreate => 1,
++ RequestData => {
++ Ticket => {
++ Title => 'Ticket Title',
++ CustomerUser => $TestCustomerUserLogin,
++ QueueID => $QueueID,
++ TypeID => $TypeID,
++ ServiceID => $ServiceID,
++ SLAID => $SLAID,
++ StateID => $StateID,
++ PriorityID => $PriorityID,
++ OwnerID => $OwnerID,
++ ResponsibleID => $ResponsibleID,
++ PendingTime => {
++ Year => 2012,
++ Month => 12,
++ Day => 16,
++ Hour => 20,
++ Minute => 48,
++ },
++ },
++ Article => {
++ Subject => 'Article subject',
++ Body => 'Article body',
++ AutoResponseType => 'auto reply',
++ ArticleTypeID => 1,
++ SenderTypeID => 1,
++ From => 'enjoy@otrs.com',
++ ContentType => 'text/plain; charset=UTF8',
++ HistoryType => 'NewTicket',
++ HistoryComment => '% % ',
++ TimeUnit => 25,
++ ForceNotificationToUserID => [1],
++ ExcludeNotificationToUserID => [1],
++ ExcludeMuteNotificationToUserID => [1],
++ },
++ DynamicField => {
++ Name => $DynamicFieldData->{Name},
++ Value => '2012-01-17 12:40:00',
++ },
++ Attachment => {
++ Content => 'VGhpcyBpcyBhIHRlc3QgdGV4dC4=',
++ ContentType => 'text/plain; charset=UTF8',
++ Filename => 'Test.txt',
++ },
++ },
++ Auth => {
++ SessionID => $NewSessionID,
++ },
++ Operation => 'TicketCreate',
++ },
++
++ {
+ Name => 'Ticket with Names',
+ SuccessRequest => 1,
+ SuccessCreate => 1,
+@@ -3153,7 +3246,188 @@
+ },
+ Operation => 'TicketCreate',
+ },
++ {
++ Name => 'Ticket with IDs Agent (No Permission)',
++ SuccessRequest => 1,
++ SuccessCreate => 0,
++ RequestData => {
++ Ticket => {
++ Title => 'Ticket Title',
++ CustomerUser => $TestCustomerUserLogin,
++ QueueID => $QueueID,
++ TypeID => $TypeID,
++ ServiceID => $ServiceID,
++ SLAID => $SLAID,
++ StateID => $StateID,
++ PriorityID => $PriorityID,
++ OwnerID => $OwnerID,
++ ResponsibleID => $ResponsibleID,
++ PendingTime => {
++ Year => 2012,
++ Month => 12,
++ Day => 16,
++ Hour => 20,
++ Minute => 48,
++ },
++ },
++ Article => {
++ Subject => 'Article subject',
++ Body => 'Article body',
++ AutoResponseType => 'auto reply',
++ ArticleTypeID => 1,
++ SenderTypeID => 1,
++ From => 'enjoy@otrs.com',
++ ContentType => 'text/plain; charset=UTF8',
++ HistoryType => 'NewTicket',
++ HistoryComment => '% % ',
++ TimeUnit => 25,
++ ForceNotificationToUserID => [1],
++ ExcludeNotificationToUserID => [1],
++ ExcludeMuteNotificationToUserID => [1],
++ },
++ DynamicField => {
++ Name => $DynamicFieldData->{Name},
++ Value => '2012-01-17 12:40:00',
++ },
++ Attachment => {
++ Content => 'VGhpcyBpcyBhIHRlc3QgdGV4dC4=',
++ ContentType => 'text/plain; charset=UTF8',
++ Filename => 'Test.txt',
++ },
++ },
++ Auth => {
++ UserLogin => $UserLogin2,
++ Password => $Password2,
++ },
++ ExpectedData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketCreate.AccessDenied',
++ }
++ },
++ Success => 1
++ },
+
++ Operation => 'TicketCreate',
++ },
++ {
++ Name => 'Ticket with IDs Customer (With Permissions)',
++ SuccessRequest => 1,
++ SuccessCreate => 1,
++ RequestData => {
++ Ticket => {
++ Title => 'Ticket Title',
++ CustomerUser => $TestCustomerUserLogin,
++ QueueID => $QueueID,
++ TypeID => $TypeID,
++ ServiceID => $ServiceID,
++ SLAID => $SLAID,
++ StateID => $StateID,
++ PriorityID => $PriorityID,
++ OwnerID => $OwnerID,
++ ResponsibleID => $ResponsibleID,
++ PendingTime => {
++ Year => 2012,
++ Month => 12,
++ Day => 16,
++ Hour => 20,
++ Minute => 48,
++ },
++ },
++ Article => {
++ Subject => 'Article subject',
++ Body => 'Article body',
++ AutoResponseType => 'auto reply',
++ ArticleTypeID => 1,
++ SenderTypeID => 1,
++ From => 'enjoy@otrs.com',
++ ContentType => 'text/plain; charset=UTF8',
++ HistoryType => 'NewTicket',
++ HistoryComment => '% % ',
++ TimeUnit => 25,
++ ForceNotificationToUserID => [1],
++ ExcludeNotificationToUserID => [1],
++ ExcludeMuteNotificationToUserID => [1],
++ },
++ DynamicField => {
++ Name => $DynamicFieldData->{Name},
++ Value => '2012-01-17 12:40:00',
++ },
++ Attachment => {
++ Content => 'VGhpcyBpcyBhIHRlc3QgdGV4dC4=',
++ ContentType => 'text/plain; charset=UTF8',
++ Filename => 'Test.txt',
++ },
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin,
++ Password => $CustomerPassword,
++ },
++ Operation => 'TicketCreate',
++ },
++ {
++ Name => 'Ticket with IDs Customer (No Permission)',
++ SuccessRequest => 1,
++ SuccessCreate => 0,
++ RequestData => {
++ Ticket => {
++ Title => 'Ticket Title',
++ CustomerUser => $TestCustomerUserLogin,
++ QueueID => $QueueID2,
++ TypeID => $TypeID,
++ ServiceID => $ServiceID,
++ SLAID => $SLAID,
++ StateID => $StateID,
++ PriorityID => $PriorityID,
++ OwnerID => $OwnerID,
++ ResponsibleID => $ResponsibleID,
++ PendingTime => {
++ Year => 2012,
++ Month => 12,
++ Day => 16,
++ Hour => 20,
++ Minute => 48,
++ },
++ },
++ Article => {
++ Subject => 'Article subject',
++ Body => 'Article body',
++ AutoResponseType => 'auto reply',
++ ArticleTypeID => 1,
++ SenderTypeID => 1,
++ From => 'enjoy@otrs.com',
++ ContentType => 'text/plain; charset=UTF8',
++ HistoryType => 'NewTicket',
++ HistoryComment => '% % ',
++ TimeUnit => 25,
++ ForceNotificationToUserID => [1],
++ ExcludeNotificationToUserID => [1],
++ ExcludeMuteNotificationToUserID => [1],
++ },
++ DynamicField => {
++ Name => $DynamicFieldData->{Name},
++ Value => '2012-01-17 12:40:00',
++ },
++ Attachment => {
++ Content => 'VGhpcyBpcyBhIHRlc3QgdGV4dC4=',
++ ContentType => 'text/plain; charset=UTF8',
++ Filename => 'Test.txt',
++ },
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin2,
++ Password => $CustomerPassword2,
++ },
++ ExpectedData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketCreate.AccessDenied',
++ }
++ },
++ Success => 1
++ },
++ Operation => 'TicketCreate',
++ },
+ );
+
+ # debugger object
+@@ -3189,15 +3463,22 @@
+ "$Test->{Name} - Create local object",
+ );
+
++ my %Auth = (
++ UserLogin => $UserLogin,
++ Password => $Password,
++ );
++ if ( IsHashRefWithData( $Test->{Auth} ) ) {
++ %Auth = %{ $Test->{Auth} };
++ }
++
+ # start requester with our webservice
+ my $LocalResult = $LocalObject->Run(
+ WebserviceID => $WebserviceID,
+ Invoker => $Test->{Operation},
+ Data => {
+- UserLogin => $UserLogin,
+- Password => $Password,
++ %Auth,
+ %{ $Test->{RequestData} },
+- }
++ },
+ );
+
+ # check result
+@@ -3223,9 +3504,9 @@
+ WebserviceID => $WebserviceID,
+ Invoker => $Test->{Operation},
+ Data => {
+- SessionID => $NewSessionID,
++ %Auth,
+ %{ $Test->{RequestData} },
+- }
++ },
+ );
+
+ # check result
+@@ -3572,7 +3853,7 @@
+ "Deleted Webservice $WebserviceID",
+ );
+
+-# invalidate queue
++# invalidate queues
+ {
+ my $Success = $QueueObject->QueueUpdate(
+ %QueueData,
+@@ -3585,6 +3866,19 @@
+ $Success,
+ "QueueUpdate() set queue $QueueData{Name} to invalid",
+ );
++
++ $Success = $QueueObject->QueueUpdate(
++ %QueueData2,
++ ValidID => $InvalidID,
++ UserID => 1,
++ );
++
++ # sanity check
++ $Self->True(
++ $Success,
++ "QueueUpdate() set queue $QueueData2{Name} to invalid",
++ );
++
+ }
+
+ # invalidate type
+diff -Naur otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketGet.t otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketGet.t
+--- otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketGet.t 2014-09-03 15:15:43.000000000 +0200
++++ otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketGet.t 2014-12-18 18:54:26.394869808 +0100
+@@ -7,6 +7,7 @@
+ # did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
+ # --
+
++## no critic (Modules::RequireExplicitPackage)
+ use strict;
+ use warnings;
+ use utf8;
+@@ -47,13 +48,27 @@
+ );
+
+ # create a new user for current test
+-my $UserLogin = $HelperObject->TestUserCreate();
+-my $Password = $UserLogin;
++my $UserLogin = $HelperObject->TestUserCreate(
++ Groups => ['users'],
++);
++my $Password = $UserLogin;
+
+ $Self->{UserID} = $UserObject->UserLookup(
+ UserLogin => $UserLogin,
+ );
+
++# create a new user without permissions for current test
++my $UserLogin2 = $HelperObject->TestUserCreate();
++my $Password2 = $UserLogin2;
++
++# create a customer where a ticket will use and will have permissions
++my $CustomerUserLogin = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword = $CustomerUserLogin;
++
++# create a customer that will not have permissions
++my $CustomerUserLogin2 = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword2 = $CustomerUserLogin2;
++
+ my %SkipFields = (
+ Age => 1,
+ AgeTimeUnix => 1,
+@@ -82,7 +97,7 @@
+ $Self->Is(
+ ref $BackendObject,
+ 'Kernel::System::DynamicField::Backend',
+- 'Backend object was created successfuly',
++ 'Backend object was created successfully',
+ );
+
+ my @TestDynamicFields;
+@@ -377,7 +392,7 @@
+ );
+
+ # get the Ticket entry
+-# withpout DF
++# without DF
+ my %TicketEntryTwo = $TicketObject->TicketGet(
+ TicketID => $TicketID2,
+ DynamicFields => 0,
+@@ -473,7 +488,7 @@
+ Lock => 'lock',
+ Priority => '3 normal',
+ State => 'new',
+- CustomerID => '654321',
++ CustomerID => $CustomerUserLogin,
+ CustomerUser => 'customerFour@example.com',
+ OwnerID => 1,
+ UserID => 1,
+@@ -508,7 +523,7 @@
+ TicketID => $TicketID4,
+ ArticleType => 'phone',
+ SenderType => 'agent',
+- From => 'Anot Real Agent <email@example.com>',
++ From => 'A not Real Agent <email@example.com>',
+ To => 'Customer A <customer-a@example.com>',
+ Cc => 'Customer B <customer-b@example.com>',
+ ReplyTo => 'Customer B <customer-b@example.com>',
+@@ -641,10 +656,10 @@
+ # add ticket id
+ push @TicketIDs, $TicketID4;
+
+-# set webservice name
++# set web-service name
+ my $WebserviceName = '-Test-' . $RandomID;
+
+-# create webservice object
++# create web-service object
+ my $WebserviceObject = Kernel::System::GenericInterface::Webservice->new(
+ %{$Self},
+ ConfigObject => $ConfigObject,
+@@ -679,22 +694,22 @@
+ my $Host;
+ my $FQDN = $Self->{ConfigObject}->Get('FQDN');
+
+-# try to resolve fqdn host
++# try to resolve FQDN host
+ if ( $FQDN ne 'yourhost.example.com' && gethostbyname($FQDN) ) {
+ $Host = $FQDN;
+ }
+
+-# try to resolve localhost instead
++# try to resolve local-host instead
+ if ( !$Host && gethostbyname('localhost') ) {
+ $Host = 'localhost';
+ }
+
+-# use hardcoded localhost ip address
++# use hard-coded local-host IP address
+ if ( !$Host ) {
+ $Host = '127.0.0.1';
+ }
+
+-# prepare webservice config
++# prepare web-service config
+ my $RemoteSystem =
+ $Self->{ConfigObject}->Get('HttpType')
+ . '://'
+@@ -751,7 +766,7 @@
+ },
+ };
+
+-# update webservice with real config
++# update web-service with real config
+ # the update is needed because we are using
+ # the WebserviceID for the Endpoint in config
+ my $WebserviceUpdate = $WebserviceObject->WebserviceUpdate(
+@@ -778,7 +793,7 @@
+ "SessionID - Create requester object",
+ );
+
+-# start requester with our webservice
++# start requester with our web-service
+ my $RequesterSessionResult = $RequesterSessionObject->Run(
+ WebserviceID => $WebserviceID,
+ Invoker => 'SessionCreate',
+@@ -789,7 +804,8 @@
+ );
+
+ my $NewSessionID = $RequesterSessionResult->{Data}->{SessionID};
+-my @Tests = (
++
++my @Tests = (
+ {
+ Name => 'Test 1',
+ SuccessRequest => 1,
+@@ -823,9 +839,9 @@
+ ExpectedReturnLocalData => {
+ Data => {
+ Error => {
+- ErrorCode => 'TicketGet.NotValidTicketID',
++ ErrorCode => 'TicketGet.AccessDenied',
+ ErrorMessage =>
+- 'TicketGet: Could not get Ticket data in Kernel::GenericInterface::Operation::Ticket::TicketGet::Run()'
++ 'TicketGet: User does not have access to the ticket!'
+ }
+ },
+ Success => 1
+@@ -833,9 +849,9 @@
+ ExpectedReturnRemoteData => {
+ Data => {
+ Error => {
+- ErrorCode => 'TicketGet.NotValidTicketID',
++ ErrorCode => 'TicketGet.AccessDenied',
+ ErrorMessage =>
+- 'TicketGet: Could not get Ticket data in Kernel::GenericInterface::Operation::Ticket::TicketGet::Run()'
++ 'TicketGet: User does not have access to the ticket!'
+ }
+ },
+ Success => 1
+@@ -862,7 +878,7 @@
+ Ticket => [
+ {
+ %TicketEntryOne,
+- }
++ },
+ ],
+ },
+ },
+@@ -888,7 +904,7 @@
+ Ticket => [
+ {
+ %TicketEntryTwo,
+- }
++ },
+ ],
+ },
+ },
+@@ -914,7 +930,7 @@
+ Ticket => [
+ {
+ %TicketEntryThree,
+- }
++ },
+ ],
+ },
+ },
+@@ -940,7 +956,7 @@
+ Ticket => [
+ {
+ %TicketEntryFour,
+- }
++ },
+ ],
+ },
+ },
+@@ -967,7 +983,7 @@
+ Ticket => [
+ {
+ %TicketEntryOneDF,
+- }
++ },
+ ],
+ },
+ },
+@@ -994,7 +1010,7 @@
+ Ticket => [
+ {
+ %TicketEntryTwoDF,
+- }
++ },
+ ],
+ },
+ },
+@@ -1030,7 +1046,7 @@
+ {
+ %TicketEntryTwoDF,
+ },
+- ]
++ ],
+ },
+ },
+ Operation => 'TicketGet',
+@@ -1058,7 +1074,7 @@
+ {
+ %TicketEntryFour,
+ Article => \@ArticleWithoutAttachments,
+- }
++ },
+ ],
+ },
+ },
+@@ -1088,12 +1104,147 @@
+ {
+ %TicketEntryFour,
+ Article => \@ArticleBox,
++ },
++ ],
++ },
++ },
++ Operation => 'TicketGet',
++ },
++ {
++ Name => 'Test 11 (With sessionID',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID4,
++ AllArticles => 1,
++ Attachments => 1,
++ },
++ Auth => {
++ SessionID => $NewSessionID,
++ },
++ ExpectedReturnRemoteData => {
++ Success => 1,
++ Data => {
++ Ticket => {
++ %TicketEntryFour,
++ Article => \@ArticleBox,
++ },
++ },
++ },
++ ExpectedReturnLocalData => {
++ Success => 1,
++ Data => {
++ Ticket => [
++ {
++ %TicketEntryFour,
++ Article => \@ArticleBox,
++ },
++ ],
++ },
++ },
++ Operation => 'TicketGet',
++ },
++ {
++ Name => 'Test 11 (No Permission)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID4,
++ AllArticles => 1,
++ Attachments => 1,
++ },
++ Auth => {
++ UserLogin => $UserLogin2,
++ Password => $Password2,
++ },
++ ExpectedReturnLocalData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketGet.AccessDenied',
++ ErrorMessage =>
++ 'TicketGet: User does not have access to the ticket!'
+ }
++ },
++ Success => 1
++ },
++ ExpectedReturnRemoteData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketGet.AccessDenied',
++ ErrorMessage =>
++ 'TicketGet: User does not have access to the ticket!'
++ }
++ },
++ Success => 1
++ },
++ Operation => 'TicketGet',
++ },
++ {
++ Name => 'Test 11 (Customer)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID4,
++ AllArticles => 1,
++ Attachments => 1,
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin,
++ Password => $CustomerPassword,
++ },
++ ExpectedReturnRemoteData => {
++ Success => 1,
++ Data => {
++ Ticket => {
++ %TicketEntryFour,
++ Article => \@ArticleBox,
++ },
++ },
++ },
++ ExpectedReturnLocalData => {
++ Success => 1,
++ Data => {
++ Ticket => [
++ {
++ %TicketEntryFour,
++ Article => \@ArticleBox,
++ },
+ ],
+ },
+ },
+ Operation => 'TicketGet',
+ },
++ {
++ Name => 'Test 11 (Customer No Permission)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID4,
++ AllArticles => 1,
++ Attachments => 1,
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin2,
++ Password => $CustomerPassword2,
++ },
++ ExpectedReturnLocalData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketGet.AccessDenied',
++ ErrorMessage =>
++ 'TicketGet: User does not have access to the ticket!'
++ }
++ },
++ Success => 1
++ },
++ ExpectedReturnRemoteData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketGet.AccessDenied',
++ ErrorMessage =>
++ 'TicketGet: User does not have access to the ticket!'
++ }
++ },
++ Success => 1
++ },
++ Operation => 'TicketGet',
++ },
+ );
+
+ # debugger object
+@@ -1110,7 +1261,7 @@
+ $Self->Is(
+ ref $DebuggerObject,
+ 'Kernel::GenericInterface::Debugger',
+- 'DebuggerObject instanciate correctly',
++ 'DebuggerObject instantiate correctly',
+ );
+
+ for my $Test (@Tests) {
+@@ -1129,15 +1280,22 @@
+ "$Test->{Name} - Create local object",
+ );
+
+- # start requester with our webservice
++ my %Auth = (
++ UserLogin => $UserLogin,
++ Password => $Password,
++ );
++ if ( IsHashRefWithData( $Test->{Auth} ) ) {
++ %Auth = %{ $Test->{Auth} };
++ }
++
++ # start requester with our web-service
+ my $LocalResult = $LocalObject->Run(
+ WebserviceID => $WebserviceID,
+ Invoker => $Test->{Operation},
+ Data => {
+- UserLogin => $UserLogin,
+- Password => $Password,
++ %Auth,
+ %{ $Test->{RequestData} },
+- }
++ },
+ );
+
+ # check result
+@@ -1158,14 +1316,14 @@
+ "$Test->{Name} - Create requester object",
+ );
+
+- # start requester with our webservice
++ # start requester with our web-service
+ my $RequesterResult = $RequesterObject->Run(
+ WebserviceID => $WebserviceID,
+ Invoker => $Test->{Operation},
+ Data => {
+- SessionID => $NewSessionID,
++ %Auth,
+ %{ $Test->{RequestData} },
+- }
++ },
+ );
+
+ # check result
+@@ -1302,7 +1460,7 @@
+
+ # clean up
+
+-# clean up webservice
++# clean up web-service
+ my $WebserviceDelete = $WebserviceObject->WebserviceDelete(
+ ID => $WebserviceID,
+ UserID => $Self->{UserID},
+diff -Naur otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketUpdate.t otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketUpdate.t
+--- otrs2-3.3.9.orig/scripts/test/GenericInterface/Operation/Ticket/TicketUpdate.t 1970-01-01 01:00:00.000000000 +0100
++++ otrs2-3.3.9/scripts/test/GenericInterface/Operation/Ticket/TicketUpdate.t 2014-12-18 18:54:26.394869808 +0100
+@@ -0,0 +1,548 @@
++# --
++# TicketUpdate.t - GenericInterface TicketCreate tests for TicketConnector backend
++# Copyright (C) 2001-2014 OTRS AG, http://otrs.com/
++# --
++# This software comes with ABSOLUTELY NO WARRANTY. For details, see
++# the enclosed file COPYING for license information (AGPL). If you
++# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
++# --
++
++## no critic (Modules::RequireExplicitPackage)
++use strict;
++use warnings;
++use utf8;
++use vars (qw($Self));
++
++use Kernel::GenericInterface::Debugger;
++use Kernel::GenericInterface::Operation::Session::SessionCreate;
++use Kernel::GenericInterface::Operation::Ticket::TicketUpdate;
++use Kernel::GenericInterface::Requester;
++use Kernel::System::GenericInterface::Webservice;
++use Kernel::System::Ticket;
++use Kernel::System::UnitTest::Helper;
++use Kernel::System::User;
++
++use Kernel::System::VariableCheck qw(:all);
++
++# helper object
++# skip SSL certificate verification
++my $HelperObject = Kernel::System::UnitTest::Helper->new(
++ %{$Self},
++ UnitTestObject => $Self,
++ RestoreSystemConfiguration => 1,
++ SkipSSLVerify => 1,
++);
++
++# new user object
++my $UserObject = Kernel::System::User->new(
++ %{$Self},
++);
++
++# create a new user for current test
++my $UserLogin = $HelperObject->TestUserCreate(
++ Groups => ['users'],
++);
++my $Password = $UserLogin;
++
++$Self->{UserID} = $UserObject->UserLookup(
++ UserLogin => $UserLogin,
++);
++
++# create a new user without permissions for current test
++my $UserLogin2 = $HelperObject->TestUserCreate();
++my $Password2 = $UserLogin2;
++
++# create a customer where a ticket will use and will have permissions
++my $CustomerUserLogin = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword = $CustomerUserLogin;
++
++# create a customer that will not have permissions
++my $CustomerUserLogin2 = $HelperObject->TestCustomerUserCreate();
++my $CustomerPassword2 = $CustomerUserLogin2;
++
++# create ticket object
++my $TicketObject = Kernel::System::Ticket->new(
++ %{$Self},
++);
++
++#ticket id container
++my @TicketIDs;
++
++# create ticket 1
++my $TicketID1 = $TicketObject->TicketCreate(
++ Title => 'Ticket One Title',
++ Queue => 'Raw',
++ Lock => 'unlock',
++ Priority => '3 normal',
++ State => 'new',
++ CustomerID => $CustomerUserLogin,
++ CustomerUser => 'customerOne@example.com',
++ OwnerID => 1,
++ UserID => 1,
++);
++
++# sanity check
++$Self->True(
++ $TicketID1,
++ "TicketCreate() successful for Ticket One ID $TicketID1",
++);
++
++my %Ticket = $TicketObject->TicketGet(
++ TicketID => $TicketID1,
++ UserID => 1,
++);
++
++# remember ticket id
++push @TicketIDs, $TicketID1;
++
++#get a random id
++my $RandomID = int rand 1_000_000_000;
++
++# set web-service name
++my $WebserviceName = '-Test-' . $RandomID;
++
++# create web-service object
++my $WebserviceObject = Kernel::System::GenericInterface::Webservice->new(
++ %{$Self},
++);
++$Self->Is(
++ 'Kernel::System::GenericInterface::Webservice',
++ ref $WebserviceObject,
++ "Create webservice object",
++);
++
++my $WebserviceID = $WebserviceObject->WebserviceAdd(
++ Name => $WebserviceName,
++ Config => {
++ Debugger => {
++ DebugThreshold => 'debug',
++ },
++ Provider => {
++ Transport => {
++ Type => '',
++ },
++ },
++ },
++ ValidID => 1,
++ UserID => 1,
++);
++$Self->True(
++ $WebserviceID,
++ "Added Webservice",
++);
++
++# get remote host with some precautions for certain unit test systems
++my $Host;
++my $FQDN = $Self->{ConfigObject}->Get('FQDN');
++
++# try to resolve FQDN host
++if ( $FQDN ne 'yourhost.example.com' && gethostbyname($FQDN) ) {
++ $Host = $FQDN;
++}
++
++# try to resolve local-host instead
++if ( !$Host && gethostbyname('localhost') ) {
++ $Host = 'localhost';
++}
++
++# use hard-coded local-host IP address
++if ( !$Host ) {
++ $Host = '127.0.0.1';
++}
++
++# prepare web-service config
++my $RemoteSystem =
++ $Self->{ConfigObject}->Get('HttpType')
++ . '://'
++ . $Host
++ . '/'
++ . $Self->{ConfigObject}->Get('ScriptAlias')
++ . '/nph-genericinterface.pl/WebserviceID/'
++ . $WebserviceID;
++
++my $WebserviceConfig = {
++
++ # Name => '',
++ Description =>
++ 'Test for Ticket Connector using SOAP transport backend.',
++ Debugger => {
++ DebugThreshold => 'debug',
++ TestMode => 1,
++ },
++ Provider => {
++ Transport => {
++ Type => 'HTTP::SOAP',
++ Config => {
++ MaxLength => 10000000,
++ NameSpace => 'http://otrs.org/SoapTestInterface/',
++ Endpoint => $RemoteSystem,
++ },
++ },
++ Operation => {
++ TicketUpdate => {
++ Type => 'Ticket::TicketUpdate',
++ },
++ SessionCreate => {
++ Type => 'Session::SessionCreate',
++ },
++ },
++ },
++ Requester => {
++ Transport => {
++ Type => 'HTTP::SOAP',
++ Config => {
++ NameSpace => 'http://otrs.org/SoapTestInterface/',
++ Encoding => 'UTF-8',
++ Endpoint => $RemoteSystem,
++ },
++ },
++ Invoker => {
++ TicketUpdate => {
++ Type => 'Test::TestSimple',
++ },
++ SessionCreate => {
++ Type => 'Test::TestSimple',
++ },
++ },
++ },
++};
++
++# update web-service with real config
++# the update is needed because we are using
++# the WebserviceID for the Endpoint in config
++my $WebserviceUpdate = $WebserviceObject->WebserviceUpdate(
++ ID => $WebserviceID,
++ Name => $WebserviceName,
++ Config => $WebserviceConfig,
++ ValidID => 1,
++ UserID => $Self->{UserID},
++);
++$Self->True(
++ $WebserviceUpdate,
++ "Updated Webservice $WebserviceID - $WebserviceName",
++);
++
++# Get SessionID
++# create requester object
++my $RequesterSessionObject = Kernel::GenericInterface::Requester->new(
++ %{$Self},
++);
++$Self->Is(
++ 'Kernel::GenericInterface::Requester',
++ ref $RequesterSessionObject,
++ "SessionID - Create requester object",
++);
++
++# start requester with our web-service
++my $RequesterSessionResult = $RequesterSessionObject->Run(
++ WebserviceID => $WebserviceID,
++ Invoker => 'SessionCreate',
++ Data => {
++ UserLogin => $UserLogin,
++ Password => $Password,
++ },
++);
++
++my $NewSessionID = $RequesterSessionResult->{Data}->{SessionID};
++
++my @Tests = (
++ {
++ Name => 'Update Agent (With Permissions)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID1,
++ Ticket => {
++ Title => 'Updated',
++ },
++ },
++ ExpectedReturnRemoteData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ ExpectedReturnLocalData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ Operation => 'TicketUpdate',
++ },
++ {
++ Name => 'Update Agent (With SessionID)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID1,
++ Ticket => {
++ Title => 'Updated',
++ },
++ },
++ Auth => {
++ SessionID => $NewSessionID,
++ },
++ ExpectedReturnRemoteData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ ExpectedReturnLocalData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ Operation => 'TicketUpdate',
++ },
++ {
++ Name => 'Update Agent (No Permission)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID1,
++ Ticket => {
++ Title => 'Updated',
++ },
++ },
++ Auth => {
++ UserLogin => $UserLogin2,
++ Password => $Password2,
++ },
++ ExpectedReturnLocalData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketUpdate.AccessDenied',
++ ErrorMessage =>
++ 'TicketUpdate: User does not have access to the ticket!'
++ },
++ },
++ Success => 1
++ },
++ ExpectedReturnRemoteData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketUpdate.AccessDenied',
++ ErrorMessage =>
++ 'TicketUpdate: User does not have access to the ticket!'
++ },
++ },
++ Success => 1
++ },
++ Operation => 'TicketUpdate',
++ },
++ {
++ Name => 'Update Customer (With Permissions)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID1,
++ Ticket => {
++ Title => 'Updated',
++ },
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin,
++ Password => $CustomerPassword,
++ },
++ ExpectedReturnRemoteData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ ExpectedReturnLocalData => {
++ Success => 1,
++ Data => {
++ TicketID => $Ticket{TicketID},
++ TicketNumber => $Ticket{TicketNumber},
++ },
++ },
++ Operation => 'TicketUpdate',
++ },
++ {
++ Name => 'Update Customer (No Permission)',
++ SuccessRequest => '1',
++ RequestData => {
++ TicketID => $TicketID1,
++ Ticket => {
++ Title => 'Updated',
++ },
++ },
++ Auth => {
++ CustomerUserLogin => $CustomerUserLogin2,
++ Password => $CustomerPassword2,
++ },
++ ExpectedReturnLocalData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketUpdate.AccessDenied',
++ ErrorMessage =>
++ 'TicketUpdate: User does not have access to the ticket!'
++ },
++ },
++ Success => 1
++ },
++ ExpectedReturnRemoteData => {
++ Data => {
++ Error => {
++ ErrorCode => 'TicketUpdate.AccessDenied',
++ ErrorMessage =>
++ 'TicketUpdate: User does not have access to the ticket!'
++ },
++ },
++ Success => 1
++ },
++ Operation => 'TicketUpdate',
++ },
++);
++
++# debugger object
++my $DebuggerObject = Kernel::GenericInterface::Debugger->new(
++ %{$Self},
++ DebuggerConfig => {
++ DebugThreshold => 'debug',
++ TestMode => 1,
++ },
++ WebserviceID => $WebserviceID,
++ CommunicationType => 'Provider',
++);
++$Self->Is(
++ ref $DebuggerObject,
++ 'Kernel::GenericInterface::Debugger',
++ 'DebuggerObject instantiate correctly',
++);
++
++for my $Test (@Tests) {
++
++ # create local object
++ my $LocalObject = "Kernel::GenericInterface::Operation::Ticket::$Test->{Operation}"->new(
++ %{$Self},
++ DebuggerObject => $DebuggerObject,
++ WebserviceID => $WebserviceID,
++ );
++
++ $Self->Is(
++ "Kernel::GenericInterface::Operation::Ticket::$Test->{Operation}",
++ ref $LocalObject,
++ "$Test->{Name} - Create local object",
++ );
++
++ my %Auth = (
++ UserLogin => $UserLogin,
++ Password => $Password,
++ );
++ if ( IsHashRefWithData( $Test->{Auth} ) ) {
++ %Auth = %{ $Test->{Auth} };
++ }
++
++ # start requester with our web-service
++ my $LocalResult = $LocalObject->Run(
++ WebserviceID => $WebserviceID,
++ Invoker => $Test->{Operation},
++ Data => {
++ %Auth,
++ %{ $Test->{RequestData} },
++ },
++ );
++
++ # check result
++ $Self->Is(
++ 'HASH',
++ ref $LocalResult,
++ "$Test->{Name} - Local result structure is valid",
++ );
++
++ # create requester object
++ my $RequesterObject = Kernel::GenericInterface::Requester->new(
++ %{$Self},
++ );
++ $Self->Is(
++ 'Kernel::GenericInterface::Requester',
++ ref $RequesterObject,
++ "$Test->{Name} - Create requester object",
++ );
++
++ # start requester with our web-service
++ my $RequesterResult = $RequesterObject->Run(
++ WebserviceID => $WebserviceID,
++ Invoker => $Test->{Operation},
++ Data => {
++ %Auth,
++ %{ $Test->{RequestData} },
++ },
++ );
++
++ # check result
++ $Self->Is(
++ 'HASH',
++ ref $RequesterResult,
++ "$Test->{Name} - Requester result structure is valid",
++ );
++
++ $Self->Is(
++ $RequesterResult->{Success},
++ $Test->{SuccessRequest},
++ "$Test->{Name} - Requester successful result",
++ );
++
++ # remove ErrorMessage parameter from direct call
++ # result to be consistent with SOAP call result
++ if ( $LocalResult->{ErrorMessage} ) {
++ delete $LocalResult->{ErrorMessage};
++ }
++
++ $Self->IsDeeply(
++ $RequesterResult,
++ $Test->{ExpectedReturnRemoteData},
++ "$Test->{Name} - Requester success status (needs configured and running webserver)",
++ );
++
++ if ( $Test->{ExpectedReturnLocalData} ) {
++ $Self->IsDeeply(
++ $LocalResult,
++ $Test->{ExpectedReturnLocalData},
++ "$Test->{Name} - Local result matched with expected local call result.",
++ );
++ }
++ else {
++ $Self->IsDeeply(
++ $LocalResult,
++ $Test->{ExpectedReturnRemoteData},
++ "$Test->{Name} - Local result matched with remote result.",
++ );
++ }
++}
++
++# clean up
++
++# clean up web-service
++my $WebserviceDelete = $WebserviceObject->WebserviceDelete(
++ ID => $WebserviceID,
++ UserID => $Self->{UserID},
++);
++$Self->True(
++ $WebserviceDelete,
++ "Deleted Webservice $WebserviceID",
++);
++
++# remove tickets
++for my $TicketID (@TicketIDs) {
++
++ # delete the ticket Three
++ my $TicketDelete = $TicketObject->TicketDelete(
++ TicketID => $TicketID,
++ UserID => $Self->{UserID},
++ );
++
++ # sanity check
++ $Self->True(
++ $TicketDelete,
++ "TicketDelete() successful for Ticket ID $TicketID",
++ );
++}
++
++1;
diff -Naur '--exclude=.svn' 3.3.9-2/debian/patches/series 3.3.9-3/debian/patches/series
--- 3.3.9-2/debian/patches/series 2014-10-29 09:32:47.200286363 +0100
+++ 3.3.9-3/debian/patches/series 2014-12-18 19:57:30.874192201 +0100
@@ -12,3 +12,4 @@
13-load-debian-libjs.diff
14-font-paths.diff
15-dbupdate-as-root.diff
+16-CVE-2014-9324.diff
unblock otrs2/3.3.9-3
-- System Information:
Debian Release: 7.7
APT prefers stable-updates
APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: amd64 (x86_64)
Kernel: Linux 3.2.0-4-amd64 (SMP w/2 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Reply to: