Blob Blame History Raw
From f446cde6f626f5a4b086a542121486bde42d0dc7 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Tue, 14 Jan 2014 13:55:56 +0200
Subject: [PATCH 23/25] trust-fetch-domains: create ranges for new child
 domains

When trust is added, we do create ranges for discovered child domains.
However, this functionality was not available through
'trust-fetch-domains' command.

Additionally, make sure non-existing trust will report proper error in
trust-fetch-domains.

https://fedorahosted.org/freeipa/ticket/4111
https://fedorahosted.org/freeipa/ticket/4104
---
 ipalib/plugins/trust.py | 256 +++++++++++++++++++++++++-----------------------
 1 file changed, 135 insertions(+), 121 deletions(-)

diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 76d609fd4de33edd96715deaaf7842c1de3ddaf4..a16c23083662fd674c45ba54b9dfb9f4837160df 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -188,6 +188,114 @@ def make_trust_dn(env, trust_type, dn):
         return DN(dn, container_dn)
     return dn
 
+def add_range(self, range_name, dom_sid, *keys, **options):
+    """
+    First, we try to derive the parameters of the ID range based on the
+    information contained in the Active Directory.
+
+    If that was not successful, we go for our usual defaults (random base,
+    range size 200 000, ipa-ad-trust range type).
+
+    Any of these can be overriden by passing appropriate CLI options
+    to the trust-add command.
+    """
+
+    range_size = None
+    range_type = None
+    base_id = None
+
+    # First, get information about ID space from AD
+    # However, we skip this step if other than ipa-ad-trust-posix
+    # range type is enforced
+
+    if options.get('range_type', None) in (None, u'ipa-ad-trust-posix'):
+
+        # Get the base dn
+        domain = keys[-1]
+        basedn = realm_to_suffix(domain)
+
+        # Search for information contained in
+        # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System
+        info_filter = '(objectClass=msSFU30DomainInfo)'
+        info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\
+                  + basedn
+
+        # Get the domain validator
+        domain_validator = ipaserver.dcerpc.DomainValidator(self.api)
+        if not domain_validator.is_configured():
+            raise errors.NotFound(
+                reason=_('Cannot search in trusted domains without own '
+                         'domain configured. Make sure you have run '
+                         'ipa-adtrust-install on the IPA server first'))
+
+        # KDC might not get refreshed data at the first time,
+        # retry several times
+        for retry in range(10):
+            info_list = domain_validator.search_in_dc(domain,
+                                                      info_filter,
+                                                      None,
+                                                      SCOPE_SUBTREE,
+                                                      basedn=info_dn,
+                                                      quiet=True)
+
+            if info_list:
+                info = info_list[0]
+                break
+            else:
+                sleep(2)
+
+        required_msSFU_attrs = ['msSFU30MaxUidNumber', 'msSFU30OrderNumber']
+
+        if not info_list:
+            # We were unable to gain UNIX specific info from the AD
+            self.log.debug("Unable to gain POSIX info from the AD")
+        else:
+            if all(attr in info for attr in required_msSFU_attrs):
+                self.log.debug("Able to gain POSIX info from the AD")
+                range_type = u'ipa-ad-trust-posix'
+
+                max_uid = info.get('msSFU30MaxUidNumber')
+                max_gid = info.get('msSFU30MaxGidNumber', None)
+                max_id = int(max(max_uid, max_gid)[0])
+
+                base_id = int(info.get('msSFU30OrderNumber')[0])
+                range_size = (1 + (max_id - base_id) / DEFAULT_RANGE_SIZE)\
+                             * DEFAULT_RANGE_SIZE
+
+    # Second, options given via the CLI options take precedence to discovery
+    if options.get('range_type', None):
+        range_type = options.get('range_type', None)
+    elif not range_type:
+        range_type = u'ipa-ad-trust'
+
+    if options.get('range_size', None):
+        range_size = options.get('range_size', None)
+    elif not range_size:
+        range_size = DEFAULT_RANGE_SIZE
+
+    if options.get('base_id', None):
+        base_id = options.get('base_id', None)
+    elif not base_id:
+        # Generate random base_id if not discovered nor given via CLI
+        base_id = DEFAULT_RANGE_SIZE + (
+            pysss_murmur.murmurhash3(
+                dom_sid,
+                len(dom_sid), 0xdeadbeefL
+            ) % 10000
+        ) * DEFAULT_RANGE_SIZE
+
+    # Finally, add new ID range
+    self.api.Command['idrange_add'](range_name,
+                                    ipabaseid=base_id,
+                                    ipaidrangesize=range_size,
+                                    ipabaserid=0,
+                                    iparangetype=range_type,
+                                    ipanttrusteddomainsid=dom_sid)
+
+    # Return the values that were generated inside this function
+    return range_type, range_size, base_id
+
+
 class trust(LDAPObject):
     """
     Trust object.
@@ -258,15 +366,11 @@ def get_dn(self, *keys, **kwargs):
             filter = ldap.make_filter({'objectclass': ['ipaNTTrustedDomain'], 'cn': [keys[-1]] },
                                       rules=ldap.MATCH_ALL)
             filter = ldap.combine_filters((filter, "ipaNTSIDBlacklistIncoming=*"), rules=ldap.MATCH_ALL)
-            try:
-                result = ldap.get_entries(DN(self.container_dn, self.env.basedn),
-                                          ldap.SCOPE_SUBTREE, filter, [''])
-            except errors.NotFound:
-                return None
-            else:
-                if len(result) > 1:
-                    raise errors.OnlyOneValueAllowed(attr='trust domain')
-                return result[0].dn
+            result = ldap.get_entries(DN(self.container_dn, self.env.basedn),
+                                      ldap.SCOPE_SUBTREE, filter, [''])
+            if len(result) > 1:
+                raise errors.OnlyOneValueAllowed(attr='trust domain')
+            return result[0].dn
 
         dn=make_trust_dn(self.env, trust_type, DN(*sdn))
         return dn
@@ -341,8 +445,8 @@ def execute(self, *keys, **options):
             # Store the created range type, since for POSIX trusts no
             # ranges for the subdomains should be added, POSIX attributes
             # provide a global mapping across all subdomains
-            (created_range_type, _, _) = self.add_range(range_name, dom_sid,
-                                                        *keys, **options)
+            (created_range_type, _, _) = add_range(self, range_name, dom_sid,
+                                                   *keys, **options)
         else:
             created_range_type = old_range['result']['iparangetype'][0]
 
@@ -382,8 +486,8 @@ def execute(self, *keys, **options):
 
                     # Try to add the range for each subdomain
                     try:
-                        self.add_range(range_name, dom_sid, *keys,
-                                       **passed_options)
+                        add_range(self, range_name, dom_sid, *keys,
+                                  **passed_options)
                     except errors.DuplicateEntry:
                         pass
 
@@ -549,120 +653,17 @@ def validate_range(self, *keys, **options):
 
         return old_range, range_name, dom_sid
 
-    def add_range(self, range_name, dom_sid, *keys, **options):
-        """
-        First, we try to derive the parameters of the ID range based on the
-        information contained in the Active Directory.
-
-        If that was not successful, we go for our usual defaults (random base,
-        range size 200 000, ipa-ad-trust range type).
-
-        Any of these can be overriden by passing appropriate CLI options
-        to the trust-add command.
-        """
-
-        range_size = None
-        range_type = None
-        base_id = None
-
-        # First, get information about ID space from AD
-        # However, we skip this step if other than ipa-ad-trust-posix
-        # range type is enforced
-
-        if options.get('range_type', None) in (None, u'ipa-ad-trust-posix'):
-
-            # Get the base dn
-            domain = keys[-1]
-            basedn = realm_to_suffix(domain)
-
-            # Search for information contained in
-            # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System
-            info_filter = '(objectClass=msSFU30DomainInfo)'
-            info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\
-                      + basedn
-
-            # Get the domain validator
-            domain_validator = ipaserver.dcerpc.DomainValidator(self.api)
-            if not domain_validator.is_configured():
-                raise errors.NotFound(
-                    reason=_('Cannot search in trusted domains without own '
-                             'domain configured. Make sure you have run '
-                             'ipa-adtrust-install on the IPA server first'))
-
-            # KDC might not get refreshed data at the first time,
-            # retry several times
-            for retry in range(10):
-                info_list = domain_validator.search_in_dc(domain,
-                                                          info_filter,
-                                                          None,
-                                                          SCOPE_SUBTREE,
-                                                          basedn=info_dn,
-                                                          quiet=True)
-
-                if info_list:
-                    info = info_list[0]
-                    break
-                else:
-                    sleep(2)
-
-            required_msSFU_attrs = ['msSFU30MaxUidNumber', 'msSFU30OrderNumber']
-
-            if not info_list:
-                # We were unable to gain UNIX specific info from the AD
-                self.log.debug("Unable to gain POSIX info from the AD")
-            else:
-                if all(attr in info for attr in required_msSFU_attrs):
-                    self.log.debug("Able to gain POSIX info from the AD")
-                    range_type = u'ipa-ad-trust-posix'
-
-                    max_uid = info.get('msSFU30MaxUidNumber')
-                    max_gid = info.get('msSFU30MaxGidNumber', None)
-                    max_id = int(max(max_uid, max_gid)[0])
-
-                    base_id = int(info.get('msSFU30OrderNumber')[0])
-                    range_size = (1 + (max_id - base_id) / DEFAULT_RANGE_SIZE)\
-                                 * DEFAULT_RANGE_SIZE
-
-        # Second, options given via the CLI options take precedence to discovery
-        if options.get('range_type', None):
-            range_type = options.get('range_type', None)
-        elif not range_type:
-            range_type = u'ipa-ad-trust'
-
-        if options.get('range_size', None):
-            range_size = options.get('range_size', None)
-        elif not range_size:
-            range_size = DEFAULT_RANGE_SIZE
-
-        if options.get('base_id', None):
-            base_id = options.get('base_id', None)
-        elif not base_id:
-            # Generate random base_id if not discovered nor given via CLI
-            base_id = DEFAULT_RANGE_SIZE + (
-                pysss_murmur.murmurhash3(
-                    dom_sid,
-                    len(dom_sid), 0xdeadbeefL
-                ) % 10000
-            ) * DEFAULT_RANGE_SIZE
-
-        # Finally, add new ID range
-        api.Command['idrange_add'](range_name,
-                                   ipabaseid=base_id,
-                                   ipaidrangesize=range_size,
-                                   ipabaserid=0,
-                                   iparangetype=range_type,
-                                   ipanttrusteddomainsid=dom_sid)
-
-        # Return the values that were generated inside this function
-        return range_type, range_size, base_id
-
     def execute_ad(self, full_join, *keys, **options):
         # Join domain using full credentials and with random trustdom
         # secret (will be generated by the join method)
 
         # First see if the trust is already in place
         # Force retrieval of the trust object by not passing trust_type
-        dn = self.obj.get_dn(keys[-1])
+        try:
+            dn = self.obj.get_dn(keys[-1])
+        except errors.NotFound:
+            dn = None
+
         if dn:
             summary = _('Re-established trust to domain "%(value)s"')
         else:
@@ -794,6 +795,7 @@ class trust_show(LDAPRetrieve):
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
 
+        assert isinstance(dn, DN)
         # Translate ipanttrusttype to trusttype
         # and ipanttrustdirection to trustdirection
         # if --raw not used
@@ -1246,6 +1248,11 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options):
     if not domains:
         return result
 
+    # trust range must exist by the time fetch_domains_from_trust is called
+    range_name = trust_name.upper() + '_id_range'
+    old_range = api.Command.idrange_show(range_name, raw=True)['result']
+    idrange_type = old_range['iparangetype']
+
     for dom in domains:
         dom['trust_type'] = u'ad'
         try:
@@ -1255,8 +1262,15 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options):
                 dom['all'] = options['all']
             if 'raw' in options:
                 dom['raw'] = options['raw']
+
             res = self.api.Command.trustdomain_add(trust_name, name, **dom)
             result.append(res['result'])
+
+            if idrange_type != u'ipa-ad-trust-posix':
+                range_name = name.upper() + '_id_range'
+                dom['range_type'] = u'ipa-ad-trust'
+                add_range(self, range_name, dom['ipanttrusteddomainsid'],
+                          trust_name, name, **dom)
         except errors.DuplicateEntry:
             # Ignore updating duplicate entries
             pass
-- 
1.8.4.2