mirror of
https://github.com/altlinux/admc.git
synced 2025-01-22 18:03:57 +03:00
Merge branch 'release/0-9-0-test' into sisyphus
This commit is contained in:
commit
9866a2fed7
@ -1,7 +1,7 @@
|
||||
%define _unpackaged_files_terminate_build 1
|
||||
|
||||
Name: admc
|
||||
Version: 0.8.3
|
||||
Version: 0.9.0
|
||||
Release: alt1
|
||||
|
||||
Summary: AD editor
|
||||
@ -65,6 +65,7 @@ Tests for ADMC
|
||||
%_libdir/libadldap.so
|
||||
%_man1dir/admc*
|
||||
%_datadir/applications/admc.desktop
|
||||
%_iconsdir/hicolor/scalable/apps/admc.svg
|
||||
|
||||
%files test
|
||||
%_libdir/libadmctest.so
|
||||
@ -75,9 +76,9 @@ Tests for ADMC
|
||||
%_bindir/admc_test_country_edit
|
||||
%_bindir/admc_test_gplink
|
||||
%_bindir/admc_test_ad_interface
|
||||
%_bindir/admc_test_ad_security
|
||||
%_bindir/admc_test_select_base_widget
|
||||
%_bindir/admc_test_filter_widget
|
||||
%_bindir/admc_test_security_tab
|
||||
%_bindir/admc_test_attributes_tab
|
||||
%_bindir/admc_test_member_of_tab
|
||||
%_bindir/admc_test_members_tab
|
||||
@ -105,6 +106,8 @@ Tests for ADMC
|
||||
%_bindir/admc_test_find_object_dialog
|
||||
%_bindir/admc_test_rename_object_dialog
|
||||
%_bindir/admc_test_create_object_dialog
|
||||
%_bindir/admc_test_select_classes_widget
|
||||
%_bindir/admc_test_sam_name_edit
|
||||
|
||||
%changelog
|
||||
* Thu Mar 31 2022 Dmitry Degtyarev <kevl@altlinux.org> 0.8.3-alt1
|
||||
@ -167,4 +170,3 @@ Tests for ADMC
|
||||
|
||||
* Thu May 21 2020 Igor Chudov <nir@altlinux.org> 0.1.0-alt1
|
||||
- Initial build
|
||||
|
||||
|
134
CHANGELOG.txt
134
CHANGELOG.txt
@ -1,6 +1,137 @@
|
||||
admc
|
||||
CHANGELOG
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
VERSION 0.9.0
|
||||
-----------------------------------------------------------------------
|
||||
- Account Tab: Improved editor for "Logon Hours".
|
||||
- Account Tab: Fixed "Logon Computers" editor
|
||||
incorrectly adding empty entry when being opened.
|
||||
- Account Tab: Fixed incorrect flag value for
|
||||
"Reversible encryption" account option.
|
||||
- Attributes Tab: Added special display format for some
|
||||
bitfield attributes, so that both the value and names
|
||||
of bitfields are displayed. Includes
|
||||
"userAccountControl", "sAMAccountType" and
|
||||
"primaryGroupId".
|
||||
- Account Tab: Added missing "DES key" account option.
|
||||
- Account Tab: Removed "Trusted for delegation" option
|
||||
because it should be in "Delegation" tab only.
|
||||
- Account Tab: Fixed some options using incorrect flags.
|
||||
- Action menu: Added creation of more object types:
|
||||
"Contact", "inetOrgPerson" and "Shared Folder".
|
||||
- Action menu: Fixed "New" sub-menu in action menu so
|
||||
that it contains only those object types that can be
|
||||
children of target object. (#343)
|
||||
- Action menu: Removed "Rename" action from computer
|
||||
objects because computer objects must be renamed from
|
||||
the machine itself in system configuration.
|
||||
- Console: Added object display limit option. Applies
|
||||
to main window and find dialog. (#319)
|
||||
- Address Tab: Changed order of country list so that
|
||||
the country of current locale is always first, for
|
||||
ease of use.
|
||||
- Console: Implemented opening action menu by right
|
||||
clicking on empty space in results pane. In this
|
||||
case, currently selected scope item is treated as
|
||||
target object for the menu. (#334)
|
||||
- Console: Fixed action menu being empty on startup
|
||||
until user selected another console item. (#340)
|
||||
- Console: Fixed being able to move an object onto it's
|
||||
current parent via action menu or drag and drop. This
|
||||
caused visual glitches. (#336, #338)
|
||||
- Console: Improved default sort setting for results
|
||||
view (for all view types - details, icons, list).
|
||||
- Create dialog: Fix incorrect field labels.
|
||||
- Logon Hours: Improved usability.
|
||||
- Logon Hours: Added legend that explains how dialog
|
||||
works.
|
||||
- Security Tab: Fixed handling of inherited rights.
|
||||
Inherited rights will now correctly display as grayed
|
||||
out checkboxes and will not be editable. (#327)
|
||||
- Security Tab: Fixed all objects having the same kinds
|
||||
of rights. Security tab will now correctly show
|
||||
rights that are appropriate for the object type.
|
||||
(#328)
|
||||
- Security Tab: Added verification of ACL order. When
|
||||
switching to security tab, order will be verified and
|
||||
if it's incorrect, a warning dialog will open
|
||||
offering to fix it. (#339)
|
||||
- Toolbar: Added keyboard shortcuts to all actions.
|
||||
- Propeties: Added LAPS(Local Administration Password
|
||||
Solution) tab for computer objects. This tab is
|
||||
accessible only if LAPS is enabled in the domain. (#312)
|
||||
- Properties: Improved how properties dialog responds
|
||||
to failing to load a user due to connection error or
|
||||
absence of object.
|
||||
- Properties: Disabled "Profile" tab, not usable
|
||||
because not implemented in backend.
|
||||
- Properties: Disabled "Logon Computers" feature, not
|
||||
usable because not implemented in backend.
|
||||
- Policies: Fixed permission check incorrectly
|
||||
complaining about policies made by RSAT. (#333)
|
||||
- Policies: Implemented "Edit" action for policies.
|
||||
Installation of "gpui" package is required for
|
||||
correct functioning.
|
||||
- Queries: Removed "Cut" and "Copy" actions from Query
|
||||
root, because they don't apply to it. (#350)
|
||||
- Queries: Remove ability to recursively cut and paste
|
||||
query folders into themselves.
|
||||
- Queries: Fixed program freezing when copying and
|
||||
pasting a query folder into itself.
|
||||
- Queries: Fixed default name for query folders when
|
||||
making them.
|
||||
- Queries: Fixed "Copy" and "Paste" of query folder
|
||||
into same parent.
|
||||
- Queries: Remove ability to drag and drop query
|
||||
folders onto themselves.
|
||||
- Find dialog: Added class filtering by all classes,
|
||||
implemented as a separate checkbox. This filtering
|
||||
will accept all classes, not just the ones in the
|
||||
list. (#341)
|
||||
- Managed by tab: Fixed tab not applying.
|
||||
- Managed by tab: Fixed some fields being editable when
|
||||
they shouldn't be.
|
||||
- Menubar: Fixed checkboxes for view types (Icons,
|
||||
List, Details) not being exclusive. (#329)
|
||||
- Menubar: Fixed search logging, now correctly works
|
||||
when browsing the object tree, in find dialog and
|
||||
other UI elements.
|
||||
- Menubar: Added keyboard shortcuts to all actions,
|
||||
except for the "Action" menu.
|
||||
- Menubar: Added keyboard navigation for all sub-menu's
|
||||
except "Action" menu.
|
||||
- Misc: Fixed class filters not working correctly until
|
||||
class selection dialog was opened. Occured in find
|
||||
dialog, query creation/editing and others. (#322)
|
||||
- Misc: Added "Operations Masters" dialog for viewing
|
||||
and editing FSMO roles. Opened from
|
||||
Menubar->File->Operations Masters. (#313)
|
||||
- Misc: Changed AD error dialogs to be modal.
|
||||
- Misc: Removed "Reset" button from rename dialogs.
|
||||
- Misc: Fixed group icons not displaying on some DE's. (#330)
|
||||
- Misc: Added app icon which is displayed next to in
|
||||
app lists and on the title bar.
|
||||
- Misc: Empty password input is now not allowed.
|
||||
- Misc: Fixed incorrect value for length limit of the
|
||||
field "Logon name (pre-Windows 2000)".
|
||||
- Misc: Improved handling of illegal characters in
|
||||
dialogs that create objects and those that rename
|
||||
objects.
|
||||
- Misc: Added automatic trimming of leading and
|
||||
trailing spaces in most fields for inputting string
|
||||
values.
|
||||
- Misc: Fixed creation of computer objects so that
|
||||
attributes are set correctly.
|
||||
- Misc: Added "Show password" checkbox to all password
|
||||
fields, which toggles password visibility when
|
||||
entering.
|
||||
- Misc: Fixed crash that sometimes happened when
|
||||
loading objects from server.
|
||||
- Misc: Fixed incorrect "Street" field for OU objects.
|
||||
Was using the wrong attribute.
|
||||
- Misc: Improved translation.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
VERSION 0.8.3
|
||||
-----------------------------------------------------------------------
|
||||
@ -107,11 +238,14 @@ CHANGELOG
|
||||
connection options.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
<<<<<<< HEAD
|
||||
VERSION 0.7.1
|
||||
-----------------------------------------------------------------------
|
||||
- Misc: Fix stack smashing on 32 bit systems. (#294)
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
=======
|
||||
>>>>>>> release/0-9-0-test
|
||||
VERSION 0.7.0
|
||||
-----------------------------------------------------------------------
|
||||
- Manual: Fixed manual not opening when app is installed
|
||||
|
@ -54,7 +54,7 @@ add_subdirectory(src)
|
||||
if(NOT ADMC_BUILD_DEB)
|
||||
add_subdirectory(tests)
|
||||
endif(NOT ADMC_BUILD_DEB)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(share)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG.txt
|
||||
${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/doc/admc.1
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/share/admc.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1/
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
|
||||
|
@ -57,7 +57,7 @@ Comment[tr]=Active Directory yönetimi için bir araç
|
||||
Comment[uk]=Інструмент для адміністрування Active Directory
|
||||
Comment[zh_CN]=用于 Active Directory 管理的工具
|
||||
Comment[zh_TW]=用於 Active Directory 管理的工具
|
||||
Icon=
|
||||
Icon=admc
|
||||
Exec=admc
|
||||
Terminal=false
|
||||
Type=Application
|
@ -12,6 +12,13 @@ pkg_check_modules(Smbclient REQUIRED IMPORTED_TARGET smbclient)
|
||||
pkg_check_modules(Krb5 REQUIRED IMPORTED_TARGET krb5)
|
||||
pkg_check_modules(Glib REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_check_modules(Uuid REQUIRED IMPORTED_TARGET uuid)
|
||||
pkg_check_modules(Sasl REQUIRED IMPORTED_TARGET libsasl2)
|
||||
|
||||
pkg_check_modules(Ndr REQUIRED IMPORTED_TARGET ndr)
|
||||
if(Ndr_VERSION VERSION_GREATER "1.0.1")
|
||||
set(NDR_VERSION_GREATER_THAN_1_0_1 ON)
|
||||
endif()
|
||||
configure_file("adldap_config.h.in" "adldap_config.h")
|
||||
|
||||
pkg_check_modules(Ndr REQUIRED IMPORTED_TARGET ndr)
|
||||
if(Ndr_VERSION VERSION_GREATER "1.0.1")
|
||||
@ -52,10 +59,10 @@ target_link_libraries(adldap
|
||||
Qt5::Core
|
||||
PkgConfig::Uuid
|
||||
PkgConfig::Smbclient
|
||||
PkgConfig::Smbclient
|
||||
PkgConfig::Krb5
|
||||
Ldap::Ldap
|
||||
PkgConfig::NdrStandard
|
||||
PkgConfig::Sasl
|
||||
resolv
|
||||
)
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "ad_interface.h"
|
||||
#include "ad_object.h"
|
||||
#include "ad_utils.h"
|
||||
#include "ad_security.h"
|
||||
|
||||
#include "samba/ndr_security.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
@ -51,6 +54,7 @@
|
||||
#define ATTRIBUTE_SYSTEM_FLAGS "systemFlags"
|
||||
#define ATTRIBUTE_LINK_ID "linkID"
|
||||
#define ATTRIBUTE_SYSTEM_AUXILIARY_CLASS "systemAuxiliaryClass"
|
||||
#define ATTRIBUTE_SUB_CLASS_OF "subClassOf"
|
||||
|
||||
#define CLASS_ATTRIBUTE_SCHEMA "attributeSchema"
|
||||
#define CLASS_CLASS_SCHEMA "classSchema"
|
||||
@ -71,7 +75,6 @@ AdConfig::~AdConfig() {
|
||||
|
||||
void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
d->domain = get_default_domain_from_krb5();
|
||||
d->domain_head = domain_to_domain_dn(d->domain);
|
||||
|
||||
d->filter_containers.clear();
|
||||
d->columns.clear();
|
||||
@ -82,6 +85,12 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
d->attribute_schemas.clear();
|
||||
d->class_schemas.clear();
|
||||
|
||||
const AdObject rootDSE_object = ad.search_object(ROOT_DSE);
|
||||
d->domain_dn = rootDSE_object.get_string(ATTRIBUTE_ROOT_DOMAIN_NAMING_CONTEXT);
|
||||
d->schema_dn = rootDSE_object.get_string(ATTRIBUTE_SCHEMA_NAMING_CONTEXT);
|
||||
d->configuration_dn = rootDSE_object.get_string(ATTRIBUTE_CONFIGURATION_NAMING_CONTEXT);
|
||||
d->supported_control_list = rootDSE_object.get_strings(ATTRIBUTE_SUPPORTED_CONTROL);
|
||||
|
||||
const QString locale_dir = [this, locale]() {
|
||||
const QString locale_code = [locale]() {
|
||||
if (locale.language() == QLocale::Russian) {
|
||||
@ -108,6 +117,7 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
ATTRIBUTE_RANGE_UPPER,
|
||||
ATTRIBUTE_LINK_ID,
|
||||
ATTRIBUTE_SYSTEM_FLAGS,
|
||||
ATTRIBUTE_SCHEMA_ID_GUID,
|
||||
};
|
||||
|
||||
const QHash<QString, AdObject> results = ad.search(schema_dn(), SearchScope_Children, filter, attributes);
|
||||
@ -115,6 +125,9 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
for (const AdObject &object : results.values()) {
|
||||
const QString attribute = object.get_string(ATTRIBUTE_LDAP_DISPLAY_NAME);
|
||||
d->attribute_schemas[attribute] = object;
|
||||
|
||||
const QByteArray guid = object.get_value(ATTRIBUTE_SCHEMA_ID_GUID);
|
||||
d->guid_to_attribute_map[guid] = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +145,8 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
ATTRIBUTE_SYSTEM_MUST_CONTAIN,
|
||||
ATTRIBUTE_AUXILIARY_CLASS,
|
||||
ATTRIBUTE_SYSTEM_AUXILIARY_CLASS,
|
||||
ATTRIBUTE_SCHEMA_ID_GUID,
|
||||
ATTRIBUTE_SUB_CLASS_OF,
|
||||
};
|
||||
|
||||
const QHash<QString, AdObject> results = ad.search(schema_dn(), SearchScope_Children, filter, attributes);
|
||||
@ -139,6 +154,12 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
for (const AdObject &object : results.values()) {
|
||||
const QString object_class = object.get_string(ATTRIBUTE_LDAP_DISPLAY_NAME);
|
||||
d->class_schemas[object_class] = object;
|
||||
|
||||
const QByteArray guid = object.get_value(ATTRIBUTE_SCHEMA_ID_GUID);
|
||||
d->guid_to_class_map[guid] = object_class;
|
||||
|
||||
const QString sub_class_of = object.get_string(ATTRIBUTE_SUB_CLASS_OF);
|
||||
d->sub_class_of_map[object_class] = sub_class_of;
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,14 +298,16 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
return out;
|
||||
}();
|
||||
|
||||
d->right_to_guid_map = [&]() {
|
||||
QHash<QString, QString> out;
|
||||
|
||||
// Extended rights
|
||||
{
|
||||
const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_OBJECT_CLASS, CLASS_CONTROL_ACCESS_RIGHT);
|
||||
|
||||
const QList<QString> attributes = {
|
||||
ATTRIBUTE_CN,
|
||||
ATTRIBUTE_DISPLAY_NAME,
|
||||
ATTRIBUTE_RIGHTS_GUID,
|
||||
ATTRIBUTE_APPLIES_TO,
|
||||
ATTRIBUTE_VALID_ACCESSES,
|
||||
};
|
||||
|
||||
const QString search_base = extended_rights_dn();
|
||||
@ -293,39 +316,65 @@ void AdConfig::load(AdInterface &ad, const QLocale &locale) {
|
||||
|
||||
for (const AdObject &object : search_results.values()) {
|
||||
const QString cn = object.get_string(ATTRIBUTE_CN);
|
||||
const QString guid = object.get_string(ATTRIBUTE_RIGHTS_GUID);
|
||||
const QString guid_string = object.get_string(ATTRIBUTE_RIGHTS_GUID);
|
||||
const QByteArray guid = guid_string_to_bytes(guid_string);
|
||||
const QByteArray display_name = object.get_value(ATTRIBUTE_DISPLAY_NAME);
|
||||
const QList<QString> applies_to = [this, object]() {
|
||||
QList<QString> out;
|
||||
|
||||
const QList<QString> class_guid_string_list = object.get_strings(ATTRIBUTE_APPLIES_TO);
|
||||
for (const QString &class_guid_string : class_guid_string_list) {
|
||||
const QByteArray class_guid = guid_string_to_bytes(class_guid_string);
|
||||
const QString object_class = guid_to_class(class_guid);
|
||||
|
||||
out[cn] = guid;
|
||||
out.append(object_class);
|
||||
}
|
||||
|
||||
return out;
|
||||
}();
|
||||
const int valid_accesses = object.get_int(ATTRIBUTE_VALID_ACCESSES);
|
||||
|
||||
d->right_to_guid_map[cn] = guid;
|
||||
d->right_guid_to_cn_map[guid] = cn;
|
||||
d->rights_guid_to_name_map[guid] = display_name;
|
||||
d->rights_name_to_guid_map[cn] = guid;
|
||||
d->rights_applies_to_map[guid] = applies_to;
|
||||
d->extended_rights_list.append(cn);
|
||||
d->rights_valid_accesses_map[cn] = valid_accesses;
|
||||
}
|
||||
|
||||
return out;
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
QString AdConfig::domain() const {
|
||||
return d->domain;
|
||||
}
|
||||
|
||||
QString AdConfig::domain_head() const {
|
||||
return d->domain_head;
|
||||
QString AdConfig::domain_dn() const {
|
||||
return d->domain_dn;
|
||||
}
|
||||
|
||||
QString AdConfig::configuration_dn() const {
|
||||
return QString("CN=Configuration,%1").arg(domain_head());
|
||||
return d->configuration_dn;
|
||||
}
|
||||
|
||||
QString AdConfig::schema_dn() const {
|
||||
return QString("CN=Schema,%1").arg(configuration_dn());
|
||||
return d->schema_dn;
|
||||
}
|
||||
|
||||
QString AdConfig::partitions_dn() const {
|
||||
return QString("CN=Partitions,CN=Configuration,%1").arg(domain_head());
|
||||
return QString("CN=Partitions,%1").arg(configuration_dn());
|
||||
}
|
||||
|
||||
QString AdConfig::extended_rights_dn() const {
|
||||
return QString("CN=Extended-Rights,%1").arg(configuration_dn());
|
||||
}
|
||||
|
||||
bool AdConfig::control_is_supported(const QString &control_oid) const {
|
||||
const bool supported = d->supported_control_list.contains(control_oid);
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
QString AdConfig::get_attribute_display_name(const Attribute &attribute, const ObjectClass &objectClass) const {
|
||||
if (d->attribute_display_names.contains(objectClass) && d->attribute_display_names[objectClass].contains(attribute)) {
|
||||
const QString display_name = d->attribute_display_names[objectClass][attribute];
|
||||
@ -393,6 +442,34 @@ QList<QString> AdConfig::get_possible_superiors(const QList<ObjectClass> &object
|
||||
return out;
|
||||
}
|
||||
|
||||
ObjectClass AdConfig::get_parent_class(const ObjectClass &object_class) const {
|
||||
const ObjectClass out = d->sub_class_of_map.value(object_class);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QList<ObjectClass> AdConfig::get_inherit_chain(const ObjectClass &object_class) const {
|
||||
QList<QString> out;
|
||||
|
||||
ObjectClass current_class = object_class;
|
||||
|
||||
while (true) {
|
||||
out.append(current_class);
|
||||
|
||||
const QString parent_class = get_parent_class(current_class);
|
||||
|
||||
const bool chain_ended = (parent_class == current_class);
|
||||
|
||||
if (chain_ended) {
|
||||
break;
|
||||
} else {
|
||||
current_class = parent_class;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QList<QString> AdConfig::get_optional_attributes(const QList<QString> &object_classes) const {
|
||||
const QList<QString> all_classes = d->add_auxiliary_classes(object_classes);
|
||||
|
||||
@ -538,11 +615,151 @@ bool AdConfig::get_attribute_is_backlink(const QString &attribute) const {
|
||||
|
||||
bool AdConfig::get_attribute_is_constructed(const QString &attribute) const {
|
||||
const int system_flags = d->attribute_schemas[attribute].get_int(ATTRIBUTE_SYSTEM_FLAGS);
|
||||
return bit_is_set(system_flags, FLAG_ATTR_IS_CONSTRUCTED);
|
||||
return bitmask_is_set(system_flags, FLAG_ATTR_IS_CONSTRUCTED);
|
||||
}
|
||||
|
||||
QString AdConfig::get_right_guid(const QString &right_cn) const {
|
||||
const QString out = d->right_to_guid_map.value(right_cn, QString());
|
||||
QByteArray AdConfig::get_right_guid(const QString &right_cn) const {
|
||||
const QByteArray out = d->right_to_guid_map.value(right_cn, QByteArray());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: technically, Active Directory provides
|
||||
// translations for right names but it's not
|
||||
// accessible, so have to translate these ourselves. On
|
||||
// Windows, you would use the localizationDisplayId
|
||||
// retrieved from schema to get translation from
|
||||
// dssec.dll. And we don't have dssec.dll, nor do we
|
||||
// have the ability to interact with it!
|
||||
QString AdConfig::get_right_name(const QByteArray &right_guid, const QLocale::Language language) const {
|
||||
const QHash<QString, QString> cn_to_map_russian = {
|
||||
{"DS-Replication-Get-Changes", QCoreApplication::translate("AdConfig", "DS Replication Get Changes")},
|
||||
{"DS-Replication-Get-Changes-All", QCoreApplication::translate("AdConfig", "DS Replication Get Changes All")},
|
||||
{"Email-Information", QCoreApplication::translate("AdConfig", "Phone and Mail Options")},
|
||||
{"DS-Bypass-Quota", QCoreApplication::translate("AdConfig", "Bypass the quota restrictions during creation.")},
|
||||
{"Receive-As", QCoreApplication::translate("AdConfig", "Receive As")},
|
||||
{"Unexpire-Password", QCoreApplication::translate("AdConfig", "Unexpire Password")},
|
||||
{"Do-Garbage-Collection", QCoreApplication::translate("AdConfig", "Do Garbage Collection")},
|
||||
{"Allowed-To-Authenticate", QCoreApplication::translate("AdConfig", "Allowed To Authenticate")},
|
||||
{"Change-PDC", QCoreApplication::translate("AdConfig", "Change PDC")},
|
||||
{"Reanimate-Tombstones", QCoreApplication::translate("AdConfig", "Reanimate Tombstones")},
|
||||
{"msmq-Peek-Dead-Letter", QCoreApplication::translate("AdConfig", "msmq Peek Dead Letter")},
|
||||
{"Certificate-AutoEnrollment", QCoreApplication::translate("AdConfig", "AutoEnrollment")},
|
||||
{"DS-Install-Replica", QCoreApplication::translate("AdConfig", "DS Install Replica")},
|
||||
{"Domain-Password", QCoreApplication::translate("AdConfig", "Domain Password & Lockout Policies")},
|
||||
{"Generate-RSoP-Logging", QCoreApplication::translate("AdConfig", "Generate RSoP Logging")},
|
||||
{"Run-Protect-Admin-Groups-Task", QCoreApplication::translate("AdConfig", "Run Protect Admin Groups Task")},
|
||||
{"Self-Membership", QCoreApplication::translate("AdConfig", "Self Membership")},
|
||||
{"DS-Clone-Domain-Controller", QCoreApplication::translate("AdConfig", "Allow a DC to create a clone of itself")},
|
||||
{"Domain-Other-Parameters", QCoreApplication::translate("AdConfig", "Other Domain Parameters (for use by SAM)")},
|
||||
{"SAM-Enumerate-Entire-Domain", QCoreApplication::translate("AdConfig", "SAM Enumerate Entire Domain")},
|
||||
{"DS-Write-Partition-Secrets", QCoreApplication::translate("AdConfig", "Write secret attributes of objects in a Partition")},
|
||||
{"Send-As", QCoreApplication::translate("AdConfig", "Send As")},
|
||||
{"DS-Replication-Manage-Topology", QCoreApplication::translate("AdConfig", "DS Replication Manage Topology")},
|
||||
{"DS-Set-Owner", QCoreApplication::translate("AdConfig", "Set Owner of an object during creation.")},
|
||||
{"Generate-RSoP-Planning", QCoreApplication::translate("AdConfig", "Generate RSoP Planning")},
|
||||
{"Certificate-Enrollment", QCoreApplication::translate("AdConfig", "Certificate Enrollment")},
|
||||
{"Web-Information", QCoreApplication::translate("AdConfig", "Web Information")},
|
||||
{"Create-Inbound-Forest-Trust", QCoreApplication::translate("AdConfig", "Create Inbound Forest Trust")},
|
||||
{"Migrate-SID-History", QCoreApplication::translate("AdConfig", "Migrate SID History")},
|
||||
{"Update-Password-Not-Required-Bit", QCoreApplication::translate("AdConfig", "Update Password Not Required Bit")},
|
||||
{"MS-TS-GatewayAccess", QCoreApplication::translate("AdConfig", "MS-TS-GatewayAccess")},
|
||||
{"Validated-MS-DS-Additional-DNS-Host-Name", QCoreApplication::translate("AdConfig", "Validated write to MS DS Additional DNS Host Name")},
|
||||
{"msmq-Receive", QCoreApplication::translate("AdConfig", "msmq Receive")},
|
||||
{"Validated-DNS-Host-Name", QCoreApplication::translate("AdConfig", "Validated DNS Host Name")},
|
||||
{"Send-To", QCoreApplication::translate("AdConfig", "Send To")},
|
||||
{"DS-Replication-Get-Changes-In-Filtered-Set", QCoreApplication::translate("AdConfig", "DS Replication Get Changes In Filtered Set")},
|
||||
{"Read-Only-Replication-Secret-Synchronization", QCoreApplication::translate("AdConfig", "Read Only Replication Secret Synchronization")},
|
||||
{"Validated-MS-DS-Behavior-Version", QCoreApplication::translate("AdConfig", "Validated write to MS DS behavior version")},
|
||||
{"msmq-Open-Connector", QCoreApplication::translate("AdConfig", "msmq Open Connector")},
|
||||
{"Terminal-Server-License-Server", QCoreApplication::translate("AdConfig", "Terminal Server License Server")},
|
||||
{"Change-Schema-Master", QCoreApplication::translate("AdConfig", "Change Schema Master")},
|
||||
{"Recalculate-Hierarchy", QCoreApplication::translate("AdConfig", "Recalculate Hierarchy")},
|
||||
{"DS-Check-Stale-Phantoms", QCoreApplication::translate("AdConfig", "DS Check Stale Phantoms")},
|
||||
{"msmq-Receive-computer-Journal", QCoreApplication::translate("AdConfig", "msmq Receive computer Journal")},
|
||||
{"User-Force-Change-Password", QCoreApplication::translate("AdConfig", "User Force Change Password")},
|
||||
{"Domain-Administer-Server", QCoreApplication::translate("AdConfig", "Domain Administer Server")},
|
||||
{"DS-Replication-Synchronize", QCoreApplication::translate("AdConfig", "DS Replication Synchronize")},
|
||||
{"Personal-Information", QCoreApplication::translate("AdConfig", "Personal Information")},
|
||||
{"msmq-Peek", QCoreApplication::translate("AdConfig", "msmq Peek")},
|
||||
{"General-Information", QCoreApplication::translate("AdConfig", "General Information")},
|
||||
{"Membership", QCoreApplication::translate("AdConfig", "Group Membership")},
|
||||
{"Add-GUID", QCoreApplication::translate("AdConfig", "Add GUID")},
|
||||
{"RAS-Information", QCoreApplication::translate("AdConfig", "Remote Access Information")},
|
||||
{"DS-Execute-Intentions-Script", QCoreApplication::translate("AdConfig", "DS Execute Intentions Script")},
|
||||
{"Allocate-Rids", QCoreApplication::translate("AdConfig", "Allocate Rids")},
|
||||
{"Update-Schema-Cache", QCoreApplication::translate("AdConfig", "Update Schema Cache")},
|
||||
{"Apply-Group-Policy", QCoreApplication::translate("AdConfig", "Apply Group Policy")},
|
||||
{"User-Account-Restrictions", QCoreApplication::translate("AdConfig", "Account Restrictions")},
|
||||
{"Validated-SPN", QCoreApplication::translate("AdConfig", "Validated SPN")},
|
||||
{"DS-Read-Partition-Secrets", QCoreApplication::translate("AdConfig", "Read secret attributes of objects in a Partition")},
|
||||
{"User-Logon", QCoreApplication::translate("AdConfig", "Logon Information")},
|
||||
{"DS-Query-Self-Quota", QCoreApplication::translate("AdConfig", "DS Query Self Quota")},
|
||||
{"Change-Infrastructure-Master", QCoreApplication::translate("AdConfig", "Change Infrastructure Master")},
|
||||
{"Open-Address-Book", QCoreApplication::translate("AdConfig", "Open Address Book")},
|
||||
{"User-Change-Password", QCoreApplication::translate("AdConfig", "User Change Password")},
|
||||
{"msmq-Peek-computer-Journal", QCoreApplication::translate("AdConfig", "msmq Peek computer Journal")},
|
||||
{"Change-Domain-Master", QCoreApplication::translate("AdConfig", "Change Domain Master")},
|
||||
{"msmq-Send", QCoreApplication::translate("AdConfig", "msmq Send")},
|
||||
{"Change-Rid-Master", QCoreApplication::translate("AdConfig", "Change Rid Master")},
|
||||
{"Recalculate-Security-Inheritance", QCoreApplication::translate("AdConfig", "Recalculate Security Inheritance")},
|
||||
{"Refresh-Group-Cache", QCoreApplication::translate("AdConfig", "Refresh Group Cache")},
|
||||
{"Manage-Optional-Features", QCoreApplication::translate("AdConfig", "Manage Optional Features")},
|
||||
{"Reload-SSL-Certificate", QCoreApplication::translate("AdConfig", "Reload SSL Certificate")},
|
||||
{"Enable-Per-User-Reversibly-Encrypted-Password", QCoreApplication::translate("AdConfig", "Enable Per User Reversibly Encrypted Password")},
|
||||
{"DS-Replication-Monitor-Topology", QCoreApplication::translate("AdConfig", "DS Replication Monitor Topology")},
|
||||
{"Public-Information", QCoreApplication::translate("AdConfig", "Public Information")},
|
||||
{"Private-Information", QCoreApplication::translate("AdConfig", "Private Information")},
|
||||
{"msmq-Receive-Dead-Letter", QCoreApplication::translate("AdConfig", "msmq Receive Dead Letter")},
|
||||
{"msmq-Receive-journal", QCoreApplication::translate("AdConfig", "msmq Receive journal")},
|
||||
{"DNS-Host-Name-Attributes", QCoreApplication::translate("AdConfig", "DNS Host Name Attributes")},
|
||||
};
|
||||
|
||||
const QString right_cn = d->right_guid_to_cn_map[right_guid];
|
||||
if (language == QLocale::Russian && cn_to_map_russian.contains(right_cn)) {
|
||||
const QString out = cn_to_map_russian[right_cn];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const QString out = d->rights_guid_to_name_map.value(right_guid, QCoreApplication::translate("AdConfig", "<unknown rights>"));
|
||||
return out;
|
||||
}
|
||||
|
||||
QList<QString> AdConfig::get_extended_rights_list(const QList<QString> &class_list) const {
|
||||
QList<QString> out;
|
||||
|
||||
for (const QString &rights : d->extended_rights_list) {
|
||||
const bool applies_to = rights_applies_to_class(rights, class_list);
|
||||
if (applies_to) {
|
||||
out.append(rights);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int AdConfig::get_rights_valid_accesses(const QString &rights_cn) const {
|
||||
// NOTE: awkward exception. Can't write group
|
||||
// membership because target attribute is
|
||||
// constructed. For some reason valid accesses for
|
||||
// membership right does allow writing.
|
||||
if (rights_cn == "Membership") {
|
||||
return SEC_ADS_READ_PROP;
|
||||
}
|
||||
|
||||
const int out = d->rights_valid_accesses_map.value(rights_cn, 0);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QString AdConfig::guid_to_attribute(const QByteArray &guid) const {
|
||||
const QString out = d->guid_to_attribute_map.value(guid, "<unknown attribute>");
|
||||
return out;
|
||||
}
|
||||
|
||||
QString AdConfig::guid_to_class(const QByteArray &guid) const {
|
||||
const QString out = d->guid_to_class_map.value(guid, "<unknown class>");
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -558,6 +775,14 @@ QList<QString> AdConfig::get_noncontainer_classes() {
|
||||
return out;
|
||||
}
|
||||
|
||||
bool AdConfig::rights_applies_to_class(const QString &rights_cn, const QList<QString> &class_list) const {
|
||||
const QByteArray rights_guid = d->rights_name_to_guid_map[rights_cn];
|
||||
const QSet<QString> applies_to = d->rights_applies_to_map[rights_guid].toSet();
|
||||
const bool applies = applies_to.intersects(class_list.toSet());
|
||||
|
||||
return applies;
|
||||
}
|
||||
|
||||
QList<QString> AdConfigPrivate::add_auxiliary_classes(const QList<QString> &object_classes) const {
|
||||
QList<QString> out;
|
||||
|
||||
|
@ -29,11 +29,14 @@
|
||||
|
||||
#include "ad_defines.h"
|
||||
|
||||
#include <QLocale>
|
||||
|
||||
class AdConfigPrivate;
|
||||
class AdInterface;
|
||||
class QLocale;
|
||||
class QString;
|
||||
class QLineEdit;
|
||||
class QByteArray;
|
||||
template <typename T>
|
||||
class QList;
|
||||
|
||||
@ -50,11 +53,12 @@ public:
|
||||
void load(AdInterface &ad, const QLocale &locale);
|
||||
|
||||
QString domain() const;
|
||||
QString domain_head() const;
|
||||
QString domain_dn() const;
|
||||
QString configuration_dn() const;
|
||||
QString schema_dn() const;
|
||||
QString partitions_dn() const;
|
||||
QString extended_rights_dn() const;
|
||||
bool control_is_supported(const QString &control_oid) const;
|
||||
|
||||
QString get_attribute_display_name(const Attribute &attribute, const ObjectClass &objectClass) const;
|
||||
|
||||
@ -67,6 +71,10 @@ public:
|
||||
QList<ObjectClass> get_filter_containers() const;
|
||||
|
||||
QList<ObjectClass> get_possible_superiors(const QList<ObjectClass> &object_classes) const;
|
||||
ObjectClass get_parent_class(const ObjectClass &object_class) const;
|
||||
// Returns all ancestors of given class and the
|
||||
// given class itself
|
||||
QList<ObjectClass> get_inherit_chain(const ObjectClass &object_class) const;
|
||||
|
||||
QList<Attribute> get_optional_attributes(const QList<ObjectClass> &object_classes) const;
|
||||
QList<Attribute> get_mandatory_attributes(const QList<ObjectClass> &object_classes) const;
|
||||
@ -81,12 +89,26 @@ public:
|
||||
bool get_attribute_is_backlink(const Attribute &attribute) const;
|
||||
bool get_attribute_is_constructed(const Attribute &attribute) const;
|
||||
|
||||
// Limit's edit's max valid input length based on
|
||||
// the upper range defined for attribute in schema
|
||||
void limit_edit(QLineEdit *edit, const QString &attribute);
|
||||
|
||||
QString get_right_guid(const QString &right_cn) const;
|
||||
QByteArray get_right_guid(const QString &right_cn) const;
|
||||
QString get_right_name(const QByteArray &right_guid, const QLocale::Language language) const;
|
||||
int get_rights_valid_accesses(const QString &rights_cn) const;
|
||||
|
||||
// Returns extended rights that apply to given
|
||||
// classes
|
||||
QList<QString> get_extended_rights_list(const QList<QString> &class_list) const;
|
||||
|
||||
QString guid_to_attribute(const QByteArray &guid) const;
|
||||
|
||||
QString guid_to_class(const QByteArray &guid) const;
|
||||
|
||||
QList<QString> get_noncontainer_classes();
|
||||
|
||||
bool rights_applies_to_class(const QString &rights_cn, const QList<QString> &class_list) const;
|
||||
|
||||
private:
|
||||
AdConfigPrivate *d;
|
||||
};
|
||||
|
@ -38,7 +38,9 @@ public:
|
||||
AdConfigPrivate();
|
||||
|
||||
QString domain;
|
||||
QString domain_head;
|
||||
QString domain_dn;
|
||||
QString configuration_dn;
|
||||
QString schema_dn;
|
||||
|
||||
QList<ObjectClass> filter_containers;
|
||||
|
||||
@ -54,7 +56,20 @@ public:
|
||||
|
||||
QList<ObjectClass> add_auxiliary_classes(const QList<QString> &object_classes) const;
|
||||
|
||||
QHash<QString, QString> right_to_guid_map;
|
||||
QHash<QString, QByteArray> right_to_guid_map;
|
||||
QHash<QByteArray, QString> right_guid_to_cn_map;
|
||||
QHash<QByteArray, QString> rights_guid_to_name_map;
|
||||
QHash<QString, QByteArray> rights_name_to_guid_map;
|
||||
QHash<QByteArray, QList<QString>> rights_applies_to_map;
|
||||
QList<QString> extended_rights_list;
|
||||
QHash<QString, int> rights_valid_accesses_map;
|
||||
|
||||
QHash<QByteArray, QString> guid_to_attribute_map;
|
||||
QHash<QByteArray, QString> guid_to_class_map;
|
||||
|
||||
QList<QString> supported_control_list;
|
||||
|
||||
QHash<QString, QString> sub_class_of_map;
|
||||
};
|
||||
|
||||
#endif /* AD_CONFIG_P_H */
|
||||
|
@ -60,6 +60,7 @@ enum LargeIntegerSubtype {
|
||||
enum AccountOption {
|
||||
AccountOption_Disabled,
|
||||
AccountOption_CantChangePassword,
|
||||
AccountOption_AllowReversibleEncryption,
|
||||
AccountOption_PasswordExpired,
|
||||
AccountOption_DontExpirePassword,
|
||||
AccountOption_UseDesKey,
|
||||
@ -89,6 +90,8 @@ enum SystemFlagsBit {
|
||||
SystemFlagsBit_CannotDelete = 0x80000000
|
||||
};
|
||||
|
||||
#define ROOT_DSE ""
|
||||
|
||||
#define ATTRIBUTE_CN "cn"
|
||||
#define ATTRIBUTE_USER_ACCOUNT_CONTROL "userAccountControl"
|
||||
#define ATTRIBUTE_LOCKOUT_TIME "lockoutTime"
|
||||
@ -97,6 +100,7 @@ enum SystemFlagsBit {
|
||||
#define ATTRIBUTE_NAME "name"
|
||||
#define ATTRIBUTE_INITIALS "initials"
|
||||
#define ATTRIBUTE_SAM_ACCOUNT_NAME "sAMAccountName"
|
||||
#define ATTRIBUTE_SAM_ACCOUNT_TYPE "sAMAccountType"
|
||||
#define ATTRIBUTE_DISPLAY_NAME "displayName"
|
||||
#define ATTRIBUTE_DESCRIPTION "description"
|
||||
#define ATTRIBUTE_USER_PRINCIPAL_NAME "userPrincipalName"
|
||||
@ -114,6 +118,7 @@ enum SystemFlagsBit {
|
||||
#define ATTRIBUTE_POSTAL_CODE "postalCode"
|
||||
#define ATTRIBUTE_STATE "st"
|
||||
#define ATTRIBUTE_STREET "streetAddress"
|
||||
#define ATTRIBUTE_STREET_OU "street"
|
||||
#define ATTRIBUTE_DN "distinguishedName"
|
||||
#define ATTRIBUTE_OBJECT_CLASS "objectClass"
|
||||
#define ATTRIBUTE_WHEN_CREATED "whenCreated"
|
||||
@ -158,7 +163,8 @@ enum SystemFlagsBit {
|
||||
#define ATTRIBUTE_PROFILE_PATH "profilePath"
|
||||
#define ATTRIBUTE_SCRIPT_PATH "scriptPath"
|
||||
#define ATTRIBUTE_HOME_DIRECTORY "homeDirectory"
|
||||
|
||||
#define ATTRIBUTE_LAPS_PASSWORD "ms-Mcs-AdmPwd"
|
||||
#define ATTRIBUTE_LAPS_EXPIRATION "ms-Mcs-AdmPwdExpirationTime"
|
||||
#define ATTRIBUTE_HOME_PHONE "homePhone"
|
||||
#define ATTRIBUTE_OTHER_HOME_PHONE "otherHomePhone"
|
||||
#define ATTRIBUTE_PAGER "pager"
|
||||
@ -179,6 +185,18 @@ enum SystemFlagsBit {
|
||||
#define ATTRIBUTE_LOGON_HOURS "logonHours"
|
||||
#define ATTRIBUTE_USER_WORKSTATIONS "userWorkstations"
|
||||
#define ATTRIBUTE_VERSION_NUMBER "versionNumber"
|
||||
#define ATTRIBUTE_SUPPORTED_CONTROL "supportedControl"
|
||||
#define ATTRIBUTE_DS_SERVICE_NAME "dsServiceName"
|
||||
#define ATTRIBUTE_SCHEMA_NAMING_CONTEXT "schemaNamingContext"
|
||||
#define ATTRIBUTE_CONFIGURATION_NAMING_CONTEXT "configurationNamingContext"
|
||||
#define ATTRIBUTE_ROOT_DOMAIN_NAMING_CONTEXT "rootDomainNamingContext"
|
||||
#define ATTRIBUTE_FSMO_ROLE_OWNER "fSMORoleOwner"
|
||||
#define ATTRIBUTE_SERVER_NAME "serverName"
|
||||
#define ATTRIBUTE_SCHEMA_ID_GUID "schemaIDGUID"
|
||||
#define ATTRIBUTE_APPLIES_TO "appliesTo"
|
||||
#define ATTRIBUTE_VALID_ACCESSES "validAccesses"
|
||||
#define ATTRIBUTE_UNC_NAME "uNCName"
|
||||
#define ATTRIBUTE_KEYWORDS "keywords"
|
||||
|
||||
#define CLASS_GROUP "group"
|
||||
#define CLASS_USER "user"
|
||||
@ -234,49 +252,53 @@ const long long MILLIS_TO_100_NANOS = 10000LL;
|
||||
#define SACL_SECURITY_INFORMATION 0x08
|
||||
#define DACL_SECURITY_INFORMATION 0x10
|
||||
|
||||
enum PermissionState {
|
||||
PermissionState_None,
|
||||
PermissionState_Allowed,
|
||||
PermissionState_Denied,
|
||||
};
|
||||
#define SAM_NAME_BAD_CHARS "@\"[]:;|=+*?<>/\\,"
|
||||
#define UPN_BAD_CHARS "#,+\"\\<>"
|
||||
// NOTE: names technically can contain these chars but
|
||||
// we choose to be more strict about it
|
||||
#define NAME_BAD_CHARS ",\\#+<>;\"="
|
||||
|
||||
enum AcePermission {
|
||||
AcePermission_FullControl,
|
||||
AcePermission_Read,
|
||||
AcePermission_Write,
|
||||
AcePermission_Delete,
|
||||
AcePermission_DeleteSubtree,
|
||||
AcePermission_CreateChild,
|
||||
AcePermission_DeleteChild,
|
||||
AcePermission_AllowedToAuthenticate,
|
||||
AcePermission_ChangePassword,
|
||||
AcePermission_ReceiveAs,
|
||||
AcePermission_ResetPassword,
|
||||
AcePermission_SendAs,
|
||||
AcePermission_ReadAccountRestrictions,
|
||||
AcePermission_WriteAccountRestrictions,
|
||||
AcePermission_ReadGeneralInfo,
|
||||
AcePermission_WriteGeneralInfo,
|
||||
AcePermission_ReadGroupMembership,
|
||||
AcePermission_ReadLogonInfo,
|
||||
AcePermission_WriteLogonInfo,
|
||||
AcePermission_ReadPersonalInfo,
|
||||
AcePermission_WritePersonalInfo,
|
||||
AcePermission_ReadPhoneAndMailOptions,
|
||||
AcePermission_WritePhoneAndMailOptions,
|
||||
AcePermission_ReadPrivateInfo,
|
||||
AcePermission_WritePrivateInfo,
|
||||
AcePermission_ReadPublicInfo,
|
||||
AcePermission_WritePublicInfo,
|
||||
AcePermission_ReadRemoteAccessInfo,
|
||||
AcePermission_WriteRemoteAccessInfo,
|
||||
AcePermission_ReadTerminalServerLicenseServer,
|
||||
AcePermission_WriteTerminalServerLicenseServer,
|
||||
AcePermission_ReadWebInfo,
|
||||
AcePermission_WriteWebInfo,
|
||||
#define UAC_SCRIPT 0x00000001
|
||||
#define UAC_ACCOUNTDISABLE 0x00000002
|
||||
#define UAC_HOMEDIR_REQUIRED 0x00000008
|
||||
#define UAC_LOCKOUT 0x00000010
|
||||
#define UAC_PASSWD_NOTREQD 0x00000020
|
||||
#define UAC_PASSWD_CANT_CHANGE 0x00000040
|
||||
#define UAC_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
|
||||
#define UAC_TEMP_DUPLICATE_ACCOUNT 0x00000100
|
||||
#define UAC_NORMAL_ACCOUNT 0x00000200
|
||||
#define UAC_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
|
||||
#define UAC_WORKSTATION_TRUST_ACCOUNT 0x00001000
|
||||
#define UAC_SERVER_TRUST_ACCOUNT 0x00002000
|
||||
#define UAC_DONT_EXPIRE_PASSWORD 0x00010000
|
||||
#define UAC_MNS_LOGON_ACCOUNT 0x00020000
|
||||
#define UAC_SMARTCARD_REQUIRED 0x00040000
|
||||
#define UAC_TRUSTED_FOR_DELEGATION 0x00080000
|
||||
#define UAC_NOT_DELEGATED 0x00100000
|
||||
#define UAC_USE_DES_KEY_ONLY 0x00200000
|
||||
#define UAC_DONT_REQUIRE_PREAUTH 0x00400000
|
||||
#define UAC_ERROR_PASSWORD_EXPIRED 0x00800000
|
||||
#define UAC_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION 0x01000000
|
||||
#define UAC_PARTIAL_SECRETS_ACCOUNT 0x04000000
|
||||
#define UAC_USER_USE_AES_KEYS 0x08000000
|
||||
|
||||
AcePermission_COUNT,
|
||||
};
|
||||
#define SAM_DOMAIN_OBJECT 0x0
|
||||
#define SAM_GROUP_OBJECT 0x10000000
|
||||
#define SAM_NON_SECURITY_GROUP_OBJECT 0x10000001
|
||||
#define SAM_ALIAS_OBJECT 0x20000000
|
||||
#define SAM_NON_SECURITY_ALIAS_OBJECT 0x20000001
|
||||
#define SAM_USER_OBJECT 0x30000000
|
||||
#define SAM_NORMAL_USER_ACCOUNT 0x30000000
|
||||
#define SAM_MACHINE_ACCOUNT 0x30000001
|
||||
#define SAM_TRUST_ACCOUNT 0x30000002
|
||||
#define SAM_APP_BASIC_GROUP 0x40000000
|
||||
#define SAM_APP_QUERY_GROUP 0x40000001
|
||||
#define SAM_ACCOUNT_TYPE_MAX 0x7fffffff
|
||||
|
||||
// NOTE: this is according to Microsoft, haven't found
|
||||
// any better source
|
||||
#define SAM_NAME_MAX_LENGTH 20
|
||||
#define SAM_NAME_COMPUTER_MAX_LENGTH 16
|
||||
|
||||
enum SearchScope {
|
||||
SearchScope_Object,
|
||||
|
@ -42,6 +42,9 @@ QString datetime_display_value(const QString &attribute, const QByteArray &bytes
|
||||
QString timespan_display_value(const QByteArray &bytes);
|
||||
QString octet_display_value(const QByteArray &bytes);
|
||||
QString guid_to_display_value(const QByteArray &bytes);
|
||||
QString uac_to_display_value(const QByteArray &bytes);
|
||||
QString samaccounttype_to_display_value(const QByteArray &bytes);
|
||||
QString primarygrouptype_to_display_value(const QByteArray &bytes);
|
||||
|
||||
QString attribute_display_value(const QString &attribute, const QByteArray &value, const AdConfig *adconfig) {
|
||||
if (adconfig == nullptr) {
|
||||
@ -51,6 +54,17 @@ QString attribute_display_value(const QString &attribute, const QByteArray &valu
|
||||
const AttributeType type = adconfig->get_attribute_type(attribute);
|
||||
|
||||
switch (type) {
|
||||
case AttributeType_Integer: {
|
||||
if (attribute == ATTRIBUTE_USER_ACCOUNT_CONTROL) {
|
||||
return uac_to_display_value(value);
|
||||
} else if (attribute == ATTRIBUTE_SAM_ACCOUNT_TYPE) {
|
||||
return samaccounttype_to_display_value(value);
|
||||
} else if (attribute == ATTRIBUTE_PRIMARY_GROUP_ID) {
|
||||
return primarygrouptype_to_display_value(value);
|
||||
} else {
|
||||
return QString(value);
|
||||
}
|
||||
}
|
||||
case AttributeType_LargeInteger: {
|
||||
const LargeIntegerSubtype subtype = adconfig->get_attribute_large_integer_subtype(attribute);
|
||||
|
||||
@ -250,3 +264,158 @@ QString octet_display_value(const QByteArray &bytes) {
|
||||
|
||||
return QString(out);
|
||||
}
|
||||
|
||||
QString uac_to_display_value(const QByteArray &bytes) {
|
||||
bool uac_toInt_ok;
|
||||
const int uac = bytes.toInt(&uac_toInt_ok);
|
||||
|
||||
if (!uac_toInt_ok) {
|
||||
return QCoreApplication::translate("attribute_display", "<invalid UAC value>");
|
||||
}
|
||||
|
||||
// Create string of the form "X | Y | Z", where X,
|
||||
// Y, Z are names of masks that are set in given UAC
|
||||
const QString masks_string = [&]() {
|
||||
// NOTE: using separate list instead of map's
|
||||
// keys() because keys() is unordered and we need
|
||||
// order so that display string is consistent
|
||||
const QList<int> mask_list = {
|
||||
UAC_SCRIPT,
|
||||
UAC_ACCOUNTDISABLE,
|
||||
UAC_HOMEDIR_REQUIRED,
|
||||
UAC_LOCKOUT,
|
||||
UAC_PASSWD_NOTREQD,
|
||||
UAC_PASSWD_CANT_CHANGE,
|
||||
UAC_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
|
||||
UAC_TEMP_DUPLICATE_ACCOUNT,
|
||||
UAC_NORMAL_ACCOUNT,
|
||||
UAC_INTERDOMAIN_TRUST_ACCOUNT,
|
||||
UAC_WORKSTATION_TRUST_ACCOUNT,
|
||||
UAC_SERVER_TRUST_ACCOUNT,
|
||||
UAC_DONT_EXPIRE_PASSWORD,
|
||||
UAC_MNS_LOGON_ACCOUNT,
|
||||
UAC_SMARTCARD_REQUIRED,
|
||||
UAC_TRUSTED_FOR_DELEGATION,
|
||||
UAC_NOT_DELEGATED,
|
||||
UAC_USE_DES_KEY_ONLY,
|
||||
UAC_DONT_REQUIRE_PREAUTH,
|
||||
UAC_ERROR_PASSWORD_EXPIRED,
|
||||
UAC_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
|
||||
UAC_PARTIAL_SECRETS_ACCOUNT,
|
||||
UAC_USER_USE_AES_KEYS,
|
||||
};
|
||||
|
||||
const QHash<int, QString> mask_name_map = {
|
||||
{UAC_SCRIPT, "SCRIPT"},
|
||||
{UAC_ACCOUNTDISABLE, "ACCOUNTDISABLE"},
|
||||
{UAC_HOMEDIR_REQUIRED, "HOMEDIR_REQUIRED"},
|
||||
{UAC_LOCKOUT, "LOCKOUT"},
|
||||
{UAC_PASSWD_NOTREQD, "PASSWD_NOTREQD"},
|
||||
{UAC_PASSWD_CANT_CHANGE, "PASSWD_CANT_CHANGE"},
|
||||
{UAC_ENCRYPTED_TEXT_PASSWORD_ALLOWED, "ENCRYPTED_TEXT_PASSWORD_ALLOWED"},
|
||||
{UAC_TEMP_DUPLICATE_ACCOUNT, "TEMP_DUPLICATE_ACCOUNT"},
|
||||
{UAC_NORMAL_ACCOUNT, "NORMAL_ACCOUNT"},
|
||||
{UAC_INTERDOMAIN_TRUST_ACCOUNT, "INTERDOMAIN_TRUST_ACCOUNT"},
|
||||
{UAC_WORKSTATION_TRUST_ACCOUNT, "WORKSTATION_TRUST_ACCOUNT"},
|
||||
{UAC_SERVER_TRUST_ACCOUNT, "SERVER_TRUST_ACCOUNT"},
|
||||
{UAC_DONT_EXPIRE_PASSWORD, "DONT_EXPIRE_PASSWORD"},
|
||||
{UAC_MNS_LOGON_ACCOUNT, "MNS_LOGON_ACCOUNT"},
|
||||
{UAC_SMARTCARD_REQUIRED, "SMARTCARD_REQUIRED"},
|
||||
{UAC_TRUSTED_FOR_DELEGATION, "TRUSTED_FOR_DELEGATION"},
|
||||
{UAC_NOT_DELEGATED, "NOT_DELEGATED"},
|
||||
{UAC_USE_DES_KEY_ONLY, "USE_DES_KEY_ONLY"},
|
||||
{UAC_DONT_REQUIRE_PREAUTH, "DONT_REQUIRE_PREAUTH"},
|
||||
{UAC_ERROR_PASSWORD_EXPIRED, "ERROR_PASSWORD_EXPIRED"},
|
||||
{UAC_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, "TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION"},
|
||||
{UAC_PARTIAL_SECRETS_ACCOUNT, "PARTIAL_SECRETS_ACCOUNT"},
|
||||
{UAC_USER_USE_AES_KEYS, "USER_USE_AES_KEYS"},
|
||||
};
|
||||
|
||||
const QList<QString> set_mask_name_list = [&]() {
|
||||
QList<QString> out_list;
|
||||
|
||||
for (const int mask : mask_list) {
|
||||
const bool mask_is_set = bitmask_is_set(uac, mask);
|
||||
|
||||
if (mask_is_set) {
|
||||
const QString mask_name = mask_name_map[mask];
|
||||
out_list.append(mask_name);
|
||||
}
|
||||
}
|
||||
|
||||
return out_list;
|
||||
}();
|
||||
|
||||
const QString out_string = set_mask_name_list.join(" | ");
|
||||
|
||||
return out_string;
|
||||
}();
|
||||
|
||||
const QString out = QString("%1 = ( %2 )").arg(QString(bytes), masks_string);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QString samaccounttype_to_display_value(const QByteArray &bytes) {
|
||||
bool toInt_ok;
|
||||
const int value_int = bytes.toInt(&toInt_ok);
|
||||
|
||||
if (!toInt_ok) {
|
||||
return QCoreApplication::translate("attribute_display", "<invalid value>");
|
||||
}
|
||||
|
||||
const QHash<int, QString> mask_name_map = {
|
||||
{SAM_DOMAIN_OBJECT, "DOMAIN_OBJECT"},
|
||||
{SAM_GROUP_OBJECT, "GROUP_OBJECT"},
|
||||
{SAM_NON_SECURITY_GROUP_OBJECT, "NON_SECURITY_GROUP_OBJECT"},
|
||||
{SAM_ALIAS_OBJECT, "ALIAS_OBJECT"},
|
||||
{SAM_NON_SECURITY_ALIAS_OBJECT, "NON_SECURITY_ALIAS_OBJECT"},
|
||||
{SAM_USER_OBJECT, "USER_OBJECT"},
|
||||
{SAM_NORMAL_USER_ACCOUNT, "NORMAL_USER_ACCOUNT"},
|
||||
{SAM_MACHINE_ACCOUNT, "MACHINE_ACCOUNT"},
|
||||
{SAM_TRUST_ACCOUNT, "TRUST_ACCOUNT"},
|
||||
{SAM_APP_BASIC_GROUP, "APP_BASIC_GROUP"},
|
||||
{SAM_APP_QUERY_GROUP, "APP_QUERY_GROUP"},
|
||||
{SAM_ACCOUNT_TYPE_MAX, "ACCOUNT_TYPE_MAX"},
|
||||
};
|
||||
|
||||
const QString mask_name = mask_name_map.value(value_int, "");
|
||||
|
||||
const QString out = QString("%1 = ( %2 )").arg(QString(bytes), mask_name);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QString primarygrouptype_to_display_value(const QByteArray &bytes) {
|
||||
bool toInt_ok;
|
||||
const int value_int = bytes.toInt(&toInt_ok);
|
||||
|
||||
if (!toInt_ok) {
|
||||
return QCoreApplication::translate("attribute_display", "<invalid value>");
|
||||
}
|
||||
|
||||
// NOTE: builtin group rid's are not included
|
||||
// because they can't be primary
|
||||
const QHash<int, QString> mask_name_map = {
|
||||
{DOMAIN_RID_ADMINS, "GROUP_RID_ADMINS"},
|
||||
{DOMAIN_RID_USERS, "GROUP_RID_USERS"},
|
||||
{DOMAIN_RID_GUESTS, "GROUP_RID_GUESTS"},
|
||||
{DOMAIN_RID_DOMAIN_MEMBERS, "GROUP_RID_DOMAIN_MEMBERS"},
|
||||
{DOMAIN_RID_DCS, "GROUP_RID_DCS"},
|
||||
{DOMAIN_RID_CERT_ADMINS, "GROUP_RID_CERT_ADMINS"},
|
||||
{DOMAIN_RID_SCHEMA_ADMINS, "GROUP_RID_SCHEMA_ADMINS"},
|
||||
{DOMAIN_RID_ENTERPRISE_ADMINS, "GROUP_RID_ENTERPRISE_ADMINS"},
|
||||
{DOMAIN_RID_POLICY_ADMINS, "GROUP_RID_POLICY_ADMINS"},
|
||||
{DOMAIN_RID_READONLY_DCS, "GROUP_RID_READONLY_DCS"},
|
||||
{DOMAIN_RID_RAS_SERVERS, "GROUP_RID_RAS_SERVERS"},
|
||||
};
|
||||
|
||||
if (mask_name_map.contains(value_int)) {
|
||||
const QString mask_name = mask_name_map[value_int];
|
||||
const QString out = QString("%1 = ( %2 )").arg(QString(bytes), mask_name);
|
||||
|
||||
return out;
|
||||
} else {
|
||||
return QString::number(value_int);
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ enum AceMaskFormat {
|
||||
QList<QString> query_server_for_hosts(const char *dname);
|
||||
int sasl_interact_gssapi(LDAP *ld, unsigned flags, void *indefaults, void *in);
|
||||
QString get_gpt_sd_string(const AdObject &gpc_object, const AceMaskFormat format);
|
||||
int create_sd_control(bool get_sacl, int iscritical, LDAPControl **ctrlp);
|
||||
|
||||
AdConfig *AdInterfacePrivate::adconfig = nullptr;
|
||||
bool AdInterfacePrivate::s_log_searches = false;
|
||||
@ -114,12 +115,10 @@ AdInterface::AdInterface() {
|
||||
|
||||
d->domain = get_default_domain_from_krb5();
|
||||
if (d->domain.isEmpty()) {
|
||||
d->error_message(connect_error_context, tr("Failed to get a domain."));
|
||||
d->error_message(connect_error_context, tr("Failed to get a domain. Check that you have initialized kerberos credentials (kinit)."));
|
||||
return;
|
||||
}
|
||||
|
||||
d->domain_head = domain_to_domain_dn(d->domain);
|
||||
|
||||
//
|
||||
// Connect via LDAP
|
||||
//
|
||||
@ -327,10 +326,6 @@ void AdInterface::set_cert_strategy(const CertStrategy strategy) {
|
||||
AdInterfacePrivate::s_cert_strat = strategy;
|
||||
}
|
||||
|
||||
QString AdInterface::get_dc() {
|
||||
return AdInterfacePrivate::s_dc;
|
||||
}
|
||||
|
||||
AdInterfacePrivate::AdInterfacePrivate(AdInterface *q_arg) {
|
||||
q = q_arg;
|
||||
}
|
||||
@ -374,52 +369,32 @@ bool AdInterfacePrivate::search_paged_internal(const char *base, const int scope
|
||||
int result;
|
||||
LDAPMessage *res = NULL;
|
||||
LDAPControl *page_control = NULL;
|
||||
LDAPControl *sd_control = NULL;
|
||||
LDAPControl **returned_controls = NULL;
|
||||
struct berval *prev_cookie = cookie->cookie;
|
||||
struct berval *new_cookie = NULL;
|
||||
BerElement *sd_control_value_be = NULL;
|
||||
berval *sd_control_value_bv = NULL;
|
||||
|
||||
auto cleanup = [&]() {
|
||||
ldap_msgfree(res);
|
||||
ldap_control_free(page_control);
|
||||
ldap_control_free(sd_control);
|
||||
ldap_controls_free(returned_controls);
|
||||
ber_bvfree(prev_cookie);
|
||||
ber_bvfree(new_cookie);
|
||||
ber_free(sd_control_value_be, 1);
|
||||
ber_bvfree(sd_control_value_bv);
|
||||
};
|
||||
|
||||
// NOTE: this control is needed so that ldap returns
|
||||
// security descriptor attribute when we ask for all
|
||||
// attributes. Otherwise it won't includ the descriptor
|
||||
// in attributes. This might break something when the
|
||||
// app is used by a client with not enough rights to get
|
||||
// some/all parts of the descriptor. Investigate.
|
||||
LDAPControl sd_control;
|
||||
const char *sd_control_oid = LDAP_SERVER_SD_FLAGS_OID;
|
||||
sd_control.ldctl_oid = (char *) sd_control_oid;
|
||||
// NOTE: sacl part of the sd can only be obtained by
|
||||
// administrators, so for normal operations we omit it.
|
||||
// For some operations sacl is required so there's an
|
||||
// option to get it.
|
||||
const int sd_control_value_int = [&]() {
|
||||
if (get_sacl) {
|
||||
return (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
|
||||
} else {
|
||||
return (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
|
||||
}
|
||||
}();
|
||||
sd_control_value_be = ber_alloc_t(LBER_USE_DER);
|
||||
ber_printf(sd_control_value_be, "{i}", sd_control_value_int);
|
||||
ber_flatten(sd_control_value_be, &sd_control_value_bv);
|
||||
sd_control.ldctl_value.bv_len = sd_control_value_bv->bv_len;
|
||||
sd_control.ldctl_value.bv_val = sd_control_value_bv->bv_val;
|
||||
sd_control.ldctl_iscritical = (char) 1;
|
||||
const int is_critical = 1;
|
||||
|
||||
result = create_sd_control(get_sacl, is_critical, &sd_control);
|
||||
if (result != LDAP_SUCCESS) {
|
||||
qDebug() << "Failed to create sd control: " << ldap_err2string(result);
|
||||
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create page control
|
||||
const ber_int_t page_size = 1000;
|
||||
const int is_critical = 1;
|
||||
const ber_int_t page_size = 100;
|
||||
result = ldap_create_page_control(ld, page_size, prev_cookie, is_critical, &page_control);
|
||||
if (result != LDAP_SUCCESS) {
|
||||
qDebug() << "Failed to create page control: " << ldap_err2string(result);
|
||||
@ -427,7 +402,7 @@ bool AdInterfacePrivate::search_paged_internal(const char *base, const int scope
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
LDAPControl *server_controls[3] = {page_control, &sd_control, NULL};
|
||||
LDAPControl *server_controls[3] = {page_control, sd_control, NULL};
|
||||
|
||||
// Perform search
|
||||
const int attrsonly = 0;
|
||||
@ -500,32 +475,33 @@ bool AdInterfacePrivate::search_paged_internal(const char *base, const int scope
|
||||
}
|
||||
|
||||
// Get page response control
|
||||
//
|
||||
// NOTE: not sure if absence of page response control is
|
||||
// an error. Decided to not treat it as error because
|
||||
// searching the rootDSE doesn't return this control.
|
||||
LDAPControl *pageresponse_control = ldap_control_find(LDAP_CONTROL_PAGEDRESULTS, returned_controls, NULL);
|
||||
if (pageresponse_control == NULL) {
|
||||
qDebug() << "Failed to find PAGEDRESULTS control";
|
||||
if (pageresponse_control != NULL) {
|
||||
// Parse page response control to determine whether
|
||||
// there are more pages
|
||||
ber_int_t total_count;
|
||||
new_cookie = (struct berval *) malloc(sizeof(struct berval));
|
||||
result = ldap_parse_pageresponse_control(ld, pageresponse_control, &total_count, new_cookie);
|
||||
if (result != LDAP_SUCCESS) {
|
||||
qDebug() << "Failed to parse pageresponse control: " << ldap_err2string(result);
|
||||
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse page response control to determine whether
|
||||
// there are more pages
|
||||
ber_int_t total_count;
|
||||
new_cookie = (struct berval *) malloc(sizeof(struct berval));
|
||||
result = ldap_parse_pageresponse_control(ld, pageresponse_control, &total_count, new_cookie);
|
||||
if (result != LDAP_SUCCESS) {
|
||||
qDebug() << "Failed to parse pageresponse control: " << ldap_err2string(result);
|
||||
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Switch to new cookie if there are more pages
|
||||
// NOTE: there are more pages if the cookie isn't
|
||||
// empty
|
||||
const bool more_pages = (new_cookie->bv_len > 0);
|
||||
if (more_pages) {
|
||||
cookie->cookie = ber_bvdup(new_cookie);
|
||||
// Switch to new cookie if there are more pages
|
||||
// NOTE: there are more pages if the cookie isn't
|
||||
// empty
|
||||
const bool more_pages = (new_cookie->bv_len > 0);
|
||||
if (more_pages) {
|
||||
cookie->cookie = ber_bvdup(new_cookie);
|
||||
} else {
|
||||
cookie->cookie = NULL;
|
||||
}
|
||||
} else {
|
||||
cookie->cookie = NULL;
|
||||
}
|
||||
@ -538,23 +514,6 @@ QHash<QString, AdObject> AdInterface::search(const QString &base, const SearchSc
|
||||
AdCookie cookie;
|
||||
QHash<QString, AdObject> results;
|
||||
|
||||
if (AdInterfacePrivate::s_log_searches) {
|
||||
const QString attributes_string = "{" + attributes.join(",") + "}";
|
||||
|
||||
const QString scope_string = [&scope]() -> QString {
|
||||
switch (scope) {
|
||||
case SearchScope_Object: return "object";
|
||||
case SearchScope_Children: return "children";
|
||||
case SearchScope_Descendants: return "descendants";
|
||||
case SearchScope_All: return "all";
|
||||
default: break;
|
||||
}
|
||||
return QString();
|
||||
}();
|
||||
|
||||
d->success_message(QString(tr("Search:\n\tfilter = \"%1\"\n\tattributes = %2\n\tscope = \"%3\"\n\tbase = \"%4\"")).arg(filter, attributes_string, scope_string, base));
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const bool success = search_paged(base, scope, filter, attributes, &results, &cookie, get_sacl);
|
||||
|
||||
@ -571,6 +530,27 @@ QHash<QString, AdObject> AdInterface::search(const QString &base, const SearchSc
|
||||
}
|
||||
|
||||
bool AdInterface::search_paged(const QString &base, const SearchScope scope, const QString &filter, const QList<QString> &attributes, QHash<QString, AdObject> *results, AdCookie *cookie, const bool get_sacl) {
|
||||
// NOTE: only log once per cycle of search pages,
|
||||
// to avoid duplicate messages
|
||||
const bool is_first_page = results->isEmpty();
|
||||
const bool need_to_log = (AdInterfacePrivate::s_log_searches && is_first_page);
|
||||
if (need_to_log) {
|
||||
const QString attributes_string = "{" + attributes.join(",") + "}";
|
||||
|
||||
const QString scope_string = [&scope]() -> QString {
|
||||
switch (scope) {
|
||||
case SearchScope_Object: return "object";
|
||||
case SearchScope_Children: return "children";
|
||||
case SearchScope_Descendants: return "descendants";
|
||||
case SearchScope_All: return "all";
|
||||
default: break;
|
||||
}
|
||||
return QString();
|
||||
}();
|
||||
|
||||
d->success_message(QString(tr("Search:\n\tfilter = \"%1\"\n\tattributes = %2\n\tscope = \"%3\"\n\tbase = \"%4\"")).arg(filter, attributes_string, scope_string, base));
|
||||
}
|
||||
|
||||
const char *base_cstr = cstr(base);
|
||||
|
||||
const int scope_int = [&]() {
|
||||
@ -805,18 +785,40 @@ bool AdInterface::attribute_replace_datetime(const QString &dn, const QString &a
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AdInterface::object_add(const QString &dn, const QString &object_class) {
|
||||
const char *classes[2] = {cstr(object_class), NULL};
|
||||
bool AdInterface::object_add(const QString &dn, const QHash<QString, QList<QString>> &attrs_map) {
|
||||
LDAPMod **attrs = [&attrs_map]() {
|
||||
LDAPMod **out = (LDAPMod **) malloc((attrs_map.size() + 1) * sizeof(LDAPMod *));
|
||||
|
||||
LDAPMod attr;
|
||||
attr.mod_op = LDAP_MOD_ADD;
|
||||
attr.mod_type = (char *) "objectClass";
|
||||
attr.mod_values = (char **) classes;
|
||||
const QList<QString> attrs_map_keys = attrs_map.keys();
|
||||
for (int i = 0; i < attrs_map_keys.size(); i++) {
|
||||
LDAPMod *attr = (LDAPMod *) malloc(sizeof(LDAPMod));
|
||||
|
||||
LDAPMod *attrs[] = {&attr, NULL};
|
||||
const QString attr_name = attrs_map_keys[i];
|
||||
const QList<QString> value_list = attrs_map[attr_name];
|
||||
|
||||
char **value_array = (char **) malloc((value_list.size() + 1) * sizeof(char *));
|
||||
for (int j = 0; j < value_list.size(); j++) {
|
||||
const QString value = value_list[j];
|
||||
value_array[j] = (char *) strdup(cstr(value));
|
||||
}
|
||||
value_array[value_list.size()] = NULL;
|
||||
|
||||
attr->mod_type = (char *) strdup(cstr(attr_name));
|
||||
attr->mod_op = LDAP_MOD_ADD;
|
||||
attr->mod_values = value_array;
|
||||
|
||||
out[i] = attr;
|
||||
}
|
||||
|
||||
out[attrs_map.size()] = NULL;
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
const int result = ldap_add_ext_s(d->ld, cstr(dn), attrs, NULL, NULL);
|
||||
|
||||
ldap_mods_free(attrs, 1);
|
||||
|
||||
if (result == LDAP_SUCCESS) {
|
||||
d->success_message(QString(tr("Object %1 was created.")).arg(dn));
|
||||
|
||||
@ -850,6 +852,16 @@ bool AdInterface::object_add(const QString &dn, const QString &object_class) {
|
||||
}
|
||||
}
|
||||
|
||||
bool AdInterface::object_add(const QString &dn, const QString &object_class) {
|
||||
const QHash<QString, QList<QString>> attrs_map = {
|
||||
{"objectClass", {object_class}},
|
||||
};
|
||||
|
||||
const bool success = object_add(dn, attrs_map);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AdInterface::object_delete(const QString &dn, const DoStatusMsg do_msg) {
|
||||
int result;
|
||||
LDAPControl *tree_delete_control = NULL;
|
||||
@ -863,14 +875,6 @@ bool AdInterface::object_delete(const QString &dn, const DoStatusMsg do_msg) {
|
||||
const QString error_context = QString(tr("Failed to delete object %1.")).arg(name);
|
||||
|
||||
// Use a tree delete control to enable recursive delete
|
||||
tree_delete_control = (LDAPControl *) malloc(sizeof(LDAPControl));
|
||||
if (tree_delete_control == NULL) {
|
||||
d->error_message(error_context, tr("LDAP Operation error - Failed to allocate tree delete control."));
|
||||
cleanup();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ldap_control_create(LDAP_CONTROL_X_TREE_DELETE, 1, NULL, 0, &tree_delete_control);
|
||||
if (result != LDAP_SUCCESS) {
|
||||
d->error_message(error_context, tr("LDAP Operation error - Failed to create tree delete control."));
|
||||
@ -879,7 +883,12 @@ bool AdInterface::object_delete(const QString &dn, const DoStatusMsg do_msg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LDAPControl *server_controls[2] = {tree_delete_control, NULL};
|
||||
LDAPControl *server_controls[2] = {NULL, NULL};
|
||||
|
||||
const bool tree_delete_is_supported = adconfig()->control_is_supported(LDAP_CONTROL_X_TREE_DELETE);
|
||||
if (tree_delete_is_supported) {
|
||||
server_controls[0] = tree_delete_control;
|
||||
}
|
||||
|
||||
result = ldap_delete_ext_s(d->ld, cstr(dn), server_controls, NULL);
|
||||
|
||||
@ -1000,12 +1009,12 @@ bool AdInterface::group_set_scope(const QString &dn, GroupScope scope, const DoS
|
||||
const GroupScope this_scope = (GroupScope) i;
|
||||
const int this_scope_bit = group_scope_bit(this_scope);
|
||||
|
||||
group_type = bit_set(group_type, this_scope_bit, false);
|
||||
group_type = bitmask_set(group_type, this_scope_bit, false);
|
||||
}
|
||||
|
||||
// Set given scope bit
|
||||
const int scope_bit = group_scope_bit(scope);
|
||||
group_type = bit_set(group_type, scope_bit, true);
|
||||
group_type = bitmask_set(group_type, scope_bit, true);
|
||||
|
||||
const QString name = dn_get_name(dn);
|
||||
const QString scope_string = group_scope_string(scope);
|
||||
@ -1030,7 +1039,7 @@ bool AdInterface::group_set_type(const QString &dn, GroupType type) {
|
||||
|
||||
const bool set_security_bit = type == GroupType_Security;
|
||||
|
||||
const int update_group_type = bit_set(group_type, GROUP_TYPE_BIT_SECURITY, set_security_bit);
|
||||
const int update_group_type = bitmask_set(group_type, GROUP_TYPE_BIT_SECURITY, set_security_bit);
|
||||
const QString update_group_type_string = QString::number(update_group_type);
|
||||
|
||||
const QString name = dn_get_name(dn);
|
||||
@ -1131,22 +1140,7 @@ bool AdInterface::user_set_account_option(const QString &dn, AccountOption optio
|
||||
|
||||
switch (option) {
|
||||
case AccountOption_CantChangePassword: {
|
||||
const AdObject object = search_object(dn, {ATTRIBUTE_SECURITY_DESCRIPTOR});
|
||||
const auto old_security_state = object.get_security_state(d->adconfig);
|
||||
|
||||
const QByteArray self_trustee = sid_string_to_bytes(SID_NT_SELF);
|
||||
|
||||
const PermissionState new_permission_state = [&]() {
|
||||
if (set) {
|
||||
return PermissionState_Denied;
|
||||
} else {
|
||||
return PermissionState_Allowed;
|
||||
}
|
||||
}();
|
||||
|
||||
const auto new_security_state = ad_security_modify(old_security_state, self_trustee, AcePermission_ChangePassword, new_permission_state);
|
||||
|
||||
success = attribute_replace_security_descriptor(this, dn, new_security_state);
|
||||
success = ad_security_set_user_cant_change_pass(this, dn, set);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1169,7 +1163,7 @@ bool AdInterface::user_set_account_option(const QString &dn, AccountOption optio
|
||||
}();
|
||||
|
||||
const int bit = account_option_bit(option);
|
||||
const int updated_uac = bit_set(uac, bit, set);
|
||||
const int updated_uac = bitmask_set(uac, bit, set);
|
||||
|
||||
success = attribute_replace_int(dn, ATTRIBUTE_USER_ACCOUNT_CONTROL, updated_uac, DoStatusMsg_No);
|
||||
}
|
||||
@ -1296,7 +1290,7 @@ bool AdInterface::gpo_add(const QString &display_name, QString &dn_out) {
|
||||
// Ex: "\\domain.alt\sysvol\domain.alt\Policies\{FF7E0880-F3AD-4540-8F1D-4472CB4A7044}"
|
||||
const QString filesys_path = QString("\\\\%1\\sysvol\\%2\\Policies\\%3").arg(d->domain.toLower(), d->domain.toLower(), uuid);
|
||||
const QString gpt_path = filesys_path_to_smb_path(filesys_path);
|
||||
const QString gpc_dn = QString("CN=%1,CN=Policies,CN=System,%2").arg(uuid, d->domain_head);
|
||||
const QString gpc_dn = QString("CN=%1,CN=Policies,CN=System,%2").arg(uuid, adconfig()->domain_dn());
|
||||
|
||||
// After each error case we need to clean up whatever we
|
||||
// have created successfully so far. Don't just use
|
||||
@ -1534,7 +1528,7 @@ bool AdInterface::gpo_delete(const QString &dn, bool *deleted_object) {
|
||||
}
|
||||
|
||||
// Unlink policy
|
||||
const QString base = d->domain_head;
|
||||
const QString base = adconfig()->domain_dn();
|
||||
const SearchScope scope = SearchScope_All;
|
||||
const QList<QString> attributes = {ATTRIBUTE_GPLINK};
|
||||
const QString filter = filter_CONDITION(Condition_Contains, ATTRIBUTE_GPLINK, dn);
|
||||
@ -1676,7 +1670,33 @@ bool AdInterface::gpo_check_perms(const QString &gpo, bool *ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool sd_match = (gpc_sd == gpt_sd);
|
||||
// SD's match if they both contain all lines of the
|
||||
// other one. Order doesn't matter. Note that
|
||||
// simple equality doesn't work because entry order
|
||||
// may not match.
|
||||
//
|
||||
// NOTE: there's also a weird thing where RSAT
|
||||
// creates GPO's with duplicate ace's for Domain
|
||||
// Admins. Not sure why that happens but this
|
||||
// matching method ignores that quirk.
|
||||
const bool sd_match = [&]() {
|
||||
const QList<QString> gpt_list = QString(gpt_sd).split(",");
|
||||
const QList<QString> gpc_list = QString(gpc_sd).split(",");
|
||||
|
||||
for (const QString &line : gpt_list) {
|
||||
if (!gpc_list.contains(line)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &line : gpc_list) {
|
||||
if (!gpt_list.contains(line)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
return sd_match;
|
||||
}
|
||||
@ -1908,6 +1928,45 @@ bool AdInterfacePrivate::smb_path_is_dir(const QString &path, bool *ok) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this f-n is analogous to
|
||||
// ldap_create_page_control() and others. See pagectl.c
|
||||
// in ldap sources for examples. Extracted to contain
|
||||
// the C madness.
|
||||
int create_sd_control(bool get_sacl, int iscritical, LDAPControl **ctrlp) {
|
||||
BerElement *value_be = NULL;
|
||||
struct berval value;
|
||||
|
||||
// Create berval to load into control
|
||||
//
|
||||
// NOTE: SACL part of the sd can only be obtained
|
||||
// by administrators. For most operations we don't
|
||||
// need SACL. Some operations, like creating a GPO,
|
||||
// do require SACL, so for those operations we turn
|
||||
// on the "get_sacl" options.
|
||||
const int value_int = [&]() {
|
||||
if (get_sacl) {
|
||||
return (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
|
||||
} else {
|
||||
return (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
|
||||
}
|
||||
}();
|
||||
value_be = ber_alloc_t(LBER_USE_DER);
|
||||
ber_printf(value_be, "{i}", value_int);
|
||||
ber_flatten2(value_be, &value, 1);
|
||||
|
||||
// Create control
|
||||
const int result = ldap_control_create( LDAP_SERVER_SD_FLAGS_OID,
|
||||
iscritical, &value, 0, ctrlp);
|
||||
|
||||
if (result != LDAP_SUCCESS) {
|
||||
ber_memfree(value.bv_val);
|
||||
}
|
||||
|
||||
ber_free(value_be, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AdInterface::logged_in_as_admin() {
|
||||
const QString user_dn = [&]() {
|
||||
const QString sam_account_name = [&]() {
|
||||
@ -1922,7 +1981,7 @@ bool AdInterface::logged_in_as_admin() {
|
||||
}
|
||||
|
||||
const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_SAM_ACCOUNT_NAME, sam_account_name);
|
||||
const QHash<QString, AdObject> results = search(d->domain_head, SearchScope_All, filter, QList<QString>());
|
||||
const QHash<QString, AdObject> results = search(adconfig()->domain_dn(), SearchScope_All, filter, QList<QString>());
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return QString();
|
||||
@ -1938,7 +1997,7 @@ bool AdInterface::logged_in_as_admin() {
|
||||
}
|
||||
|
||||
const bool user_is_admin = [&]() {
|
||||
const QString domain_admins_dn = QString("CN=Domain Admins,CN=Users,%1").arg(d->domain_head);
|
||||
const QString domain_admins_dn = QString("CN=Domain Admins,CN=Users,%1").arg(adconfig()->domain_dn());
|
||||
|
||||
const AdObject domain_admins_object = search_object(domain_admins_dn);
|
||||
const QList<QString> member_list = domain_admins_object.get_strings(ATTRIBUTE_MEMBER);
|
||||
@ -1951,6 +2010,10 @@ bool AdInterface::logged_in_as_admin() {
|
||||
return user_is_admin;
|
||||
}
|
||||
|
||||
QString AdInterface::get_dc() const {
|
||||
return d->dc;
|
||||
}
|
||||
|
||||
QList<QString> get_domain_hosts(const QString &domain, const QString &site) {
|
||||
QList<QString> hosts;
|
||||
|
||||
@ -2140,7 +2203,7 @@ int sasl_interact_gssapi(LDAP *ld, unsigned flags, void *indefaults, void *in) {
|
||||
QString get_gpt_sd_string(const AdObject &gpc_object, const AceMaskFormat format_enum) {
|
||||
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
||||
|
||||
security_descriptor *gpc_sd = gpc_object.get_sd(mem_ctx);
|
||||
security_descriptor *gpc_sd = gpc_object.get_security_descriptor(mem_ctx);
|
||||
|
||||
struct security_descriptor *gpt_sd;
|
||||
const NTSTATUS create_sd_status = gp_create_gpt_security_descriptor(mem_ctx, gpc_sd, &gpt_sd);
|
||||
@ -2152,7 +2215,7 @@ QString get_gpt_sd_string(const AdObject &gpc_object, const AceMaskFormat format
|
||||
return QString();
|
||||
}
|
||||
|
||||
ad_security_sort_dacl(gpt_sd);
|
||||
security_descriptor_sort_dacl(gpt_sd);
|
||||
|
||||
QList<QString> all_elements;
|
||||
|
||||
|
@ -104,7 +104,6 @@ public:
|
||||
static void set_sasl_nocanon(const bool is_on);
|
||||
static void set_port(const int port);
|
||||
static void set_cert_strategy(const CertStrategy strategy);
|
||||
static QString get_dc();
|
||||
|
||||
bool is_connected() const;
|
||||
QList<AdMessage> messages() const;
|
||||
@ -113,6 +112,7 @@ public:
|
||||
AdConfig *adconfig() const;
|
||||
QString client_user() const;
|
||||
bool logged_in_as_admin();
|
||||
QString get_dc() const;
|
||||
|
||||
// NOTE: If request attributes list is empty, all
|
||||
// attributes are returned
|
||||
@ -143,7 +143,15 @@ public:
|
||||
bool attribute_replace_int(const QString &dn, const QString &attribute, const int value, const DoStatusMsg do_msg = DoStatusMsg_Yes);
|
||||
bool attribute_replace_datetime(const QString &dn, const QString &attribute, const QDateTime &datetime);
|
||||
|
||||
// NOTE: attrs_map should contain attribute values
|
||||
// that will be added to the newly created object.
|
||||
// Note that it *must* contain a valid value for
|
||||
// objectClass attribute.
|
||||
bool object_add(const QString &dn, const QHash<QString, QList<QString>> &attrs_map);
|
||||
// Simplified version that only only adds one
|
||||
// objectClass value
|
||||
bool object_add(const QString &dn, const QString &object_class);
|
||||
|
||||
bool object_delete(const QString &dn, const DoStatusMsg do_msg = DoStatusMsg_Yes);
|
||||
bool object_move(const QString &dn, const QString &new_container);
|
||||
bool object_rename(const QString &dn, const QString &new_name);
|
||||
|
@ -41,7 +41,6 @@ public:
|
||||
LDAP *ld;
|
||||
bool is_connected;
|
||||
QString domain;
|
||||
QString domain_head;
|
||||
QString dc;
|
||||
QString client_user;
|
||||
QList<AdMessage> messages;
|
||||
|
@ -162,7 +162,7 @@ bool AdObject::get_bool(const QString &attribute) const {
|
||||
bool AdObject::get_system_flag(const SystemFlagsBit bit) const {
|
||||
if (contains(ATTRIBUTE_SYSTEM_FLAGS)) {
|
||||
const int system_flags_bits = get_int(ATTRIBUTE_SYSTEM_FLAGS);
|
||||
const bool is_set = bit_is_set(system_flags_bits, bit);
|
||||
const bool is_set = bitmask_is_set(system_flags_bits, bit);
|
||||
|
||||
return is_set;
|
||||
} else {
|
||||
@ -173,16 +173,9 @@ bool AdObject::get_system_flag(const SystemFlagsBit bit) const {
|
||||
bool AdObject::get_account_option(AccountOption option, AdConfig *adconfig) const {
|
||||
switch (option) {
|
||||
case AccountOption_CantChangePassword: {
|
||||
if (contains(ATTRIBUTE_SECURITY_DESCRIPTOR)) {
|
||||
const auto security_state = get_security_state(adconfig);
|
||||
const QByteArray self_trustee = sid_string_to_bytes(SID_NT_SELF);
|
||||
const PermissionState permission_state = security_state[self_trustee][AcePermission_ChangePassword];
|
||||
const bool denied = (permission_state == PermissionState_Denied);
|
||||
const bool out = ad_security_get_user_cant_change_pass(this, adconfig);
|
||||
|
||||
return denied;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
case AccountOption_PasswordExpired: {
|
||||
if (contains(ATTRIBUTE_PWD_LAST_SET)) {
|
||||
@ -230,7 +223,7 @@ GroupScope AdObject::get_group_scope() const {
|
||||
const GroupScope this_scope = (GroupScope) i;
|
||||
const int scope_bit = group_scope_bit(this_scope);
|
||||
|
||||
if (bit_is_set(group_type, scope_bit)) {
|
||||
if (bitmask_is_set(group_type, scope_bit)) {
|
||||
return this_scope;
|
||||
}
|
||||
}
|
||||
@ -267,25 +260,17 @@ QString AdObject::get_upn_suffix() const {
|
||||
return upn_split[1];
|
||||
}
|
||||
|
||||
security_descriptor *AdObject::get_sd(TALLOC_CTX *mem_ctx) const {
|
||||
const QByteArray descriptor_bytes = get_value(ATTRIBUTE_SECURITY_DESCRIPTOR);
|
||||
DATA_BLOB blob = data_blob_const(descriptor_bytes.data(), descriptor_bytes.size());
|
||||
security_descriptor *AdObject::get_security_descriptor(TALLOC_CTX *mem_ctx_arg) const {
|
||||
TALLOC_CTX *mem_ctx = [&]() -> void * {
|
||||
if (mem_ctx_arg != nullptr) {
|
||||
return mem_ctx_arg;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}();
|
||||
|
||||
security_descriptor *sd = talloc(mem_ctx, struct security_descriptor);
|
||||
|
||||
ndr_pull_struct_blob(&blob, mem_ctx, sd, (ndr_pull_flags_fn_t) ndr_pull_security_descriptor);
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> AdObject::get_security_state(AdConfig *adconfig) const {
|
||||
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
||||
|
||||
security_descriptor *sd = get_sd(mem_ctx);
|
||||
|
||||
const auto out = ad_security_get_state_from_sd(sd, adconfig);
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
const QByteArray sd_bytes = get_value(ATTRIBUTE_SECURITY_DESCRIPTOR);
|
||||
security_descriptor *out = security_descriptor_make_from_bytes(mem_ctx, sd_bytes);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
@ -40,8 +40,8 @@
|
||||
|
||||
class QDateTime;
|
||||
class AdConfig;
|
||||
struct security_descriptor;
|
||||
typedef void TALLOC_CTX;
|
||||
struct security_descriptor;
|
||||
|
||||
class AdObject {
|
||||
|
||||
@ -84,8 +84,8 @@ public:
|
||||
QString get_upn_prefix() const;
|
||||
QString get_upn_suffix() const;
|
||||
|
||||
security_descriptor *get_sd(TALLOC_CTX *mem_ctx) const;
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> get_security_state(AdConfig *adconfig) const;
|
||||
// NOTE: if no mem_ctx is given, then returned value has to be free'd using security_descriptor_free()
|
||||
security_descriptor *get_security_descriptor(TALLOC_CTX *mem_ctx = nullptr) const;
|
||||
|
||||
private:
|
||||
QString dn;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,8 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functions for working with security descriptors.
|
||||
* Functions for working with AD security and security
|
||||
* descriptors.
|
||||
*/
|
||||
|
||||
#ifndef AD_SECURITY_H
|
||||
@ -28,40 +29,84 @@
|
||||
#include "ad_defines.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QLocale>
|
||||
|
||||
class AdInterface;
|
||||
class AdConfig;
|
||||
class AdObject;
|
||||
struct security_descriptor;
|
||||
struct dom_sid;
|
||||
typedef void TALLOC_CTX;
|
||||
|
||||
extern const QList<QString> well_known_sid_list;
|
||||
extern const QHash<AcePermission, uint32_t> ace_permission_to_mask_map;
|
||||
extern const QHash<AcePermission, QString> ace_permission_to_type_map;
|
||||
extern const QList<AcePermission> all_permissions_list;
|
||||
extern const QSet<AcePermission> all_permissions;
|
||||
extern const QSet<AcePermission> access_permissions;
|
||||
extern const QSet<AcePermission> read_prop_permissions;
|
||||
extern const QSet<AcePermission> write_prop_permissions;
|
||||
extern const QList<uint32_t> common_rights_list;
|
||||
|
||||
enum SecurityRightStateType {
|
||||
SecurityRightStateType_Allow,
|
||||
SecurityRightStateType_Deny,
|
||||
SecurityRightStateType_COUNT,
|
||||
};
|
||||
|
||||
enum SecurityRightStateInherited {
|
||||
SecurityRightStateInherited_Yes,
|
||||
SecurityRightStateInherited_No,
|
||||
SecurityRightStateInherited_COUNT,
|
||||
};
|
||||
|
||||
class SecurityRightState {
|
||||
public:
|
||||
SecurityRightState(const bool data[SecurityRightStateInherited_COUNT][SecurityRightStateType_COUNT]);
|
||||
|
||||
bool get(const SecurityRightStateInherited inherited, const SecurityRightStateType type) const;
|
||||
|
||||
private:
|
||||
bool data[SecurityRightStateInherited_COUNT][SecurityRightStateType_COUNT];
|
||||
};
|
||||
|
||||
class SecurityRight {
|
||||
public:
|
||||
uint32_t access_mask;
|
||||
QByteArray object_type;
|
||||
};
|
||||
|
||||
QHash<QByteArray, QHash<AcePermission, PermissionState>> ad_security_modify(const QHash<QByteArray, QHash<AcePermission, PermissionState>> ¤t, const QByteArray &trustee, const AcePermission permission, const PermissionState new_state);
|
||||
QString ad_security_get_well_known_trustee_name(const QByteArray &trustee);
|
||||
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);
|
||||
bool ad_security_get_protected_against_deletion(const AdObject &object);
|
||||
bool ad_security_set_protected_against_deletion(AdInterface &ad, const QString dn, const bool enabled);
|
||||
bool ad_security_get_user_cant_change_pass(const AdObject *object, AdConfig *adconfig);
|
||||
bool ad_security_set_user_cant_change_pass(AdInterface *ad, const QString &dn, const bool enabled);
|
||||
bool ad_security_replace_security_descriptor(AdInterface &ad, const QString &dn, security_descriptor *new_sd);
|
||||
|
||||
// NOTE: have to talloc_free() returned sd
|
||||
security_descriptor *ad_security_get_sd(const AdObject &object);
|
||||
// Returns the full right name, adding "Write" or
|
||||
// "Read" depending on access mask.
|
||||
QString ad_security_get_right_name(AdConfig *adconfig, const uint32_t access_mask, const QByteArray &object_type, QLocale::Language language);
|
||||
|
||||
void ad_security_sort_dacl(security_descriptor *sd);
|
||||
// NOTE: returned sd needs to be free'd with
|
||||
// security_descriptor_free()
|
||||
security_descriptor *security_descriptor_make_from_bytes(const QByteArray &sd_bytes);
|
||||
security_descriptor *security_descriptor_make_from_bytes(TALLOC_CTX *mem_ctx, const QByteArray &sd_bytes);
|
||||
security_descriptor *security_descriptor_copy(security_descriptor *sd);
|
||||
void security_descriptor_free(security_descriptor *sd);
|
||||
void security_descriptor_sort_dacl(security_descriptor *sd);
|
||||
QList<QByteArray> security_descriptor_get_trustee_list(security_descriptor *sd);
|
||||
SecurityRightState security_descriptor_get_right(const security_descriptor *sd, const QByteArray &trustee, const uint32_t access_mask, const QByteArray &object_type);
|
||||
void security_descriptor_print(security_descriptor *sd, AdInterface &ad);
|
||||
bool security_descriptor_verify_acl_order(security_descriptor *sd);
|
||||
|
||||
QByteArray dom_sid_to_bytes(const dom_sid &sid);
|
||||
QByteArray dom_sid_string_to_bytes(const dom_sid &sid);
|
||||
// Remove all ACE's from DACL for given trustee. Note
|
||||
// that inherited ACE's are untouched, so trustee might
|
||||
// still have ace's remaining after this is called.
|
||||
void security_descriptor_remove_trustee(security_descriptor *sd, const QList<QByteArray> &trustee_list);
|
||||
|
||||
// "Complete" versions of add/remove right f-ns that do A
|
||||
// LOT more than just add rights. They also take care
|
||||
// of superior and subordinate rights to follow a logic
|
||||
// of a typical gui checklist of rights.
|
||||
void security_descriptor_add_right(security_descriptor *sd, AdConfig *adconfig, const QList<QString> &class_list, const QByteArray &trustee, const uint32_t access_mask, const QByteArray &object_type, const bool allow);
|
||||
void security_descriptor_remove_right(security_descriptor *sd, AdConfig *adconfig, const QList<QString> &class_list, const QByteArray &trustee, const uint32_t access_mask, const QByteArray &object_type, const bool allow);
|
||||
|
||||
QList<SecurityRight> ad_security_get_right_list_for_class(AdConfig *adconfig, const QList<QString> &class_list);
|
||||
QList<SecurityRight> ad_security_get_superior_right_list(const uint32_t access_mask, const QByteArray &object_type);
|
||||
QList<SecurityRight> ad_security_get_subordinate_right_list(AdConfig *adconfig, const uint32_t access_mask, const QByteArray &object_type, const QList<QString> &class_list);
|
||||
|
||||
#endif /* AD_SECURITY_H */
|
||||
|
@ -126,9 +126,10 @@ QString account_option_string(const AccountOption &option) {
|
||||
switch (option) {
|
||||
case AccountOption_Disabled: return QCoreApplication::translate("ad_utils", "Account disabled");
|
||||
case AccountOption_CantChangePassword: return QCoreApplication::translate("ad_utils", "User cannot change password");
|
||||
case AccountOption_AllowReversibleEncryption: return QCoreApplication::translate("ad_utils", "Store password using reversible encryption");
|
||||
case AccountOption_PasswordExpired: return QCoreApplication::translate("ad_utils", "User must change password on next logon");
|
||||
case AccountOption_DontExpirePassword: return QCoreApplication::translate("ad_utils", "Don't expire password");
|
||||
case AccountOption_UseDesKey: return QCoreApplication::translate("ad_utils", "Store password using reversible encryption");
|
||||
case AccountOption_UseDesKey: return QCoreApplication::translate("ad_utils", "Use Kerberos DES encryption types for this account");
|
||||
case AccountOption_SmartcardRequired: return QCoreApplication::translate("ad_utils", "Smartcard is required for interactive logon");
|
||||
case AccountOption_CantDelegate: return QCoreApplication::translate("ad_utils", "Account is sensitive and cannot be delegated");
|
||||
case AccountOption_DontRequirePreauth: return QCoreApplication::translate("ad_utils", "Don't require Kerberos preauthentication");
|
||||
@ -142,18 +143,20 @@ QString account_option_string(const AccountOption &option) {
|
||||
int account_option_bit(const AccountOption &option) {
|
||||
switch (option) {
|
||||
case AccountOption_Disabled:
|
||||
return 0x00000002;
|
||||
return UAC_ACCOUNTDISABLE;
|
||||
case AccountOption_AllowReversibleEncryption:
|
||||
return UAC_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
|
||||
case AccountOption_DontExpirePassword:
|
||||
return 0x00010000;
|
||||
return UAC_DONT_EXPIRE_PASSWORD;
|
||||
case AccountOption_UseDesKey:
|
||||
return 0x00200000;
|
||||
return UAC_USE_DES_KEY_ONLY;
|
||||
case AccountOption_SmartcardRequired:
|
||||
return 0x00040000;
|
||||
return UAC_SMARTCARD_REQUIRED;
|
||||
case AccountOption_DontRequirePreauth:
|
||||
return 0x00400000;
|
||||
case AccountOption_CantDelegate: return 0x00100000;
|
||||
return UAC_DONT_REQUIRE_PREAUTH;
|
||||
case AccountOption_CantDelegate: return UAC_NOT_DELEGATED;
|
||||
case AccountOption_TrustedForDelegation:
|
||||
return 0x00080000;
|
||||
return UAC_TRUSTED_FOR_DELEGATION;
|
||||
|
||||
// NOTE: not all account options can be directly
|
||||
// mapped to bits
|
||||
@ -344,28 +347,16 @@ QString get_default_domain_from_krb5() {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Transform domain to domain DN
|
||||
// "DOMAIN.COM" => "DC=domain,DC=com"
|
||||
QString domain_to_domain_dn(const QString &domain) {
|
||||
QString domain_dn = domain;
|
||||
|
||||
domain_dn = domain_dn.toLower();
|
||||
domain_dn = "DC=" + domain_dn;
|
||||
domain_dn = domain_dn.replace(".", ",DC=");
|
||||
|
||||
return domain_dn;
|
||||
}
|
||||
|
||||
int bit_set(int bitmask, int bit, bool set) {
|
||||
if (set) {
|
||||
return bitmask | bit;
|
||||
int bitmask_set(const int input_mask, const int mask_to_set, const bool is_set) {
|
||||
if (is_set) {
|
||||
return input_mask | mask_to_set;
|
||||
} else {
|
||||
return bitmask & ~bit;
|
||||
return input_mask & ~mask_to_set;
|
||||
}
|
||||
}
|
||||
|
||||
bool bit_is_set(int bitmask, int bit) {
|
||||
return ((bitmask & bit) != 0);
|
||||
bool bitmask_is_set(const int input_mask, const int mask_to_read) {
|
||||
return ((input_mask & mask_to_read) == mask_to_read);
|
||||
}
|
||||
|
||||
const char *cstr(const QString &qstr) {
|
||||
@ -452,3 +443,7 @@ QString attribute_type_display_string(const AttributeType type) {
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString int_to_hex_string(const int n) {
|
||||
return QString("0x%1").arg(n, 8, 16, QLatin1Char('0'));
|
||||
}
|
||||
|
@ -64,10 +64,9 @@ QString dn_canonical(const QString &dn);
|
||||
QString dn_from_name_and_parent(const QString &name, const QString &parent, const QString &object_class);
|
||||
|
||||
QString get_default_domain_from_krb5();
|
||||
QString domain_to_domain_dn(const QString &domain);
|
||||
|
||||
int bit_set(int bitmask, int bit, bool set);
|
||||
bool bit_is_set(int bitmask, int bit);
|
||||
int bitmask_set(const int input_mask, const int mask_to_set, const bool is_set);
|
||||
bool bitmask_is_set(const int input_mask, const int mask_to_read);
|
||||
|
||||
// NOTE: uses a buffer that is capped at 100 strings, so
|
||||
// pointers returned from this become invalid after 99 more
|
||||
@ -84,4 +83,6 @@ QByteArray sid_string_to_bytes(const QString &sid_string);
|
||||
|
||||
QString attribute_type_display_string(const AttributeType type);
|
||||
|
||||
QString int_to_hex_string(const int n);
|
||||
|
||||
#endif /* AD_UTILS_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -205,7 +205,7 @@ bool Gplink::get_option(const QString &gpo_case, const GplinkOption option) cons
|
||||
}
|
||||
|
||||
const int option_bits = options[gpo];
|
||||
const bool is_set = bit_is_set(option_bits, (int) option);
|
||||
const bool is_set = bitmask_is_set(option_bits, (int) option);
|
||||
|
||||
return is_set;
|
||||
}
|
||||
@ -218,7 +218,7 @@ void Gplink::set_option(const QString &gpo_case, const GplinkOption option, cons
|
||||
}
|
||||
|
||||
const int option_bits = options[gpo];
|
||||
const int option_bits_new = bit_set(option_bits, (int) option, value);
|
||||
const int option_bits_new = bitmask_set(option_bits, (int) option, value);
|
||||
options[gpo] = option_bits_new;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ set(ADMC_SOURCES
|
||||
globals.cpp
|
||||
utils.cpp
|
||||
settings.cpp
|
||||
widget_state.cpp
|
||||
|
||||
main_window.cpp
|
||||
main_window_connection_error.cpp
|
||||
@ -43,19 +42,22 @@ set(ADMC_SOURCES
|
||||
tab_widget.cpp
|
||||
policy_results_widget.cpp
|
||||
edit_query_item_widget.cpp
|
||||
fsmo_tab.cpp
|
||||
|
||||
console_filter_dialog.cpp
|
||||
password_dialog.cpp
|
||||
rename_object_dialog.cpp
|
||||
rename_object_helper.cpp
|
||||
rename_other_dialog.cpp
|
||||
rename_policy_dialog.cpp
|
||||
rename_user_dialog.cpp
|
||||
rename_group_dialog.cpp
|
||||
create_object_dialog.cpp
|
||||
create_object_helper.cpp
|
||||
create_user_dialog.cpp
|
||||
create_group_dialog.cpp
|
||||
create_computer_dialog.cpp
|
||||
create_ou_dialog.cpp
|
||||
create_shared_folder_dialog.cpp
|
||||
create_contact_dialog.cpp
|
||||
create_policy_dialog.cpp
|
||||
create_query_item_dialog.cpp
|
||||
create_query_folder_dialog.cpp
|
||||
@ -71,9 +73,11 @@ set(ADMC_SOURCES
|
||||
properties_dialog.cpp
|
||||
properties_multi_dialog.cpp
|
||||
properties_warning_dialog.cpp
|
||||
security_sort_warning_dialog.cpp
|
||||
connection_options_dialog.cpp
|
||||
changelog_dialog.cpp
|
||||
error_log_dialog.cpp
|
||||
fsmo_dialog.cpp
|
||||
|
||||
filter_widget/filter_widget.cpp
|
||||
filter_widget/filter_dialog.cpp
|
||||
@ -85,12 +89,12 @@ set(ADMC_SOURCES
|
||||
filter_widget/class_filter_dialog.cpp
|
||||
filter_widget/select_base_widget.cpp
|
||||
|
||||
tabs/properties_tab.cpp
|
||||
tabs/general_user_tab.cpp
|
||||
tabs/general_group_tab.cpp
|
||||
tabs/general_ou_tab.cpp
|
||||
tabs/general_computer_tab.cpp
|
||||
tabs/general_policy_tab.cpp
|
||||
tabs/general_shared_folder_tab.cpp
|
||||
tabs/general_other_tab.cpp
|
||||
tabs/object_tab.cpp
|
||||
tabs/attributes_tab.cpp
|
||||
@ -100,7 +104,6 @@ set(ADMC_SOURCES
|
||||
tabs/membership_tab.cpp
|
||||
tabs/address_tab.cpp
|
||||
tabs/group_policy_tab.cpp
|
||||
tabs/gpo_links_tab.cpp
|
||||
tabs/organization_tab.cpp
|
||||
tabs/telephones_tab.cpp
|
||||
tabs/profile_tab.cpp
|
||||
@ -109,8 +112,9 @@ set(ADMC_SOURCES
|
||||
tabs/os_tab.cpp
|
||||
tabs/delegation_tab.cpp
|
||||
tabs/select_well_known_trustee_dialog.cpp
|
||||
tabs/laps_tab.cpp
|
||||
tabs/error_tab.cpp
|
||||
|
||||
multi_tabs/properties_multi_tab.cpp
|
||||
multi_tabs/general_user_multi_tab.cpp
|
||||
multi_tabs/general_other_multi_tab.cpp
|
||||
multi_tabs/account_multi_tab.cpp
|
||||
@ -121,8 +125,10 @@ set(ADMC_SOURCES
|
||||
attribute_edits/attribute_edit.cpp
|
||||
attribute_edits/string_edit.cpp
|
||||
attribute_edits/string_other_edit.cpp
|
||||
attribute_edits/string_list_edit.cpp
|
||||
attribute_edits/string_large_edit.cpp
|
||||
attribute_edits/sam_name_edit.cpp
|
||||
attribute_edits/computer_sam_name_edit.cpp
|
||||
attribute_edits/country_edit.cpp
|
||||
attribute_edits/expiry_edit.cpp
|
||||
attribute_edits/expiry_widget.cpp
|
||||
@ -144,14 +150,11 @@ set(ADMC_SOURCES
|
||||
attribute_edits/logon_computers_edit.cpp
|
||||
attribute_edits/logon_computers_dialog.cpp
|
||||
attribute_edits/protect_deletion_edit.cpp
|
||||
attribute_edits/laps_expiry_edit.cpp
|
||||
attribute_edits/general_name_edit.cpp
|
||||
|
||||
attribute_multi_edits/attribute_multi_edit.cpp
|
||||
attribute_multi_edits/string_multi_edit.cpp
|
||||
attribute_multi_edits/expiry_multi_edit.cpp
|
||||
attribute_multi_edits/upn_multi_edit.cpp
|
||||
attribute_multi_edits/account_option_multi_edit.cpp
|
||||
attribute_multi_edits/country_multi_edit.cpp
|
||||
attribute_multi_edits/manager_multi_edit.cpp
|
||||
attribute_edits/upn_multi_edit.cpp
|
||||
attribute_edits/account_option_multi_edit.cpp
|
||||
|
||||
attribute_dialogs/attribute_dialog.cpp
|
||||
attribute_dialogs/list_attribute_dialog.cpp
|
||||
@ -172,6 +175,7 @@ set(ADMC_SOURCES
|
||||
console_impls/query_item_impl.cpp
|
||||
console_impls/query_folder_impl.cpp
|
||||
console_impls/policy_root_impl.cpp
|
||||
console_impls/find_root_impl.cpp
|
||||
|
||||
admc.qrc
|
||||
)
|
||||
@ -211,3 +215,9 @@ if(NOT ADMC_BUILD_DEB)
|
||||
install(TARGETS admctest DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
endif(NOT ADMC_BUILD_DEB)
|
||||
|
||||
install(
|
||||
FILES data/admc.svg
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>428</width>
|
||||
<height>300</height>
|
||||
<width>432</width>
|
||||
<height>164</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -15,9 +15,16 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="version_label">
|
||||
<widget class="QLabel" name="label_1">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>20</pointsize>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Version x.y.z (placeholder)</string>
|
||||
<string notr="true">ADMC</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
@ -25,19 +32,32 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>ADMC is a tool for Active Directory administration.</string>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Copyright (C) 2021 BaseALT Ltd.</string>
|
||||
<string>Copyright (C) 2022 BaseALT Ltd.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="version_label">
|
||||
<property name="text">
|
||||
<string notr="true">Version x.y.z (placeholder)</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
|
@ -3,5 +3,6 @@
|
||||
<file alias="countries.csv">data/countries.csv</file>
|
||||
<file>admc_ru.qm</file>
|
||||
<file>admc_en.qm</file>
|
||||
<file alias="admc.svg">data/admc.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
1308
src/admc/admc_en.ts
1308
src/admc/admc_en.ts
File diff suppressed because it is too large
Load Diff
1344
src/admc/admc_ru.ts
1344
src/admc/admc_ru.ts
File diff suppressed because it is too large
Load Diff
@ -30,29 +30,6 @@ AttributeDialog::AttributeDialog(const QString &attribute, const bool read_only,
|
||||
: QDialog(parent) {
|
||||
m_attribute = attribute;
|
||||
m_read_only = read_only;
|
||||
|
||||
const QString title = [&]() {
|
||||
const AttributeType type = g_adconfig->get_attribute_type(m_attribute);
|
||||
const bool single_valued = g_adconfig->get_attribute_is_single_valued(attribute);
|
||||
|
||||
const QString title_action = [&]() {
|
||||
if (m_read_only) {
|
||||
return tr("Edit");
|
||||
} else {
|
||||
return tr("View");
|
||||
}
|
||||
}();
|
||||
|
||||
const QString title_attribute = attribute_type_display_string(type);
|
||||
|
||||
if (single_valued) {
|
||||
return QString("%1 %2").arg(title_action, title_attribute);
|
||||
} else {
|
||||
return QString(tr("%1 Multi-Valued %2", "This is a dialog title for attribute editors. Example: \"Edit Multi-Valued String\"")).arg(title_action, title_attribute);
|
||||
}
|
||||
}();
|
||||
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
QString AttributeDialog::get_attribute() const {
|
||||
|
@ -37,6 +37,9 @@ ListAttributeDialog::ListAttributeDialog(const QList<QByteArray> &value_list, co
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// Default value indiciating no max length
|
||||
max_length = 0;
|
||||
|
||||
AttributeDialog::load_attribute_label(ui->attribute_label);
|
||||
|
||||
ui->add_button->setVisible(!read_only);
|
||||
@ -60,6 +63,35 @@ ListAttributeDialog::~ListAttributeDialog() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ListAttributeDialog::accept() {
|
||||
const bool contains_empty_values = [&]() {
|
||||
const bool is_bool = (g_adconfig->get_attribute_type(get_attribute()) == AttributeType_Boolean);
|
||||
if (is_bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QList<QByteArray> value_list = get_value_list();
|
||||
|
||||
for (const QByteArray &value : value_list) {
|
||||
const QString value_string = QString(value);
|
||||
const bool value_is_all_spaces = (value.count(' ') == value.length());
|
||||
const bool value_is_empty = value.isEmpty() || value_is_all_spaces;
|
||||
|
||||
if (value_is_empty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (contains_empty_values) {
|
||||
message_box_warning(this, tr("Error"), tr("One or more values are empty. Edit or remove them to proceed."));
|
||||
} else {
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
void ListAttributeDialog::on_add_button() {
|
||||
AttributeDialog *dialog = [this]() -> AttributeDialog * {
|
||||
const bool is_bool = (g_adconfig->get_attribute_type(get_attribute()) == AttributeType_Boolean);
|
||||
@ -70,14 +102,19 @@ void ListAttributeDialog::on_add_button() {
|
||||
if (is_bool) {
|
||||
return new BoolAttributeDialog(value_list, attribute, read_only, this);
|
||||
} else {
|
||||
return new StringAttributeDialog(value_list, attribute, read_only, this);
|
||||
auto string_dialog = new StringAttributeDialog(value_list, attribute, read_only, this);
|
||||
string_dialog->set_max_length(max_length);
|
||||
|
||||
return string_dialog;
|
||||
}
|
||||
}();
|
||||
|
||||
dialog->setWindowTitle(tr("Add Value"));
|
||||
dialog->open();
|
||||
|
||||
connect(
|
||||
dialog, &QDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
const QList<QByteArray> new_values = dialog->get_value_list();
|
||||
|
||||
@ -110,9 +147,18 @@ QList<QByteArray> ListAttributeDialog::get_value_list() const {
|
||||
return new_values;
|
||||
}
|
||||
|
||||
void ListAttributeDialog::set_value_max_length(const int max_length_arg) {
|
||||
max_length = max_length_arg;
|
||||
}
|
||||
|
||||
void ListAttributeDialog::add_value(const QByteArray value) {
|
||||
const QString text = bytes_to_string(value);
|
||||
ui->list_widget->addItem(text);
|
||||
const QList<QListWidgetItem *> find_results = ui->list_widget->findItems(text, Qt::MatchExactly);
|
||||
const bool value_already_exists = !find_results.isEmpty();
|
||||
|
||||
if (!value_already_exists) {
|
||||
ui->list_widget->addItem(text);
|
||||
}
|
||||
}
|
||||
|
||||
ListAttributeDialogType ListAttributeDialog::get_type() const {
|
||||
|
@ -44,9 +44,21 @@ public:
|
||||
ListAttributeDialog(const QList<QByteArray> &value_list, const QString &attribute, const bool read_only, QWidget *parent);
|
||||
~ListAttributeDialog();
|
||||
|
||||
void accept() override;
|
||||
|
||||
QList<QByteArray> get_value_list() const override;
|
||||
|
||||
// Sets max length for input of individual values
|
||||
// of the list attribute, if it's of string type.
|
||||
// Note that this *does not* apply to the list
|
||||
// attribute itself. By default the limit from
|
||||
// schema is used, but most list attributes are
|
||||
// unlimited.
|
||||
void set_value_max_length(const int max_length);
|
||||
|
||||
private:
|
||||
int max_length;
|
||||
|
||||
void on_add_button();
|
||||
void on_remove_button();
|
||||
void add_value(const QByteArray value);
|
||||
|
@ -47,7 +47,7 @@ StringAttributeDialog::StringAttributeDialog(const QList<QByteArray> &value_list
|
||||
const QString value_string = QString(value);
|
||||
ui->edit->setText(value_string);
|
||||
|
||||
settings_setup_dialog_geometry(SETTING_list_attribute_dialog_geometry, this);
|
||||
settings_setup_dialog_geometry(SETTING_string_attribute_dialog_geometry, this);
|
||||
}
|
||||
|
||||
StringAttributeDialog::~StringAttributeDialog() {
|
||||
@ -64,3 +64,9 @@ QList<QByteArray> StringAttributeDialog::get_value_list() const {
|
||||
return {new_value};
|
||||
}
|
||||
}
|
||||
|
||||
void StringAttributeDialog::set_max_length(const int max_length) {
|
||||
if (max_length > 0) {
|
||||
ui->edit->setMaxLength(max_length);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,11 @@ public:
|
||||
~StringAttributeDialog();
|
||||
|
||||
QList<QByteArray> get_value_list() const override;
|
||||
|
||||
// NOTE: by default, most (not all) attributes have
|
||||
// a pre-defined max length that is obtained from
|
||||
// schema. Calling this f-n overrides it.
|
||||
void set_max_length(const int max_length);
|
||||
};
|
||||
|
||||
#endif /* STRING_ATTRIBUTE_DIALOG_H */
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include <QGroupBox>
|
||||
#include <QMap>
|
||||
|
||||
AccountOptionEdit::AccountOptionEdit(QCheckBox *check_arg, const AccountOption option_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
AccountOptionEdit::AccountOptionEdit(QCheckBox *check_arg, const AccountOption option_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
option = option_arg;
|
||||
check = check_arg;
|
||||
|
||||
@ -39,17 +39,13 @@ AccountOptionEdit::AccountOptionEdit(QCheckBox *check_arg, const AccountOption o
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void AccountOptionEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void AccountOptionEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const bool option_is_set = object.get_account_option(option, g_adconfig);
|
||||
check->setChecked(option_is_set);
|
||||
}
|
||||
|
||||
void AccountOptionEdit::set_read_only(const bool read_only) {
|
||||
check->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool AccountOptionEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool new_value = check->isChecked();
|
||||
const bool success = ad.user_set_account_option(dn, option, new_value);
|
||||
@ -74,6 +70,7 @@ void account_option_setup_conflicts(const QHash<AccountOption, QCheckBox *> &che
|
||||
|
||||
QObject::connect(
|
||||
subject, &QCheckBox::clicked,
|
||||
blocker,
|
||||
[subject, blocker, subject_option, blocker_option]() {
|
||||
const bool conflict = (subject->isChecked() && blocker->isChecked());
|
||||
if (conflict) {
|
||||
|
@ -31,8 +31,10 @@ class QWidget;
|
||||
class AccountOptionEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountOptionEdit(QCheckBox *check, const AccountOption option_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
AccountOptionEdit(QCheckBox *check, const AccountOption option_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
AccountOption option;
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "attribute_multi_edits/account_option_multi_edit.h"
|
||||
#include "attribute_edits/account_option_multi_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "attribute_edits/account_option_edit.h"
|
||||
@ -26,13 +26,11 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
AccountOptionMultiEdit::AccountOptionMultiEdit(const QHash<AccountOption, QCheckBox *> &check_map_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, QObject *parent)
|
||||
: AttributeMultiEdit(check, edits_out, parent) {
|
||||
AccountOptionMultiEdit::AccountOptionMultiEdit(const QHash<AccountOption, QCheckBox *> &check_map_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
check_map = check_map_arg;
|
||||
|
||||
account_option_setup_conflicts(check_map);
|
||||
|
||||
set_enabled(false);
|
||||
}
|
||||
|
||||
// NOTE: this is slightly inefficient because every account
|
||||
@ -40,7 +38,7 @@ AccountOptionMultiEdit::AccountOptionMultiEdit(const QHash<AccountOption, QCheck
|
||||
// bitmask can be changed at the same time. BUT, do need to
|
||||
// do this if want to get separate status messages for each
|
||||
// bit.
|
||||
bool AccountOptionMultiEdit::apply_internal(AdInterface &ad, const QString &target) {
|
||||
bool AccountOptionMultiEdit::apply(AdInterface &ad, const QString &target) const {
|
||||
const QList<AccountOption> option_change_list = [&]() {
|
||||
QList<AccountOption> out;
|
||||
|
||||
@ -77,9 +75,7 @@ bool AccountOptionMultiEdit::apply_internal(AdInterface &ad, const QString &targ
|
||||
}
|
||||
|
||||
void AccountOptionMultiEdit::set_enabled(const bool enabled) {
|
||||
if (!enabled) {
|
||||
for (QCheckBox *check : check_map.values()) {
|
||||
check->setChecked(false);
|
||||
}
|
||||
for (QCheckBox *check : check_map.values()) {
|
||||
check->setEnabled(enabled);
|
||||
}
|
||||
}
|
@ -21,18 +21,28 @@
|
||||
#ifndef ACCOUNT_OPTION_MULTI_EDIT_H
|
||||
#define ACCOUNT_OPTION_MULTI_EDIT_H
|
||||
|
||||
#include "attribute_multi_edits/attribute_multi_edit.h"
|
||||
/**
|
||||
* Edit for editing account options of multiple objects
|
||||
* at the same time. Needed because in this case all of
|
||||
* the checks are grouped together, unlike the normal
|
||||
* account option edit.
|
||||
*/
|
||||
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
#include "ad_defines.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
class AccountOptionMultiEdit final : public AttributeMultiEdit {
|
||||
class QCheckBox;
|
||||
|
||||
class AccountOptionMultiEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountOptionMultiEdit(const QHash<AccountOption, QCheckBox *> &check_map_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, QObject *parent);
|
||||
AccountOptionMultiEdit(const QHash<AccountOption, QCheckBox *> &check_map, QObject *parent);
|
||||
|
||||
DECL_ATTRIBUTE_MULTI_EDIT_VIRTUALS();
|
||||
bool apply(AdInterface &ad, const QString &target) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
private:
|
||||
QHash<AccountOption, QCheckBox *> check_map;
|
@ -20,34 +20,8 @@
|
||||
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
#include "tabs/properties_tab.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
AttributeEdit::AttributeEdit(QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: QObject(parent) {
|
||||
if (edits_out != nullptr) {
|
||||
if (edits_out->contains(this)) {
|
||||
qDebug() << "ERROR: attribute edit added twice to list!";
|
||||
} else {
|
||||
edits_out->append(this);
|
||||
}
|
||||
}
|
||||
|
||||
m_modified = false;
|
||||
connect(
|
||||
this, &AttributeEdit::edited,
|
||||
[this]() {
|
||||
m_modified = true;
|
||||
});
|
||||
}
|
||||
|
||||
void AttributeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
load_internal(ad, object);
|
||||
m_modified = false;
|
||||
}
|
||||
|
||||
bool AttributeEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(dn);
|
||||
@ -55,70 +29,50 @@ bool AttributeEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttributeEdit::modified() const {
|
||||
return m_modified;
|
||||
}
|
||||
bool AttributeEdit::verify(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const QString &dn) {
|
||||
for (auto edit : edit_list) {
|
||||
const bool verify_success = edit->verify(ad, dn);
|
||||
|
||||
void AttributeEdit::set_modified(const bool modified) {
|
||||
m_modified = modified;
|
||||
}
|
||||
|
||||
void AttributeEdit::reset_modified() {
|
||||
m_modified = false;
|
||||
}
|
||||
|
||||
bool edits_verify(AdInterface &ad, QList<AttributeEdit *> edits, const QString &dn, const bool ignore_modified) {
|
||||
for (auto edit : edits) {
|
||||
if (edit->modified() || ignore_modified) {
|
||||
const bool verify_success = edit->verify(ad, dn);
|
||||
if (!verify_success) {
|
||||
return false;
|
||||
}
|
||||
if (!verify_success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool edits_apply(AdInterface &ad, QList<AttributeEdit *> edits, const QString &dn) {
|
||||
bool AttributeEdit::apply(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const QString &dn) {
|
||||
bool success = true;
|
||||
|
||||
for (auto edit : edits) {
|
||||
if (edit->modified()) {
|
||||
const bool apply_success = edit->apply(ad, dn);
|
||||
if (apply_success) {
|
||||
edit->reset_modified();
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
for (auto edit : edit_list) {
|
||||
const bool apply_success = edit->apply(ad, dn);
|
||||
|
||||
if (!apply_success) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void edits_load(QList<AttributeEdit *> edits, AdInterface &ad, const AdObject &object) {
|
||||
for (auto edit : edits) {
|
||||
void AttributeEdit::load(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const AdObject &object) {
|
||||
for (auto edit : edit_list) {
|
||||
edit->load(ad, object);
|
||||
}
|
||||
}
|
||||
|
||||
void edits_connect_to_tab(QList<AttributeEdit *> edits, PropertiesTab *tab) {
|
||||
for (auto edit : edits) {
|
||||
QObject::connect(
|
||||
edit, &AttributeEdit::edited,
|
||||
tab, &PropertiesTab::on_edit_edited);
|
||||
}
|
||||
void AttributeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(object);
|
||||
}
|
||||
|
||||
void edits_set_read_only(QList<AttributeEdit *> edits, const bool read_only) {
|
||||
for (AttributeEdit *edit : edits) {
|
||||
edit->set_read_only(read_only);
|
||||
}
|
||||
bool AttributeEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(dn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void edits_set_modified(QList<AttributeEdit *> edits, const bool modified) {
|
||||
for (AttributeEdit *edit : edits) {
|
||||
edit->set_modified(modified);
|
||||
}
|
||||
void AttributeEdit::set_enabled(const bool enabled) {
|
||||
UNUSED_ARG(enabled);
|
||||
}
|
||||
|
@ -30,20 +30,34 @@
|
||||
* are used to represent different data types.
|
||||
*/
|
||||
|
||||
class PropertiesTab;
|
||||
class AdInterface;
|
||||
class AdObject;
|
||||
|
||||
class AttributeEdit : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AttributeEdit(QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
|
||||
// Load state from object, used to initialize or reset edit
|
||||
// Calls load_internal() implemented by subclasses
|
||||
void load(AdInterface &ad, const AdObject &object);
|
||||
// Verify edit. Verify process will stop on first
|
||||
// failure. This is so that only one failure message is
|
||||
// shown at a time.
|
||||
static bool verify(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const QString &dn);
|
||||
|
||||
virtual void set_read_only(const bool read_only) = 0;
|
||||
// Applies edits. If one of the edits fails to apply
|
||||
// midway, the apply process still continues. This is
|
||||
// so that if more errors occur, they are all gathered
|
||||
// together and presented to the user together. If
|
||||
// process stopped on first error, the user would have
|
||||
// to apply multiple times while fixing errors to see
|
||||
// all of them.
|
||||
static bool apply(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const QString &dn);
|
||||
|
||||
static void load(const QList<AttributeEdit *> &edit_list, AdInterface &ad, const AdObject &object);
|
||||
|
||||
using QObject::QObject;
|
||||
|
||||
// Load state from object, used to initialize or
|
||||
// reset edit.
|
||||
virtual void load(AdInterface &ad, const AdObject &object);
|
||||
|
||||
// Verify current input. This is for the kinds of errors
|
||||
// that the server doesn't or can't check for. For
|
||||
@ -53,67 +67,13 @@ public:
|
||||
|
||||
// Apply current input by making a modification to the
|
||||
// AD server
|
||||
virtual bool apply(AdInterface &ad, const QString &dn) const = 0;
|
||||
virtual bool apply(AdInterface &ad, const QString &dn) const;
|
||||
|
||||
// Returns whether edit was edited by user. Rsets on
|
||||
// load(). Note that this will be true if user EVER
|
||||
// edited this edit. This won't become false if user
|
||||
// manually undoes changes by retyping original value
|
||||
// for StringEdit for example.
|
||||
bool modified() const;
|
||||
void set_modified(const bool modified);
|
||||
|
||||
void reset_modified();
|
||||
virtual void set_enabled(const bool enabled);
|
||||
|
||||
signals:
|
||||
// Emitted when edit was edited by user
|
||||
void edited();
|
||||
|
||||
protected:
|
||||
virtual void load_internal(AdInterface &ad, const AdObject &object) = 0;
|
||||
|
||||
private:
|
||||
bool m_modified;
|
||||
};
|
||||
|
||||
#define DECL_ATTRIBUTE_EDIT_VIRTUALS() \
|
||||
void set_read_only(const bool read_only) override; \
|
||||
bool apply(AdInterface &ad, const QString &dn) const override; \
|
||||
\
|
||||
protected: \
|
||||
void load_internal(AdInterface &ad, const AdObject &object) override; \
|
||||
\
|
||||
public:
|
||||
|
||||
// Helper f-ns that iterate over edit lists for you
|
||||
void edits_connect_to_tab(QList<AttributeEdit *> edits, PropertiesTab *tab);
|
||||
|
||||
// NOTE: "ignore_modified" argument is solely for a edge
|
||||
// case in CreateObjectDialog. If it's set to true, then edits are
|
||||
// verified/applied regardless or whether they are modified
|
||||
// or not
|
||||
|
||||
// Verify all edits that were modified. Verify process will
|
||||
// stop on first failure. This is so that only one failure
|
||||
// message is shown at a time.
|
||||
bool edits_verify(AdInterface &ad, QList<AttributeEdit *> edits, const QString &dn, const bool ignore_modified = false);
|
||||
|
||||
// Applies all edits that were modified. If one of the edits
|
||||
// fails to apply midway, the apply process still continues.
|
||||
// This is so that if more errors occur, they are all
|
||||
// gathered together and presented to the user together. If
|
||||
// process stopped on first error, the user would have to
|
||||
// apply multiple times while fixing errors to see all of
|
||||
// them.
|
||||
bool edits_apply(AdInterface &ad, QList<AttributeEdit *> edits, const QString &dn);
|
||||
|
||||
void edits_load(QList<AttributeEdit *> edits, AdInterface &ad, const AdObject &object);
|
||||
|
||||
// NOTE: not all edits might support read-only mode, see
|
||||
// specific edit headers to verify that they implement
|
||||
// set_read_only()
|
||||
void edits_set_read_only(QList<AttributeEdit *> edits, const bool read_only);
|
||||
|
||||
void edits_set_modified(QList<AttributeEdit *> edits, const bool modified);
|
||||
|
||||
#endif /* ATTRIBUTE_EDIT_H */
|
||||
|
88
src/admc/attribute_edits/computer_sam_name_edit.cpp
Normal file
88
src/admc/attribute_edits/computer_sam_name_edit.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 "attribute_edits/computer_sam_name_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
#include "attribute_edits/sam_name_edit.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QRegularExpression>
|
||||
|
||||
ComputerSamNameEdit::ComputerSamNameEdit(QLineEdit *edit_arg, QLineEdit *domain_edit, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit = edit_arg;
|
||||
|
||||
edit->setMaxLength(SAM_NAME_COMPUTER_MAX_LENGTH);
|
||||
|
||||
const QString domain_text = []() {
|
||||
const QString domain = g_adconfig->domain();
|
||||
const QString domain_name = domain.split(".")[0];
|
||||
const QString out = domain_name + "\\";
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
domain_edit->setText(domain_text);
|
||||
|
||||
connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void ComputerSamNameEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
// NOTE: display value without the '$' at the end
|
||||
const QString value = [&]() {
|
||||
QString out = object.get_string(ATTRIBUTE_SAM_ACCOUNT_NAME);
|
||||
|
||||
if (out.endsWith('$')) {
|
||||
out.chop(1);
|
||||
}
|
||||
|
||||
return out;
|
||||
}();
|
||||
edit->setText(value);
|
||||
}
|
||||
|
||||
// NOTE: requirements are from here
|
||||
// https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx#Note_Regarding_the_quot_quot_Character_in_sAMAccountName
|
||||
bool ComputerSamNameEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(dn);
|
||||
|
||||
const bool out = sam_name_edit_verify(edit);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ComputerSamNameEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = QString("%1$").arg(edit->text());
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_SAM_ACCOUNT_NAME, new_value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ComputerSamNameEdit::set_enabled(const bool enabled) {
|
||||
edit->setEnabled(enabled);
|
||||
}
|
43
src/admc/attribute_edits/computer_sam_name_edit.h
Normal file
43
src/admc/attribute_edits/computer_sam_name_edit.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 COMPUTER_SAM_NAME_EDIT_H
|
||||
#define COMPUTER_SAM_NAME_EDIT_H
|
||||
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
class ComputerSamNameEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComputerSamNameEdit(QLineEdit *edit, QLineEdit *domain_edit, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool verify(AdInterface &ad, const QString &dn) const override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
void set_enabled(const bool enabled);
|
||||
|
||||
private:
|
||||
QLineEdit *edit;
|
||||
};
|
||||
|
||||
#endif /* COMPUTER_SAM_NAME_EDIT_H */
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "adldap.h"
|
||||
#include "globals.h"
|
||||
#include "settings.h"
|
||||
#include "status.h"
|
||||
#include "utils.h"
|
||||
|
||||
@ -34,10 +35,19 @@
|
||||
#define COUNTRY_CODE_NONE 0
|
||||
|
||||
bool loaded_country_data = false;
|
||||
QList<QString> all_countries;
|
||||
QHash<QString, int> string_to_code;
|
||||
QHash<int, QString> country_strings;
|
||||
QHash<int, QString> country_strings_ru;
|
||||
QHash<int, QString> country_abbreviations;
|
||||
QHash<QString, int> abbreviation_to_code;
|
||||
|
||||
enum CountryColumn {
|
||||
CountryColumn_Country,
|
||||
CountryColumn_CountryRu,
|
||||
CountryColumn_Abbreviation,
|
||||
CountryColumn_Code,
|
||||
CountryColumn_COUNT,
|
||||
};
|
||||
|
||||
void country_combo_load_data() {
|
||||
if (loaded_country_data) {
|
||||
@ -60,48 +70,131 @@ void country_combo_load_data() {
|
||||
|
||||
while (!file.atEnd()) {
|
||||
const QByteArray line_array = file.readLine();
|
||||
const QString line(line_array);
|
||||
const QList<QString> line_split = line.split(',');
|
||||
const QString line = QString(line_array);
|
||||
|
||||
// Split line by comma's, taking into
|
||||
// account that some comma's are inside
|
||||
// quoted parts and ignoring those.
|
||||
//
|
||||
// NOTE: there's definitely a better way to
|
||||
// do this
|
||||
const QList<QString> line_split = [&]() -> QList<QString> {
|
||||
|
||||
if (line.contains('\"')) {
|
||||
QList<QString> split_by_quotes = line.split('\"');
|
||||
split_by_quotes.removeAll("");
|
||||
|
||||
if (split_by_quotes.size() == 2) {
|
||||
QList<QString> split_rest = split_by_quotes[1].split(',');
|
||||
split_rest.removeAll("");
|
||||
|
||||
QList<QString> out;
|
||||
out.append(split_by_quotes[0]);
|
||||
out.append(split_rest);
|
||||
|
||||
return out;
|
||||
} else {
|
||||
return QList<QString>();
|
||||
}
|
||||
} else {
|
||||
return line.split(',');
|
||||
}
|
||||
}();
|
||||
|
||||
if (line_split.size() != CountryColumn_COUNT) {
|
||||
qDebug() << "country.csv contains malformed line: " << line;
|
||||
|
||||
if (line_split.size() != 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString country_string = line_split[0];
|
||||
const QString abbreviation = line_split[1];
|
||||
const QString code_string = line_split[2];
|
||||
const QString country_string = line_split[CountryColumn_Country];
|
||||
const QString country_string_ru = line_split[CountryColumn_CountryRu];
|
||||
const QString abbreviation = line_split[CountryColumn_Abbreviation];
|
||||
const QString code_string = line_split[CountryColumn_Code];
|
||||
const int code = code_string.toInt();
|
||||
|
||||
country_strings[code] = country_string;
|
||||
country_strings_ru[code] = country_string_ru;
|
||||
country_abbreviations[code] = abbreviation;
|
||||
abbreviation_to_code[abbreviation] = code;
|
||||
|
||||
all_countries.append(country_string);
|
||||
string_to_code[country_string] = code;
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Sort countries by name
|
||||
std::sort(all_countries.begin(), all_countries.end());
|
||||
|
||||
// Special case for "None" country
|
||||
const QString none_string = QCoreApplication::translate("country_widget", "None");
|
||||
string_to_code[none_string] = COUNTRY_CODE_NONE;
|
||||
all_countries.insert(0, none_string);
|
||||
country_strings[COUNTRY_CODE_NONE] = "";
|
||||
country_abbreviations[COUNTRY_CODE_NONE] = "";
|
||||
|
||||
loaded_country_data = true;
|
||||
}
|
||||
|
||||
void country_combo_init(QComboBox *combo) {
|
||||
// Fill combo with country names. Add country codes to
|
||||
// item data.
|
||||
for (auto country_string : all_countries) {
|
||||
const int code = string_to_code[country_string];
|
||||
const QHash<int, QString> name_map = [&]() {
|
||||
const bool locale_is_ru = [&]() {
|
||||
const QLocale locale = settings_get_variant(SETTING_locale).toLocale();
|
||||
const bool out = (locale.language() == QLocale::Russian);
|
||||
|
||||
combo->addItem(country_string, code);
|
||||
return out;
|
||||
}();
|
||||
|
||||
if (locale_is_ru) {
|
||||
return country_strings_ru;
|
||||
} else {
|
||||
return country_strings;
|
||||
}
|
||||
}();
|
||||
|
||||
// Generate order of countries that will be used to
|
||||
// fill the combo.
|
||||
//
|
||||
// NOTE: modify order of countries in the combo to
|
||||
// put a particular country at the top of the list.
|
||||
// If this program ever happens to be used outside
|
||||
// of that particular country, there is a feature
|
||||
// flag "SETTING_feature_current_locale_first".
|
||||
const QList<QString> country_list = [&]() {
|
||||
const QString country_russia = [&]() {
|
||||
const QLocale top_locale = [&]() {
|
||||
const bool current_locale_first = settings_get_variant(SETTING_feature_current_locale_first).toBool();
|
||||
|
||||
if (current_locale_first) {
|
||||
const QLocale current_locale = settings_get_variant(SETTING_locale).toLocale();
|
||||
|
||||
return current_locale;
|
||||
} else {
|
||||
const QLocale russia_locale = QLocale(QLocale::Russian, QLocale::Russia);
|
||||
|
||||
return russia_locale;
|
||||
}
|
||||
}();
|
||||
const QString locale_name = top_locale.name();
|
||||
const QList<QString> locale_name_split = locale_name.split("_");
|
||||
|
||||
if (locale_name_split.size() == 2) {
|
||||
const QString abbreviation = locale_name_split[1];
|
||||
const int code = abbreviation_to_code[abbreviation];
|
||||
const QString country_name = name_map[code];
|
||||
|
||||
return country_name;
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}();
|
||||
|
||||
QList<QString> out = name_map.values();
|
||||
std::sort(out.begin(), out.end());
|
||||
out.removeAll(country_russia);
|
||||
out.prepend(country_russia);
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
// Add "None" at the start
|
||||
combo->addItem(QCoreApplication::translate("country_widget", "None"), COUNTRY_CODE_NONE);
|
||||
|
||||
for (const QString &country : country_list) {
|
||||
const int code = name_map.key(country);
|
||||
|
||||
combo->addItem(country, code);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,17 +216,11 @@ void country_combo_load(QComboBox *combo, const AdObject &object) {
|
||||
bool country_combo_apply(const QComboBox *combo, AdInterface &ad, const QString &dn) {
|
||||
const int code = combo->currentData().toInt();
|
||||
|
||||
const bool country_code_is_known = (country_strings.contains(code) && country_abbreviations.contains(code));
|
||||
|
||||
if (!country_code_is_known) {
|
||||
qDebug() << "Unknown country code:" << code;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: this handles the COUNTRY_CODE_NONE case by
|
||||
// using empty strings for it's values
|
||||
const QString code_string = QString::number(code);
|
||||
const QString country_string = country_strings[code];
|
||||
const QString abbreviation = country_abbreviations[code];
|
||||
const QString country_string = country_strings.value(code, QString());
|
||||
const QString abbreviation = country_abbreviations.value(code, QString());
|
||||
|
||||
bool success = true;
|
||||
success = success && ad.attribute_replace_string(dn, ATTRIBUTE_COUNTRY_CODE, code_string);
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
CountryEdit::CountryEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
CountryEdit::CountryEdit(QComboBox *combo_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
combo = combo_arg;
|
||||
|
||||
country_combo_init(combo);
|
||||
@ -38,16 +38,16 @@ CountryEdit::CountryEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edits_out
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void CountryEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void CountryEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
country_combo_load(combo, object);
|
||||
}
|
||||
|
||||
void CountryEdit::set_read_only(const bool read_only) {
|
||||
combo->setEnabled(!read_only);
|
||||
}
|
||||
|
||||
bool CountryEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
return country_combo_apply(combo, ad, dn);
|
||||
}
|
||||
|
||||
void CountryEdit::set_enabled(const bool enabled) {
|
||||
combo->setEnabled(enabled);
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ class QComboBox;
|
||||
class CountryEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CountryEdit(QComboBox *combo, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
CountryEdit(QComboBox *combo, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
private:
|
||||
QComboBox *combo;
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
#include <QDateTimeEdit>
|
||||
|
||||
DateTimeEdit::DateTimeEdit(QDateTimeEdit *edit_arg, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
DateTimeEdit::DateTimeEdit(QDateTimeEdit *edit_arg, const QString &attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit = edit_arg;
|
||||
attribute = attribute_arg;
|
||||
attribute = attribute_arg;
|
||||
@ -39,7 +39,7 @@ DateTimeEdit::DateTimeEdit(QDateTimeEdit *edit_arg, const QString &attribute_arg
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void DateTimeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void DateTimeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QDateTime datetime = object.get_datetime(attribute, g_adconfig);
|
||||
@ -48,10 +48,6 @@ void DateTimeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
edit->setDateTime(datetime_local);
|
||||
}
|
||||
|
||||
void DateTimeEdit::set_read_only(const bool read_only) {
|
||||
edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool DateTimeEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QDateTime datetime_local = edit->dateTime();
|
||||
const QDateTime datetime = datetime_local.toUTC();
|
||||
|
@ -30,8 +30,10 @@ class QDateTimeEdit;
|
||||
class DateTimeEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DateTimeEdit(QDateTimeEdit *edit, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
DateTimeEdit(QDateTimeEdit *edit, const QString &attribute_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QString attribute;
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
#include <QRadioButton>
|
||||
|
||||
DelegationEdit::DelegationEdit(QRadioButton *off_button_arg, QRadioButton *on_button_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
DelegationEdit::DelegationEdit(QRadioButton *off_button_arg, QRadioButton *on_button_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
off_button = off_button_arg;
|
||||
on_button = on_button_arg;
|
||||
|
||||
@ -39,7 +39,7 @@ DelegationEdit::DelegationEdit(QRadioButton *off_button_arg, QRadioButton *on_bu
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void DelegationEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void DelegationEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const bool is_on = object.get_account_option(AccountOption_TrustedForDelegation, g_adconfig);
|
||||
@ -51,11 +51,6 @@ void DelegationEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
}
|
||||
}
|
||||
|
||||
void DelegationEdit::set_read_only(const bool read_only) {
|
||||
on_button->setEnabled(read_only);
|
||||
off_button->setEnabled(read_only);
|
||||
}
|
||||
|
||||
bool DelegationEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool is_on = [&]() {
|
||||
if (on_button->isChecked()) {
|
||||
|
@ -28,8 +28,10 @@ class QRadioButton;
|
||||
class DelegationEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DelegationEdit(QRadioButton *off_button, QRadioButton *on_button, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
DelegationEdit(QRadioButton *off_button, QRadioButton *on_button, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QRadioButton *off_button;
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
ExpiryEdit::ExpiryEdit(ExpiryWidget *edit_widget_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
ExpiryEdit::ExpiryEdit(ExpiryWidget *edit_widget_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit_widget = edit_widget_arg;
|
||||
|
||||
connect(
|
||||
@ -34,16 +34,16 @@ ExpiryEdit::ExpiryEdit(ExpiryWidget *edit_widget_arg, QList<AttributeEdit *> *ed
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void ExpiryEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void ExpiryEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
edit_widget->load(object);
|
||||
}
|
||||
|
||||
void ExpiryEdit::set_read_only(const bool read_only) {
|
||||
edit_widget->set_read_only(read_only);
|
||||
}
|
||||
|
||||
bool ExpiryEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
return edit_widget->apply(ad, dn);
|
||||
}
|
||||
|
||||
void ExpiryEdit::set_enabled(const bool enabled) {
|
||||
edit_widget->setEnabled(enabled);
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ class ExpiryWidget;
|
||||
class ExpiryEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ExpiryEdit(ExpiryWidget *edit_widget, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
ExpiryEdit(ExpiryWidget *edit_widget, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
private:
|
||||
ExpiryWidget *edit_widget;
|
||||
|
@ -33,18 +33,15 @@ ExpiryWidget::ExpiryWidget(QWidget *parent)
|
||||
ui = new Ui::ExpiryWidget();
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->never_check->setAutoExclusive(true);
|
||||
ui->end_of_check->setAutoExclusive(true);
|
||||
|
||||
auto button_group = new QButtonGroup(this);
|
||||
button_group->addButton(ui->never_check);
|
||||
button_group->addButton(ui->end_of_check);
|
||||
|
||||
connect(
|
||||
ui->never_check, &QCheckBox::stateChanged,
|
||||
ui->never_check, &QRadioButton::toggled,
|
||||
this, &ExpiryWidget::on_never_check);
|
||||
connect(
|
||||
ui->end_of_check, &QCheckBox::stateChanged,
|
||||
ui->end_of_check, &QRadioButton::toggled,
|
||||
this, &ExpiryWidget::on_end_of_check);
|
||||
connect(
|
||||
ui->date_edit, &QDateEdit::dateChanged,
|
||||
@ -86,12 +83,6 @@ void ExpiryWidget::load(const AdObject &object) {
|
||||
ui->date_edit->setDate(date);
|
||||
}
|
||||
|
||||
void ExpiryWidget::set_read_only(const bool read_only) {
|
||||
ui->never_check->setDisabled(read_only);
|
||||
ui->end_of_check->setDisabled(read_only);
|
||||
ui->date_edit->setReadOnly(read_only);
|
||||
}
|
||||
|
||||
bool ExpiryWidget::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool never = ui->never_check->isChecked();
|
||||
|
||||
|
@ -39,7 +39,6 @@ public:
|
||||
~ExpiryWidget();
|
||||
|
||||
void load(const AdObject &object);
|
||||
void set_read_only(const bool read_only);
|
||||
bool apply(AdInterface &ad, const QString &dn) const;
|
||||
|
||||
signals:
|
||||
|
@ -15,7 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="never_check">
|
||||
<widget class="QRadioButton" name="never_check">
|
||||
<property name="text">
|
||||
<string>Never</string>
|
||||
</property>
|
||||
@ -24,7 +24,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="end_of_check">
|
||||
<widget class="QRadioButton" name="end_of_check">
|
||||
<property name="text">
|
||||
<string>End of:</string>
|
||||
</property>
|
||||
|
53
src/admc/attribute_edits/general_name_edit.cpp
Normal file
53
src/admc/attribute_edits/general_name_edit.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 "attribute_edits/general_name_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
GeneralNameEdit::GeneralNameEdit(QLabel *label_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
label = label_arg;
|
||||
}
|
||||
|
||||
void GeneralNameEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString label_text = [&]() {
|
||||
const QString name_attribute = [&]() {
|
||||
const bool is_gpc = object.is_class(CLASS_GP_CONTAINER);
|
||||
|
||||
if (is_gpc) {
|
||||
return ATTRIBUTE_DISPLAY_NAME;
|
||||
} else {
|
||||
return ATTRIBUTE_NAME;
|
||||
}
|
||||
}();
|
||||
|
||||
const QString name = object.get_string(name_attribute);
|
||||
|
||||
return name;
|
||||
}();
|
||||
|
||||
label->setText(label_text);
|
||||
}
|
@ -18,37 +18,27 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GPO_LINKS_TAB_H
|
||||
#define GPO_LINKS_TAB_H
|
||||
|
||||
#include "tabs/properties_tab.h"
|
||||
|
||||
class QTreeView;
|
||||
class QStandardItemModel;
|
||||
#ifndef GENERAL_NAME_EDIT_H
|
||||
#define GENERAL_NAME_EDIT_H
|
||||
|
||||
/**
|
||||
* List objects that this GPO links to. Does not provide a
|
||||
* way to edit, editing should be done in group policy tabs
|
||||
* of objects.
|
||||
* Edit for displaying name of object in a label. Used
|
||||
* in general tabs of the properties dialog
|
||||
*/
|
||||
|
||||
namespace Ui {
|
||||
class GpoLinksTab;
|
||||
}
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
class GpoLinksTab final : public PropertiesTab {
|
||||
class QLabel;
|
||||
|
||||
class GeneralNameEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Ui::GpoLinksTab *ui;
|
||||
|
||||
GpoLinksTab();
|
||||
~GpoLinksTab();
|
||||
GeneralNameEdit(QLabel *label, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
|
||||
private:
|
||||
QStandardItemModel *model;
|
||||
QLabel *label;
|
||||
};
|
||||
|
||||
#endif /* GPO_LINKS_TAB_H */
|
||||
#endif /* GENERAL_NAME_EDIT_H */
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
GpoptionsEdit::GpoptionsEdit(QCheckBox *check_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
GpoptionsEdit::GpoptionsEdit(QCheckBox *check_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
check = check_arg;
|
||||
|
||||
connect(
|
||||
@ -34,7 +34,7 @@ GpoptionsEdit::GpoptionsEdit(QCheckBox *check_arg, QList<AttributeEdit *> *edits
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void GpoptionsEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void GpoptionsEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString value = object.get_string(ATTRIBUTE_GPOPTIONS);
|
||||
@ -43,10 +43,6 @@ void GpoptionsEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
check->setChecked(checked);
|
||||
}
|
||||
|
||||
void GpoptionsEdit::set_read_only(const bool read_only) {
|
||||
check->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool GpoptionsEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = [this]() {
|
||||
const bool checked = check->isChecked();
|
||||
|
@ -28,8 +28,10 @@ class QCheckBox;
|
||||
class GpoptionsEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GpoptionsEdit(QCheckBox *check, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
GpoptionsEdit(QCheckBox *check, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QCheckBox *check;
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include <QComboBox>
|
||||
#include <QFormLayout>
|
||||
|
||||
GroupScopeEdit::GroupScopeEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
GroupScopeEdit::GroupScopeEdit(QComboBox *combo_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
combo = combo_arg;
|
||||
|
||||
for (int i = 0; i < GroupScope_COUNT; i++) {
|
||||
@ -42,16 +42,18 @@ GroupScopeEdit::GroupScopeEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edi
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void GroupScopeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void GroupScopeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const GroupScope scope = object.get_group_scope();
|
||||
|
||||
combo->setCurrentIndex((int) scope);
|
||||
}
|
||||
|
||||
void GroupScopeEdit::set_read_only(const bool read_only) {
|
||||
combo->setDisabled(read_only);
|
||||
const bool is_critical_system_object = object.get_bool(ATTRIBUTE_IS_CRITICAL_SYSTEM_OBJECT);
|
||||
|
||||
if (is_critical_system_object) {
|
||||
combo->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupScopeEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
|
@ -28,8 +28,10 @@ class QComboBox;
|
||||
class GroupScopeEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupScopeEdit(QComboBox *combo, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
GroupScopeEdit(QComboBox *combo, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QComboBox *combo;
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
GroupTypeEdit::GroupTypeEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
GroupTypeEdit::GroupTypeEdit(QComboBox *combo_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
combo = combo_arg;
|
||||
|
||||
for (int i = 0; i < GroupType_COUNT; i++) {
|
||||
@ -41,16 +41,18 @@ GroupTypeEdit::GroupTypeEdit(QComboBox *combo_arg, QList<AttributeEdit *> *edits
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void GroupTypeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void GroupTypeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const GroupType type = object.get_group_type();
|
||||
|
||||
combo->setCurrentIndex((int) type);
|
||||
}
|
||||
|
||||
void GroupTypeEdit::set_read_only(const bool read_only) {
|
||||
combo->setDisabled(read_only);
|
||||
const bool is_critical_system_object = object.get_bool(ATTRIBUTE_IS_CRITICAL_SYSTEM_OBJECT);
|
||||
|
||||
if (is_critical_system_object) {
|
||||
combo->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupTypeEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
|
@ -28,8 +28,10 @@ class QComboBox;
|
||||
class GroupTypeEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupTypeEdit(QComboBox *combo, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
GroupTypeEdit(QComboBox *combo, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QComboBox *combo;
|
||||
|
65
src/admc/attribute_edits/laps_expiry_edit.cpp
Normal file
65
src/admc/attribute_edits/laps_expiry_edit.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 "attribute_edits/laps_expiry_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDateTimeEdit>
|
||||
|
||||
LAPSExpiryEdit::LAPSExpiryEdit(QDateTimeEdit *edit_arg, QPushButton *reset_expiry_button, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit = edit_arg;
|
||||
|
||||
connect(
|
||||
edit, &QDateTimeEdit::dateTimeChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
connect(
|
||||
reset_expiry_button, &QPushButton::clicked,
|
||||
this, &LAPSExpiryEdit::reset_expiry);
|
||||
}
|
||||
|
||||
void LAPSExpiryEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QDateTime datetime = object.get_datetime(ATTRIBUTE_LAPS_EXPIRATION, g_adconfig);
|
||||
const QDateTime datetime_local = datetime.toLocalTime();
|
||||
|
||||
edit->setDateTime(datetime_local);
|
||||
}
|
||||
|
||||
bool LAPSExpiryEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QDateTime datetime_local = edit->dateTime();
|
||||
const QDateTime datetime = datetime_local.toUTC();
|
||||
|
||||
const bool success = ad.attribute_replace_datetime(dn, ATTRIBUTE_LAPS_EXPIRATION, datetime);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void LAPSExpiryEdit::reset_expiry() {
|
||||
const QDateTime current_datetime_local = QDateTime::currentDateTime();
|
||||
edit->setDateTime(current_datetime_local);
|
||||
|
||||
emit edited();
|
||||
}
|
@ -18,24 +18,26 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tabs/properties_tab.h"
|
||||
#ifndef LAPS_EXPIRY_EDIT_H
|
||||
#define LAPS_EXPIRY_EDIT_H
|
||||
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
class QDateTimeEdit;
|
||||
class QPushButton;
|
||||
|
||||
void PropertiesTab::load(AdInterface &ad, const AdObject &object) {
|
||||
edits_load(edits, ad, object);
|
||||
}
|
||||
class LAPSExpiryEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LAPSExpiryEdit(QDateTimeEdit *edit_arg, QPushButton *reset_expiry_button, QObject *parent);
|
||||
|
||||
bool PropertiesTab::verify(AdInterface &ad, const QString &target) const {
|
||||
return edits_verify(ad, edits, target);
|
||||
}
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
bool PropertiesTab::apply(AdInterface &ad, const QString &target) {
|
||||
return edits_apply(ad, edits, target);
|
||||
}
|
||||
private:
|
||||
QDateTimeEdit *edit;
|
||||
|
||||
void PropertiesTab::on_edit_edited() {
|
||||
emit edited();
|
||||
}
|
||||
void reset_expiry();
|
||||
};
|
||||
|
||||
#endif /* LAPS_EXPIRY_EDIT_H */
|
@ -25,13 +25,25 @@
|
||||
#include "utils.h"
|
||||
#include "settings.h"
|
||||
|
||||
LogonComputersDialog::LogonComputersDialog(QWidget *parent)
|
||||
#include <QPushButton>
|
||||
|
||||
LogonComputersDialog::LogonComputersDialog(const QString &value, QWidget *parent)
|
||||
: QDialog(parent) {
|
||||
ui = new Ui::LogonComputersDialog();
|
||||
ui->setupUi(this);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (!value.isEmpty()) {
|
||||
const QList<QString> value_list = value.split(",");
|
||||
|
||||
for (const QString &subvalue : value_list) {
|
||||
ui->list->addItem(subvalue);
|
||||
}
|
||||
}
|
||||
|
||||
enable_widget_on_selection(ui->remove_button, ui->list);
|
||||
|
||||
settings_setup_dialog_geometry(SETTING_logon_computers_dialog_geometry, this);
|
||||
|
||||
connect(
|
||||
@ -46,20 +58,6 @@ LogonComputersDialog::~LogonComputersDialog() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void LogonComputersDialog::load(const QString &value) {
|
||||
ui->list->clear();
|
||||
|
||||
if (value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QList<QString> value_list = value.split(",");
|
||||
|
||||
for (const QString &subvalue : value_list) {
|
||||
ui->list->addItem(subvalue);
|
||||
}
|
||||
}
|
||||
|
||||
QString LogonComputersDialog::get() const {
|
||||
const QList<QString> value_list = [&]() {
|
||||
QList<QString> out;
|
||||
|
@ -33,10 +33,9 @@ class LogonComputersDialog final : public QDialog {
|
||||
public:
|
||||
Ui::LogonComputersDialog *ui;
|
||||
|
||||
LogonComputersDialog(QWidget *parent);
|
||||
LogonComputersDialog(const QString &value, QWidget *parent);
|
||||
~LogonComputersDialog();
|
||||
|
||||
void load(const QString &value);
|
||||
QString get() const;
|
||||
|
||||
private:
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
LogonComputersEdit::LogonComputersEdit(QPushButton *button_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
LogonComputersEdit::LogonComputersEdit(QPushButton *button_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
button = button_arg;
|
||||
|
||||
connect(
|
||||
@ -36,16 +36,12 @@ LogonComputersEdit::LogonComputersEdit(QPushButton *button_arg, QList<AttributeE
|
||||
this, &LogonComputersEdit::open_dialog);
|
||||
}
|
||||
|
||||
void LogonComputersEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void LogonComputersEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
current_value = object.get_value(ATTRIBUTE_USER_WORKSTATIONS);
|
||||
}
|
||||
|
||||
void LogonComputersEdit::set_read_only(const bool read_only) {
|
||||
button->setEnabled(read_only);
|
||||
}
|
||||
|
||||
bool LogonComputersEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_USER_WORKSTATIONS, current_value);
|
||||
|
||||
@ -53,12 +49,12 @@ bool LogonComputersEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
}
|
||||
|
||||
void LogonComputersEdit::open_dialog() {
|
||||
auto dialog = new LogonComputersDialog(button);
|
||||
dialog->load(current_value);
|
||||
auto dialog = new LogonComputersDialog(current_value, button);
|
||||
dialog->open();
|
||||
|
||||
connect(
|
||||
dialog, &QDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
current_value = dialog->get();
|
||||
|
||||
|
@ -28,8 +28,10 @@ class QPushButton;
|
||||
class LogonComputersEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LogonComputersEdit(QPushButton *button, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
LogonComputersEdit(QPushButton *button, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QPushButton *button;
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
QList<bool> shift_list(const QList<bool> &list, const int shift_amount);
|
||||
|
||||
LogonHoursDialog::LogonHoursDialog(QWidget *parent)
|
||||
LogonHoursDialog::LogonHoursDialog(const QByteArray &value, QWidget *parent)
|
||||
: QDialog(parent) {
|
||||
ui = new Ui::LogonHoursDialog();
|
||||
ui->setupUi(this);
|
||||
@ -48,6 +48,18 @@ LogonHoursDialog::LogonHoursDialog(QWidget *parent)
|
||||
tr("Saturday"),
|
||||
});
|
||||
|
||||
const QList<QString> horizontalheader_labels = []() {
|
||||
QList<QString> out;
|
||||
|
||||
for (int i = 0; i < HOURS_IN_DAY; i++) {
|
||||
const QString label = QString::number(i);
|
||||
out.append(label);
|
||||
}
|
||||
|
||||
return out;
|
||||
}();
|
||||
model->setHorizontalHeaderLabels(horizontalheader_labels);
|
||||
|
||||
ui->view->setModel(model);
|
||||
ui->view->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
ui->view->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
@ -59,8 +71,28 @@ LogonHoursDialog::LogonHoursDialog(QWidget *parent)
|
||||
ui->local_time_button->setChecked(true);
|
||||
is_local_time = true;
|
||||
|
||||
load(value);
|
||||
|
||||
settings_setup_dialog_geometry(SETTING_logon_hours_dialog_geometry, this);
|
||||
|
||||
const QString allowed_style_sheet = [&]() {
|
||||
const QPalette palette = ui->view->palette();
|
||||
const QColor color = palette.highlight().color();
|
||||
const QString out = QString("background-color: rgb(%1, %2, %3);").arg(QString::number(color.red()), QString::number(color.green()), QString::number(color.blue()));
|
||||
|
||||
return out;
|
||||
}();
|
||||
ui->legend_allowed->setStyleSheet(allowed_style_sheet);
|
||||
|
||||
const QString denied_style_sheet = [&]() {
|
||||
const QPalette palette = ui->view->palette();
|
||||
const QColor color = palette.base().color();
|
||||
const QString out = QString("background-color: rgb(%1, %2, %3);").arg(QString::number(color.red()), QString::number(color.green()), QString::number(color.blue()));
|
||||
|
||||
return out;
|
||||
}();
|
||||
ui->legend_denied->setStyleSheet(denied_style_sheet);
|
||||
|
||||
connect(
|
||||
ui->local_time_button, &QRadioButton::toggled,
|
||||
this, &LogonHoursDialog::on_local_time_button_toggled);
|
||||
@ -73,10 +105,7 @@ LogonHoursDialog::~LogonHoursDialog() {
|
||||
void LogonHoursDialog::load(const QByteArray &value) {
|
||||
ui->view->clearSelection();
|
||||
|
||||
// NOTE: value may be empty if it's undefined
|
||||
if (value.size() != LOGON_HOURS_SIZE) {
|
||||
return;
|
||||
}
|
||||
original_value = value;
|
||||
|
||||
const QList<QList<bool>> bools = logon_hours_to_bools(value, get_offset());
|
||||
|
||||
@ -110,9 +139,19 @@ QByteArray LogonHoursDialog::get() const {
|
||||
return out;
|
||||
}();
|
||||
|
||||
const QByteArray out = logon_hours_to_bytes(bools, get_offset());
|
||||
const QList<QList<bool>> original_bools = logon_hours_to_bools(original_value);
|
||||
|
||||
return out;
|
||||
// NOTE: input has to always be equal to output.
|
||||
// Therefore, for the case where original value was
|
||||
// unset, we need this special logic so that input
|
||||
// doesn't change to a non-empty bytearray.
|
||||
if (bools == original_bools) {
|
||||
return original_value;
|
||||
} else {
|
||||
const QByteArray out = logon_hours_to_bytes(bools, get_offset());
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current value, change time state and reload value
|
||||
@ -142,7 +181,20 @@ int LogonHoursDialog::get_offset() const {
|
||||
}
|
||||
}
|
||||
|
||||
QList<QList<bool>> logon_hours_to_bools(const QByteArray &byte_list, const int time_offset) {
|
||||
QList<QList<bool>> logon_hours_to_bools(const QByteArray &byte_list_arg, const int time_offset) {
|
||||
// NOTE: value may be empty or malformed. In that
|
||||
// case treat both as values that "allow all logon
|
||||
// times" (all bits set). This also handles the
|
||||
// case where value is unset and we need to treat
|
||||
// it as "allow all logon times".
|
||||
const QByteArray byte_list = [&]() {
|
||||
if (byte_list_arg.size() == LOGON_HOURS_SIZE) {
|
||||
return byte_list_arg;
|
||||
} else {
|
||||
return QByteArray(LOGON_HOURS_SIZE, (char) 0xFF);
|
||||
}
|
||||
}();
|
||||
|
||||
// Convet byte array to list of bools
|
||||
const QList<bool> joined = [&]() {
|
||||
QList<bool> out;
|
||||
@ -150,7 +202,7 @@ QList<QList<bool>> logon_hours_to_bools(const QByteArray &byte_list, const int t
|
||||
for (const char byte : byte_list) {
|
||||
for (int bit_i = 0; bit_i < 8; bit_i++) {
|
||||
const int bit = (0x01 << bit_i);
|
||||
const bool is_set = bit_is_set((int) byte, bit);
|
||||
const bool is_set = bitmask_is_set((int) byte, bit);
|
||||
out.append(is_set);
|
||||
}
|
||||
}
|
||||
@ -197,7 +249,7 @@ QByteArray logon_hours_to_bytes(const QList<QList<bool>> bool_list, const int ti
|
||||
int byte = 0;
|
||||
for (int bit_i = 0; bit_i < 8; bit_i++) {
|
||||
const int bit = (0x01 << bit_i);
|
||||
byte = bit_set(byte, bit, byte_list[bit_i]);
|
||||
byte = bitmask_set(byte, bit, byte_list[bit_i]);
|
||||
}
|
||||
|
||||
bytes.append(byte);
|
||||
|
@ -56,15 +56,16 @@ class LogonHoursDialog : public QDialog {
|
||||
public:
|
||||
Ui::LogonHoursDialog *ui;
|
||||
|
||||
LogonHoursDialog(QWidget *parent);
|
||||
LogonHoursDialog(const QByteArray &value, QWidget *parent);
|
||||
~LogonHoursDialog();
|
||||
|
||||
void load(const QByteArray &value);
|
||||
QByteArray get() const;
|
||||
|
||||
private:
|
||||
QStandardItemModel *model;
|
||||
QByteArray original_value;
|
||||
|
||||
void load(const QByteArray &value);
|
||||
void switch_to_local_time();
|
||||
void on_local_time_button_toggled(bool checked);
|
||||
int get_offset() const;
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<height>318</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -15,21 +15,115 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableView" name="view"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="local_time_button">
|
||||
<property name="text">
|
||||
<string>Local time</string>
|
||||
<widget class="QTableView" name="view">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="utc_time_button">
|
||||
<property name="text">
|
||||
<string>UTC time</string>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="utc_time_button">
|
||||
<property name="text">
|
||||
<string>UTC time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="local_time_button">
|
||||
<property name="text">
|
||||
<string>Local time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Logon allowed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QFrame" name="legend_allowed">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Logon denied:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFrame" name="legend_denied">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="button_box">
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
LogonHoursEdit::LogonHoursEdit(QPushButton *button_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
LogonHoursEdit::LogonHoursEdit(QPushButton *button_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
button = button_arg;
|
||||
|
||||
connect(
|
||||
@ -35,16 +35,12 @@ LogonHoursEdit::LogonHoursEdit(QPushButton *button_arg, QList<AttributeEdit *> *
|
||||
this, &LogonHoursEdit::open_dialog);
|
||||
}
|
||||
|
||||
void LogonHoursEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void LogonHoursEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
current_value = object.get_value(ATTRIBUTE_LOGON_HOURS);
|
||||
}
|
||||
|
||||
void LogonHoursEdit::set_read_only(const bool read_only) {
|
||||
button->setEnabled(read_only);
|
||||
}
|
||||
|
||||
bool LogonHoursEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool success = ad.attribute_replace_value(dn, ATTRIBUTE_LOGON_HOURS, current_value);
|
||||
|
||||
@ -52,15 +48,20 @@ bool LogonHoursEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
}
|
||||
|
||||
void LogonHoursEdit::open_dialog() {
|
||||
auto dialog = new LogonHoursDialog(button);
|
||||
dialog->load(current_value);
|
||||
auto dialog = new LogonHoursDialog(current_value, button);
|
||||
dialog->open();
|
||||
|
||||
connect(
|
||||
dialog, &QDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
current_value = dialog->get();
|
||||
const QByteArray new_value = dialog->get();
|
||||
const bool value_changed = (new_value != current_value);
|
||||
|
||||
emit edited();
|
||||
if (value_changed) {
|
||||
current_value = dialog->get();
|
||||
|
||||
emit edited();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -28,8 +28,10 @@ class QPushButton;
|
||||
class LogonHoursEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LogonHoursEdit(QPushButton *button, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
LogonHoursEdit(QPushButton *button, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QPushButton *button;
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
ManagerEdit::ManagerEdit(ManagerWidget *widget_arg, const QString &manager_attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
ManagerEdit::ManagerEdit(ManagerWidget *widget_arg, const QString &manager_attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
manager_attribute = manager_attribute_arg;
|
||||
|
||||
widget = widget_arg;
|
||||
@ -37,20 +37,20 @@ ManagerEdit::ManagerEdit(ManagerWidget *widget_arg, const QString &manager_attri
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void ManagerEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void ManagerEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
widget->load(object);
|
||||
}
|
||||
|
||||
void ManagerEdit::set_read_only(const bool read_only) {
|
||||
widget->setEnabled(!read_only);
|
||||
}
|
||||
|
||||
bool ManagerEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
return widget->apply(ad, dn);
|
||||
}
|
||||
|
||||
void ManagerEdit::set_enabled(const bool enabled) {
|
||||
widget->setEnabled(enabled);
|
||||
}
|
||||
|
||||
QString ManagerEdit::get_manager() const {
|
||||
return widget->get_manager();
|
||||
}
|
||||
|
@ -36,8 +36,11 @@ class ManagerWidget;
|
||||
class ManagerEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ManagerEdit(ManagerWidget *widget_arg, const QString &manager_attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
ManagerEdit(ManagerWidget *widget_arg, const QString &manager_attribute_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
QString get_manager() const;
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "adldap.h"
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
#include "properties_dialog.h"
|
||||
#include "select_object_dialog.h"
|
||||
|
||||
@ -31,6 +32,8 @@ ManagerWidget::ManagerWidget(QWidget *parent)
|
||||
ui = new Ui::ManagerWidget();
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->manager_display->setReadOnly(true);
|
||||
|
||||
connect(
|
||||
ui->change_button, &QPushButton::clicked,
|
||||
this, &ManagerWidget::on_change);
|
||||
@ -76,6 +79,7 @@ void ManagerWidget::on_change() {
|
||||
|
||||
connect(
|
||||
dialog, &SelectObjectDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
const QList<QString> selected = dialog->get_selected();
|
||||
|
||||
@ -88,7 +92,12 @@ void ManagerWidget::on_change() {
|
||||
}
|
||||
|
||||
void ManagerWidget::on_properties() {
|
||||
PropertiesDialog::open_for_target(current_value);
|
||||
AdInterface ad;
|
||||
if (ad_failed(ad, this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PropertiesDialog::open_for_target(ad, current_value);
|
||||
}
|
||||
|
||||
void ManagerWidget::on_clear() {
|
||||
@ -100,8 +109,8 @@ void ManagerWidget::on_clear() {
|
||||
void ManagerWidget::load_value(const QString &value) {
|
||||
current_value = value;
|
||||
|
||||
const QString rdn = dn_get_name(current_value);
|
||||
ui->manager_display->setText(current_value);
|
||||
const QString name = dn_get_name(current_value);
|
||||
ui->manager_display->setText(name);
|
||||
|
||||
const bool have_manager = !current_value.isEmpty();
|
||||
ui->properties_button->setEnabled(have_manager);
|
||||
|
@ -22,13 +22,15 @@
|
||||
|
||||
#include "adldap.h"
|
||||
#include "globals.h"
|
||||
#include "settings.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QCheckBox>
|
||||
#include <QTextCodec>
|
||||
|
||||
PasswordEdit::PasswordEdit(QLineEdit *edit_arg, QLineEdit *confirm_edit_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
PasswordEdit::PasswordEdit(QLineEdit *edit_arg, QLineEdit *confirm_edit_arg, QCheckBox *show_password_check, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit = edit_arg;
|
||||
confirm_edit = confirm_edit_arg;
|
||||
|
||||
@ -38,9 +40,15 @@ PasswordEdit::PasswordEdit(QLineEdit *edit_arg, QLineEdit *confirm_edit_arg, QLi
|
||||
connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
connect(
|
||||
show_password_check, &QCheckBox::toggled,
|
||||
this, &PasswordEdit::on_show_password_check);
|
||||
|
||||
const bool show_password_is_ON = settings_get_variant(SETTING_show_password).toBool();
|
||||
show_password_check->setChecked(show_password_is_ON);
|
||||
}
|
||||
|
||||
void PasswordEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void PasswordEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(object);
|
||||
|
||||
@ -48,16 +56,19 @@ void PasswordEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
confirm_edit->clear();
|
||||
}
|
||||
|
||||
void PasswordEdit::set_read_only(const bool read_only) {
|
||||
edit->setDisabled(read_only);
|
||||
confirm_edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool PasswordEdit::verify(AdInterface &ad, const QString &) const {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString pass = edit->text();
|
||||
const QString confirm_pass = confirm_edit->text();
|
||||
|
||||
if (pass.isEmpty()) {
|
||||
const QString error_text = QString(tr("Password cannot be empty."));
|
||||
message_box_warning(edit, tr("Error"), error_text);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pass != confirm_pass) {
|
||||
const QString error_text = QString(tr("Passwords don't match!"));
|
||||
message_box_warning(edit, tr("Error"), error_text);
|
||||
@ -81,7 +92,7 @@ bool PasswordEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = edit->text();
|
||||
|
||||
const bool success = ad.user_set_pass(dn, new_value);
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -92,3 +103,18 @@ QLineEdit *PasswordEdit::get_edit() const {
|
||||
QLineEdit *PasswordEdit::get_confirm_edit() const {
|
||||
return confirm_edit;
|
||||
}
|
||||
|
||||
void PasswordEdit::on_show_password_check(bool checked) {
|
||||
const QLineEdit::EchoMode echo_mode = [&]() {
|
||||
if (checked) {
|
||||
return QLineEdit::Normal;
|
||||
} else {
|
||||
return QLineEdit::Password;
|
||||
}
|
||||
}();
|
||||
|
||||
edit->setEchoMode(echo_mode);
|
||||
confirm_edit->setEchoMode(echo_mode);
|
||||
|
||||
settings_set_variant(SETTING_show_password, checked);
|
||||
}
|
||||
|
@ -24,14 +24,16 @@
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
class QLineEdit;
|
||||
class QCheckBox;
|
||||
|
||||
class PasswordEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PasswordEdit(QLineEdit *edit_arg, QLineEdit *confirm_edit_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
PasswordEdit(QLineEdit *edit_arg, QLineEdit *confirm_edit_arg, QCheckBox *show_password_check, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool verify(AdInterface &ad, const QString &dn) const override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
QLineEdit *get_edit() const;
|
||||
QLineEdit *get_confirm_edit() const;
|
||||
@ -39,6 +41,8 @@ public:
|
||||
private:
|
||||
QLineEdit *edit;
|
||||
QLineEdit *confirm_edit;
|
||||
|
||||
void on_show_password_check(bool checked);
|
||||
};
|
||||
|
||||
#endif /* PASSWORD_EDIT_H */
|
||||
|
@ -30,8 +30,8 @@
|
||||
// permissions for "delete" and "delete subtree" for
|
||||
// "WORLD"(everyone) trustee
|
||||
|
||||
ProtectDeletionEdit::ProtectDeletionEdit(QCheckBox *check_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
ProtectDeletionEdit::ProtectDeletionEdit(QCheckBox *check_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
check = check_arg;
|
||||
|
||||
connect(
|
||||
@ -43,21 +43,17 @@ void ProtectDeletionEdit::set_enabled(const bool enabled) {
|
||||
check->setChecked(enabled);
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void ProtectDeletionEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const bool enabled = ad_security_get_protected_against_deletion(object, g_adconfig);
|
||||
const bool enabled = ad_security_get_protected_against_deletion(object);
|
||||
|
||||
check->setChecked(enabled);
|
||||
}
|
||||
|
||||
void ProtectDeletionEdit::set_read_only(const bool read_only) {
|
||||
check->setDisabled(read_only);
|
||||
}
|
||||
|
||||
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);
|
||||
const bool apply_success = ad_security_set_protected_against_deletion(ad, dn, enabled);
|
||||
|
||||
return apply_success;
|
||||
}
|
||||
|
@ -33,8 +33,10 @@ class QCheckBox;
|
||||
class ProtectDeletionEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProtectDeletionEdit(QCheckBox *check, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
ProtectDeletionEdit(QCheckBox *check, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
void set_enabled(const bool enabled);
|
||||
|
||||
|
@ -25,40 +25,14 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QRegularExpression>
|
||||
|
||||
SamNameEdit::SamNameEdit(QLineEdit *edit_arg, QLineEdit *domain_edit_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
SamNameEdit::SamNameEdit(QLineEdit *edit_arg, QLineEdit *domain_edit, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
edit = edit_arg;
|
||||
domain_edit = domain_edit_arg;
|
||||
|
||||
limit_edit(edit, ATTRIBUTE_SAM_ACCOUNT_NAME);
|
||||
edit->setMaxLength(SAM_NAME_MAX_LENGTH);
|
||||
|
||||
connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void SamNameEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString value = object.get_string(ATTRIBUTE_SAM_ACCOUNT_NAME);
|
||||
edit->setText(value);
|
||||
|
||||
load_domain();
|
||||
}
|
||||
|
||||
void SamNameEdit::set_read_only(const bool read_only) {
|
||||
edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool SamNameEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = edit->text();
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_SAM_ACCOUNT_NAME, new_value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void SamNameEdit::load_domain() {
|
||||
const QString domain_text = []() {
|
||||
const QString domain = g_adconfig->domain();
|
||||
const QString domain_name = domain.split(".")[0];
|
||||
@ -68,4 +42,56 @@ void SamNameEdit::load_domain() {
|
||||
}();
|
||||
|
||||
domain_edit->setText(domain_text);
|
||||
|
||||
connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void SamNameEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString value = object.get_string(ATTRIBUTE_SAM_ACCOUNT_NAME);
|
||||
edit->setText(value);
|
||||
}
|
||||
|
||||
bool SamNameEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(dn);
|
||||
|
||||
const bool out = sam_name_edit_verify(edit);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// NOTE: requirements are from here
|
||||
// https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx#Note_Regarding_the_quot_quot_Character_in_sAMAccountName
|
||||
bool sam_name_edit_verify(QLineEdit *edit) {
|
||||
const QString new_value = edit->text().trimmed();
|
||||
|
||||
const bool contains_bad_chars = string_contains_bad_chars(new_value, SAM_NAME_BAD_CHARS);
|
||||
|
||||
const bool ends_with_dot = new_value.endsWith(".");
|
||||
|
||||
const bool value_is_valid = (!contains_bad_chars && !ends_with_dot);
|
||||
|
||||
if (!value_is_valid) {
|
||||
const QString error_text = QString(QCoreApplication::translate("SamNameEdit", "Input field for Logon name (pre-Windows 2000) contains one or more of the following illegal characters: @ \" [ ] : ; | = + * ? < > / \\ ,"));
|
||||
message_box_warning(edit, QCoreApplication::translate("SamNameEdit", "Error"), error_text);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SamNameEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = edit->text().trimmed();
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_SAM_ACCOUNT_NAME, new_value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void SamNameEdit::set_enabled(const bool enabled) {
|
||||
edit->setEnabled(enabled);
|
||||
}
|
||||
|
@ -28,14 +28,18 @@ class QLineEdit;
|
||||
class SamNameEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SamNameEdit(QLineEdit *edit, QLineEdit *domain_edit_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
SamNameEdit(QLineEdit *edit, QLineEdit *domain_edit, QObject *parent);
|
||||
|
||||
void load_domain();
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool verify(AdInterface &ad, const QString &dn) const override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
void set_enabled(const bool enabled);
|
||||
|
||||
private:
|
||||
QLineEdit *edit;
|
||||
QLineEdit *domain_edit;
|
||||
};
|
||||
|
||||
bool sam_name_edit_verify(QLineEdit *edit);
|
||||
|
||||
#endif /* SAM_NAME_EDIT_H */
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
StringEdit::StringEdit(QLineEdit *edit_arg, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
StringEdit::StringEdit(QLineEdit *edit_arg, const QString &attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
attribute = attribute_arg;
|
||||
edit = edit_arg;
|
||||
|
||||
@ -42,7 +42,7 @@ StringEdit::StringEdit(QLineEdit *edit_arg, const QString &attribute_arg, QList<
|
||||
this, &AttributeEdit::edited);
|
||||
}
|
||||
|
||||
void StringEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void StringEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString value = [=]() {
|
||||
@ -58,13 +58,13 @@ void StringEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
edit->setText(value);
|
||||
}
|
||||
|
||||
void StringEdit::set_read_only(const bool read_only) {
|
||||
edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool StringEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = edit->text();
|
||||
const QString new_value = edit->text().trimmed();
|
||||
const bool success = ad.attribute_replace_string(dn, attribute, new_value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void StringEdit::set_enabled(const bool enabled) {
|
||||
edit->setEnabled(enabled);
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ class QLineEdit;
|
||||
class StringEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
StringEdit(QLineEdit *edit_arg, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
StringEdit(QLineEdit *edit_arg, const QString &attribute_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
private:
|
||||
QLineEdit *edit;
|
||||
|
@ -22,20 +22,25 @@
|
||||
|
||||
#include "adldap.h"
|
||||
#include "utils.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
StringLargeEdit::StringLargeEdit(QPlainTextEdit *edit_arg, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
StringLargeEdit::StringLargeEdit(QPlainTextEdit *edit_arg, const QString &attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
attribute = attribute_arg;
|
||||
edit = edit_arg;
|
||||
ignore_on_text_changed = false;
|
||||
|
||||
connect(
|
||||
edit, &QPlainTextEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
connect(
|
||||
edit, &QPlainTextEdit::textChanged,
|
||||
this, &StringLargeEdit::on_text_changed);
|
||||
}
|
||||
|
||||
void StringLargeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void StringLargeEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
const QString value = object.get_string(attribute);
|
||||
@ -43,13 +48,26 @@ void StringLargeEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
edit->setPlainText(value);
|
||||
}
|
||||
|
||||
void StringLargeEdit::set_read_only(const bool read_only) {
|
||||
edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool StringLargeEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = edit->toPlainText();
|
||||
const bool success = ad.attribute_replace_string(dn, attribute, new_value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// NOTE: this is a custom length limit mechanism
|
||||
// because QPlainText doesn't have it built-in
|
||||
void StringLargeEdit::on_text_changed() {
|
||||
ignore_on_text_changed = true;
|
||||
{
|
||||
const int range_upper = g_adconfig->get_attribute_range_upper(attribute);
|
||||
|
||||
const QString value = edit->toPlainText();
|
||||
|
||||
if (value.length() > range_upper) {
|
||||
const QString shortened_value = value.left(range_upper);
|
||||
edit->setPlainText(shortened_value);
|
||||
}
|
||||
}
|
||||
ignore_on_text_changed = false;
|
||||
}
|
||||
|
@ -33,12 +33,17 @@ class QPlainTextEdit;
|
||||
class StringLargeEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
StringLargeEdit(QPlainTextEdit *edit, const QString &attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
StringLargeEdit(QPlainTextEdit *edit, const QString &attribute_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QPlainTextEdit *edit;
|
||||
QString attribute;
|
||||
bool ignore_on_text_changed;
|
||||
|
||||
void on_text_changed();
|
||||
};
|
||||
|
||||
#endif /* STRING_LARGE_EDIT_H */
|
||||
|
65
src/admc/attribute_edits/string_list_edit.cpp
Normal file
65
src/admc/attribute_edits/string_list_edit.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 "attribute_edits/string_list_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "utils.h"
|
||||
#include "attribute_dialogs/list_attribute_dialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
StringListEdit::StringListEdit(QPushButton *button_arg, const QString &attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
button = button_arg;
|
||||
attribute = attribute_arg;
|
||||
|
||||
connect(
|
||||
button, &QPushButton::clicked,
|
||||
this, &StringListEdit::on_button);
|
||||
}
|
||||
|
||||
void StringListEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
values = object.get_values(attribute);
|
||||
}
|
||||
|
||||
bool StringListEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
const bool success = ad.attribute_replace_values(dn, attribute, values);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void StringListEdit::on_button() {
|
||||
const bool read_only = false;
|
||||
auto dialog = new ListAttributeDialog(values, attribute, read_only, button);
|
||||
dialog->setWindowTitle(tr("Edit values"));
|
||||
dialog->open();
|
||||
|
||||
connect(
|
||||
dialog, &QDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
values = dialog->get_value_list();
|
||||
|
||||
emit edited();
|
||||
});
|
||||
}
|
@ -18,27 +18,28 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef STRING_MULTI_EDIT_H
|
||||
#define STRING_MULTI_EDIT_H
|
||||
#ifndef STRING_LIST_EDIT_H
|
||||
#define STRING_LIST_EDIT_H
|
||||
|
||||
#include "attribute_multi_edits/attribute_multi_edit.h"
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
||||
/**
|
||||
* Edit for editing string attributes of multiple objects.
|
||||
*/
|
||||
|
||||
class StringMultiEdit : public AttributeMultiEdit {
|
||||
class StringListEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
StringMultiEdit(QLineEdit *edit, QCheckBox *check, const QString &attribute_arg, QList<AttributeMultiEdit *> &edits_out, QObject *parent);
|
||||
StringListEdit(QPushButton *button, const QString &attribute, QObject *parent);
|
||||
|
||||
DECL_ATTRIBUTE_MULTI_EDIT_VIRTUALS();
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QLineEdit *edit;
|
||||
QPushButton *button;
|
||||
QString attribute;
|
||||
QList<QByteArray> values;
|
||||
|
||||
void on_button();
|
||||
};
|
||||
|
||||
#endif /* STRING_MULTI_EDIT_H */
|
||||
#endif /* STRING_LIST_EDIT_H */
|
@ -28,10 +28,12 @@
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
StringOtherEdit::StringOtherEdit(QLineEdit *line_edit_arg, QPushButton *other_button_arg, const QString &main_attribute, const QString &other_attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent)
|
||||
StringOtherEdit::StringOtherEdit(QLineEdit *line_edit_arg, QPushButton *other_button_arg, const QString &main_attribute, const QString &other_attribute_arg, QObject *parent)
|
||||
: AttributeEdit(parent)
|
||||
, other_attribute(other_attribute_arg) {
|
||||
main_edit = new StringEdit(line_edit_arg, main_attribute, nullptr, parent);
|
||||
main_edit = new StringEdit(line_edit_arg, main_attribute, parent);
|
||||
|
||||
line_edit = line_edit_arg;
|
||||
|
||||
other_button = other_button_arg;
|
||||
|
||||
@ -43,7 +45,7 @@ StringOtherEdit::StringOtherEdit(QLineEdit *line_edit_arg, QPushButton *other_bu
|
||||
this, &StringOtherEdit::on_other_button);
|
||||
}
|
||||
|
||||
void StringOtherEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void StringOtherEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
main_edit->load(ad, object);
|
||||
|
||||
other_values = object.get_values(other_attribute);
|
||||
@ -51,7 +53,7 @@ void StringOtherEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
|
||||
void StringOtherEdit::set_read_only(const bool read_only_arg) {
|
||||
read_only = read_only_arg;
|
||||
main_edit->set_read_only(read_only);
|
||||
line_edit->setReadOnly(read_only);
|
||||
}
|
||||
|
||||
bool StringOtherEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
@ -63,10 +65,12 @@ bool StringOtherEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
|
||||
void StringOtherEdit::on_other_button() {
|
||||
auto dialog = new ListAttributeDialog(other_values, other_attribute, read_only, other_button);
|
||||
dialog->setWindowTitle(tr("Edit other values"));
|
||||
dialog->open();
|
||||
|
||||
connect(
|
||||
dialog, &QDialog::accepted,
|
||||
this,
|
||||
[this, dialog]() {
|
||||
other_values = dialog->get_value_list();
|
||||
|
||||
|
@ -38,12 +38,22 @@ class QLineEdit;
|
||||
class StringOtherEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
StringOtherEdit(QLineEdit *line_edit, QPushButton *other_button, const QString &main_attribute_arg, const QString &other_attribute_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
StringOtherEdit(QLineEdit *line_edit, QPushButton *other_button, const QString &main_attribute_arg, const QString &other_attribute_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
|
||||
// Sets read only property on both main edit and
|
||||
// edit dialog for "Other" values. Dialog for
|
||||
// "Other" values can still be opened to view them,
|
||||
// while read only is active.
|
||||
void set_read_only(const bool read_only);
|
||||
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
StringEdit *main_edit;
|
||||
QPushButton *other_button;
|
||||
QLineEdit *line_edit;
|
||||
bool read_only;
|
||||
|
||||
const QString other_attribute;
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
UnlockEdit::UnlockEdit(QCheckBox *check_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
UnlockEdit::UnlockEdit(QCheckBox *check_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
check = check_arg;
|
||||
|
||||
connect(
|
||||
@ -38,17 +38,13 @@ QString UnlockEdit::label_text() {
|
||||
return tr("Unlock account");
|
||||
}
|
||||
|
||||
void UnlockEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void UnlockEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
UNUSED_ARG(object);
|
||||
|
||||
check->setChecked(false);
|
||||
}
|
||||
|
||||
void UnlockEdit::set_read_only(const bool read_only) {
|
||||
check->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool UnlockEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
|
||||
if (check->isChecked()) {
|
||||
|
@ -39,8 +39,10 @@ class QCheckBox;
|
||||
class UnlockEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UnlockEdit(QCheckBox *check_arg, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
UnlockEdit(QCheckBox *check_arg, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
static QString label_text();
|
||||
|
||||
|
@ -28,26 +28,26 @@
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
|
||||
UpnEdit::UpnEdit(QLineEdit *prefix_edit_arg, QComboBox *upn_suffix_combo_arg, QList<AttributeEdit *> *edits_out, QObject *parent)
|
||||
: AttributeEdit(edits_out, parent) {
|
||||
UpnEdit::UpnEdit(QLineEdit *prefix_edit_arg, QComboBox *upn_suffix_combo_arg, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
prefix_edit = prefix_edit_arg;
|
||||
upn_suffix_combo = upn_suffix_combo_arg;
|
||||
|
||||
limit_edit(prefix_edit, ATTRIBUTE_USER_PRINCIPAL_NAME);
|
||||
|
||||
connect(
|
||||
prefix_edit, &QLineEdit::textChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
connect(
|
||||
upn_suffix_combo, &QComboBox::currentTextChanged,
|
||||
this, &AttributeEdit::edited);
|
||||
this, &UpnEdit::on_suffix_combo_changed);
|
||||
}
|
||||
|
||||
void UpnEdit::init_suffixes(AdInterface &ad) {
|
||||
upn_suffix_combo_init(upn_suffix_combo, ad);
|
||||
|
||||
on_suffix_combo_changed();
|
||||
}
|
||||
|
||||
void UpnEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
void UpnEdit::load(AdInterface &ad, const AdObject &object) {
|
||||
UNUSED_ARG(ad);
|
||||
|
||||
upn_suffix_combo_load(upn_suffix_combo, object);
|
||||
@ -56,15 +56,22 @@ void UpnEdit::load_internal(AdInterface &ad, const AdObject &object) {
|
||||
prefix_edit->setText(prefix);
|
||||
}
|
||||
|
||||
void UpnEdit::set_read_only(const bool read_only) {
|
||||
prefix_edit->setDisabled(read_only);
|
||||
}
|
||||
|
||||
bool UpnEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
const QString new_value = get_new_value();
|
||||
const QString new_prefix = prefix_edit->text();
|
||||
|
||||
if (new_value.isEmpty()) {
|
||||
const QString text = tr("UPN may not be empty.");
|
||||
const bool contains_bad_chars = [&]() {
|
||||
const bool some_bad_chars = string_contains_bad_chars(new_prefix, UPN_BAD_CHARS);
|
||||
const bool starts_with_space = new_prefix.startsWith(" ");
|
||||
const bool ends_with_space = new_prefix.endsWith(" ");
|
||||
|
||||
const bool out = (some_bad_chars || starts_with_space || ends_with_space);
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
if (contains_bad_chars) {
|
||||
const QString text = tr("Input field for User Principal Name contains one or more of the following illegal characters: # , + \" \\ < > (leading space) (trailing space)");
|
||||
message_box_warning(prefix_edit, tr("Error"), text);
|
||||
|
||||
return false;
|
||||
@ -72,7 +79,7 @@ bool UpnEdit::verify(AdInterface &ad, const QString &dn) const {
|
||||
|
||||
// Check that new upn is unique
|
||||
// NOTE: filter has to also check that it's not the same object because of attribute edit weirdness. If user edits logon name, then retypes original, then applies, the edit will apply because it was modified by the user, even if the value didn't change. Without "not_object_itself", this check would determine that object's logon name conflicts with itself.
|
||||
const QString base = g_adconfig->domain_head();
|
||||
const QString base = g_adconfig->domain_dn();
|
||||
const SearchScope scope = SearchScope_All;
|
||||
const QString filter = [=]() {
|
||||
const QString not_object_itself = filter_CONDITION(Condition_NotEquals, ATTRIBUTE_DN, dn);
|
||||
@ -104,7 +111,21 @@ bool UpnEdit::apply(AdInterface &ad, const QString &dn) const {
|
||||
}
|
||||
|
||||
QString UpnEdit::get_new_value() const {
|
||||
const QString prefix = prefix_edit->text();
|
||||
const QString prefix = prefix_edit->text().trimmed();
|
||||
const QString suffix = upn_suffix_combo->currentText();
|
||||
return QString("%1@%2").arg(prefix, suffix);
|
||||
}
|
||||
|
||||
void UpnEdit::on_suffix_combo_changed() {
|
||||
const int prefix_range_upper = [&]() {
|
||||
const int total_range_upper = g_adconfig->get_attribute_range_upper(ATTRIBUTE_USER_PRINCIPAL_NAME);
|
||||
const int at_length = QString("@").length();
|
||||
const int suffix_length = upn_suffix_combo->currentText().length();
|
||||
const int out = total_range_upper - at_length - suffix_length;
|
||||
|
||||
return out;
|
||||
}();
|
||||
prefix_edit->setMaxLength(prefix_range_upper);
|
||||
|
||||
emit edited();
|
||||
}
|
||||
|
@ -30,13 +30,14 @@ class QComboBox;
|
||||
class UpnEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UpnEdit(QLineEdit *prefix_edit, QComboBox *suffix_combo, QList<AttributeEdit *> *edits_out, QObject *parent);
|
||||
DECL_ATTRIBUTE_EDIT_VIRTUALS();
|
||||
UpnEdit(QLineEdit *prefix_edit, QComboBox *suffix_combo, QObject *parent);
|
||||
|
||||
void load(AdInterface &ad, const AdObject &object) override;
|
||||
bool verify(AdInterface &ad, const QString &dn) const override;
|
||||
bool apply(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
void init_suffixes(AdInterface &ad);
|
||||
|
||||
bool verify(AdInterface &ad, const QString &dn) const override;
|
||||
|
||||
private:
|
||||
QLineEdit *prefix_edit;
|
||||
QComboBox *upn_suffix_combo;
|
||||
@ -44,6 +45,8 @@ private:
|
||||
friend class StringOtherEdit;
|
||||
|
||||
QString get_new_value() const;
|
||||
void on_suffix_combo_changed();
|
||||
void update_prefix_limit();
|
||||
};
|
||||
|
||||
#endif /* UPN_EDIT_H */
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "attribute_multi_edits/upn_multi_edit.h"
|
||||
#include "attribute_edits/upn_multi_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "attribute_edits/upn_suffix_combo.h"
|
||||
@ -26,19 +26,13 @@
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
UpnMultiEdit::UpnMultiEdit(QComboBox *upn_suffix_combo_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, AdInterface &ad, QObject *parent)
|
||||
: AttributeMultiEdit(check, edits_out, parent) {
|
||||
UpnMultiEdit::UpnMultiEdit(QComboBox *upn_suffix_combo_arg, AdInterface &ad, QObject *parent)
|
||||
: AttributeEdit(parent) {
|
||||
upn_suffix_combo = upn_suffix_combo_arg;
|
||||
upn_suffix_combo_init(upn_suffix_combo, ad);
|
||||
|
||||
connect(
|
||||
upn_suffix_combo, &QComboBox::currentTextChanged,
|
||||
this, &AttributeMultiEdit::edited);
|
||||
|
||||
set_enabled(false);
|
||||
}
|
||||
|
||||
bool UpnMultiEdit::apply_internal(AdInterface &ad, const QString &target) {
|
||||
bool UpnMultiEdit::apply(AdInterface &ad, const QString &target) const {
|
||||
const QString new_value = [&]() {
|
||||
const AdObject current_object = ad.search_object(target);
|
||||
const QString current_prefix = current_object.get_upn_prefix();
|
@ -22,20 +22,23 @@
|
||||
#define UPN_MULTI_EDIT_H
|
||||
|
||||
/**
|
||||
* Edit for editing UPN suffixes of multiple objects. Note
|
||||
* that prefix remains unchanged.
|
||||
* Edit for editing UPN suffixes of multiple objects.
|
||||
* This special version is needed because when editing
|
||||
* multiple objects, only the suffix is edited, so
|
||||
* normal UpnEdit doesn't work for this.
|
||||
*/
|
||||
|
||||
#include "attribute_multi_edits/attribute_multi_edit.h"
|
||||
#include "attribute_edits/attribute_edit.h"
|
||||
|
||||
class QComboBox;
|
||||
|
||||
class UpnMultiEdit final : public AttributeMultiEdit {
|
||||
class UpnMultiEdit final : public AttributeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UpnMultiEdit(QComboBox *upn_suffix_combo_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, AdInterface &ad, QObject *parent);
|
||||
UpnMultiEdit(QComboBox *upn_suffix_combo, AdInterface &ad, QObject *parent);
|
||||
|
||||
DECL_ATTRIBUTE_MULTI_EDIT_VIRTUALS();
|
||||
bool apply(AdInterface &ad, const QString &target) const override;
|
||||
void set_enabled(const bool enabled) override;
|
||||
|
||||
private:
|
||||
QComboBox *upn_suffix_combo;
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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 "attribute_multi_edits/attribute_multi_edit.h"
|
||||
|
||||
#include "multi_tabs/properties_multi_tab.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
|
||||
AttributeMultiEdit::AttributeMultiEdit(QCheckBox *apply_check_arg, QList<AttributeMultiEdit *> &edits_out, QObject *parent)
|
||||
: QObject(parent) {
|
||||
if (edits_out.contains(this)) {
|
||||
qDebug() << "ERROR: attribute edit added twice to list!";
|
||||
} else {
|
||||
edits_out.append(this);
|
||||
}
|
||||
|
||||
apply_check = apply_check_arg;
|
||||
|
||||
connect(
|
||||
apply_check, &QAbstractButton::toggled,
|
||||
this, &AttributeMultiEdit::on_check_toggled);
|
||||
}
|
||||
|
||||
bool AttributeMultiEdit::apply(AdInterface &ad, const QList<QString> &target_list) {
|
||||
const bool need_to_apply = apply_check->isChecked();
|
||||
if (!need_to_apply) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool total_success = true;
|
||||
|
||||
for (const QString &target : target_list) {
|
||||
const bool success = apply_internal(ad, target);
|
||||
|
||||
if (!success) {
|
||||
total_success = false;
|
||||
}
|
||||
}
|
||||
|
||||
apply_check->setChecked(false);
|
||||
|
||||
return total_success;
|
||||
}
|
||||
|
||||
void AttributeMultiEdit::reset() {
|
||||
// NOTE: when apply_check is unchecked, the
|
||||
// on_check_toggled() calls set_enabled()
|
||||
apply_check->setChecked(false);
|
||||
}
|
||||
|
||||
void AttributeMultiEdit::on_check_toggled() {
|
||||
if (apply_check->isChecked()) {
|
||||
emit edited();
|
||||
}
|
||||
|
||||
// NOTE: call set_enabled() of the subclass
|
||||
const bool enabled = apply_check->isChecked();
|
||||
set_enabled(enabled);
|
||||
}
|
||||
|
||||
void multi_edits_connect_to_tab(const QList<AttributeMultiEdit *> &edits, PropertiesMultiTab *tab) {
|
||||
for (auto edit : edits) {
|
||||
QObject::connect(
|
||||
edit, &AttributeMultiEdit::edited,
|
||||
tab, &PropertiesMultiTab::on_edit_edited);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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 ATTRIBUTE_MULTI_EDIT_H
|
||||
#define ATTRIBUTE_MULTI_EDIT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AdInterface;
|
||||
class PropertiesMultiTab;
|
||||
class QCheckBox;
|
||||
|
||||
/**
|
||||
* Base class for attribute multi edits.
|
||||
*/
|
||||
|
||||
class AttributeMultiEdit : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AttributeMultiEdit(QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, QObject *parent);
|
||||
|
||||
bool apply(AdInterface &ad, const QList<QString> &target_list);
|
||||
void reset();
|
||||
|
||||
private slots:
|
||||
void on_check_toggled();
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
|
||||
protected:
|
||||
QCheckBox *apply_check;
|
||||
|
||||
virtual bool apply_internal(AdInterface &ad, const QString &target) = 0;
|
||||
virtual void set_enabled(const bool enabled) = 0;
|
||||
};
|
||||
|
||||
#define DECL_ATTRIBUTE_MULTI_EDIT_VIRTUALS() \
|
||||
protected: \
|
||||
bool apply_internal(AdInterface &ad, const QString &target) override; \
|
||||
void set_enabled(const bool enabled) override; \
|
||||
\
|
||||
public:
|
||||
|
||||
void multi_edits_connect_to_tab(const QList<AttributeMultiEdit *> &edits, PropertiesMultiTab *tab);
|
||||
|
||||
#endif /* ATTRIBUTE_MULTI_EDIT_H */
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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 "attribute_multi_edits/country_multi_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "attribute_edits/country_combo.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
|
||||
CountryMultiEdit::CountryMultiEdit(QComboBox *country_combo_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, QObject *parent)
|
||||
: AttributeMultiEdit(check, edits_out, parent) {
|
||||
country_combo = country_combo_arg;
|
||||
|
||||
connect(
|
||||
country_combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &AttributeMultiEdit::edited);
|
||||
|
||||
set_enabled(false);
|
||||
}
|
||||
|
||||
bool CountryMultiEdit::apply_internal(AdInterface &ad, const QString &target) {
|
||||
return country_combo_apply(country_combo, ad, target);
|
||||
}
|
||||
|
||||
void CountryMultiEdit::set_enabled(const bool enabled) {
|
||||
country_combo->setEnabled(enabled);
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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 "attribute_multi_edits/expiry_multi_edit.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "attribute_edits/expiry_widget.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
|
||||
ExpiryMultiEdit::ExpiryMultiEdit(ExpiryWidget *edit_widget_arg, QCheckBox *check, QList<AttributeMultiEdit *> &edits_out, QObject *parent)
|
||||
: AttributeMultiEdit(check, edits_out, parent) {
|
||||
edit_widget = edit_widget_arg;
|
||||
|
||||
const QString label_text = g_adconfig->get_attribute_display_name(ATTRIBUTE_ACCOUNT_EXPIRES, "") + ":";
|
||||
apply_check->setText(label_text);
|
||||
|
||||
connect(
|
||||
edit_widget, &ExpiryWidget::edited,
|
||||
this, &AttributeMultiEdit::edited);
|
||||
|
||||
set_enabled(false);
|
||||
}
|
||||
|
||||
bool ExpiryMultiEdit::apply_internal(AdInterface &ad, const QString &target) {
|
||||
return edit_widget->apply(ad, target);
|
||||
}
|
||||
|
||||
void ExpiryMultiEdit::set_enabled(const bool enabled) {
|
||||
if (!enabled) {
|
||||
edit_widget->load(AdObject());
|
||||
}
|
||||
|
||||
edit_widget->setEnabled(enabled);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user