mirror of
https://github.com/altlinux/admc.git
synced 2025-03-23 02:50:17 +03:00
Merge pull request #284 from altlinux/feature/protect-against-deletion
Feature/protect against deletion
This commit is contained in:
commit
e22f521f81
@ -100,6 +100,7 @@ Tests for ADMC
|
||||
%_bindir/admc_test_delegation_edit
|
||||
%_bindir/admc_test_string_other_edit
|
||||
%_bindir/admc_test_account_option_edit
|
||||
%_bindir/admc_test_protect_deletion_edit
|
||||
%_bindir/admc_test_gpoptions_edit
|
||||
%_bindir/admc_test_octet_editor
|
||||
%_bindir/admc_test_bool_editor
|
||||
|
@ -244,6 +244,8 @@ enum AcePermission {
|
||||
AcePermission_FullControl,
|
||||
AcePermission_Read,
|
||||
AcePermission_Write,
|
||||
AcePermission_Delete,
|
||||
AcePermission_DeleteSubtree,
|
||||
AcePermission_CreateChild,
|
||||
AcePermission_DeleteChild,
|
||||
AcePermission_AllowedToAuthenticate,
|
||||
|
@ -113,6 +113,8 @@ const QHash<AcePermission, uint32_t> ace_permission_to_mask_map = {
|
||||
{AcePermission_Read, (SEC_STD_READ_CONTROL | SEC_ADS_LIST | SEC_ADS_READ_PROP)},
|
||||
// {AcePermission_Write, SEC_ADS_GENERIC_WRITE},
|
||||
{AcePermission_Write, (SEC_ADS_SELF_WRITE | SEC_ADS_WRITE_PROP)},
|
||||
{AcePermission_Delete, SEC_STD_DELETE},
|
||||
{AcePermission_DeleteSubtree, SEC_DIR_DELETE_CHILD},
|
||||
{AcePermission_CreateChild, SEC_ADS_CREATE_CHILD},
|
||||
{AcePermission_DeleteChild, SEC_ADS_DELETE_CHILD},
|
||||
{AcePermission_AllowedToAuthenticate, SEC_ADS_CONTROL_ACCESS},
|
||||
@ -458,6 +460,14 @@ QByteArray dom_sid_to_bytes(const dom_sid &sid) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
QByteArray dom_sid_string_to_bytes(const QString &string) {
|
||||
dom_sid sid;
|
||||
dom_sid_parse(cstr(string), &sid);
|
||||
const QByteArray bytes = dom_sid_to_bytes(sid);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void ad_security_sort_dacl(security_descriptor *sd) {
|
||||
qsort(sd->dacl->aces, sd->dacl->num_aces, sizeof(security_ace), ace_compare);
|
||||
}
|
||||
@ -600,3 +610,43 @@ QHash<QByteArray, QHash<AcePermission, PermissionState>> ad_security_get_state_f
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ad_security_get_protected_against_deletion(const AdObject &object, AdConfig *adconfig) {
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> permissions = object.get_security_state(adconfig);
|
||||
|
||||
const QByteArray world_trustee = dom_sid_string_to_bytes(SID_WORLD);
|
||||
|
||||
const PermissionState delete_state = permissions[world_trustee][AcePermission_Delete];
|
||||
const PermissionState delete_subtree_state = permissions[world_trustee][AcePermission_DeleteSubtree];
|
||||
const bool out = ((delete_state == PermissionState_Denied) && (delete_subtree_state == PermissionState_Denied));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ad_security_set_protected_against_deletion(AdInterface &ad, const QString dn, AdConfig *adconfig, const bool enabled) {
|
||||
const AdObject object = ad.search_object(dn);
|
||||
const QHash<QByteArray, QHash<AcePermission, PermissionState>> old_permissions = object.get_security_state(adconfig);
|
||||
|
||||
const QHash<QByteArray, QHash<AcePermission, PermissionState>> new_permissions = [&]() {
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> out;
|
||||
|
||||
const QByteArray world_trustee = dom_sid_string_to_bytes(SID_WORLD);
|
||||
|
||||
const PermissionState state = [&]() {
|
||||
if (enabled) {
|
||||
return PermissionState_Denied;
|
||||
} else {
|
||||
return PermissionState_None;
|
||||
}
|
||||
}();
|
||||
out = old_permissions;
|
||||
out = ad_security_modify(out, world_trustee, AcePermission_Delete, state);
|
||||
out = ad_security_modify(out, world_trustee, AcePermission_DeleteSubtree, state);
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
const bool apply_success = attribute_replace_security_descriptor(&ad, dn, new_permissions);
|
||||
|
||||
return apply_success;
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ QString ad_security_get_trustee_name(AdInterface &ad, const QByteArray &trustee)
|
||||
bool attribute_replace_security_descriptor(AdInterface *ad, const QString &dn, const QHash<QByteArray, QHash<AcePermission, PermissionState>> &descriptor_state_arg);
|
||||
QList<QByteArray> ad_security_get_trustee_list_from_object(const AdObject &object);
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> ad_security_get_state_from_sd(security_descriptor *sd, AdConfig *adconfig);
|
||||
bool ad_security_get_protected_against_deletion(const AdObject &object, AdConfig *config);
|
||||
bool ad_security_set_protected_against_deletion(AdInterface &ad, const QString dn, AdConfig *config, const bool enabled);
|
||||
|
||||
// NOTE: have to talloc_free() returned sd
|
||||
security_descriptor *ad_security_get_sd(const AdObject &object);
|
||||
@ -60,5 +62,6 @@ security_descriptor *ad_security_get_sd(const AdObject &object);
|
||||
void ad_security_sort_dacl(security_descriptor *sd);
|
||||
|
||||
QByteArray dom_sid_to_bytes(const dom_sid &sid);
|
||||
QByteArray dom_sid_string_to_bytes(const dom_sid &sid);
|
||||
|
||||
#endif /* AD_SECURITY_H */
|
||||
|
@ -144,6 +144,7 @@ set(ADMC_SOURCES
|
||||
edits/delegation_edit.cpp
|
||||
edits/logon_hours_edit.cpp
|
||||
edits/logon_computers_edit.cpp
|
||||
edits/protect_deletion_edit.cpp
|
||||
|
||||
console_widget/console_widget.cpp
|
||||
console_widget/scope_proxy_model.cpp
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "edits/password_edit.h"
|
||||
#include "edits/string_edit.h"
|
||||
#include "edits/upn_edit.h"
|
||||
#include "edits/protect_deletion_edit.h"
|
||||
#include "globals.h"
|
||||
#include "settings.h"
|
||||
#include "status.h"
|
||||
@ -188,6 +189,10 @@ CreateObjectDialog::CreateObjectDialog(const QString &parent_dn_arg, const QStri
|
||||
});
|
||||
} else if (object_class == CLASS_OU) {
|
||||
edits_layout->addRow(tr("Name:"), name_edit);
|
||||
|
||||
auto protect_deletion_edit = new ProtectDeletionEdit(&all_edits, this);
|
||||
protect_deletion_edit->set_enabled(true);
|
||||
protect_deletion_edit->add_to_layout(edits_layout);
|
||||
} else {
|
||||
qWarning() << "Class" << object_class << "is unsupported by create dialog";
|
||||
return;
|
||||
|
68
src/admc/edits/protect_deletion_edit.cpp
Normal file
68
src/admc/edits/protect_deletion_edit.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020-2021 BaseALT Ltd.
|
||||
* Copyright (C) 2020-2021 Dmitry Degtyarev
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "edits/protect_deletion_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "utils.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
|
||||
// Object is protected from deletion if it denies
|
||||
// permissions for "delete" and "delete subtree" for
|
||||
// "WORLD"(everyone) trustee
|
||||
|
||||
ProtectDeletionEdit::ProtectDeletionEdit(QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
check = new QCheckBox(tr("Protect against deletion"));
|
||||
|
||||
connect(
|
||||
check, &QCheckBox::stateChanged,
|
||||
[this]() {
|
||||
emit edited();
|
||||
});
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::set_enabled(const bool enabled) {
|
||||
check->setChecked(enabled);
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
const bool enabled = ad_security_get_protected_against_deletion(object, g_adconfig);
|
||||
|
||||
check->setChecked(enabled);
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::set_read_only(const bool read_only) {
|
||||
check->setDisabled(read_only);
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::add_to_layout(QFormLayout *layout) {
|
||||
layout->addRow(check);
|
||||
}
|
||||
|
||||
bool ProtectDeletionEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool enabled = check->isChecked();
|
||||
const bool apply_success = ad_security_set_protected_against_deletion(ad, dn, g_adconfig, enabled);
|
||||
|
||||
return apply_success;
|
||||
}
|
45
src/admc/edits/protect_deletion_edit.h
Normal file
45
src/admc/edits/protect_deletion_edit.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020-2021 BaseALT Ltd.
|
||||
* Copyright (C) 2020-2021 Dmitry Degtyarev
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PROTECT_DELETION_EDIT_H
|
||||
#define PROTECT_DELETION_EDIT_H
|
||||
|
||||
/**
|
||||
* Checkbox edit that modifies ACL to protect (or not)
|
||||
* against deletion by denying/allowing deletion.
|
||||
*/
|
||||
|
||||
#include "edits/attribute_edit.h"
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
class ProtectDeletionEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProtectDeletionEdit(QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
|
||||
void set_enabled(const bool enabled);
|
||||
|
||||
private:
|
||||
QCheckBox *check;
|
||||
};
|
||||
|
||||
#endif /* PROTECT_DELETION_EDIT_H */
|
@ -23,6 +23,7 @@
|
||||
#include "adldap.h"
|
||||
#include "edits/datetime_edit.h"
|
||||
#include "edits/string_edit.h"
|
||||
#include "edits/protect_deletion_edit.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
|
||||
@ -38,6 +39,8 @@ ObjectTab::ObjectTab() {
|
||||
|
||||
edits_set_read_only(edits, true);
|
||||
|
||||
new ProtectDeletionEdit(&edits, this);
|
||||
|
||||
edits_connect_to_tab(edits, this);
|
||||
|
||||
const auto layout = new QFormLayout();
|
||||
|
@ -47,6 +47,8 @@ const QHash<AcePermission, QString> ace_permission_to_name_map = {
|
||||
{AcePermission_FullControl, QCoreApplication::translate("Security", "Full control")},
|
||||
{AcePermission_Read, QCoreApplication::translate("Security", "Read")},
|
||||
{AcePermission_Write, QCoreApplication::translate("Security", "Write")},
|
||||
{AcePermission_Delete, QCoreApplication::translate("Security", "Delete")},
|
||||
{AcePermission_DeleteSubtree, QCoreApplication::translate("Security", "Delete subtree")},
|
||||
{AcePermission_CreateChild, QCoreApplication::translate("Security", "Create child")},
|
||||
{AcePermission_DeleteChild, QCoreApplication::translate("Security", "Delete child")},
|
||||
{AcePermission_AllowedToAuthenticate, QCoreApplication::translate("Security", "Allowed to authenticate")},
|
||||
|
@ -59,6 +59,7 @@ set(TEST_TARGETS
|
||||
admc_test_string_other_edit
|
||||
admc_test_account_option_edit
|
||||
admc_test_gpoptions_edit
|
||||
admc_test_protect_deletion_edit
|
||||
admc_test_octet_editor
|
||||
admc_test_bool_editor
|
||||
admc_test_datetime_editor
|
||||
|
91
tests/admc_test_protect_deletion_edit.cpp
Normal file
91
tests/admc_test_protect_deletion_edit.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020-2021 BaseALT Ltd.
|
||||
* Copyright (C) 2020-2021 Dmitry Degtyarev
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "admc_test_protect_deletion_edit.h"
|
||||
|
||||
#include "edits/protect_deletion_edit.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
|
||||
// NOTE: this doesn't really "lock" accounts. Accounts can
|
||||
// only be locked by the server and lockout time only
|
||||
// displays the state. Since unlock edit modifies lockout
|
||||
// time, test it like this.
|
||||
#define LOCKOUT_LOCKED_VALUE "1"
|
||||
|
||||
void ADMCTestProtectDeletionEdit::init() {
|
||||
ADMCTest::init();
|
||||
|
||||
edit = new ProtectDeletionEdit(&edits, parent_widget);
|
||||
add_attribute_edit(edit);
|
||||
|
||||
checkbox = parent_widget->findChild<QCheckBox *>();
|
||||
QVERIFY(checkbox != nullptr);
|
||||
|
||||
dn = test_object_dn(TEST_OU, CLASS_OU);
|
||||
const bool create_success = ad.object_add(dn, CLASS_OU);
|
||||
QVERIFY(create_success);
|
||||
}
|
||||
|
||||
// edited() signal should be emitted when checkbox is toggled
|
||||
void ADMCTestProtectDeletionEdit::emit_edited_signal() {
|
||||
bool edited_signal_emitted = false;
|
||||
connect(
|
||||
edit, &AttributeEdit::edited,
|
||||
[&edited_signal_emitted]() {
|
||||
edited_signal_emitted = true;
|
||||
});
|
||||
|
||||
// Check checkbox
|
||||
checkbox->setChecked(true);
|
||||
QVERIFY(edited_signal_emitted);
|
||||
|
||||
// Unheck checkbox
|
||||
edited_signal_emitted = false;
|
||||
checkbox->setChecked(false);
|
||||
QVERIFY(edited_signal_emitted);
|
||||
}
|
||||
|
||||
// Edit should unlock locked user if checkbox is checked
|
||||
void ADMCTestProtectDeletionEdit::apply() {
|
||||
const AdObject object = ad.search_object(dn);
|
||||
edit->load(ad, object);
|
||||
|
||||
// Enable protection against deletion
|
||||
checkbox->setChecked(true);
|
||||
const bool apply_success = edit->apply(ad, dn);
|
||||
QVERIFY(apply_success);
|
||||
|
||||
// Try to delete, should fail
|
||||
qInfo() << "Error relating to \"Insufficient access\" is part of the test";
|
||||
const bool delete_success = ad.object_delete(dn);
|
||||
QCOMPARE(delete_success, false);
|
||||
|
||||
// Disable protection against deletion
|
||||
checkbox->setChecked(false);
|
||||
const bool apply_2_success = edit->apply(ad, dn);
|
||||
QVERIFY(apply_2_success);
|
||||
|
||||
const bool delete_2_success = ad.object_delete(dn);
|
||||
QCOMPARE(delete_2_success, true);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ADMCTestProtectDeletionEdit)
|
44
tests/admc_test_protect_deletion_edit.h
Normal file
44
tests/admc_test_protect_deletion_edit.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020-2021 BaseALT Ltd.
|
||||
* Copyright (C) 2020-2021 Dmitry Degtyarev
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADMC_TEST_PROTECT_DELETION_EDIT_H
|
||||
#define ADMC_TEST_PROTECT_DELETION_EDIT_H
|
||||
|
||||
#include "admc_test.h"
|
||||
|
||||
class ProtectDeletionEdit;
|
||||
class QCheckBox;
|
||||
|
||||
class ADMCTestProtectDeletionEdit : public ADMCTest {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void init() override;
|
||||
|
||||
void emit_edited_signal();
|
||||
void apply();
|
||||
|
||||
private:
|
||||
ProtectDeletionEdit *edit;
|
||||
QCheckBox *checkbox;
|
||||
QString dn;
|
||||
};
|
||||
|
||||
#endif /* ADMC_TEST_PROTECT_DELETION_EDIT_H */
|
Loading…
x
Reference in New Issue
Block a user