URL: https://github.com/freeipa/freeipa/pull/1367
Author: abbra
 Title: #1367: [backport ipa-4-5] Trust avoid mitkrb trust type backport
Action: opened

PR body:
"""
Manual backport of https://github.com/freeipa/freeipa/pull/1294 because the 
code did diverge between 4.5 and 4.6.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1367/head:pr1367
git checkout pr1367
From fbb41aa8f4c4bac279c96dbd8fcecb5edba5ea6e Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Thu, 9 Nov 2017 09:57:47 +0200
Subject: [PATCH 1/3] ipaserver/plugins/trust.py; fix some indenting issues

---
 ipaserver/plugins/trust.py | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
index d0bbfbc47c..f06aa25486 100644
--- a/ipaserver/plugins/trust.py
+++ b/ipaserver/plugins/trust.py
@@ -315,15 +315,17 @@ def generate_creds(trustinstance, style, **options):
         elif style == CRED_STYLE_KERBEROS:
             sp = admin_name.split('\\')
             if len(sp) > 1:
-               sp = [sp[1]]
+                sp = [sp[1]]
             else:
-               sp = admin_name.split(sep)
+                sp = admin_name.split(sep)
             if len(sp) == 1:
-                sp.append(trustinstance.remote_domain.info['dns_domain'].upper())
+                sp.append(trustinstance.remote_domain
+                          .info['dns_domain'].upper())
         creds = u"{name}%{password}".format(name=sep.join(sp),
                                             password=password)
     return creds
 
+
 def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
     """
     First, we try to derive the parameters of the ID range based on the
@@ -354,7 +356,7 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
         # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System
         info_filter = '(objectClass=msSFU30DomainInfo)'
         info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\
-                  + basedn
+            + basedn
 
         # Get the domain validator
         domain_validator = ipaserver.dcerpc.DomainValidator(myapi)
@@ -402,7 +404,7 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
 
                 base_id = int(info.get('msSFU30OrderNumber')[0])
                 range_size = (1 + (max_id - base_id) // DEFAULT_RANGE_SIZE)\
-                             * DEFAULT_RANGE_SIZE
+                    * DEFAULT_RANGE_SIZE
 
     # Second, options given via the CLI options take precedence to discovery
     if options.get('range_type', None):
@@ -630,11 +632,10 @@ def warning_if_ad_trust_dom_have_missing_SID(self, result, **options):
             pass
         else:
             for entry in entries:
-                 add_message(
+                add_message(
                     options['version'],
                     result,
-                    BrokenTrust(domain=entry.single_value['cn'])
-                 )
+                    BrokenTrust(domain=entry.single_value['cn']))
 
 
 @register()

From 81abf2bff8762dfb2725f34df51cae9b84b68200 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Fri, 17 Nov 2017 17:19:25 +0200
Subject: [PATCH 2/3] trust: detect and error out when non-AD trust with IPA
 domain name exists

Quite often users choose wrong type of trust on Active Directory side
when setting up a trust to freeIPA. The trust type supported by freeIPA
is just a normal forest trust to another Active Directory. However,
some people follow old internet recipes that force using a trust to MIT
Kerberos realm.

This is a wrong type of trust. Unfortunately, when someone used MIT
Kerberos realm trust, there is no way to programmatically remote the
trust from freeIPA side. As result, we have to detect such situation and
report an error.

To do proper reporting, we need reuse some constants and trust type
names we use in IPA CLI/Web UI. These common components were moved to
a separate ipaserver/dcerpc_common.py module that is imported by both
ipaserver/plugins/trust.py and ipaserver/dcerpc.py.

Fixes https://pagure.io/freeipa/issue/7264
---
 ipaserver/dcerpc.py        | 37 +++++++++++++++--------
 ipaserver/dcerpc_common.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++
 ipaserver/plugins/trust.py | 65 ++++++++++-------------------------------
 3 files changed, 113 insertions(+), 62 deletions(-)
 create mode 100644 ipaserver/dcerpc_common.py

diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index aa63cd9db0..ac1b2a3478 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -31,6 +31,10 @@
 from ipapython.ipa_log_manager import root_logger
 from ipapython.dn import DN
 from ipaserver.install import installutils
+from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL,
+                                     TRUST_JOIN_EXTERNAL,
+                                     trust_type_string)
+
 from ipalib.util import normalize_name
 
 import os
@@ -77,15 +81,6 @@
 and Samba4 python bindings.
 """)
 
-# Both constants can be used as masks against trust direction
-# because bi-directional has two lower bits set.
-TRUST_ONEWAY = 1
-TRUST_BIDIRECTIONAL = 3
-
-# Trust join behavior
-# External trust -- allow creating trust to a non-root domain in the forest
-TRUST_JOIN_EXTERNAL = 1
-
 
 def is_sid_valid(sid):
     try:
@@ -151,6 +146,7 @@ def is_sid_valid(sid):
     pysss_nss_idmap.ID_BOTH: 'both',
 }
 
+
 class TrustTopologyConflictSolved(Exception):
     """
     Internal trust error: raised when previously detected
@@ -1254,9 +1250,26 @@ def establish_trust(self, another_domain, trustdom_secret,
             dname = lsa.String()
             dname.string = another_domain.info['dns_domain']
             res = self._pipe.QueryTrustedDomainInfoByName(
-                                self._policy_handle,
-                                dname,
-                                lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
+                self._policy_handle,
+                dname,
+                lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO
+            )
+            if res.info_ex.trust_type != lsa.LSA_TRUST_TYPE_UPLEVEL:
+                msg = _('There is already a trust to {ipa_domain} with '
+                        'unsupported type {trust_type}. Please remove '
+                        'it manually on AD DC side.')
+                ttype = trust_type_string(
+                    res.info_ex.trust_type, res.info_ex.trust_attributes
+                )
+                err = unicode(msg).format(
+                    ipa_domain=another_domain.info['dns_domain'],
+                    trust_type=ttype)
+
+                raise errors.ValidationError(
+                    name=_('AD domain controller'),
+                    error=err
+                )
+
             self._pipe.DeleteTrustedDomain(self._policy_handle,
                                            res.info_ex.sid)
         except RuntimeError as e:
diff --git a/ipaserver/dcerpc_common.py b/ipaserver/dcerpc_common.py
new file mode 100644
index 0000000000..526b025e32
--- /dev/null
+++ b/ipaserver/dcerpc_common.py
@@ -0,0 +1,73 @@
+import six
+from ipalib import _
+if six.PY3:
+    unicode = six.text_type
+
+# Both constants can be used as masks against trust direction
+# because bi-directional has two lower bits set.
+TRUST_ONEWAY = 1
+TRUST_BIDIRECTIONAL = 3
+
+# Trust join behavior
+# External trust -- allow creating trust to a non-root domain in the forest
+TRUST_JOIN_EXTERNAL = 1
+
+# We don't want to import any of Samba Python code here just for constants
+# Since these constants set in MS-ADTS, we can rely on their stability
+LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001
+
+_trust_direction_dict = {
+        1: _('Trusting forest'),
+        2: _('Trusted forest'),
+        3: _('Two-way trust')
+}
+
+_trust_status_dict = {
+        True: _('Established and verified'),
+        False: _('Waiting for confirmation by remote side')
+}
+
+_trust_type_dict_unknown = _('Unknown')
+
+# Trust type is a combination of ipanttrusttype and ipanttrustattributes
+# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and
+# 2+(1 << 3) becomes 10.
+_trust_type_dict = {
+        1: _('Non-Active Directory domain'),
+        2: _('Active Directory domain'),
+        3: _('RFC4120-compliant Kerberos realm'),
+        10: _('Non-transitive external trust to a domain in '
+              'another Active Directory forest'),
+        11: _('Non-transitive external trust to an RFC4120-'
+              'compliant Kerberos realm')
+}
+
+
+def trust_type_string(level, attrs):
+    """
+    Returns a string representing a type of the trust.
+    The original field is an enum:
+      LSA_TRUST_TYPE_DOWNLEVEL  = 0x00000001,
+      LSA_TRUST_TYPE_UPLEVEL    = 0x00000002,
+      LSA_TRUST_TYPE_MIT        = 0x00000003
+    """
+    transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
+    string = _trust_type_dict.get(int(level) | (transitive << 3),
+                                  _trust_type_dict_unknown)
+    return unicode(string)
+
+
+def trust_direction_string(level):
+    """
+    Returns a string representing a direction of the trust.
+    The original field is a bitmask taking two bits in use
+      LSA_TRUST_DIRECTION_INBOUND  = 0x00000001,
+      LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
+    """
+    string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
+    return unicode(string)
+
+
+def trust_status_string(level):
+    string = _trust_status_dict.get(level, _trust_type_dict_unknown)
+    return unicode(string)
diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
index f06aa25486..d01529ee02 100644
--- a/ipaserver/plugins/trust.py
+++ b/ipaserver/plugins/trust.py
@@ -44,6 +44,13 @@
 from ipalib import output
 from ldap import SCOPE_SUBTREE
 from time import sleep
+from ipaserver.dcerpc_common import (TRUST_ONEWAY,
+                                     TRUST_BIDIRECTIONAL,
+                                     TRUST_JOIN_EXTERNAL,
+                                     LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE,
+                                     trust_type_string,
+                                     trust_direction_string,
+                                     trust_status_string)
 
 if six.PY3:
     unicode = str
@@ -63,9 +70,6 @@
 if api.env.in_server and api.env.context in ['lite', 'server']:
     try:
         import ipaserver.dcerpc
-        from ipaserver.dcerpc import (TRUST_ONEWAY,
-                                      TRUST_BIDIRECTIONAL,
-                                      TRUST_JOIN_EXTERNAL)
         import dbus
         import dbus.mainloop.glib
         _bindings_installed = True
@@ -157,28 +161,14 @@
 
 register = Registry()
 
-# Trust type is a combination of ipanttrusttype and ipanttrustattributes
-# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and
-# 2+(1 << 3) becomes 10.
-_trust_type_dict = {1 : _('Non-Active Directory domain'),
-                    2 : _('Active Directory domain'),
-                    3 : _('RFC4120-compliant Kerberos realm'),
-                    10: _('Non-transitive external trust to a domain in another Active Directory forest')}
-
-_trust_direction_dict = {1 : _('Trusting forest'),
-                         2 : _('Trusted forest'),
-                         3 : _('Two-way trust')}
-_trust_status_dict = {True : _('Established and verified'),
-                 False : _('Waiting for confirmation by remote side')}
-_trust_type_dict_unknown = _('Unknown')
-
-_trust_type_option = StrEnum('trust_type',
-                        cli_name='type',
-                        label=_('Trust type (ad for Active Directory, default)'),
-                        values=(u'ad',),
-                        default=u'ad',
-                        autofill=True,
-                    )
+_trust_type_option = StrEnum(
+         'trust_type',
+         cli_name='type',
+         label=_('Trust type (ad for Active Directory, default)'),
+         values=(u'ad',),
+         default=u'ad',
+         autofill=True,
+        )
 
 DEFAULT_RANGE_SIZE = 200000
 
@@ -187,31 +177,6 @@
 CRED_STYLE_SAMBA = 1
 CRED_STYLE_KERBEROS = 2
 
-LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001
-
-def trust_type_string(level, attrs):
-    """
-    Returns a string representing a type of the trust. The original field is an enum:
-      LSA_TRUST_TYPE_DOWNLEVEL  = 0x00000001,
-      LSA_TRUST_TYPE_UPLEVEL    = 0x00000002,
-      LSA_TRUST_TYPE_MIT        = 0x00000003
-    """
-    transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
-    string = _trust_type_dict.get(int(level) | (transitive << 3), _trust_type_dict_unknown)
-    return unicode(string)
-
-def trust_direction_string(level):
-    """
-    Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use
-      LSA_TRUST_DIRECTION_INBOUND  = 0x00000001,
-      LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
-    """
-    string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
-    return unicode(string)
-
-def trust_status_string(level):
-    string = _trust_status_dict.get(level, _trust_type_dict_unknown)
-    return unicode(string)
 
 def make_trust_dn(env, trust_type, dn):
     assert isinstance(dn, DN)

From 06321c5140ed43cc7b5c850a3be18f823b4d7b23 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Fri, 17 Nov 2017 17:25:57 +0200
Subject: [PATCH 3/3] ipaserver/plugins/trust.py: pep8 compliance

---
 ipaserver/plugins/trust.py | 356 +++++++++++++++++++++++++++------------------
 1 file changed, 214 insertions(+), 142 deletions(-)

diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
index d01529ee02..73e137abce 100644
--- a/ipaserver/plugins/trust.py
+++ b/ipaserver/plugins/trust.py
@@ -81,10 +81,10 @@
 
 Manage trust relationship between IPA and Active Directory domains.
 
-In order to allow users from a remote domain to access resources in IPA
-domain, trust relationship needs to be established. Currently IPA supports
-only trusts between IPA and Active Directory domains under control of Windows
-Server 2008 or later, with functional level 2008 or later.
+In order to allow users from a remote domain to access resources in IPA domain,
+trust relationship needs to be established. Currently IPA supports only trusts
+between IPA and Active Directory domains under control of Windows Server 2008
+or later, with functional level 2008 or later.
 
 Please note that DNS on both IPA and Active Directory domain sides should be
 configured properly to discover each other. Trust relationship relies on
@@ -95,7 +95,8 @@
 1. Establish cross-realm trust with Active Directory using AD administrator
    credentials:
 
-   ipa trust-add --type=ad <ad.domain> --admin <AD domain administrator> --password
+   ipa trust-add --type=ad <ad.domain> --admin <AD domain administrator> \
+           --password
 
 2. List all existing trust relationships:
 
@@ -110,35 +111,39 @@
    ipa trust-del <ad.domain>
 
 Once trust relationship is established, remote users will need to be mapped
-to local POSIX groups in order to actually use IPA resources. The mapping should
-be done via use of external membership of non-POSIX group and then this group
-should be included into one of local POSIX groups.
+to local POSIX groups in order to actually use IPA resources. The mapping
+should be done via use of external membership of non-POSIX group and then
+this group should be included into one of local POSIX groups.
 
 Example:
 
-1. Create group for the trusted domain admins' mapping and their local POSIX group:
+1. Create group for the trusted domain admins' mapping and their local POSIX
+group:
 
-   ipa group-add --desc='<ad.domain> admins external map' ad_admins_external --external
+   ipa group-add --desc='<ad.domain> admins external map' \
+           ad_admins_external --external
    ipa group-add --desc='<ad.domain> admins' ad_admins
 
-2. Add security identifier of Domain Admins of the <ad.domain> to the ad_admins_external
-   group:
+2. Add security identifier of Domain Admins of the <ad.domain> to the
+   ad_admins_external group:
 
    ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'
 
-3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group:
+3. Allow members of ad_admins_external group to be associated with
+   ad_admins POSIX group:
 
    ipa group-add-member ad_admins --groups ad_admins_external
 
-4. List members of external members of ad_admins_external group to see their SIDs:
+4. List members of external members of ad_admins_external group to see
+   their SIDs:
 
    ipa group-show ad_admins_external
 
 
 GLOBAL TRUST CONFIGURATION
 
-When IPA AD trust subpackage is installed and ipa-adtrust-install is run,
-a local domain configuration (SID, GUID, NetBIOS name) is generated. These
+When IPA AD trust subpackage is installed and ipa-adtrust-install is run, a
+local domain configuration (SID, GUID, NetBIOS name) is generated. These
 identifiers are then used when communicating with a trusted domain of the
 particular type.
 
@@ -147,11 +152,11 @@
    ipa trustconfig-show --type ad
 
 2. Modify global configuration for all trusts of Active Directory type and set
-   a different fallback primary group (fallback primary group GID is used as
-   a primary user GID if user authenticating to IPA domain does not have any other
-   primary GID already set):
+   a different fallback primary group (fallback primary group GID is used as a
+   primary user GID if user authenticating to IPA domain does not have any
+   other primary GID already set):
 
-   ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group"
+   ipa trustconfig-mod --type ad --fallback-primary-group "another AD group"
 
 3. Change primary fallback group back to default hidden group (any group with
    posixGroup object class is allowed):
@@ -185,6 +190,7 @@ def make_trust_dn(env, trust_type, dn):
         return DN(dn, container_dn)
     return dn
 
+
 def find_adtrust_masters(ldap, api):
     """
     Returns a list of names of IPA servers with ADTRUST component configured.
@@ -200,6 +206,7 @@ def find_adtrust_masters(ldap, api):
 
     return [entry.dn[1].value for entry in entries]
 
+
 def verify_samba_component_presence(ldap, api):
     """
     Verifies that Samba is installed and configured on this particular master.
@@ -233,7 +240,7 @@ def raise_missing_component_error(message):
 
     # First check for packages missing
     elif not _bindings_installed:
-        error_message=_(
+        error_message = _(
             'Cannot perform the selected command without Samba 4 support '
             'installed. Make sure you have installed server-trust-ad '
             'sub-package of IPA.'
@@ -243,7 +250,7 @@ def raise_missing_component_error(message):
 
     # Packages present, but ADTRUST instance is not configured
     elif not adtrust_present:
-        error_message=_(
+        error_message = _(
             'Cannot perform the selected command without Samba 4 instance '
             'configured on this machine. Make sure you have run '
             'ipa-adtrust-install on this server.'
@@ -263,7 +270,8 @@ def generate_creds(trustinstance, style, **options):
        **options     -- options with realm_admin and realm_passwd keys
 
     Result:
-       a string representing credentials with first % separating username and password
+       a string representing credentials with first % separating
+       username and password
        None is returned if realm_passwd key returns nothing from options
     """
     creds = None
@@ -284,8 +292,9 @@ def generate_creds(trustinstance, style, **options):
             else:
                 sp = admin_name.split(sep)
             if len(sp) == 1:
-                sp.append(trustinstance.remote_domain
-                          .info['dns_domain'].upper())
+                sp.append(
+                    trustinstance.remote_domain.info['dns_domain'].upper()
+                )
         creds = u"{name}%{password}".format(name=sep.join(sp),
                                             password=password)
     return creds
@@ -334,7 +343,8 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
         creds = None
         if trustinstance:
             # Re-use AD administrator credentials if they were provided
-            creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options)
+            creds = generate_creds(trustinstance,
+                                   style=CRED_STYLE_KERBEROS, **options)
             if creds:
                 domain_validator._admin_creds = creds
         # KDC might not get refreshed data at the first time,
@@ -417,21 +427,32 @@ def fetch_trusted_domains_over_dbus(myapi, log, forest_name):
         _stdout = ''
         _stderr = ''
         bus = dbus.SystemBus()
-        intf = bus.get_object(DBUS_IFACE_TRUST,"/", follow_name_owner_changes=True)
-        fetch_domains_method = intf.get_dbus_method('fetch_domains', dbus_interface=DBUS_IFACE_TRUST)
+        intf = bus.get_object(DBUS_IFACE_TRUST, "/",
+                              follow_name_owner_changes=True)
+        fetch_domains_method = intf.get_dbus_method(
+                'fetch_domains',
+                dbus_interface=DBUS_IFACE_TRUST)
         (_ret, _stdout, _stderr) = fetch_domains_method(forest_name)
     except dbus.DBusException as e:
-        log.error('Failed to call %(iface)s.fetch_domains helper.'
-                       'DBus exception is %(exc)s.' % dict(iface=DBUS_IFACE_TRUST, exc=str(e)))
+        log.error(
+            'Failed to call %(iface)s.fetch_domains helper. '
+            'DBus exception is %(exc)s.' % dict(iface=DBUS_IFACE_TRUST, exc=str(e))
+        )
         if _ret != 0:
-            log.error('Helper was called for forest %(forest)s, return code is %(ret)d' % dict(forest=forest_name, ret=_ret))
-            log.error('Standard output from the helper:\n%s---\n' % (_stdout))
-            log.error('Error output from the helper:\n%s--\n' % (_stderr))
-        raise errors.ServerCommandError(server=myapi.env.host,
-                                        error=_('Fetching domains from trusted forest failed. '
-                                                'See details in the error_log'))
+            log.error(
+                'Helper was called for forest %s, return code is %d',
+                forest_name, _ret
+            )
+            log.error('Standard output from the helper:\n%s---\n', _stdout)
+            log.error('Error output from the helper:\n%s--\n', _stderr)
+        raise errors.ServerCommandError(
+            server=myapi.env.host,
+            error=_('Fetching domains from trusted forest failed. '
+                    'See details in the error_log')
+        )
     return
 
+
 @register()
 class trust(LDAPObject):
     """
@@ -538,8 +559,8 @@ def validate_sid_blacklists(self, entry_attrs):
                 continue
             for value in values:
                 if not ipaserver.dcerpc.is_sid_valid(value):
-                    raise errors.ValidationError(name=attr,
-                            error=_("invalid SID: %(value)s") % dict(value=value))
+                    err = unicode(_("invalid SID: {SID}")).format(SID=value)
+                    raise errors.ValidationError(name=attr, error=err)
 
     def get_dn(self, *keys, **kwargs):
         trust_type = kwargs.get('trust_type')
@@ -600,7 +621,8 @@ def warning_if_ad_trust_dom_have_missing_SID(self, result, **options):
                 add_message(
                     options['version'],
                     result,
-                    BrokenTrust(domain=entry.single_value['cn']))
+                    BrokenTrust(domain=entry.single_value['cn'])
+                )
 
 
 @register()
@@ -622,7 +644,7 @@ class trust_add(LDAPCreate):
     range_types = {
         u'ipa-ad-trust': unicode(_('Active Directory domain range')),
         u'ipa-ad-trust-posix': unicode(_('Active Directory trust range with '
-                                        'POSIX attributes')),
+                                         'POSIX attributes')),
                   }
 
     takes_options = LDAPCreate.takes_options + (
@@ -720,9 +742,10 @@ def execute(self, *keys, **options):
 
         trust_filter = "cn=%s" % result['value']
         trusts, _truncated = ldap.find_entries(
-                         base_dn=DN(self.api.env.container_trusts, self.api.env.basedn),
-                         filter=trust_filter,
-                         attrs_list=attrs_list)
+            base_dn=DN(self.api.env.container_trusts, self.api.env.basedn),
+            filter=trust_filter,
+            attrs_list=attrs_list
+        )
 
         result['result'] = entry_to_dict(trusts[0], **options)
 
@@ -731,10 +754,11 @@ def execute(self, *keys, **options):
         # Note that add_new_domains_from_trust will add needed ranges for
         # the algorithmic ID mapping case.
         if (options.get('trust_type') == u'ad' and
-            options.get('trust_secret') is None):
+                options.get('trust_secret') is None):
+
             if options.get('bidirectional') == True:
-                # Bidirectional trust allows us to use cross-realm TGT, so we can
-                # run the call under original user's credentials
+                # Bidirectional trust allows us to use cross-realm TGT,
+                # so we can run the call under original user's credentials
                 res = fetch_domains_from_trust(self.api, self.trustinstance,
                                                **options)
                 add_new_domains_from_trust(
@@ -790,7 +814,9 @@ def validate_options(self, *keys, **options):
         # If domain name and realm does not match, IPA server is not be able
         # to establish trust with Active Directory.
 
-        realm_not_matching_domain = (self.api.env.domain.upper() != self.api.env.realm)
+        realm_not_matching_domain = (
+            self.api.env.domain.upper() != self.api.env.realm
+        )
 
         if options['trust_type'] == u'ad' and realm_not_matching_domain:
             raise errors.ValidationError(
@@ -917,11 +943,12 @@ def validate_range(self, *keys, **options):
                 )
 
             if range_type and range_type != old_range_type:
-                raise errors.ValidationError(name=_('range type change'),
-                    error=_('ID range for the trusted domain already exists, '
-                            'but it has a different type. Please remove the '
-                            'old range manually, or do not enforce type '
-                            'via --range-type option.'))
+                raise errors.ValidationError(
+                    name=_('range type change'),
+                    error=_('ID range for the trusted domain already '
+                            'exists, but it has a different type. Please '
+                            'remove the old range manually, or do not '
+                            'enforce type via --range-type option.'))
 
         return old_range, range_name, dom_sid
 
@@ -956,33 +983,55 @@ def execute_ad(self, full_join, *keys, **options):
                     trust_type
                 )
             except errors.NotFound:
-                error_message=_("Unable to resolve domain controller for '%s' domain. ") % (keys[-1])
-                instructions=[]
+                _message = _("Unable to resolve domain controller for "
+                             "{domain} domain. ")
+                error_message = unicode(_message).format(domain=keys[-1])
+                instructions = []
+
                 if dns_container_exists(self.obj.backend):
                     try:
-                        dns_zone = self.api.Command.dnszone_show(keys[-1])['result']
-                        if ('idnsforwardpolicy' in dns_zone) and dns_zone['idnsforwardpolicy'][0] == u'only':
-                            instructions.append(_("Forward policy is defined for it in IPA DNS, "
-                                                   "perhaps forwarder points to incorrect host?"))
+                        dns_zone = self.api.Command.dnszone_show(
+                            keys[-1])['result']
+
+                        if (('idnsforwardpolicy' in dns_zone) and
+                                dns_zone['idnsforwardpolicy'][0] == u'only'):
+
+                            instructions.append(
+                                _("Forward policy is defined for it in "
+                                  "IPA DNS, perhaps forwarder points to "
+                                  "incorrect host?")
+                            )
                     except (errors.NotFound, KeyError):
-                        instructions.append(_("IPA manages DNS, please verify "
-                                              "your DNS configuration and "
-                                              "make sure that service records "
-                                              "of the '%(domain)s' domain can "
-                                              "be resolved. Examples how to "
-                                              "configure DNS with CLI commands "
-                                              "or the Web UI can be found in "
-                                              "the documentation. " ) %
-                                              dict(domain=keys[-1]))
+                        _instruction = _(
+                            "IPA manages DNS, please verify your DNS "
+                            "configuration and make sure that service "
+                            "records of the '{domain}' domain can be "
+                            "resolved. Examples how to configure DNS "
+                            "with CLI commands or the Web UI can be "
+                            "found in the documentation. "
+                        )
+                        instructions.append(
+                            unicode(_instruction).format(domain=keys[-1])
+                        )
                 else:
-                    instructions.append(_("Since IPA does not manage DNS records, ensure DNS "
-                                           "is configured to resolve '%(domain)s' domain from "
-                                           "IPA hosts and back.") % dict(domain=keys[-1]))
-                raise errors.NotFound(reason=error_message, instructions=instructions)
+                    _instruction = _(
+                        "Since IPA does not manage DNS records, ensure "
+                        "DNS is configured to resolve '{domain}' "
+                        "domain from IPA hosts and back."
+                    )
+                    instructions.append(
+                        unicode(_instruction).format(domain=keys[-1])
+                    )
+                raise errors.NotFound(
+                    reason=error_message,
+                    instructions=instructions
+                )
 
             if result is None:
-                raise errors.ValidationError(name=_('AD Trust setup'),
-                                             error=_('Unable to verify write permissions to the AD'))
+                raise errors.ValidationError(
+                    name=_('AD Trust setup'),
+                    error=_('Unable to verify write permissions to the AD')
+                )
 
             ret = dict(
                 value=pkey_to_value(
@@ -1019,12 +1068,14 @@ def execute_ad(self, full_join, *keys, **options):
                 error=_('Not enough arguments specified to perform trust '
                         'setup'))
 
+
 @register()
 class trust_del(LDAPDelete):
     __doc__ = _('Delete a trust.')
 
     msg_summary = _('Deleted trust "%(value)s"')
 
+
 @register()
 class trust_mod(LDAPUpdate):
     __doc__ = _("""
@@ -1037,13 +1088,14 @@ class trust_mod(LDAPUpdate):
     msg_summary = _('Modified trust "%(value)s" '
                     '(change will be effective in 60 seconds)')
 
-    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+    def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
 
-        self.obj.validate_sid_blacklists(entry_attrs)
+        self.obj.validate_sid_blacklists(e_attrs)
 
         return dn
 
+
 @register()
 class trust_find(LDAPSearch):
     __doc__ = _('Search for trusts.')
@@ -1054,9 +1106,10 @@ class trust_find(LDAPSearch):
         '%(count)d trust matched', '%(count)d trusts matched', 0
     )
 
-    # Since all trusts types are stored within separate containers under 'cn=trusts',
-    # search needs to be done on a sub-tree scope
-    def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+    # Since all trusts types are stored within separate containers
+    # under 'cn=trusts', search needs to be done on a sub-tree scope
+    def pre_callback(self, ldap, filters, attrs_list,
+                     base_dn, scope, *args, **options):
         # list only trust, not trust domains
         return (filters, base_dn, ldap.SCOPE_SUBTREE)
 
@@ -1076,13 +1129,16 @@ def post_callback(self, ldap, entries, truncated, *args, **options):
             trust_type = attrs.single_value.get('ipanttrusttype', None)
             attributes = attrs.single_value.get('ipanttrustattributes', 0)
             if not options.get('raw', False) and trust_type is not None:
-                attrs['trusttype'] = [trust_type_string(trust_type, attributes)]
+                attrs['trusttype'] = [
+                    trust_type_string(trust_type, attributes)
+                ]
                 del attrs['ipanttrusttype']
                 if attributes:
                     del attrs['ipanttrustattributes']
 
         return truncated
 
+
 @register()
 class trust_show(LDAPRetrieve):
     __doc__ = _('Display information about a trust.')
@@ -1098,7 +1154,7 @@ def execute(self, *keys, **options):
 
         return result
 
-    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+    def post_callback(self, ldap, dn, e_attrs, *keys, **options):
 
         assert isinstance(dn, DN)
         # Translate ipanttrusttype to trusttype
@@ -1106,25 +1162,28 @@ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         # if --raw not used
 
         if not options.get('raw', False):
-            trust_type = entry_attrs.single_value.get('ipanttrusttype', None)
-            attributes = entry_attrs.single_value.get('ipanttrustattributes', 0)
+            trust_type = e_attrs.single_value.get('ipanttrusttype', None)
+            attributes = e_attrs.single_value.get('ipanttrustattributes', 0)
             if trust_type is not None:
-                entry_attrs['trusttype'] = [trust_type_string(trust_type, attributes)]
-                del entry_attrs['ipanttrusttype']
+                e_attrs['trusttype'] = [
+                    trust_type_string(trust_type, attributes)
+                ]
+                del e_attrs['ipanttrusttype']
 
-            dir_str = entry_attrs.single_value.get('ipanttrustdirection', None)
+            dir_str = e_attrs.single_value.get('ipanttrustdirection', None)
             if dir_str is not None:
-                entry_attrs['trustdirection'] = [trust_direction_string(dir_str)]
-                del entry_attrs['ipanttrustdirection']
+                e_attrs['trustdirection'] = [trust_direction_string(dir_str)]
+                del e_attrs['ipanttrustdirection']
 
             if attributes:
-                del entry_attrs['ipanttrustattributes']
+                del e_attrs['ipanttrustattributes']
 
         return dn
 
 
 _trustconfig_dn = {
-    u'ad': DN(('cn', api.env.domain), api.env.container_cifsdomains, api.env.basedn),
+    u'ad': DN(('cn', api.env.domain),
+              api.env.container_cifsdomains, api.env.basedn),
 }
 
 
@@ -1184,8 +1243,10 @@ def get_dn(self, *keys, **kwargs):
         try:
             return _trustconfig_dn[kwargs['trust_type']]
         except KeyError:
-            raise errors.ValidationError(name='trust_type',
-                error=_("unsupported trust type"))
+            raise errors.ValidationError(
+                name='trust_type',
+                error=_("unsupported trust type")
+            )
 
     def _normalize_groupdn(self, entry_attrs):
         """
@@ -1254,8 +1315,8 @@ class trustconfig_mod(LDAPUpdate):
     msg_summary = _('Modified "%(value)s" trust configuration')
     has_output = output.simple_entry
 
-    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
-        self.obj._normalize_groupdn(entry_attrs)
+    def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options):
+        self.obj._normalize_groupdn(e_attrs)
         return dn
 
     def execute(self, *keys, **options):
@@ -1263,14 +1324,13 @@ def execute(self, *keys, **options):
         result['value'] = pkey_to_value(options['trust_type'], options)
         return result
 
-    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-        self.obj._convert_groupdn(entry_attrs, options)
+    def post_callback(self, ldap, dn, e_attrs, *keys, **options):
+        self.obj._convert_groupdn(e_attrs, options)
         self.api.Object.config.show_servroles_attributes(
-            entry_attrs, "AD trust agent", "AD trust controller", **options)
+            e_attrs, "AD trust agent", "AD trust controller", **options)
         return dn
 
 
-
 @register()
 class trustconfig_show(LDAPRetrieve):
     __doc__ = _('Show global trust configuration.')
@@ -1293,18 +1353,21 @@ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
 
 if _nss_idmap_installed:
     _idmap_type_dict = {
-        pysss_nss_idmap.ID_USER  : 'user',
-        pysss_nss_idmap.ID_GROUP : 'group',
-        pysss_nss_idmap.ID_BOTH  : 'both',
+        pysss_nss_idmap.ID_USER: 'user',
+        pysss_nss_idmap.ID_GROUP: 'group',
+        pysss_nss_idmap.ID_BOTH: 'both',
     }
+
     def idmap_type_string(level):
         string = _idmap_type_dict.get(int(level), 'unknown')
         return unicode(string)
 
+
 @register()
 class trust_resolve(Command):
     NO_CLI = True
-    __doc__ = _('Resolve security identifiers of users and groups in trusted domains')
+    __doc__ = _('Resolve security identifiers of users and groups '
+                'in trusted domains')
 
     takes_options = (
         Str('sids+',
@@ -1313,8 +1376,8 @@ class trust_resolve(Command):
     )
 
     has_output_params = (
-        Str('name', label= _('Name')),
-        Str('sid', label= _('SID')),
+        Str('name', label=_('Name')),
+        Str('sid', label=_('SID')),
     )
 
     has_output = (
@@ -1326,13 +1389,15 @@ def execute(self, *keys, **options):
         if not _nss_idmap_installed:
             return dict(result=result)
         try:
+            NAME_KEY = pysss_nss_idmap.NAME_KEY
+            TYPE_KEY = pysss_nss_idmap.TYPE_KEY
             sids = [str(x) for x in options['sids']]
             xlate = pysss_nss_idmap.getnamebysid(sids)
             for sid in xlate:
                 entry = dict()
                 entry['sid'] = [unicode(sid)]
-                entry['name'] = [unicode(xlate[sid][pysss_nss_idmap.NAME_KEY])]
-                entry['type'] = [idmap_type_string(xlate[sid][pysss_nss_idmap.TYPE_KEY])]
+                entry['name'] = [unicode(xlate[sid][NAME_KEY])]
+                entry['type'] = [idmap_type_string(xlate[sid][TYPE_KEY])]
                 result.append(entry)
         except ValueError:
             pass
@@ -1340,7 +1405,6 @@ def execute(self, *keys, **options):
         return dict(result=result)
 
 
-
 @register()
 class adtrust_is_enabled(Command):
     NO_CLI = True
@@ -1367,7 +1431,6 @@ def execute(self, *keys, **options):
         return dict(result=True)
 
 
-
 @register()
 class compat_is_enabled(Command):
     NO_CLI = True
@@ -1411,7 +1474,6 @@ def execute(self, *keys, **options):
         return dict(result=True)
 
 
-
 @register()
 class sidgen_was_run(Command):
     """
@@ -1461,7 +1523,7 @@ class trustdomain(LDAPObject):
     Object representing a domain of the AD trust.
     """
     parent_object = 'trust'
-    trust_type_idx = {'2':u'ad'}
+    trust_type_idx = {'2': u'ad'}
     object_name = _('trust domain')
     object_name_plural = _('trust domains')
     object_class = ['ipaNTTrustedDomain']
@@ -1478,40 +1540,39 @@ class trustdomain(LDAPObject):
         Str('cn',
             label=_('Domain name'),
             cli_name='domain',
-            primary_key=True
-        ),
+            primary_key=True),
         Str('ipantflatname?',
             cli_name='flat_name',
-            label=_('Domain NetBIOS name'),
-        ),
+            label=_('Domain NetBIOS name')),
         Str('ipanttrusteddomainsid?',
             cli_name='sid',
-            label=_('Domain Security Identifier'),
-        ),
+            label=_('Domain Security Identifier')),
         Flag('domain_enabled',
-            label=_('Domain enabled'),
-            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
-        ),
+             label=_('Domain enabled'),
+             flags={'virtual_attribute',
+                    'no_create', 'no_update', 'no_search'}),
     )
 
