From f7c4ec15908a30cd7ca6f83ccd582ff65a82f2b8 Mon Sep 17 00:00:00 2001 From: Lukas Oyen Date: Wed, 28 Jun 2017 15:53:14 +0200 Subject: [PATCH 1/2] Bug #xxx: umc-diagnostic: new check `inconsistent_policies.py` Inspired by `inconsistent_pw_policies_posix.py` and `inconsistent_pw_policies_samba.py` by Julian Hupertz. --- .../diagnostic/plugins/inconsistent_policies.py | 184 +++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100755 management/univention-management-console-module-diagnostic/umc/python/diagnostic/plugins/inconsistent_policies.py diff --git a/management/univention-management-console-module-diagnostic/umc/python/diagnostic/plugins/inconsistent_policies.py b/management/univention-management-console-module-diagnostic/umc/python/diagnostic/plugins/inconsistent_policies.py new file mode 100755 index 0000000..c337da1 --- /dev/null +++ b/management/univention-management-console-module-diagnostic/umc/python/diagnostic/plugins/inconsistent_policies.py @@ -0,0 +1,184 @@ +#!/usr/bin/python2.7 +# coding: utf-8 +# +# Univention Management Console module: +# System Diagnosis UMC module +# +# Copyright 2017 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +import ldap + +import univention.uldap +import univention.admin.uldap +import univention.admin.modules as udm_modules +from univention.management.console.modules.diagnostic import Warning + +from univention.lib.i18n import Translation +_ = Translation('univention-management-console-module-diagnostic').translate + +title = _('Check password policy inconsistencies') +description = _('No problems found.') + + +def fix_policies(): + for mismatch in check_policies(): + mismatch.fix() + return run() + + +actions = { + 'fix_policies': fix_policies, +} + + +class PolicyMismatch(Exception): + def __init__(self, policy, mismatches): + super(PolicyMismatch, self).__init__(policy.dn) + self.policy = policy + self.mismatches = mismatches + + def __str__(self): + msg = _('In policy {name!r} (see {{udm:policies/policy}}):') + messages = [msg.format(name=self.policy.get('name'))] + empty_tmpl = _('Attribute {attr} should be empty.') + mismatch_tmpl = _('Attribute {attr} should have value {value}.') + properties = udm_modules.get(self.policy.module).property_descriptions + + for (attr, value) in self.mismatches: + template = empty_tmpl if value is None else mismatch_tmpl + attr_desc = properties.get(attr).short_description + messages.append(template.format(attr=attr_desc, value=value)) + return '\n'.join(messages) + + def module(self): + return { + 'module': 'udm', + 'flavor': 'policies/policy', + 'props': { + 'openObject': { + 'objectDN': self.policy.dn, + 'objectType': 'policies/pwhistory' + } + } + } + + def fix(self): + for (attr, value) in self.mismatches: + self.policy[attr] = value + self.policy.modify() + + +def get_samba_domain(ldap_connection, position): + module = udm_modules.get('settings/sambadomain') + udm_modules.init(ldap_connection, position, module) + for sambadomain in module.lookup(None, ldap_connection, ''): + sambadomain.open() + return sambadomain + + +def policy_used(ldap_connection, dn): + filter_expr = ldap.filter.filter_format('(univentionPolicyReference=%s)', (dn,)) + search = ldap_connection.search(filter=filter_expr, sizelimit=3, attr=['dn']) + return any(dn is not None for (dn, attr) in search) + + +def get_pw_policies(ldap_connection, position): + module = udm_modules.get('policies/pwhistory') + udm_modules.init(ldap_connection, position, module) + for policy in module.lookup(None, ldap_connection, ''): + if policy_used(ldap_connection, policy.dn): + policy.open() + yield policy + + +def to_days(unix_time_interval, default_unit='seconds'): + if unix_time_interval is None: + return None + + try: + (value, unit) = unix_time_interval + except ValueError: + (value, unit) = (unix_time_interval, default_unit) + + try: + as_int = int(value) + except ValueError: + as_int = 0 + + if unit == 'days': + return str(as_int) + elif unit == 'hours': + return str(as_int / 24) + elif unit == 'minutes': + return str(as_int / (24 * 60)) + return str(as_int / (24 * 60 * 60)) + + +def policy_mismatch(samba_domain, pw_policy): + def compare(policy_attr, domain_attr, convert=lambda x: x): + (policy_value, domain_value) = (pw_policy.get(policy_attr), samba_domain.get(domain_attr)) + converted_domain_value = convert(domain_value) + if policy_value != converted_domain_value: + yield (policy_attr, converted_domain_value) + + for result in compare('length', 'passwordHistory'): + yield result + for result in compare('pwLength', 'passwordLength'): + yield result + for result in compare('expiryInterval', 'maxPasswordAge', to_days): + yield result + + +def check_policies(): + (ldap_connection, position) = univention.admin.uldap.getAdminConnection() + samba_domain = get_samba_domain(ldap_connection, position) + for policy in get_pw_policies(ldap_connection, position): + mismatch = list(policy_mismatch(samba_domain, policy)) + if mismatch: + yield PolicyMismatch(policy, mismatch) + + +def run(): + univention.admin.modules.update() + problems = list(check_policies()) + error = _('There are inconsistencies between the Univention policies and the Samba settings.') + buttons = [{ + 'action': 'fix_policies', + 'label': _('Fix password policies'), + }] + + if problems: + ed = [error, ''] + ed.extend(str(error) for error in problems) + umc_modules = [e.module() for e in problems] + raise Warning(description='\n'.join(ed), umc_modules=umc_modules, buttons=buttons) + + +if __name__ == '__main__': + from univention.management.console.modules.diagnostic import main + main() -- 2.7.4 From 2a9edd309b15d1fd1ffd8246cf8906dac77199f5 Mon Sep 17 00:00:00 2001 From: Lukas Oyen Date: Thu, 29 Jun 2017 14:48:10 +0200 Subject: [PATCH 2/2] Bug #xxx: umc-diagnostic: new check `inconsistent_policies.py` (po) --- .../umc/python/diagnostic/de.po | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/management/univention-management-console-module-diagnostic/umc/python/diagnostic/de.po b/management/univention-management-console-module-diagnostic/umc/python/diagnostic/de.po index affad86..e7cec70 100644 --- a/management/univention-management-console-module-diagnostic/umc/python/diagnostic/de.po +++ b/management/univention-management-console-module-diagnostic/umc/python/diagnostic/de.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: univention-management-console-module-diagnostic\n" -"Report-Msgid-Bugs-To: packages@univention.de\n" -"POT-Creation-Date: 2016-01-14 12:19+0100\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-29 14:47+0200\n" "PO-Revision-Date: \n" "Last-Translator: Univention GmbH \n" "Language-Team: Univention GmbH \n" @@ -27,6 +27,22 @@ msgstr "" msgid "Adjust to suggested limits" msgstr "An vorgeschlagene Limits anpassen" +#: umc/python/diagnostic/plugins/inconsistent_policies.py:69 +msgid "Attribute {attr} should be empty." +msgstr "Attribut {attr} sollte nicht gesetzt sein." + +#: umc/python/diagnostic/plugins/inconsistent_policies.py:70 +msgid "Attribute {attr} should have value {value}." +msgstr "Attribut {attr} sollte den Wert {value} haben." + +#: umc/python/diagnostic/plugins/inconsistent_policies.py:44 +msgid "Check password policy inconsistencies" +msgstr "Überprüfe Password Richtlinien" + +#: umc/python/diagnostic/plugins/inconsistent_policies.py:171 +msgid "Fix password policies" +msgstr "Berichtige Password Richtlinien" + #: umc/python/diagnostic/plugins/gateway.py:11 msgid "Gateway is not reachable" msgstr "Gateway ist nicht erreichbar" @@ -49,6 +65,10 @@ msgid "If these settings are correct the problem relies in the gateway itself:" msgstr "" "Wenn diese Einstellungen richtig sind liegt das Problem im Gateway selbst:" +#: umc/python/diagnostic/plugins/inconsistent_policies.py:66 +msgid "In policy {name!r} (see {{udm:policies/policy}}):" +msgstr "In der Richtlinie {name!r} (siehe {{udm:policies/policy}}):" + #: umc/python/diagnostic/plugins/security_limits.py:19 #, python-brace-format msgid "" @@ -97,6 +117,10 @@ msgstr "" msgid "Nameserver(s) are not responsive" msgstr "Nameserver sind nicht ansprechbar" +#: umc/python/diagnostic/plugins/inconsistent_policies.py:45 +msgid "No problems found." +msgstr "Keine Probleme gefunden." + #: umc/python/diagnostic/plugins/package_status.py:11 msgid "Package status corrupt" msgstr "Paketstatus korrupt" @@ -231,6 +255,14 @@ msgstr "" "Der SSH Host-Key des entfernten Rechners hat sich geändert (vielleicht wurde " "der Rechner neu installiert). " +#: umc/python/diagnostic/plugins/inconsistent_policies.py:168 +msgid "" +"There are inconsistencies between the Univention policies and the Samba " +"settings." +msgstr "" +"Es gibt Widersprüche in den Univention Password Richtlinien und den Samba " +"Einstellungen." + #: umc/python/diagnostic/plugins/proxy.py:16 msgid "" "There was an error using the proxy server. The {setup:network} can be used " -- 2.7.4