From f446cde6f626f5a4b086a542121486bde42d0dc7 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy 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