-    # LDAPObject.get_dn() only passes all but last element of keys and no kwargs
-    # to the parent object's get_dn() no matter what you pass to it. Make own get_dn()
-    # as we really need all elements to construct proper dn.
+    # LDAPObject.get_dn() only passes all but last element of keys and no
+    # kwargs to the parent object's get_dn() no matter what you pass to it.
+    # Make own get_dn() as we really need all elements to construct proper dn.
     def get_dn(self, *keys, **kwargs):
         sdn = [('cn', x) for x in keys]
         sdn.reverse()
         trust_type = kwargs.get('trust_type')
         if not trust_type:
-            trust_type=u'ad'
+            trust_type = u'ad'
 
-        dn=make_trust_dn(self.env, trust_type, DN(*sdn))
+        dn = make_trust_dn(self.env, trust_type, DN(*sdn))
         return dn
 
+
 @register()
 class trustdomain_find(LDAPSearch):
     __doc__ = _('Search domains of the trust')
 
-    def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+    def pre_callback(self, ldap, filters, attrs_list, base_dn,
+                     scope, *args, **options):
         return (filters, base_dn, ldap.SCOPE_SUBTREE)
 
     def post_callback(self, ldap, entries, truncated, *args, **options):
@@ -1532,7 +1593,6 @@ def post_callback(self, ldap, entries, truncated, *args, **options):
         return truncated
 
 
-
 @register()
 class trustdomain_mod(LDAPUpdate):
     __doc__ = _('Modify trustdomain of the trust')
@@ -1540,31 +1600,36 @@ class trustdomain_mod(LDAPUpdate):
     NO_CLI = True
     takes_options = LDAPUpdate.takes_options + (_trust_type_option,)
 
+
 @register()
 class trustdomain_add(LDAPCreate):
     __doc__ = _('Allow access from the trusted domain')
     NO_CLI = True
 
     takes_options = LDAPCreate.takes_options + (_trust_type_option,)
-    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
-        # ipaNTTrustPartner must always be set to the name of the trusted domain
-        # See MS-ADTS 6.1.6.7.13
-        entry_attrs['ipanttrustpartner'] = [dn[0]['cn']]
+
+    def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options):
+        # ipaNTTrustPartner must always be set to the name of the trusted
+        # domain. See MS-ADTS 6.1.6.7.13
+        e_attrs['ipanttrustpartner'] = [dn[0]['cn']]
         return dn
 
 
 @register()
 class trustdomain_del(LDAPDelete):
-    __doc__ = _('Remove information about the domain associated with the trust.')
+    __doc__ = _('Remove information about the domain associated '
+                'with the trust.')
 
-    msg_summary = _('Removed information about the trusted domain "%(value)s"')
+    msg_summary = _('Removed information about the trusted domain '
+                    '"%(value)s"')
 
     def execute(self, *keys, **options):
         ldap = self.api.Backend.ldap2
         verify_samba_component_presence(ldap, self.api)
 
