Commit 24c95007 authored by Côme Chilliet's avatar Côme Chilliet

Merge branch '5715-snapshots-are-not-typed-and-no-check-is-done-when-restoring' into '1.4-dev'

Resolve "Snapshots are not typed, and no check is done when restoring"

See merge request fusiondirectory/fd!597
parents 6e4ff6e5 b6468a56
...@@ -57,6 +57,12 @@ attributetype ( 1.3.6.1.4.1.38414.62.1.3 NAME 'fdLockTimestamp' ...@@ -57,6 +57,12 @@ attributetype ( 1.3.6.1.4.1.38414.62.1.3 NAME 'fdLockTimestamp'
ORDERING generalizedTimeOrderingMatch ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
attributetype ( 1.3.6.1.4.1.38414.62.1.4 NAME 'fdSnapshotObjectType'
DESC 'FusionDirectory - object type of the snapshotted object'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
# Classes # Classes
objectclass ( 1.3.6.1.4.1.10098.1.2.1.19.4 NAME 'gosaDepartment' SUP top AUXILIARY objectclass ( 1.3.6.1.4.1.10098.1.2.1.19.4 NAME 'gosaDepartment' SUP top AUXILIARY
...@@ -84,7 +90,7 @@ objectclass ( 1.3.6.1.4.1.10098.1.2.1.19.19 NAME 'gosaSnapshotObject' ...@@ -84,7 +90,7 @@ objectclass ( 1.3.6.1.4.1.10098.1.2.1.19.19 NAME 'gosaSnapshotObject'
DESC 'GOsa - Container object for undo and snapshot data' DESC 'GOsa - Container object for undo and snapshot data'
SUP top STRUCTURAL SUP top STRUCTURAL
MUST ( gosaSnapshotTimestamp $ gosaSnapshotDN $ gosaSnapshotData ) MUST ( gosaSnapshotTimestamp $ gosaSnapshotDN $ gosaSnapshotData )
MAY ( description ) ) MAY ( fdSnapshotObjectType $ description ) )
objectclass ( 1.3.6.1.4.1.38414.62.2.1 NAME 'fdLockEntry' SUP top STRUCTURAL objectclass ( 1.3.6.1.4.1.38414.62.2.1 NAME 'fdLockEntry' SUP top STRUCTURAL
DESC 'FusionDirectory - Class for FD locking' DESC 'FusionDirectory - Class for FD locking'
......
...@@ -1037,27 +1037,8 @@ class LDAP ...@@ -1037,27 +1037,8 @@ class LDAP
return @ldap_read($this->cid, $dn, "(objectClass=*)", ["objectClass"]); return @ldap_read($this->cid, $dn, "(objectClass=*)", ["objectClass"]);
} }
/*! function parseLdif (string $str_attr): array
* \brief Function to imports ldifs
*
* If DeleteOldEntries is TRUE, the destination entry will be deleted first.
* If JustModify is TRUE the destination entry will only be touched by the attributes specified in the ldif.
* if JustMofify is FALSE the destination dn will be overwritten by the new ldif.
*
* \param integer $srp
*
* \param string $str_attr
*
* \param boolean $JustModify
*
* \param boolean $DeleteOldEntries
*/
function import_complete_ldif ($srp, $str_attr, $JustModify, $DeleteOldEntries)
{ {
if ($this->reconnect) {
$this->connect();
}
/* First we split the string into lines */ /* First we split the string into lines */
$fileLines = preg_split("/\n/", $str_attr); $fileLines = preg_split("/\n/", $str_attr);
if (end($fileLines) != '') { if (end($fileLines) != '') {
...@@ -1126,6 +1107,32 @@ class LDAP ...@@ -1126,6 +1107,32 @@ class LDAP
} }
} }
return $entries;
}
/*!
* \brief Function to imports ldifs
*
* If DeleteOldEntries is TRUE, the destination entry will be deleted first.
* If JustModify is TRUE the destination entry will only be touched by the attributes specified in the ldif.
* if JustMofify is FALSE the destination dn will be overwritten by the new ldif.
*
* \param integer $srp
*
* \param string $str_attr
*
* \param boolean $JustModify
*
* \param boolean $DeleteOldEntries
*/
function import_complete_ldif ($srp, $str_attr, $JustModify, $DeleteOldEntries)
{
$entries = $this->parseLdif($str_attr);
if ($this->reconnect) {
$this->connect();
}
foreach ($entries as $startLine => $entry) { foreach ($entries as $startLine => $entry) {
/* Delete before insert */ /* Delete before insert */
$usermdir = ($this->dn_exists($entry['dn']) && $DeleteOldEntries); $usermdir = ($this->dn_exists($entry['dn']) && $DeleteOldEntries);
......
...@@ -1055,7 +1055,7 @@ class management ...@@ -1055,7 +1055,7 @@ class management
function createSnapshotDialog (array $action) function createSnapshotDialog (array $action)
{ {
global $config, $ui; global $config, $ui;
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action['targets'], 'Snaptshot creation initiated!'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $action['targets'], 'Snapshot creation initiated!');
$this->currentDn = array_pop($action['targets']); $this->currentDn = array_pop($action['targets']);
if (empty($this->currentDn)) { if (empty($this->currentDn)) {
...@@ -1093,7 +1093,7 @@ class management ...@@ -1093,7 +1093,7 @@ class management
} }
if ($ui->allow_snapshot_restore($this->currentDn, $aclCategory, empty($action['targets']))) { if ($ui->allow_snapshot_restore($this->currentDn, $aclCategory, empty($action['targets']))) {
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Snaptshot restoring initiated!'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->currentDn, 'Snapshot restoring initiated!');
$this->dialogObject = new SnapshotRestoreDialog($this->currentDn, $this, empty($action['targets']), $aclCategory); $this->dialogObject = new SnapshotRestoreDialog($this->currentDn, $this, empty($action['targets']), $aclCategory);
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $this->currentDn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $this->currentDn),
...@@ -1176,13 +1176,14 @@ class management ...@@ -1176,13 +1176,14 @@ class management
function createSnapshot (string $dn, string $description) function createSnapshot (string $dn, string $description)
{ {
global $ui; global $ui;
if ($this->currentDn !== $dn) { if (empty($dn) || ($this->currentDn !== $dn)) {
trigger_error('There was a problem with the snapshot workflow'); trigger_error('There was a problem with the snapshot workflow');
return; return;
} }
if (!empty($dn) && $ui->allow_snapshot_create($dn, $this->dialogObject->aclCategory)) { $entry = $this->listing->getEntry($dn);
$this->snapHandler->createSnapshot($dn, $description); if ($entry->snapshotCreationAllowed()) {
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot created!'); $this->snapHandler->createSnapshot($dn, $description, $entry->type);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot created!');
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
ERROR_DIALOG); ERROR_DIALOG);
...@@ -1198,9 +1199,20 @@ class management ...@@ -1198,9 +1199,20 @@ class management
{ {
global $ui; global $ui;
if (!empty($dn) && $ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory, $this->dialogObject->global)) { if (!empty($dn) && $ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory, $this->dialogObject->global)) {
$this->snapHandler->restoreSnapshot($dn); $dn = $this->snapHandler->restoreSnapshot($dn);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot restored'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot restored');
$this->closeDialogs(); $this->closeDialogs();
if ($dn !== FALSE) {
$this->listing->focusDn($dn);
$entry = $this->listing->getEntry($dn);
$this->currentDn = $dn;
set_object_info($this->currentDn);
add_lock($this->currentDn, $ui->dn);
// Open object
$this->openTabObject(objects::open($this->currentDn, $entry->getTemplatedType()), $this->currentDn);
$this->saveChanges();
}
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
ERROR_DIALOG); ERROR_DIALOG);
...@@ -1217,7 +1229,7 @@ class management ...@@ -1217,7 +1229,7 @@ class management
global $ui; global $ui;
if (!empty($dn) && $ui->allow_snapshot_delete($dn, $this->dialogObject->aclCategory)) { if (!empty($dn) && $ui->allow_snapshot_delete($dn, $this->dialogObject->aclCategory)) {
$this->snapHandler->removeSnapshot($dn); $this->snapHandler->removeSnapshot($dn);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot deleted'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot deleted');
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to delete a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to delete a snapshot for %s.'), $dn),
ERROR_DIALOG); ERROR_DIALOG);
......
...@@ -462,16 +462,7 @@ class managementListing ...@@ -462,16 +462,7 @@ class managementListing
/* Pre-render list to init things if a dn is gonna be opened on first load */ /* Pre-render list to init things if a dn is gonna be opened on first load */
$dn = urldecode($_REQUEST['dn']); $dn = urldecode($_REQUEST['dn']);
$action = $m[1]; $action = $m[1];
/* Detect the longer base valid for this dn */ $this->focusDn($dn);
$longerBase = '';
foreach (array_keys($this->bases) as $base) {
if (preg_match('/'.preg_quote($base, '/').'$/i', $dn)
&& (strlen($base) > strlen($longerBase))) {
$longerBase = $base;
}
}
$this->setBase($longerBase);
$this->update($dn);
$this->render(); $this->render();
$result['action'] = $action; $result['action'] = $action;
...@@ -527,6 +518,23 @@ class managementListing ...@@ -527,6 +518,23 @@ class managementListing
return $result; return $result;
} }
/*!
* \brief Set base close to this dn and load only him
*/
function focusDn (string $dn)
{
/* Detect the longer base valid for this dn */
$longerBase = '';
foreach (array_keys($this->bases) as $base) {
if (preg_match('/'.preg_quote($base, '/').'$/i', $dn)
&& (strlen($base) > strlen($longerBase))) {
$longerBase = $base;
}
}
$this->setBase($longerBase);
$this->update($dn);
}
/*! /*!
* \brief Refresh the bases list * \brief Refresh the bases list
*/ */
......
<?php <?php
/* /*
This code is part of FusionDirectory (http://www.fusiondirectory.org/) This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2003-2010 Cajus Pollmeier Copyright (C) 2003-2010 Cajus Pollmeier
Copyright (C) 2011-2016 FusionDirectory Copyright (C) 2011-2019 FusionDirectory
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -190,13 +191,15 @@ class SnapshotHandler ...@@ -190,13 +191,15 @@ class SnapshotHandler
* *
* \param string $dn The DN * \param string $dn The DN
* *
* \param array $description Snapshot description * \param string $description Snapshot description
*
* \param string $objectType Type of snapshotted object
*/ */
function createSnapshot ($dn, $description = []) function createSnapshot ($dn, string $description, string $objectType)
{ {
global $config; global $config;
if (!$this->enabled()) { if (!$this->enabled()) {
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot are disabled but tried to create snapshot'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot are disabled but tried to create snapshot');
return; return;
} }
...@@ -230,12 +233,13 @@ class SnapshotHandler ...@@ -230,12 +233,13 @@ class SnapshotHandler
} }
} }
$target = []; $target = [];
$target['objectClass'] = ['top', 'gosaSnapshotObject']; $target['objectClass'] = ['top', 'gosaSnapshotObject'];
$target['gosaSnapshotData'] = gzcompress($data, 6); $target['gosaSnapshotData'] = gzcompress($data, 6);
$target['gosaSnapshotDN'] = $dn; $target['gosaSnapshotDN'] = $dn;
$target['description'] = $description; $target['description'] = $description;
$target['fdSnapshotObjectType'] = $objectType;
/* Insert the new snapshot /* Insert the new snapshot
But we have to check first, if the given gosaSnapshotTimestamp But we have to check first, if the given gosaSnapshotTimestamp
...@@ -299,7 +303,7 @@ class SnapshotHandler ...@@ -299,7 +303,7 @@ class SnapshotHandler
$ldap->cd($new_base); $ldap->cd($new_base);
$ldap->search( $ldap->search(
'(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN='.ldap_escape_f($dn).'))', '(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN='.ldap_escape_f($dn).'))',
['gosaSnapshotTimestamp','gosaSnapshotDN','description'], ['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType'],
'one' 'one'
); );
...@@ -335,7 +339,7 @@ class SnapshotHandler ...@@ -335,7 +339,7 @@ class SnapshotHandler
$ldap->cd($new_base); $ldap->cd($new_base);
$ldap->search( $ldap->search(
'(objectClass=gosaSnapshotObject)', '(objectClass=gosaSnapshotObject)',
['gosaSnapshotTimestamp','gosaSnapshotDN','description'], ['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType'],
'one' 'one'
); );
while ($entry = $ldap->fetch()) { while ($entry = $ldap->fetch()) {
...@@ -371,34 +375,37 @@ class SnapshotHandler ...@@ -371,34 +375,37 @@ class SnapshotHandler
{ {
global $config; global $config;
if (!$this->enabled()) { if (!$this->enabled()) {
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot are disabled but tried to restore snapshot'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot are disabled but tried to restore snapshot');
return []; return FALSE;
} }
$ldap = $config->get_ldap_link(); $ldap = $config->get_ldap_link();
/* Get the snapshot */ /* Get the snapshot */
$ldap->cat($dn, ['gosaSnapshotData'], '(gosaSnapshotData=*)'); $ldap->cat($dn, ['gosaSnapshotData','gosaSnapshotDN','fdSnapshotObjectType'], '(gosaSnapshotData=*)');
if ($attrs = $ldap->fetch()) { if ($attrs = $ldap->fetch()) {
/* Prepare import string */ /* Prepare import string */
$data = gzuncompress($attrs['gosaSnapshotData'][0]); $data = gzuncompress($attrs['gosaSnapshotData'][0]);
if ($data === FALSE) { if ($data === FALSE) {
msg_dialog::display(_('Error'), _('There was a problem uncompressing snapshot data'), ERROR_DIALOG); msg_dialog::display(_('Error'), _('There was a problem uncompressing snapshot data'), ERROR_DIALOG);
return []; return FALSE;
} }
} else { } else {
msg_dialog::display(_('Error'), _('Snapshot data could not be fetched'), ERROR_DIALOG); msg_dialog::display(_('Error'), _('Snapshot data could not be fetched'), ERROR_DIALOG);
return []; return FALSE;
} }
/* Import the given data */ /* Import the given data */
try { try {
$ldap->import_complete_ldif($data, FALSE, FALSE); $ldap->import_complete_ldif($data, FALSE, FALSE);
if (!$ldap->success()) { if (!$ldap->success()) {
msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, "", get_class()), LDAP_ERROR); msg_dialog::display(_('LDAP error'), msgPool::ldaperror($ldap->get_error(), $dn, '', get_class()), LDAP_ERROR);
return FALSE;
} }
return $attrs['gosaSnapshotDN'][0];
} catch (LDIFImportException $e) { } catch (LDIFImportException $e) {
msg_dialog::display(_('LDAP error'), $e->getMessage(), ERROR_DIALOG); msg_dialog::display(_('LDAP error'), $e->getMessage(), ERROR_DIALOG);
return FALSE;
} }
} }
} }
...@@ -1107,7 +1107,7 @@ class simpleManagement ...@@ -1107,7 +1107,7 @@ class simpleManagement
function createSnapshotDialog ($action, array $target) function createSnapshotDialog ($action, array $target)
{ {
global $config, $ui; global $config, $ui;
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, 'Snaptshot creation initiated!'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, 'Snapshot creation initiated!');
if (count($target) == 1) { if (count($target) == 1) {
$this->dn = array_pop($target); $this->dn = array_pop($target);
...@@ -1163,7 +1163,7 @@ class simpleManagement ...@@ -1163,7 +1163,7 @@ class simpleManagement
} }
if ($ui->allow_snapshot_restore($this->dn, $aclCategory, !count($target))) { if ($ui->allow_snapshot_restore($this->dn, $aclCategory, !count($target))) {
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'Snaptshot restoring initiated!'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'Snapshot restoring initiated!');
$this->dialogObject = new SnapshotRestoreDialog($this->dn, $this, !count($target), $aclCategory); $this->dialogObject = new SnapshotRestoreDialog($this->dn, $this, !count($target), $aclCategory);
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $this->dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $this->dn),
...@@ -1244,7 +1244,7 @@ class simpleManagement ...@@ -1244,7 +1244,7 @@ class simpleManagement
} }
if (!empty($dn) && $ui->allow_snapshot_create($dn, $this->dialogObject->aclCategory)) { if (!empty($dn) && $ui->allow_snapshot_create($dn, $this->dialogObject->aclCategory)) {
$this->snapHandler->createSnapshot($dn, $description); $this->snapHandler->createSnapshot($dn, $description);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot created!'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot created!');
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
ERROR_DIALOG); ERROR_DIALOG);
...@@ -1261,7 +1261,7 @@ class simpleManagement ...@@ -1261,7 +1261,7 @@ class simpleManagement
global $ui; global $ui;
if (!empty($dn) && $ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory, $this->dialogObject->global)) { if (!empty($dn) && $ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory, $this->dialogObject->global)) {
$this->snapHandler->restoreSnapshot($dn); $this->snapHandler->restoreSnapshot($dn);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot restored'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot restored');
$this->closeDialogs(); $this->closeDialogs();
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
...@@ -1317,7 +1317,7 @@ class simpleManagement ...@@ -1317,7 +1317,7 @@ class simpleManagement
global $ui; global $ui;
if (!empty($dn) && $ui->allow_snapshot_delete($dn, $this->dialogObject->aclCategory)) { if (!empty($dn) && $ui->allow_snapshot_delete($dn, $this->dialogObject->aclCategory)) {
$this->snapHandler->removeSnapshot($dn); $this->snapHandler->removeSnapshot($dn);
@DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot deleted'); @DEBUG(DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snapshot deleted');
} else { } else {
msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to delete a snapshot for %s.'), $dn), msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to delete a snapshot for %s.'), $dn),
ERROR_DIALOG); ERROR_DIALOG);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment