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