|
|
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 |
|