diff --git a/src/adldap/ad_defines.h b/src/adldap/ad_defines.h index 825b6209e..d68e59bfa 100644 --- a/src/adldap/ad_defines.h +++ b/src/adldap/ad_defines.h @@ -149,6 +149,10 @@ enum SystemFlagsBit { #define ATTRIBUTE_MAX_PWD_AGE "maxPwdAge" #define ATTRIBUTE_MIN_PWD_AGE "minPwdAge" #define ATTRIBUTE_LOCKOUT_DURATION "lockoutDuration" +#define ATTRIBUTE_PWD_PROPERTIES "pwdProperties" +#define ATTRIBUTE_PWD_HISTORY_LENGTH "pwdHistoryLength" +#define ATTRIBUTE_MIN_PWD_LENGTH "minPwdLength" +#define ATTRIBUTE_LOCKOUT_THRESHOLD "lockoutThreshold" #define ATTRIBUTE_IS_CRITICAL_SYSTEM_OBJECT "isCriticalSystemObject" #define ATTRIBUTE_GPC_FILE_SYS_PATH "gPCFileSysPath" #define ATTRIBUTE_GPC_FUNCTIONALITY_VERSION "gpCFunctionalityVersion" @@ -407,6 +411,13 @@ const long long MILLIS_TO_100_NANOS = 10000LL; #define ETYPES_AES128_CTS_HMAC_SHA1_96 0x00000008 #define ETYPES_AES256_CTS_HMAC_SHA1_96 0x00000010 +#define SAM_MASK_DOMAIN_PASSWORD_COMPLEX 1 +#define SAM_MASK_DOMAIN_PASSWORD_NO_ANON_CHANGE 2 +#define SAM_MASK_DOMAIN_PASSWORD_NO_CLEAR_CHANGE 4 +#define SAM_MASK_DOMAIN_LOCKOUT_ADMINS 8 +#define SAM_MASK_DOMAIN_PASSWORD_STORE_CLEARTEXT 16 +#define SAM_MASK_DOMAIN_REFUSE_PASSWORD_CHANGE 32 + enum SearchScope { SearchScope_Object, SearchScope_Children, diff --git a/src/admc/CMakeLists.txt b/src/admc/CMakeLists.txt index b1e0c9197..a644cdbda 100644 --- a/src/admc/CMakeLists.txt +++ b/src/admc/CMakeLists.txt @@ -254,6 +254,7 @@ set(ADMC_SOURCES console_impls/policy_ou_impl.cpp console_impls/found_policy_impl.cpp console_impls/domain_info_impl.cpp + console_impls/password_settings_impl.cpp permission_control_widgets/permissions_widget.cpp permission_control_widgets/creation_deletion_permissions_widget.cpp diff --git a/src/admc/console_impls/item_type.h b/src/admc/console_impls/item_type.h index 71181d43f..17bcfdbb6 100644 --- a/src/admc/console_impls/item_type.h +++ b/src/admc/console_impls/item_type.h @@ -34,6 +34,7 @@ enum ItemType { ItemType_FindPolicy, ItemType_FoundPolicy, ItemType_DomainInfo, + ItemType_PasswordSettings, ItemType_LAST, }; diff --git a/src/admc/console_impls/object_impl/console_object_operations.cpp b/src/admc/console_impls/object_impl/console_object_operations.cpp index 00e463877..f67f308b7 100644 --- a/src/admc/console_impls/object_impl/console_object_operations.cpp +++ b/src/admc/console_impls/object_impl/console_object_operations.cpp @@ -596,6 +596,10 @@ bool ConsoleObjectTreeOperations::console_object_deletion_dialog(ConsoleWidget * } void ConsoleObjectTreeOperations::console_tree_add_password_settings(ConsoleWidget *console, AdInterface &ad) { + QStandardItem *password_settings_root = console->add_scope_item(ItemType_PasswordSettings, console->domain_info_index())[0]; + password_settings_root->setText(QCoreApplication::translate("password_settings_impl", "Password settings")); + password_settings_root->setIcon(g_icon_manager->item_icon(ItemIcon_Password_Settings_Object)); + password_settings_root->setDragEnabled(false); const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_OBJECT_CLASS, CLASS_PSO_CONTAINER); auto search_results = ad.search(g_adconfig->domain_dn(), SearchScope_All, filter, {}); const QString err = QObject::tr("Password settings container is not available"); @@ -604,8 +608,10 @@ void ConsoleObjectTreeOperations::console_tree_add_password_settings(ConsoleWidg return; } + console_object_item_data_load(password_settings_root, search_results.values()[0]); + const int pso_container_sort_idx = 3; - console_tree_add_root_child(console, search_results.values()[0], pso_container_sort_idx); + console->set_item_sort_index(password_settings_root->index(), pso_container_sort_idx); } QString ConsoleObjectTreeOperations::console_object_count_string(ConsoleWidget *console, const QModelIndex &index) { @@ -936,13 +942,6 @@ void ConsoleObjectTreeOperations::console_object_properties(const QList row = console->add_scope_item(ItemType_Object, console->domain_info_index()); - console_object_item_data_load(row[0], obj); - row[0]->setText(obj.get_string(ATTRIBUTE_NAME)); - console->set_item_sort_index(row[0]->index(), sort_idx); -} - void ConsoleObjectTreeOperations::console_tree_add_sites_container(ConsoleWidget *console, AdInterface &ad) { const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_OBJECT_CLASS, CLASS_SITES_CONTAINER); auto search_results = ad.search(g_adconfig->configuration_dn(), SearchScope_All, filter, {}); @@ -953,7 +952,10 @@ void ConsoleObjectTreeOperations::console_tree_add_sites_container(ConsoleWidget } const int sites_container_sort_idx = 4; - console_tree_add_root_child(console, search_results.values()[0], sites_container_sort_idx); + QStandardItem *main_item = console->add_scope_item(ItemType_Object, console->domain_info_index())[0]; + console_object_item_data_load(main_item, search_results.values()[0]); + main_item->setText(search_results.values()[0].get_string(ATTRIBUTE_NAME)); + console->set_item_sort_index(main_item->index(), sites_container_sort_idx); } CreateObjectDialog *ConsoleObjectTreeOperations::create_dialog(const QString &object_class, AdInterface &ad, const QString &parent_dn, ConsoleWidget *parent) { diff --git a/src/admc/console_impls/object_impl/console_object_operations.h b/src/admc/console_impls/object_impl/console_object_operations.h index 66d3c2a8a..37bd87ea9 100644 --- a/src/admc/console_impls/object_impl/console_object_operations.h +++ b/src/admc/console_impls/object_impl/console_object_operations.h @@ -52,8 +52,6 @@ namespace ConsoleObjectTreeOperations { void console_object_properties(const QList &console_list, const QList &index_list, const int dn_role, const QList &class_list); bool console_object_deletion_dialog(ConsoleWidget *console, const QList &index_deleted_list); - // Adds object as direct child to the root tree item - void console_tree_add_root_child(ConsoleWidget *console, AdObject &obj, int sort_idx); // Adds password settings container to the root item childs void console_tree_add_password_settings(ConsoleWidget *console, AdInterface &ad); void console_tree_add_sites_container(ConsoleWidget *console, AdInterface &ad); diff --git a/src/admc/console_impls/object_impl/object_impl.cpp b/src/admc/console_impls/object_impl/object_impl.cpp index 89dcadbea..fa420ecbc 100755 --- a/src/admc/console_impls/object_impl/object_impl.cpp +++ b/src/admc/console_impls/object_impl/object_impl.cpp @@ -481,8 +481,10 @@ void ObjectImpl::selected_as_scope(const QModelIndex &index) else if (object.is_class(CLASS_SUBNET)) { stacked_widget->setCurrentWidget(subnet_results_widget); subnet_results_widget->update(object); - } - else { + } else if (object.is_class(CLASS_COMPUTER)) { + stacked_widget->setCurrentWidget(computer_results_widget); + computer_results_widget->update(ad, object); + } else { stacked_widget->setCurrentWidget(view()); } } @@ -509,6 +511,11 @@ void ObjectImpl::update_results_widget(const QModelIndex &index) const { return; } + if (object.is_class(CLASS_COMPUTER)) { + computer_results_widget->update(ad, object); + return; + } + if (object.is_class(CLASS_CONTACT) || object.is_class(CLASS_USER) || object.is_class(CLASS_INET_ORG_PERSON)) { @@ -950,9 +957,11 @@ void ObjectImpl::setup_widgets() { set_results_view(new ResultsView(console)); group_results_widget = new GeneralGroupTab(); user_results_widget = new GeneralUserTab(); + computer_results_widget = new GeneralComputerTab(); pso_results_widget = new PSOResultsWidget(); subnet_results_widget = new SubnetResultsWidget(); stacked_widget->addWidget(group_results_widget); + stacked_widget->addWidget(computer_results_widget); stacked_widget->addWidget(user_results_widget); stacked_widget->addWidget(pso_results_widget); stacked_widget->addWidget(subnet_results_widget); diff --git a/src/admc/console_impls/object_impl/object_impl.h b/src/admc/console_impls/object_impl/object_impl.h index 647b2cbc7..7e8b233cc 100644 --- a/src/admc/console_impls/object_impl/object_impl.h +++ b/src/admc/console_impls/object_impl/object_impl.h @@ -31,6 +31,7 @@ #include "console_widget/console_impl.h" #include "console_widget/console_widget.h" #include "console_object_operations.h" +#include "tabs/general_computer_tab.h" class QStandardItem; class AdObject; @@ -151,6 +152,7 @@ private slots: QStackedWidget *stacked_widget; GeneralGroupTab *group_results_widget; GeneralUserTab *user_results_widget; + GeneralComputerTab *computer_results_widget; PSOResultsWidget *pso_results_widget; SubnetResultsWidget *subnet_results_widget; diff --git a/src/admc/console_impls/password_settings_impl.cpp b/src/admc/console_impls/password_settings_impl.cpp new file mode 100644 index 000000000..2a7437752 --- /dev/null +++ b/src/admc/console_impls/password_settings_impl.cpp @@ -0,0 +1,130 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020-2025 BaseALT Ltd. + * Copyright (C) 2020-2025 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 . + */ + +#include "console_impls/password_settings_impl.h" + +#include "ad_defines.h" +#include "adldap.h" +#include "console_impls/item_type.h" +#include "console_impls/object_impl/object_impl.h" +#include "console_impls/policy_impl.h" +#include "console_widget/results_view.h" +#include "create_dialogs/create_policy_dialog.h" +#include "fsmo/fsmo_utils.h" +#include "globals.h" +#include "object_impl/console_object_operations.h" +#include "results_widgets/pso_results_widget/pso_results_widget.h" +#include "status.h" +#include "utils.h" + +#include +#include +#include +#include + +PasswordSettingsImpl::PasswordSettingsImpl(ConsoleWidget *console_arg) +: ConsoleImpl(console_arg) { + set_results_widget(new PSOResultsWidget(console_arg)); + + create_pso_action = new QAction(tr("Create password settings object"), this); + + connect( + create_pso_action, &QAction::triggered, + this, [this]() { + const QString parent_dn = get_selected_target_dn(console, ItemType_PasswordSettings, ObjectRole_DN); + ConsoleObjectTreeOperations::console_object_create({console}, CLASS_PSO, parent_dn); + }); +} + +void PasswordSettingsImpl::fetch(const QModelIndex &index) { + AdInterface ad; + if (ad_failed(ad, console)) { + return; + } + + const QString base = g_adconfig->pso_container_dn(); + const SearchScope scope = SearchScope_Children; + const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_OBJECT_CLASS, CLASS_PSO_CONTAINER); + const QList attributes = QList(); + const QHash results = ad.search(base, scope, "", attributes); + + ConsoleObjectTreeOperations::add_objects_to_console(console, results.values(), index); +} + +void PasswordSettingsImpl::refresh(const QList &index_list) { + const QModelIndex index = index_list[0]; + + console->delete_children(index); + fetch(index); +} + +QList PasswordSettingsImpl::get_all_custom_actions() const { + QList out; + + out.append(create_pso_action); + + return out; +} + +QSet PasswordSettingsImpl::get_custom_actions(const QModelIndex &index, const bool single_selection) const { + UNUSED_ARG(index); + UNUSED_ARG(single_selection); + + QSet out; + + out.insert(create_pso_action); + + return out; +} + +QSet PasswordSettingsImpl::get_standard_actions(const QModelIndex &index, const bool single_selection) const { + UNUSED_ARG(index); + UNUSED_ARG(single_selection); + + QSet out; + + out.insert(StandardAction_Refresh); + + return out; +} + +void password_settings_impl_add_objects(ConsoleWidget *console, const QList &object_list, const QModelIndex &parent) { + if (!parent.isValid()) { + return; + } + + const bool parent_was_fetched = console_item_get_was_fetched(parent); + if (!parent_was_fetched) { + return; + } + + for (const AdObject &object : object_list) { + const QList row = console->add_scope_item(ItemType_Object, parent); + ConsoleObjectTreeOperations::console_object_load(row, object); + } +} + +QList PasswordSettingsImpl::column_labels() const { + return ConsoleObjectTreeOperations::object_impl_column_labels(); +} + +QList PasswordSettingsImpl::default_columns() const { + return ConsoleObjectTreeOperations::object_impl_default_columns(); +} diff --git a/src/admc/console_impls/password_settings_impl.h b/src/admc/console_impls/password_settings_impl.h new file mode 100644 index 000000000..ee256136a --- /dev/null +++ b/src/admc/console_impls/password_settings_impl.h @@ -0,0 +1,57 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020-2025 BaseALT Ltd. + * Copyright (C) 2020-2025 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 . + */ + +#ifndef PASSWORD_SETTINGS_IMPL_H +#define PASSWORD_SETTINGS_IMPL_H + +/** + * Impl for a virtual container for "All policies". Displays + * all of the policies present in the domain. + */ + +#include "console_widget/console_impl.h" +#include "console_widget/console_widget.h" + +class AdObject; +class AdInterface; + +class PasswordSettingsImpl final : public ConsoleImpl { + Q_OBJECT + +public: + PasswordSettingsImpl(ConsoleWidget *console_arg); + + void fetch(const QModelIndex &index) override; + void refresh(const QList &index_list) override; + + QList get_all_custom_actions() const override; + QSet get_custom_actions(const QModelIndex &index, const bool single_selection) const override; + QSet get_standard_actions(const QModelIndex &index, const bool single_selection) const override; + + QList column_labels() const override; + QList default_columns() const override; + +private: + QAction *create_pso_action; +}; + +void password_settings_impl_add_objects(ConsoleWidget *console, const QList &object_list, const QModelIndex &parent); + +#endif /* PASSWORD_SETTINGS_IMPL_H */ diff --git a/src/admc/main_window.cpp b/src/admc/main_window.cpp index eab8ff834..fd6a3b4f8 100644 --- a/src/admc/main_window.cpp +++ b/src/admc/main_window.cpp @@ -19,6 +19,7 @@ */ #include "main_window.h" +#include "console_impls/password_settings_impl.h" #include "ui_main_window.h" #include "about_dialog.h" @@ -479,6 +480,9 @@ void MainWindow::init_on_connect(AdInterface &ad) { auto policy_impl = new PolicyImpl(ui->console); ui->console->register_impl(ItemType_Policy, policy_impl); + auto pso_impl = new PasswordSettingsImpl(ui->console); + ui->console->register_impl(ItemType_PasswordSettings, pso_impl); + auto query_item_impl = new QueryItemImpl(ui->console); ui->console->register_impl(ItemType_QueryItem, query_item_impl); diff --git a/src/admc/results_widgets/pso_results_widget/pso_edit_widget.cpp b/src/admc/results_widgets/pso_results_widget/pso_edit_widget.cpp index cc9acb73b..00ce5e1ba 100644 --- a/src/admc/results_widgets/pso_results_widget/pso_edit_widget.cpp +++ b/src/admc/results_widgets/pso_results_widget/pso_edit_widget.cpp @@ -18,6 +18,7 @@ */ #include "pso_edit_widget.h" +#include "ad_defines.h" #include "ui_pso_edit_widget.h" #include "ad_interface.h" #include "ad_object.h" @@ -26,6 +27,7 @@ #include "managers/icon_manager.h" #include "status.h" #include "globals.h" +#include "ad_config.h" #include @@ -189,21 +191,34 @@ bool PSOEditWidget::settings_are_default() { } void PSOEditWidget::update_defaults() { - // TODO: Get defaults from Default Domain Policy. - - ui->min_passwd_len_spinbox->setValue(7); - ui->history_length_spinbox->setValue(24); - ui->logon_attempts_spinbox->setValue(0); - - ui->lockout_duration_spinbox->setValue(30); - ui->reset_lockout_spinbox->setValue(30); - ui->min_age_spinbox->setValue(1); - ui->max_age_spinbox->setValue(42); - - ui->complexity_req_checkbox->setChecked(true); - ui->store_passwd_checkbox->setChecked(false); + AdInterface ad; + if (!ad.is_connected()) { + return; + } + AdObject result = ad.search_object(g_adconfig->domain_dn(), {ATTRIBUTE_PWD_PROPERTIES, + ATTRIBUTE_PWD_HISTORY_LENGTH, + ATTRIBUTE_MIN_PWD_LENGTH, + ATTRIBUTE_MIN_PWD_AGE, + ATTRIBUTE_MAX_PWD_AGE, + ATTRIBUTE_LOCKOUT_DURATION, + ATTRIBUTE_LOCKOUT_THRESHOLD, + ATTRIBUTE_LOCKOUT_OBSERVATION_WINDOW}); + + ui->min_passwd_len_spinbox->setValue(result.get_int(ATTRIBUTE_MIN_PWD_LENGTH)); + ui->history_length_spinbox->setValue(result.get_int(ATTRIBUTE_PWD_HISTORY_LENGTH)); + ui->logon_attempts_spinbox->setValue(result.get_int(ATTRIBUTE_LOCKOUT_THRESHOLD)); + + ui->lockout_duration_spinbox->setValue(spinbox_timespan_units(result, ATTRIBUTE_LOCKOUT_DURATION)); + ui->reset_lockout_spinbox->setValue(spinbox_timespan_units(result, ATTRIBUTE_LOCKOUT_OBSERVATION_WINDOW)); + ui->min_age_spinbox->setValue(spinbox_timespan_units(result, ATTRIBUTE_MIN_PWD_AGE)); + ui->max_age_spinbox->setValue(spinbox_timespan_units(result, ATTRIBUTE_MAX_PWD_AGE)); + + ui->complexity_req_checkbox->setChecked(result.get_int(ATTRIBUTE_PWD_PROPERTIES) & SAM_MASK_DOMAIN_PASSWORD_COMPLEX); + ui->store_passwd_checkbox->setChecked(result.get_int(ATTRIBUTE_PWD_PROPERTIES) & SAM_MASK_DOMAIN_PASSWORD_STORE_CLEARTEXT); ui->applied_list_widget->clear(); + + ui->name_edit->setReadOnly(true); } void PSOEditWidget::on_add() { diff --git a/src/admc/results_widgets/pso_results_widget/pso_results_widget.cpp b/src/admc/results_widgets/pso_results_widget/pso_results_widget.cpp index e948d823c..a529ee9a1 100644 --- a/src/admc/results_widgets/pso_results_widget/pso_results_widget.cpp +++ b/src/admc/results_widgets/pso_results_widget/pso_results_widget.cpp @@ -25,13 +25,16 @@ #include "../ui_results_widget_base.h" #include -// #include - PSOResultsWidget::PSOResultsWidget(QWidget *parent) : ResultsWidgetBase(parent), pso_edit_widget(new PSOEditWidget(this)) { ui->verticalLayout->addWidget(pso_edit_widget); + + ui->edit_button->setDisabled(true); + ui->cancel_button->setDisabled(true); + ui->apply_button->setDisabled(true); + pso_edit_widget->set_read_only(true); } void PSOResultsWidget::update(const QModelIndex &index) { diff --git a/src/admc/tabs/general_computer_tab.cpp b/src/admc/tabs/general_computer_tab.cpp index b62a5dd8c..53d73cb1e 100644 --- a/src/admc/tabs/general_computer_tab.cpp +++ b/src/admc/tabs/general_computer_tab.cpp @@ -31,6 +31,33 @@ GeneralComputerTab::GeneralComputerTab(QList *edit_list, QWidge ui = new Ui::GeneralComputerTab(); ui->setupUi(this); + edit_list->append(create_edits()); +} + +GeneralComputerTab::GeneralComputerTab(QWidget *parent) +: QWidget(parent) { + ui = new Ui::GeneralComputerTab(); + ui->setupUi(this); + + m_edit_list = create_edits(); + + ui->name_label->setVisible(false); + ui->description_edit->setReadOnly(true); + ui->dns_host_name_edit->setReadOnly(true); + ui->sam_name_domain_edit->setReadOnly(true); + ui->sam_name_edit->setReadOnly(true); + ui->location_edit->setReadOnly(true); +} + +void GeneralComputerTab::update(AdInterface &ad, const AdObject &object) { + AttributeEdit::load(m_edit_list, ad, object); +} + +GeneralComputerTab::~GeneralComputerTab() { + delete ui; +} + +QList GeneralComputerTab::create_edits() { auto name_edit = new GeneralNameEdit(ui->name_label, this); auto sam_name_edit = new ComputerSamNameEdit(ui->sam_name_edit, ui->sam_name_domain_edit, this); auto dns_edit = new StringEdit(ui->dns_host_name_edit, ATTRIBUTE_DNS_HOST_NAME, this); @@ -40,15 +67,13 @@ GeneralComputerTab::GeneralComputerTab(QList *edit_list, QWidge sam_name_edit->set_enabled(false); dns_edit->set_enabled(false); - edit_list->append({ + QList edit_list = { name_edit, sam_name_edit, dns_edit, description_edit, location_edit, - }); -} + }; -GeneralComputerTab::~GeneralComputerTab() { - delete ui; + return edit_list; } diff --git a/src/admc/tabs/general_computer_tab.h b/src/admc/tabs/general_computer_tab.h index 05c6eb8cf..58f4e9f9a 100644 --- a/src/admc/tabs/general_computer_tab.h +++ b/src/admc/tabs/general_computer_tab.h @@ -23,6 +23,8 @@ #include +#include "ad_interface.h" + class AttributeEdit; class AdObject; @@ -37,7 +39,15 @@ class GeneralComputerTab final : public QWidget { Ui::GeneralComputerTab *ui; GeneralComputerTab(QList *edit_list, QWidget *parent); + GeneralComputerTab(QWidget *parent = nullptr); ~GeneralComputerTab(); + + void update(AdInterface &ad, const AdObject &object); + +private: + QList m_edit_list; + + QList create_edits(); }; #endif /* GENERAL_COMPUTER_TAB_H */