-        # Note that pre-/post- callback handling for LDAPDelete is causing pre_callback
-        # to always receive empty keys. We need to catch the case when root domain is being deleted
+        # Note that pre-/post- callback handling for LDAPDelete is causing
+        # pre_callback to always receive empty keys. We need to catch the case
+        # when root domain is being deleted
 
         for domain in keys[1]:
             try:
@@ -1603,10 +1668,10 @@ def fetch_domains_from_trust(myapi, trustinstance, **options):
     forest_root_name = trustinstance.remote_domain.info['dns_forest']
 
     # We want to use Kerberos if we have admin credentials even with SMB calls
-    # as eventually use of NTLMSSP will be deprecated for trusted domain operations
-    # If admin credentials are missing, 'creds' will be None and fetch_domains
-    # will use HTTP/ipa.master@IPA.REALM principal, e.g. Kerberos authentication
-    # as well.
+    # as eventually use of NTLMSSP will be deprecated for trusted domain
+    # operations If admin credentials are missing, 'creds' will be None and
+    # fetch_domains will use HTTP/ipa.master@IPA.REALM principal, e.g. Kerberos
+    # authentication as well.
     creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options)
     server = options.get('realm_server', None)
     domains = ipaserver.dcerpc.fetch_domains(
@@ -1616,7 +1681,8 @@ def fetch_domains_from_trust(myapi, trustinstance, **options):
     return domains
 
 
-def add_new_domains_from_trust(myapi, trustinstance, trust_entry, domains, **options):
+def add_new_domains_from_trust(myapi, trustinstance, trust_entry,
+                               domains, **options):
     result = []
     if not domains:
         return result
@@ -1728,8 +1794,11 @@ def execute(self, *keys, **options):
         verify_samba_component_presence(ldap, self.api)
 
         if keys[0].lower() == keys[1].lower():
-            raise errors.ValidationError(name='domain',
-                error=_("Root domain of the trust is always enabled for the existing trust"))
+            raise errors.ValidationError(
+                name='domain',
+                error=_("Root domain of the trust is always enabled "
+                        "for the existing trust")
+            )
         try:
             trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad')
             trust_entry = ldap.get_entry(trust_dn)
@@ -1766,8 +1835,11 @@ def execute(self, *keys, **options):
         verify_samba_component_presence(ldap, self.api)
 
         if keys[0].lower() == keys[1].lower():
-            raise errors.ValidationError(name='domain',
-                error=_("cannot disable root domain of the trust, use trust-del to delete the trust itself"))
+            raise errors.ValidationError(
+                name='domain',
+                error=_("cannot disable root domain of the trust, "
+                        "use trust-del to delete the trust itself")
+            )
         try:
             trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad')
             trust_entry = ldap.get_entry(trust_dn)
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to