|
|
403b09 |
From a9a73b0e0b601767324d5b6747b6ba46b6e5e90f Mon Sep 17 00:00:00 2001
|
|
|
403b09 |
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
|
403b09 |
Date: Tue, 7 Jun 2016 22:41:10 +0300
|
|
|
403b09 |
Subject: [PATCH] ipaserver/dcerpc: reformat to make the code closer to pep8
|
|
|
403b09 |
|
|
|
403b09 |
Because Samba Python bindings provide long-named methods and constants,
|
|
|
403b09 |
sometimes it is impossible to fit into 80 columns without causing
|
|
|
403b09 |
damage to readability of the code. This patchset attempts to reduce
|
|
|
403b09 |
pep8 complaints to a minimum.
|
|
|
403b09 |
|
|
|
403b09 |
https://fedorahosted.org/freeipa/ticket/6076
|
|
|
403b09 |
|
|
|
403b09 |
Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
|
|
|
403b09 |
---
|
|
|
403b09 |
ipaserver/dcerpc.py | 473 +++++++++++++++++++++++++++++++++-------------------
|
|
|
403b09 |
1 file changed, 298 insertions(+), 175 deletions(-)
|
|
|
403b09 |
|
|
|
403b09 |
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
|
|
403b09 |
index 21ac89dfd71271ed384b875f95054d7ad1c0556d..19be6bf7a3617a3b867d51a9358c9926e91049a7 100644
|
|
|
403b09 |
--- a/ipaserver/dcerpc.py
|
|
|
403b09 |
+++ b/ipaserver/dcerpc.py
|
|
|
403b09 |
@@ -44,10 +44,12 @@ import samba
|
|
|
403b09 |
import random
|
|
|
403b09 |
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
|
|
|
403b09 |
from cryptography.hazmat.backends import default_backend
|
|
|
403b09 |
+# pylint: disable=F0401
|
|
|
403b09 |
try:
|
|
|
403b09 |
- from ldap.controls import RequestControl as LDAPControl #pylint: disable=F0401
|
|
|
403b09 |
+ from ldap.controls import RequestControl as LDAPControl
|
|
|
403b09 |
except ImportError:
|
|
|
403b09 |
- from ldap.controls import LDAPControl as LDAPControl #pylint: disable=F0401
|
|
|
403b09 |
+ from ldap.controls import LDAPControl as LDAPControl
|
|
|
403b09 |
+# pylint: enable=F0401
|
|
|
403b09 |
import ldap as _ldap
|
|
|
403b09 |
from ipapython.ipaldap import IPAdmin
|
|
|
403b09 |
from ipaserver.session import krbccache_dir, krbccache_prefix
|
|
|
403b09 |
@@ -74,7 +76,7 @@ and Samba4 python bindings.
|
|
|
403b09 |
|
|
|
403b09 |
# Both constants can be used as masks against trust direction
|
|
|
403b09 |
# because bi-directional has two lower bits set.
|
|
|
403b09 |
-TRUST_ONEWAY = 1
|
|
|
403b09 |
+TRUST_ONEWAY = 1
|
|
|
403b09 |
TRUST_BIDIRECTIONAL = 3
|
|
|
403b09 |
|
|
|
403b09 |
# Trust join behavior
|
|
|
403b09 |
@@ -91,31 +93,44 @@ def is_sid_valid(sid):
|
|
|
403b09 |
return True
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
-access_denied_error = errors.ACIError(info=_('CIFS server denied your credentials'))
|
|
|
403b09 |
+access_denied_error = errors.ACIError(
|
|
|
403b09 |
+ info=_('CIFS server denied your credentials'))
|
|
|
403b09 |
dcerpc_error_codes = {
|
|
|
403b09 |
-1073741823:
|
|
|
403b09 |
- errors.RemoteRetrieveError(reason=_('communication with CIFS server was unsuccessful')),
|
|
|
403b09 |
+ errors.RemoteRetrieveError(
|
|
|
403b09 |
+ reason=_('communication with CIFS server was unsuccessful')),
|
|
|
403b09 |
-1073741790: access_denied_error,
|
|
|
403b09 |
-1073741715: access_denied_error,
|
|
|
403b09 |
-1073741614: access_denied_error,
|
|
|
403b09 |
-1073741603:
|
|
|
403b09 |
- errors.ValidationError(name=_('AD domain controller'), error=_('unsupported functional level')),
|
|
|
403b09 |
- -1073741811: # NT_STATUS_INVALID_PARAMETER
|
|
|
403b09 |
+ errors.ValidationError(
|
|
|
403b09 |
+ name=_('AD domain controller'),
|
|
|
403b09 |
+ error=_('unsupported functional level')),
|
|
|
403b09 |
+ -1073741811: # NT_STATUS_INVALID_PARAMETER
|
|
|
403b09 |
errors.RemoteRetrieveError(
|
|
|
403b09 |
- reason=_('AD domain controller complains about communication sequence. It may mean unsynchronized time on both sides, for example')),
|
|
|
403b09 |
- -1073741776: # NT_STATUS_INVALID_PARAMETER_MIX, we simply will skip the binding
|
|
|
403b09 |
+ reason=_('AD domain controller complains about communication '
|
|
|
403b09 |
+ 'sequence. It may mean unsynchronized time on both '
|
|
|
403b09 |
+ 'sides, for example')),
|
|
|
403b09 |
+ -1073741776: # NT_STATUS_INVALID_PARAMETER_MIX,
|
|
|
403b09 |
+ # we simply will skip the binding
|
|
|
403b09 |
access_denied_error,
|
|
|
403b09 |
- -1073741772: # NT_STATUS_OBJECT_NAME_NOT_FOUND
|
|
|
403b09 |
- errors.RemoteRetrieveError(reason=_('CIFS server configuration does not allow access to \\\\pipe\\lsarpc')),
|
|
|
403b09 |
+ -1073741772: # NT_STATUS_OBJECT_NAME_NOT_FOUND
|
|
|
403b09 |
+ errors.RemoteRetrieveError(
|
|
|
403b09 |
+ reason=_('CIFS server configuration does not allow '
|
|
|
403b09 |
+ 'access to \\\\pipe\\lsarpc')),
|
|
|
403b09 |
}
|
|
|
403b09 |
|
|
|
403b09 |
dcerpc_error_messages = {
|
|
|
403b09 |
"NT_STATUS_OBJECT_NAME_NOT_FOUND":
|
|
|
403b09 |
- errors.NotFound(reason=_('Cannot find specified domain or server name')),
|
|
|
403b09 |
+ errors.NotFound(
|
|
|
403b09 |
+ reason=_('Cannot find specified domain or server name')),
|
|
|
403b09 |
"WERR_NO_LOGON_SERVERS":
|
|
|
403b09 |
- errors.RemoteRetrieveError(reason=_('AD DC was unable to reach any IPA domain controller. Most likely it is a DNS or firewall issue')),
|
|
|
403b09 |
+ errors.RemoteRetrieveError(
|
|
|
403b09 |
+ reason=_('AD DC was unable to reach any IPA domain controller. '
|
|
|
403b09 |
+ 'Most likely it is a DNS or firewall issue')),
|
|
|
403b09 |
"NT_STATUS_INVALID_PARAMETER_MIX":
|
|
|
403b09 |
- errors.RequirementError(name=_('At least the domain or IP address should be specified')),
|
|
|
403b09 |
+ errors.RequirementError(
|
|
|
403b09 |
+ name=_('At least the domain or IP address should be specified')),
|
|
|
403b09 |
}
|
|
|
403b09 |
|
|
|
403b09 |
pysss_type_key_translation_dict = {
|
|
|
403b09 |
@@ -126,7 +141,7 @@ pysss_type_key_translation_dict = {
|
|
|
403b09 |
}
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
-def assess_dcerpc_exception(num=None,message=None):
|
|
|
403b09 |
+def assess_dcerpc_exception(num=None, message=None):
|
|
|
403b09 |
"""
|
|
|
403b09 |
Takes error returned by Samba bindings and converts it into
|
|
|
403b09 |
an IPA error class.
|
|
|
403b09 |
@@ -135,8 +150,9 @@ def assess_dcerpc_exception(num=None,message=None):
|
|
|
403b09 |
return dcerpc_error_codes[num]
|
|
|
403b09 |
if message and message in dcerpc_error_messages:
|
|
|
403b09 |
return dcerpc_error_messages[message]
|
|
|
403b09 |
- reason = _('''CIFS server communication error: code "%(num)s",
|
|
|
403b09 |
- message "%(message)s" (both may be "None")''') % dict(num=num, message=message)
|
|
|
403b09 |
+ reason = _('CIFS server communication error: code "%(num)s", '
|
|
|
403b09 |
+ 'message "%(message)s" (both may be "None")') % \
|
|
|
403b09 |
+ dict(num=num, message=message)
|
|
|
403b09 |
return errors.RemoteRetrieveError(reason=reason)
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
@@ -182,9 +198,13 @@ class DomainValidator(object):
|
|
|
403b09 |
self._parm = None
|
|
|
403b09 |
|
|
|
403b09 |
def is_configured(self):
|
|
|
403b09 |
- cn_trust_local = DN(('cn', self.api.env.domain), self.api.env.container_cifsdomains, self.api.env.basedn)
|
|
|
403b09 |
+ cn_trust_local = DN(('cn', self.api.env.domain),
|
|
|
403b09 |
+ self.api.env.container_cifsdomains,
|
|
|
403b09 |
+ self.api.env.basedn)
|
|
|
403b09 |
try:
|
|
|
403b09 |
- entry_attrs = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID])
|
|
|
403b09 |
+ entry_attrs = self.ldap.get_entry(cn_trust_local,
|
|
|
403b09 |
+ [self.ATTR_FLATNAME,
|
|
|
403b09 |
+ self.ATTR_SID])
|
|
|
403b09 |
self.flatname = entry_attrs[self.ATTR_FLATNAME][0]
|
|
|
403b09 |
self.sid = entry_attrs[self.ATTR_SID][0]
|
|
|
403b09 |
self.dn = entry_attrs.dn
|
|
|
403b09 |
@@ -203,7 +223,8 @@ class DomainValidator(object):
|
|
|
403b09 |
|
|
|
403b09 |
try:
|
|
|
403b09 |
search_kw = {'objectClass': 'ipaNTTrustedDomain'}
|
|
|
403b09 |
- filter = self.ldap.make_filter(search_kw, rules=self.ldap.MATCH_ALL)
|
|
|
403b09 |
+ filter = self.ldap.make_filter(search_kw,
|
|
|
403b09 |
+ rules=self.ldap.MATCH_ALL)
|
|
|
403b09 |
(entries, truncated) = self.ldap.find_entries(
|
|
|
403b09 |
filter=filter,
|
|
|
403b09 |
base_dn=cn_trust,
|
|
|
403b09 |
@@ -216,22 +237,22 @@ class DomainValidator(object):
|
|
|
403b09 |
# domain names as keys and those are generally case-insensitive
|
|
|
403b09 |
result = ipautil.CIDict()
|
|
|
403b09 |
|
|
|
403b09 |
- for entry in entries:
|
|
|
403b09 |
+ for e in entries:
|
|
|
403b09 |
try:
|
|
|
403b09 |
- trust_partner = entry[self.ATTR_TRUST_PARTNER][0]
|
|
|
403b09 |
- flatname_normalized = entry[self.ATTR_FLATNAME][0].lower()
|
|
|
403b09 |
- trusted_sid = entry[self.ATTR_TRUSTED_SID][0]
|
|
|
403b09 |
- except KeyError as e:
|
|
|
403b09 |
+ t_partner = e.single_value.get(self.ATTR_TRUST_PARTNER)
|
|
|
403b09 |
+ fname_norm = e.single_value.get(self.ATTR_FLATNAME).lower()
|
|
|
403b09 |
+ trusted_sid = e.single_value.get(self.ATTR_TRUSTED_SID)
|
|
|
403b09 |
+ except KeyError as exc:
|
|
|
403b09 |
# Some piece of trusted domain info in LDAP is missing
|
|
|
403b09 |
# Skip the domain, but leave log entry for investigation
|
|
|
403b09 |
api.log.warning("Trusted domain '%s' entry misses an "
|
|
|
403b09 |
- "attribute: %s", entry.dn, e)
|
|
|
403b09 |
+ "attribute: %s", e.dn, exc)
|
|
|
403b09 |
continue
|
|
|
403b09 |
|
|
|
403b09 |
- result[trust_partner] = (flatname_normalized,
|
|
|
403b09 |
- security.dom_sid(trusted_sid))
|
|
|
403b09 |
+ result[t_partner] = (fname_norm,
|
|
|
403b09 |
+ security.dom_sid(trusted_sid))
|
|
|
403b09 |
return result
|
|
|
403b09 |
- except errors.NotFound as e:
|
|
|
403b09 |
+ except errors.NotFound as exc:
|
|
|
403b09 |
return []
|
|
|
403b09 |
|
|
|
403b09 |
def set_trusted_domains(self):
|
|
|
403b09 |
@@ -244,21 +265,22 @@ class DomainValidator(object):
|
|
|
403b09 |
# This means we can't check the correctness of a trusted
|
|
|
403b09 |
# domain SIDs
|
|
|
403b09 |
raise errors.ValidationError(name='sid',
|
|
|
403b09 |
- error=_('no trusted domain is configured'))
|
|
|
403b09 |
+ error=_('no trusted domain '
|
|
|
403b09 |
+ 'is configured'))
|
|
|
403b09 |
|
|
|
403b09 |
def get_domain_by_sid(self, sid, exact_match=False):
|
|
|
403b09 |
if not self.domain:
|
|
|
403b09 |
# our domain is not configured or self.is_configured() never run
|
|
|
403b09 |
# reject SIDs as we can't check correctness of them
|
|
|
403b09 |
raise errors.ValidationError(name='sid',
|
|
|
403b09 |
- error=_('domain is not configured'))
|
|
|
403b09 |
+ error=_('domain is not configured'))
|
|
|
403b09 |
|
|
|
403b09 |
# Parse sid string to see if it is really in a SID format
|
|
|
403b09 |
try:
|
|
|
403b09 |
test_sid = security.dom_sid(sid)
|
|
|
403b09 |
except TypeError:
|
|
|
403b09 |
raise errors.ValidationError(name='sid',
|
|
|
403b09 |
- error=_('SID is not valid'))
|
|
|
403b09 |
+ error=_('SID is not valid'))
|
|
|
403b09 |
|
|
|
403b09 |
# At this point we have SID_NT_AUTHORITY family SID and really need to
|
|
|
403b09 |
# check it against prefixes of domain SIDs we trust to
|
|
|
403b09 |
@@ -314,30 +336,34 @@ class DomainValidator(object):
|
|
|
403b09 |
return None
|
|
|
403b09 |
|
|
|
403b09 |
def get_trusted_domain_objects(self, domain=None, flatname=None, filter="",
|
|
|
403b09 |
- attrs=None, scope=_ldap.SCOPE_SUBTREE, basedn=None):
|
|
|
403b09 |
+ attrs=None, scope=_ldap.SCOPE_SUBTREE,
|
|
|
403b09 |
+ basedn=None):
|
|
|
403b09 |
"""
|
|
|
403b09 |
- Search for LDAP objects in a trusted domain specified either by `domain'
|
|
|
403b09 |
- or `flatname'. The actual LDAP search is specified by `filter', `attrs',
|
|
|
403b09 |
- `scope' and `basedn'. When `basedn' is empty, database root DN is used.
|
|
|
403b09 |
+ Search for LDAP objects in a trusted domain specified either by
|
|
|
403b09 |
+ `domain' or `flatname'. The actual LDAP search is specified by
|
|
|
403b09 |
+ `filter', `attrs', `scope' and `basedn'. When `basedn' is empty,
|
|
|
403b09 |
+ database root DN is used.
|
|
|
403b09 |
"""
|
|
|
403b09 |
assert domain is not None or flatname is not None
|
|
|
403b09 |
"""Returns SID for the trusted domain object (user or group only)"""
|
|
|
403b09 |
if not self.domain:
|
|
|
403b09 |
# our domain is not configured or self.is_configured() never run
|
|
|
403b09 |
raise errors.ValidationError(name=_('Trust setup'),
|
|
|
403b09 |
- error=_('Our domain is not configured'))
|
|
|
403b09 |
+ error=_('Our domain is '
|
|
|
403b09 |
+ 'not configured'))
|
|
|
403b09 |
if not self._domains:
|
|
|
403b09 |
self._domains = self.get_trusted_domains()
|
|
|
403b09 |
if len(self._domains) == 0:
|
|
|
403b09 |
# Our domain is configured but no trusted domains are configured
|
|
|
403b09 |
raise errors.ValidationError(name=_('Trust setup'),
|
|
|
403b09 |
- error=_('No trusted domain is not configured'))
|
|
|
403b09 |
+ error=_('No trusted domain is '
|
|
|
403b09 |
+ 'not configured'))
|
|
|
403b09 |
|
|
|
403b09 |
entries = None
|
|
|
403b09 |
if domain is not None:
|
|
|
403b09 |
if domain not in self._domains:
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('domain is not trusted'))
|
|
|
403b09 |
+ error=_('domain is not trusted'))
|
|
|
403b09 |
# Now we have a name to check against our list of trusted domains
|
|
|
403b09 |
entries = self.search_in_dc(domain, filter, attrs, scope, basedn)
|
|
|
403b09 |
elif flatname is not None:
|
|
|
403b09 |
@@ -347,53 +373,65 @@ class DomainValidator(object):
|
|
|
403b09 |
for domain in self._domains:
|
|
|
403b09 |
if self._domains[domain][0] == flatname:
|
|
|
403b09 |
found_flatname = True
|
|
|
403b09 |
- entries = self.search_in_dc(domain, filter, attrs, scope, basedn)
|
|
|
403b09 |
+ entries = self.search_in_dc(domain, filter,
|
|
|
403b09 |
+ attrs, scope, basedn)
|
|
|
403b09 |
if entries:
|
|
|
403b09 |
break
|
|
|
403b09 |
if not found_flatname:
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('no trusted domain matched the specified flat name'))
|
|
|
403b09 |
+ error=_('no trusted domain '
|
|
|
403b09 |
+ 'matched the specified '
|
|
|
403b09 |
+ 'flat name'))
|
|
|
403b09 |
if not entries:
|
|
|
403b09 |
raise errors.NotFound(reason=_('trusted domain object not found'))
|
|
|
403b09 |
|
|
|
403b09 |
return entries
|
|
|
403b09 |
|
|
|
403b09 |
- def get_trusted_domain_object_sid(self, object_name, fallback_to_ldap=True):
|
|
|
403b09 |
+ def get_trusted_domain_object_sid(self, object_name,
|
|
|
403b09 |
+ fallback_to_ldap=True):
|
|
|
403b09 |
result = pysss_nss_idmap.getsidbyname(object_name)
|
|
|
403b09 |
- if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]):
|
|
|
403b09 |
+ if object_name in result and \
|
|
|
403b09 |
+ (pysss_nss_idmap.SID_KEY in result[object_name]):
|
|
|
403b09 |
object_sid = result[object_name][pysss_nss_idmap.SID_KEY]
|
|
|
403b09 |
return object_sid
|
|
|
403b09 |
|
|
|
403b09 |
# If fallback to AD DC LDAP is not allowed, bail out
|
|
|
403b09 |
if not fallback_to_ldap:
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('SSSD was unable to resolve the object to a valid SID'))
|
|
|
403b09 |
+ error=_('SSSD was unable to resolve '
|
|
|
403b09 |
+ 'the object to a valid SID'))
|
|
|
403b09 |
|
|
|
403b09 |
# Else, we are going to contact AD DC LDAP
|
|
|
403b09 |
components = normalize_name(object_name)
|
|
|
403b09 |
if not ('domain' in components or 'flatname' in components):
|
|
|
403b09 |
# No domain or realm specified, ambiguous search
|
|
|
403b09 |
- raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('Ambiguous search, user domain was not specified'))
|
|
|
403b09 |
+ raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
+ error=_('Ambiguous search, user '
|
|
|
403b09 |
+ 'domain was not specified'))
|
|
|
403b09 |
|
|
|
403b09 |
attrs = ['objectSid']
|
|
|
403b09 |
- filter = '(&(sAMAccountName=%(name)s)(|(objectClass=user)(objectClass=group)))' \
|
|
|
403b09 |
- % dict(name=components['name'])
|
|
|
403b09 |
+ filter = '(&(sAMAccountName=%(name)s)' \
|
|
|
403b09 |
+ '(|(objectClass=user)(objectClass=group)))' \
|
|
|
403b09 |
+ % dict(name=components['name'])
|
|
|
403b09 |
scope = _ldap.SCOPE_SUBTREE
|
|
|
403b09 |
entries = self.get_trusted_domain_objects(components.get('domain'),
|
|
|
403b09 |
- components.get('flatname'), filter, attrs, scope)
|
|
|
403b09 |
+ components.get('flatname'),
|
|
|
403b09 |
+ filter, attrs, scope)
|
|
|
403b09 |
|
|
|
403b09 |
if len(entries) > 1:
|
|
|
403b09 |
# Treat non-unique entries as invalid
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('Trusted domain did not return a unique object'))
|
|
|
403b09 |
+ error=_('Trusted domain did not '
|
|
|
403b09 |
+ 'return a unique object'))
|
|
|
403b09 |
sid = self.__sid_to_str(entries[0]['objectSid'][0])
|
|
|
403b09 |
try:
|
|
|
403b09 |
test_sid = security.dom_sid(sid)
|
|
|
403b09 |
return unicode(test_sid)
|
|
|
403b09 |
except TypeError as e:
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('Trusted domain did not return a valid SID for the object'))
|
|
|
403b09 |
+ error=_('Trusted domain did not '
|
|
|
403b09 |
+ 'return a valid SID for '
|
|
|
403b09 |
+ 'the object'))
|
|
|
403b09 |
|
|
|
403b09 |
def get_trusted_domain_object_type(self, name_or_sid):
|
|
|
403b09 |
"""
|
|
|
403b09 |
@@ -443,7 +481,8 @@ class DomainValidator(object):
|
|
|
403b09 |
)
|
|
|
403b09 |
|
|
|
403b09 |
attrs = ['sAMAccountName']
|
|
|
403b09 |
- filter = (r'(&(objectSid=%(sid)s)(|(objectClass=user)(objectClass=group)))'
|
|
|
403b09 |
+ filter = (r'(&(objectSid=%(sid)s)'
|
|
|
403b09 |
+ '(|(objectClass=user)(objectClass=group)))'
|
|
|
403b09 |
% dict(sid=escaped_sid)) # sid in binary
|
|
|
403b09 |
domain = self.get_domain_by_sid(sid)
|
|
|
403b09 |
|
|
|
403b09 |
@@ -454,7 +493,8 @@ class DomainValidator(object):
|
|
|
403b09 |
if len(entries) > 1:
|
|
|
403b09 |
# Treat non-unique entries as invalid
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error=_('Trusted domain did not return a unique object'))
|
|
|
403b09 |
+ error=_('Trusted domain did not '
|
|
|
403b09 |
+ 'return a unique object'))
|
|
|
403b09 |
|
|
|
403b09 |
object_name = (
|
|
|
403b09 |
"%s@%s" % (entries[0].single_value['sAMAccountName'].lower(),
|
|
|
403b09 |
@@ -486,27 +526,31 @@ class DomainValidator(object):
|
|
|
403b09 |
# Now search a trusted domain for a user with this SID
|
|
|
403b09 |
attrs = ['cn']
|
|
|
403b09 |
filter = '(&(objectClass=user)(objectSid=%(sid)s))' \
|
|
|
403b09 |
- % dict(sid=object_name)
|
|
|
403b09 |
+ % dict(sid=object_name)
|
|
|
403b09 |
try:
|
|
|
403b09 |
- entries = self.get_trusted_domain_objects(domain=domain, filter=filter,
|
|
|
403b09 |
- attrs=attrs, scope=_ldap.SCOPE_SUBTREE)
|
|
|
403b09 |
+ entries = self.get_trusted_domain_objects(domain=domain,
|
|
|
403b09 |
+ filter=filter,
|
|
|
403b09 |
+ attrs=attrs,
|
|
|
403b09 |
+ scope=_ldap.SCOPE_SUBTREE)
|
|
|
403b09 |
except errors.NotFound:
|
|
|
403b09 |
raise errors.NotFound(reason=_('trusted domain user not found'))
|
|
|
403b09 |
user_dn = entries[0].dn
|
|
|
403b09 |
elif domain or flatname:
|
|
|
403b09 |
attrs = ['cn']
|
|
|
403b09 |
filter = '(&(sAMAccountName=%(name)s)(objectClass=user))' \
|
|
|
403b09 |
- % dict(name=name)
|
|
|
403b09 |
+ % dict(name=name)
|
|
|
403b09 |
try:
|
|
|
403b09 |
entries = self.get_trusted_domain_objects(domain,
|
|
|
403b09 |
- flatname, filter, attrs, _ldap.SCOPE_SUBTREE)
|
|
|
403b09 |
+ flatname, filter, attrs,
|
|
|
403b09 |
+ _ldap.SCOPE_SUBTREE)
|
|
|
403b09 |
except errors.NotFound:
|
|
|
403b09 |
raise errors.NotFound(reason=_('trusted domain user not found'))
|
|
|
403b09 |
user_dn = entries[0].dn
|
|
|
403b09 |
else:
|
|
|
403b09 |
# No domain or realm specified, ambiguous search
|
|
|
403b09 |
raise errors.ValidationError(name=_('trusted domain object'),
|
|
|
403b09 |
- error= _('Ambiguous search, user domain was not specified'))
|
|
|
403b09 |
+ error=_('Ambiguous search, '
|
|
|
403b09 |
+ 'user domain was not specified'))
|
|
|
403b09 |
|
|
|
403b09 |
# Get SIDs of user object and it's groups
|
|
|
403b09 |
# tokenGroups attribute must be read with a scope BASE for a known user
|
|
|
403b09 |
@@ -514,9 +558,11 @@ class DomainValidator(object):
|
|
|
403b09 |
attrs = ['objectSID', 'tokenGroups']
|
|
|
403b09 |
filter = "(objectClass=user)"
|
|
|
403b09 |
entries = self.get_trusted_domain_objects(domain,
|
|
|
403b09 |
- flatname, filter, attrs, _ldap.SCOPE_BASE, user_dn)
|
|
|
403b09 |
+ flatname, filter, attrs,
|
|
|
403b09 |
+ _ldap.SCOPE_BASE, user_dn)
|
|
|
403b09 |
object_sid = self.__sid_to_str(entries[0]['objectSid'][0])
|
|
|
403b09 |
- group_sids = [self.__sid_to_str(sid) for sid in entries[0]['tokenGroups']]
|
|
|
403b09 |
+ group_sids = [self.__sid_to_str(sid)
|
|
|
403b09 |
+ for sid in entries[0]['tokenGroups']]
|
|
|
403b09 |
return (object_sid, group_sids)
|
|
|
403b09 |
|
|
|
403b09 |
def get_trusted_domain_user_and_groups(self, object_name):
|
|
|
403b09 |
@@ -540,11 +586,14 @@ class DomainValidator(object):
|
|
|
403b09 |
if is_valid_sid:
|
|
|
403b09 |
object_sid = object_name
|
|
|
403b09 |
result = pysss_nss_idmap.getnamebysid(object_name)
|
|
|
403b09 |
- if object_name in result and (pysss_nss_idmap.NAME_KEY in result[object_name]):
|
|
|
403b09 |
- group_list = pysss.getgrouplist(result[object_name][pysss_nss_idmap.NAME_KEY])
|
|
|
403b09 |
+ if object_name in result and \
|
|
|
403b09 |
+ (pysss_nss_idmap.NAME_KEY in result[object_name]):
|
|
|
403b09 |
+ group_list = pysss.getgrouplist(
|
|
|
403b09 |
+ result[object_name][pysss_nss_idmap.NAME_KEY])
|
|
|
403b09 |
else:
|
|
|
403b09 |
result = pysss_nss_idmap.getsidbyname(object_name)
|
|
|
403b09 |
- if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]):
|
|
|
403b09 |
+ if object_name in result and \
|
|
|
403b09 |
+ (pysss_nss_idmap.SID_KEY in result[object_name]):
|
|
|
403b09 |
object_sid = result[object_name][pysss_nss_idmap.SID_KEY]
|
|
|
403b09 |
group_list = pysss.getgrouplist(object_name)
|
|
|
403b09 |
|
|
|
403b09 |
@@ -552,7 +601,10 @@ class DomainValidator(object):
|
|
|
403b09 |
return self.__get_trusted_domain_user_and_groups(object_name)
|
|
|
403b09 |
|
|
|
403b09 |
group_sids = pysss_nss_idmap.getsidbyname(group_list)
|
|
|
403b09 |
- return (object_sid, [el[1][pysss_nss_idmap.SID_KEY] for el in group_sids.items()])
|
|
|
403b09 |
+ return (
|
|
|
403b09 |
+ object_sid,
|
|
|
403b09 |
+ [el[1][pysss_nss_idmap.SID_KEY] for el in group_sids.items()]
|
|
|
403b09 |
+ )
|
|
|
403b09 |
|
|
|
403b09 |
def __sid_to_str(self, sid):
|
|
|
403b09 |
"""
|
|
|
403b09 |
@@ -561,12 +613,13 @@ class DomainValidator(object):
|
|
|
403b09 |
"""
|
|
|
403b09 |
sid_rev_num = ord(sid[0])
|
|
|
403b09 |
number_sub_id = ord(sid[1])
|
|
|
403b09 |
- ia = struct.unpack('!Q','\x00\x00'+sid[2:8])[0]
|
|
|
403b09 |
+ ia = struct.unpack('!Q', '\x00\x00'+sid[2:8])[0]
|
|
|
403b09 |
subs = [
|
|
|
403b09 |
- struct.unpack('
|
|
|
403b09 |
+ struct.unpack('
|
|
|
403b09 |
for i in range(number_sub_id)
|
|
|
403b09 |
]
|
|
|
403b09 |
- return u'S-%d-%d-%s' % ( sid_rev_num, ia, '-'.join([str(s) for s in subs]),)
|
|
|
403b09 |
+ return u'S-%d-%d-%s' % (sid_rev_num, ia,
|
|
|
403b09 |
+ '-'.join([str(s) for s in subs]),)
|
|
|
403b09 |
|
|
|
403b09 |
def kinit_as_http(self, domain):
|
|
|
403b09 |
"""
|
|
|
403b09 |
@@ -624,7 +677,7 @@ class DomainValidator(object):
|
|
|
403b09 |
error on ccache initialization
|
|
|
403b09 |
"""
|
|
|
403b09 |
|
|
|
403b09 |
- if self._admin_creds == None:
|
|
|
403b09 |
+ if self._admin_creds is None:
|
|
|
403b09 |
return (None, None)
|
|
|
403b09 |
|
|
|
403b09 |
domain_suffix = domain.replace('.', '-')
|
|
|
403b09 |
@@ -691,7 +744,8 @@ class DomainValidator(object):
|
|
|
403b09 |
ccache_name = None
|
|
|
403b09 |
|
|
|
403b09 |
if self._admin_creds:
|
|
|
403b09 |
- (ccache_name, principal) = self.kinit_as_administrator(info['dns_domain'])
|
|
|
403b09 |
+ (ccache_name,
|
|
|
403b09 |
+ principal) = self.kinit_as_administrator(info['dns_domain'])
|
|
|
403b09 |
|
|
|
403b09 |
if ccache_name:
|
|
|
403b09 |
with ipautil.private_ccache(path=ccache_name):
|
|
|
403b09 |
@@ -736,7 +790,7 @@ class DomainValidator(object):
|
|
|
403b09 |
|
|
|
403b09 |
if not self._creds:
|
|
|
403b09 |
self._parm = param.LoadParm()
|
|
|
403b09 |
- self._parm.load(os.path.join(ipautil.SHARE_DIR,"smb.conf.empty"))
|
|
|
403b09 |
+ self._parm.load(os.path.join(ipautil.SHARE_DIR, "smb.conf.empty"))
|
|
|
403b09 |
self._parm.set('netbios name', self.flatname)
|
|
|
403b09 |
self._creds = credentials.Credentials()
|
|
|
403b09 |
self._creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
|
|
|
403b09 |
@@ -746,12 +800,14 @@ class DomainValidator(object):
|
|
|
403b09 |
netrc = net.Net(creds=self._creds, lp=self._parm)
|
|
|
403b09 |
finddc_error = None
|
|
|
403b09 |
result = None
|
|
|
403b09 |
+ flags = nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC | nbt.NBT_SERVER_CLOSEST
|
|
|
403b09 |
try:
|
|
|
403b09 |
- result = netrc.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC | nbt.NBT_SERVER_CLOSEST)
|
|
|
403b09 |
+ result = netrc.finddc(domain=domain, flags=flags)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
try:
|
|
|
403b09 |
# If search of closest GC failed, attempt to find any one
|
|
|
403b09 |
- result = netrc.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC)
|
|
|
403b09 |
+ flags = nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC
|
|
|
403b09 |
+ result = netrc.finddc(domain=domain, flags=flags)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
finddc_error = e
|
|
|
403b09 |
|
|
|
403b09 |
@@ -789,6 +845,7 @@ class DomainValidator(object):
|
|
|
403b09 |
self._info[domain] = info
|
|
|
403b09 |
return info
|
|
|
403b09 |
|
|
|
403b09 |
+
|
|
|
403b09 |
def string_to_array(what):
|
|
|
403b09 |
return [ord(v) for v in what]
|
|
|
403b09 |
|
|
|
403b09 |
@@ -797,7 +854,7 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
|
|
|
403b09 |
def __init__(self, hostname, creds=None):
|
|
|
403b09 |
self.parm = param.LoadParm()
|
|
|
403b09 |
- self.parm.load(os.path.join(ipautil.SHARE_DIR,"smb.conf.empty"))
|
|
|
403b09 |
+ self.parm.load(os.path.join(ipautil.SHARE_DIR, "smb.conf.empty"))
|
|
|
403b09 |
if len(hostname) > 0:
|
|
|
403b09 |
self.parm.set('netbios name', hostname)
|
|
|
403b09 |
self.creds = creds
|
|
|
403b09 |
@@ -810,14 +867,14 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
self.validation_attempts = 0
|
|
|
403b09 |
|
|
|
403b09 |
def __gen_lsa_connection(self, binding):
|
|
|
403b09 |
- if self.creds is None:
|
|
|
403b09 |
- raise errors.RequirementError(name=_('CIFS credentials object'))
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- result = lsa.lsarpc(binding, self.parm, self.creds)
|
|
|
403b09 |
- return result
|
|
|
403b09 |
- except RuntimeError as e:
|
|
|
403b09 |
- num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
- raise assess_dcerpc_exception(num=num, message=message)
|
|
|
403b09 |
+ if self.creds is None:
|
|
|
403b09 |
+ raise errors.RequirementError(name=_('CIFS credentials object'))
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ result = lsa.lsarpc(binding, self.parm, self.creds)
|
|
|
403b09 |
+ return result
|
|
|
403b09 |
+ except RuntimeError as e:
|
|
|
403b09 |
+ num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
+ raise assess_dcerpc_exception(num=num, message=message)
|
|
|
403b09 |
|
|
|
403b09 |
def init_lsa_pipe(self, remote_host):
|
|
|
403b09 |
"""
|
|
|
403b09 |
@@ -847,30 +904,35 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
# When session key is not available, we just skip this binding
|
|
|
403b09 |
session_attempts = session_attempts + 1
|
|
|
403b09 |
|
|
|
403b09 |
- if self._pipe is None and (attempts + session_attempts) == len(bindings):
|
|
|
403b09 |
+ if self._pipe is None and \
|
|
|
403b09 |
+ (attempts + session_attempts) == len(bindings):
|
|
|
403b09 |
raise errors.ACIError(
|
|
|
403b09 |
- info=_('CIFS server %(host)s denied your credentials') % dict(host=remote_host))
|
|
|
403b09 |
+ info=_('CIFS server %(host)s denied your credentials')
|
|
|
403b09 |
+ % dict(host=remote_host))
|
|
|
403b09 |
|
|
|
403b09 |
if self._pipe is None:
|
|
|
403b09 |
raise errors.RemoteRetrieveError(
|
|
|
403b09 |
- reason=_('Cannot establish LSA connection to %(host)s. Is CIFS server running?') % dict(host=remote_host))
|
|
|
403b09 |
+ reason=_('Cannot establish LSA connection to %(host)s. '
|
|
|
403b09 |
+ 'Is CIFS server running?') % dict(host=remote_host))
|
|
|
403b09 |
self.binding = binding
|
|
|
403b09 |
self.session_key = self._pipe.session_key
|
|
|
403b09 |
|
|
|
403b09 |
def __gen_lsa_bindings(self, remote_host):
|
|
|
403b09 |
"""
|
|
|
403b09 |
- There are multiple transports to issue LSA calls. However, depending on a
|
|
|
403b09 |
- system in use they may be blocked by local operating system policies.
|
|
|
403b09 |
+ There are multiple transports to issue LSA calls. However, depending on
|
|
|
403b09 |
+ a system in use they may be blocked by local operating system policies.
|
|
|
403b09 |
Generate all we can use. init_lsa_pipe() will try them one by one until
|
|
|
403b09 |
there is one working.
|
|
|
403b09 |
|
|
|
403b09 |
- We try NCACN_NP before NCACN_IP_TCP and use SMB2 before SMB1 or defaults.
|
|
|
403b09 |
+ We try NCACN_NP before NCACN_IP_TCP and use SMB2 before SMB1.
|
|
|
403b09 |
"""
|
|
|
403b09 |
transports = (u'ncacn_np', u'ncacn_ip_tcp')
|
|
|
403b09 |
- options = ( u'smb2,print', u'print')
|
|
|
403b09 |
- return [u'%s:%s[%s]' % (t, remote_host, o) for t in transports for o in options]
|
|
|
403b09 |
+ options = (u'smb2,print', u'print')
|
|
|
403b09 |
+ return [u'%s:%s[%s]' % (t, remote_host, o)
|
|
|
403b09 |
+ for t in transports for o in options]
|
|
|
403b09 |
|
|
|
403b09 |
- def retrieve_anonymously(self, remote_host, discover_srv=False, search_pdc=False):
|
|
|
403b09 |
+ def retrieve_anonymously(self, remote_host,
|
|
|
403b09 |
+ discover_srv=False, search_pdc=False):
|
|
|
403b09 |
"""
|
|
|
403b09 |
When retrieving DC information anonymously, we can't get SID of the domain
|
|
|
403b09 |
"""
|
|
|
403b09 |
@@ -896,7 +958,8 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
self.info['is_pdc'] = (result.server_type & nbt.NBT_SERVER_PDC) != 0
|
|
|
403b09 |
|
|
|
403b09 |
# Netlogon response doesn't contain SID of the domain.
|
|
|
403b09 |
- # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID control to reveal the SID
|
|
|
403b09 |
+ # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID
|
|
|
403b09 |
+ # control to reveal the SID
|
|
|
403b09 |
ldap_uri = 'ldap://%s' % (result.pdc_dns_name)
|
|
|
403b09 |
conn = _ldap.initialize(ldap_uri)
|
|
|
403b09 |
conn.set_option(_ldap.OPT_SERVER_CONTROLS, [ExtendedDNControl()])
|
|
|
403b09 |
@@ -908,7 +971,7 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
except _ldap.LDAPError as e:
|
|
|
403b09 |
root_logger.error(
|
|
|
403b09 |
"LDAP error when connecting to %(host)s: %(error)s" %
|
|
|
403b09 |
- dict(host=unicode(result.pdc_name), error=str(e)))
|
|
|
403b09 |
+ dict(host=unicode(result.pdc_name), error=str(e)))
|
|
|
403b09 |
except KeyError as e:
|
|
|
403b09 |
root_logger.error("KeyError: {err}, LDAP entry from {host} "
|
|
|
403b09 |
"returned malformed. Your DNS might be "
|
|
|
403b09 |
@@ -930,8 +993,11 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
objectAttribute = lsa.ObjectAttribute()
|
|
|
403b09 |
objectAttribute.sec_qos = lsa.QosInfo()
|
|
|
403b09 |
try:
|
|
|
403b09 |
- self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
|
403b09 |
- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS)
|
|
|
403b09 |
+ self._policy_handle = \
|
|
|
403b09 |
+ self._pipe.OpenPolicy2(u"", objectAttribute,
|
|
|
403b09 |
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
|
403b09 |
+ result = self._pipe.QueryInfoPolicy2(self._policy_handle,
|
|
|
403b09 |
+ lsa.LSA_POLICY_INFO_DNS)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
raise assess_dcerpc_exception(num=num, message=message)
|
|
|
403b09 |
@@ -944,7 +1010,8 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
self.info['dc'] = remote_host
|
|
|
403b09 |
|
|
|
403b09 |
try:
|
|
|
403b09 |
- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_ROLE)
|
|
|
403b09 |
+ result = self._pipe.QueryInfoPolicy2(self._policy_handle,
|
|
|
403b09 |
+ lsa.LSA_POLICY_INFO_ROLE)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
raise assess_dcerpc_exception(num=num, message=message)
|
|
|
403b09 |
@@ -958,18 +1025,18 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
clear_value.size = len(password_blob)
|
|
|
403b09 |
clear_value.password = password_blob
|
|
|
403b09 |
|
|
|
403b09 |
- clear_authentication_information = drsblobs.AuthenticationInformation()
|
|
|
403b09 |
- clear_authentication_information.LastUpdateTime = samba.unix2nttime(int(time.time()))
|
|
|
403b09 |
- clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR
|
|
|
403b09 |
- clear_authentication_information.AuthInfo = clear_value
|
|
|
403b09 |
+ clear_authinfo = drsblobs.AuthenticationInformation()
|
|
|
403b09 |
+ clear_authinfo.LastUpdateTime = samba.unix2nttime(int(time.time()))
|
|
|
403b09 |
+ clear_authinfo.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR
|
|
|
403b09 |
+ clear_authinfo.AuthInfo = clear_value
|
|
|
403b09 |
|
|
|
403b09 |
- authentication_information_array = drsblobs.AuthenticationInformationArray()
|
|
|
403b09 |
- authentication_information_array.count = 1
|
|
|
403b09 |
- authentication_information_array.array = [clear_authentication_information]
|
|
|
403b09 |
+ authinfo_array = drsblobs.AuthenticationInformationArray()
|
|
|
403b09 |
+ authinfo_array.count = 1
|
|
|
403b09 |
+ authinfo_array.array = [clear_authinfo]
|
|
|
403b09 |
|
|
|
403b09 |
outgoing = drsblobs.trustAuthInOutBlob()
|
|
|
403b09 |
outgoing.count = 1
|
|
|
403b09 |
- outgoing.current = authentication_information_array
|
|
|
403b09 |
+ outgoing.current = authinfo_array
|
|
|
403b09 |
|
|
|
403b09 |
confounder = [3]*512
|
|
|
403b09 |
for i in range(512):
|
|
|
403b09 |
@@ -983,7 +1050,8 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
|
|
|
403b09 |
trustpass_blob = ndr_pack(trustpass)
|
|
|
403b09 |
|
|
|
403b09 |
- encrypted_trustpass = arcfour_encrypt(self._pipe.session_key, trustpass_blob)
|
|
|
403b09 |
+ encrypted_trustpass = arcfour_encrypt(self._pipe.session_key,
|
|
|
403b09 |
+ trustpass_blob)
|
|
|
403b09 |
|
|
|
403b09 |
auth_blob = lsa.DATA_BUF2()
|
|
|
403b09 |
auth_blob.size = len(encrypted_trustpass)
|
|
|
403b09 |
@@ -993,7 +1061,6 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
auth_info.auth_blob = auth_blob
|
|
|
403b09 |
self.auth_info = auth_info
|
|
|
403b09 |
|
|
|
403b09 |
-
|
|
|
403b09 |
def generate_ftinfo(self, another_domain):
|
|
|
403b09 |
"""
|
|
|
403b09 |
Generates TrustDomainInfoFullInfo2Internal structure
|
|
|
403b09 |
@@ -1032,27 +1099,38 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
# smbd already has the information about itself
|
|
|
403b09 |
ldname = lsa.StringLarge()
|
|
|
403b09 |
ldname.string = another_domain.info['dns_domain']
|
|
|
403b09 |
- collision_info = self._pipe.lsaRSetForestTrustInformation(self._policy_handle,
|
|
|
403b09 |
- ldname,
|
|
|
403b09 |
- lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
|
|
|
403b09 |
- ftinfo, 0)
|
|
|
403b09 |
- if collision_info:
|
|
|
403b09 |
- root_logger.error("When setting forest trust information, got collision info back:\n%s" % (ndr_print(collision_info)))
|
|
|
403b09 |
+ ftlevel = lsa.LSA_FOREST_TRUST_DOMAIN_INFO
|
|
|
403b09 |
+ # RSetForestTrustInformation returns collision information
|
|
|
403b09 |
+ # for trust topology
|
|
|
403b09 |
+ cinfo = self._pipe.lsaRSetForestTrustInformation(
|
|
|
403b09 |
+ self._policy_handle,
|
|
|
403b09 |
+ ldname,
|
|
|
403b09 |
+ ftlevel,
|
|
|
403b09 |
+ ftinfo, 0)
|
|
|
403b09 |
+ if cinfo:
|
|
|
403b09 |
+ root_logger.error("When setting forest trust information, "
|
|
|
403b09 |
+ "got collision info back:\n%s"
|
|
|
403b09 |
+ % (ndr_print(cinfo)))
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
- # We can ignore the error here -- setting up name suffix routes may fail
|
|
|
403b09 |
+ # We can ignore the error here --
|
|
|
403b09 |
+ # setting up name suffix routes may fail
|
|
|
403b09 |
pass
|
|
|
403b09 |
|
|
|
403b09 |
- def establish_trust(self, another_domain, trustdom_secret, trust_type='bidirectional', trust_external=False):
|
|
|
403b09 |
+ def establish_trust(self, another_domain, trustdom_secret,
|
|
|
403b09 |
+ trust_type='bidirectional', trust_external=False):
|
|
|
403b09 |
"""
|
|
|
403b09 |
Establishes trust between our and another domain
|
|
|
403b09 |
- Input: another_domain -- instance of TrustDomainInstance, initialized with #retrieve call
|
|
|
403b09 |
+ Input: another_domain -- instance of TrustDomainInstance,
|
|
|
403b09 |
+ initialized with #retrieve call
|
|
|
403b09 |
trustdom_secret -- shared secred used for the trust
|
|
|
403b09 |
"""
|
|
|
403b09 |
if self.info['name'] == another_domain.info['name']:
|
|
|
403b09 |
# Check that NetBIOS names do not clash
|
|
|
403b09 |
raise errors.ValidationError(name=u'AD Trust Setup',
|
|
|
403b09 |
- error=_('the IPA server and the remote domain cannot share the same '
|
|
|
403b09 |
- 'NetBIOS name: %s') % self.info['name'])
|
|
|
403b09 |
+ error=_('the IPA server and the '
|
|
|
403b09 |
+ 'remote domain cannot share '
|
|
|
403b09 |
+ 'the same NetBIOS name: %s')
|
|
|
403b09 |
+ % self.info['name'])
|
|
|
403b09 |
|
|
|
403b09 |
self.generate_auth(trustdom_secret)
|
|
|
403b09 |
|
|
|
403b09 |
@@ -1071,8 +1149,12 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
try:
|
|
|
403b09 |
dname = lsa.String()
|
|
|
403b09 |
dname.string = another_domain.info['dns_domain']
|
|
|
403b09 |
- res = self._pipe.QueryTrustedDomainInfoByName(self._policy_handle, dname, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
|
|
|
403b09 |
- self._pipe.DeleteTrustedDomain(self._policy_handle, res.info_ex.sid)
|
|
|
403b09 |
+ res = self._pipe.QueryTrustedDomainInfoByName(
|
|
|
403b09 |
+ self._policy_handle,
|
|
|
403b09 |
+ dname,
|
|
|
403b09 |
+ lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
|
|
|
403b09 |
+ self._pipe.DeleteTrustedDomain(self._policy_handle,
|
|
|
403b09 |
+ res.info_ex.sid)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
# Ignore anything but access denied (NT_STATUS_ACCESS_DENIED)
|
|
|
403b09 |
@@ -1080,7 +1162,10 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
raise access_denied_error
|
|
|
403b09 |
|
|
|
403b09 |
try:
|
|
|
403b09 |
- trustdom_handle = self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
|
|
|
403b09 |
+ trustdom_handle = self._pipe.CreateTrustedDomainEx2(
|
|
|
403b09 |
+ self._policy_handle,
|
|
|
403b09 |
+ info, self.auth_info,
|
|
|
403b09 |
+ security.SEC_STD_DELETE)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
raise assess_dcerpc_exception(num=num, message=message)
|
|
|
403b09 |
@@ -1089,13 +1174,19 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
# trust settings. Samba insists this has to be done with LSA
|
|
|
403b09 |
# OpenTrustedDomain* calls, it is not enough to have a handle
|
|
|
403b09 |
# returned by the CreateTrustedDomainEx2 call.
|
|
|
403b09 |
- trustdom_handle = self._pipe.OpenTrustedDomainByName(self._policy_handle, dname, security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
|
403b09 |
+ trustdom_handle = self._pipe.OpenTrustedDomainByName(
|
|
|
403b09 |
+ self._policy_handle,
|
|
|
403b09 |
+ dname,
|
|
|
403b09 |
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
|
|
|
403b09 |
try:
|
|
|
403b09 |
- infoclass = lsa.TrustDomainInfoSupportedEncTypes()
|
|
|
403b09 |
- infoclass.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
|
|
|
403b09 |
- infoclass.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
|
|
|
403b09 |
- infoclass.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
|
|
|
403b09 |
- self._pipe.SetInformationTrustedDomain(trustdom_handle, lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES, infoclass)
|
|
|
403b09 |
+ infocls = lsa.TrustDomainInfoSupportedEncTypes()
|
|
|
403b09 |
+ infocls.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
|
|
|
403b09 |
+ infocls.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
|
|
|
403b09 |
+ infocls.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
|
|
|
403b09 |
+ self._pipe.SetInformationTrustedDomain(
|
|
|
403b09 |
+ trustdom_handle,
|
|
|
403b09 |
+ lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES,
|
|
|
403b09 |
+ infocls)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
# We can ignore the error here -- changing enctypes is for
|
|
|
403b09 |
# improved security but the trust will work with default values as
|
|
|
403b09 |
@@ -1105,13 +1196,16 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
|
|
|
403b09 |
if not trust_external:
|
|
|
403b09 |
try:
|
|
|
403b09 |
- info = self._pipe.QueryTrustedDomainInfo(trustdom_handle,
|
|
|
403b09 |
- lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
|
|
|
403b09 |
+ info = self._pipe.QueryTrustedDomainInfo(
|
|
|
403b09 |
+ trustdom_handle,
|
|
|
403b09 |
+ lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
|
|
|
403b09 |
info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
|
|
|
403b09 |
- self._pipe.SetInformationTrustedDomain(trustdom_handle,
|
|
|
403b09 |
- lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX, info)
|
|
|
403b09 |
+ self._pipe.SetInformationTrustedDomain(
|
|
|
403b09 |
+ trustdom_handle,
|
|
|
403b09 |
+ lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX, info)
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
- root_logger.error('unable to set trust transitivity status: %s' % (str(e)))
|
|
|
403b09 |
+ root_logger.error(
|
|
|
403b09 |
+ 'unable to set trust transitivity status: %s' % (str(e)))
|
|
|
403b09 |
|
|
|
403b09 |
if self.info['is_pdc'] or trust_external:
|
|
|
403b09 |
self.update_ftinfo(another_domain)
|
|
|
403b09 |
@@ -1119,12 +1213,13 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
def verify_trust(self, another_domain):
|
|
|
403b09 |
def retrieve_netlogon_info_2(logon_server, domain, function_code, data):
|
|
|
403b09 |
try:
|
|
|
403b09 |
- netr_pipe = netlogon.netlogon(domain.binding, domain.parm, domain.creds)
|
|
|
403b09 |
- result = netr_pipe.netr_LogonControl2Ex(logon_server=logon_server,
|
|
|
403b09 |
+ netr_pipe = netlogon.netlogon(domain.binding,
|
|
|
403b09 |
+ domain.parm, domain.creds)
|
|
|
403b09 |
+ result = netr_pipe.netr_LogonControl2Ex(
|
|
|
403b09 |
+ logon_server=logon_server,
|
|
|
403b09 |
function_code=function_code,
|
|
|
403b09 |
level=2,
|
|
|
403b09 |
- data=data
|
|
|
403b09 |
- )
|
|
|
403b09 |
+ data=data)
|
|
|
403b09 |
return result
|
|
|
403b09 |
except RuntimeError as e:
|
|
|
403b09 |
num, message = e.args # pylint: disable=unpacking-non-sequence
|
|
|
403b09 |
@@ -1135,9 +1230,11 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
another_domain.info['dns_domain'])
|
|
|
403b09 |
|
|
|
403b09 |
if result and result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED:
|
|
|
403b09 |
- if result.pdc_connection_status[0] != 0 and result.tc_connection_status[0] != 0:
|
|
|
403b09 |
+ if result.pdc_connection_status[0] != 0 and \
|
|
|
403b09 |
+ result.tc_connection_status[0] != 0:
|
|
|
403b09 |
if result.pdc_connection_status[1] == "WERR_ACCESS_DENIED":
|
|
|
403b09 |
- # Most likely AD DC hit another IPA replica which yet has no trust secret replicated
|
|
|
403b09 |
+ # Most likely AD DC hit another IPA replica which
|
|
|
403b09 |
+ # yet has no trust secret replicated
|
|
|
403b09 |
|
|
|
403b09 |
# Sleep and repeat again
|
|
|
403b09 |
self.validation_attempts += 1
|
|
|
403b09 |
@@ -1176,23 +1273,23 @@ class TrustDomainInstance(object):
|
|
|
403b09 |
|
|
|
403b09 |
def fetch_domains(api, mydomain, trustdomain, creds=None, server=None):
|
|
|
403b09 |
trust_flags = dict(
|
|
|
403b09 |
- NETR_TRUST_FLAG_IN_FOREST = 0x00000001,
|
|
|
403b09 |
- NETR_TRUST_FLAG_OUTBOUND = 0x00000002,
|
|
|
403b09 |
- NETR_TRUST_FLAG_TREEROOT = 0x00000004,
|
|
|
403b09 |
- NETR_TRUST_FLAG_PRIMARY = 0x00000008,
|
|
|
403b09 |
- NETR_TRUST_FLAG_NATIVE = 0x00000010,
|
|
|
403b09 |
- NETR_TRUST_FLAG_INBOUND = 0x00000020,
|
|
|
403b09 |
- NETR_TRUST_FLAG_MIT_KRB5 = 0x00000080,
|
|
|
403b09 |
- NETR_TRUST_FLAG_AES = 0x00000100)
|
|
|
403b09 |
+ NETR_TRUST_FLAG_IN_FOREST=0x00000001,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_OUTBOUND=0x00000002,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_TREEROOT=0x00000004,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_PRIMARY=0x00000008,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_NATIVE=0x00000010,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_INBOUND=0x00000020,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_MIT_KRB5=0x00000080,
|
|
|
403b09 |
+ NETR_TRUST_FLAG_AES=0x00000100)
|
|
|
403b09 |
|
|
|
403b09 |
trust_attributes = dict(
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY = 0x00000002,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE = 0x00000008,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_WITHIN_FOREST = 0x00000020,
|
|
|
403b09 |
- NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040)
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE=0x00000001,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY=0x00000002,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN=0x00000004,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE=0x00000008,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION=0x00000010,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_WITHIN_FOREST=0x00000020,
|
|
|
403b09 |
+ NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL=0x00000040)
|
|
|
403b09 |
|
|
|
403b09 |
def communicate(td):
|
|
|
403b09 |
td.init_lsa_pipe(td.info['dc'])
|
|
|
403b09 |
@@ -1314,7 +1411,8 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
ld.retrieve(installutils.get_fqdn())
|
|
|
403b09 |
self.local_domain = ld
|
|
|
403b09 |
|
|
|
403b09 |
- def populate_remote_domain(self, realm, realm_server=None, realm_admin=None, realm_passwd=None):
|
|
|
403b09 |
+ def populate_remote_domain(self, realm, realm_server=None,
|
|
|
403b09 |
+ realm_admin=None, realm_passwd=None):
|
|
|
403b09 |
def get_instance(self):
|
|
|
403b09 |
# Fetch data from foreign domain using password only
|
|
|
403b09 |
rd = TrustDomainInstance('')
|
|
|
403b09 |
@@ -1330,7 +1428,8 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
if realm_server is None:
|
|
|
403b09 |
rd.retrieve_anonymously(realm, discover_srv=True, search_pdc=True)
|
|
|
403b09 |
else:
|
|
|
403b09 |
- rd.retrieve_anonymously(realm_server, discover_srv=False, search_pdc=True)
|
|
|
403b09 |
+ rd.retrieve_anonymously(realm_server,
|
|
|
403b09 |
+ discover_srv=False, search_pdc=True)
|
|
|
403b09 |
rd.read_only = True
|
|
|
403b09 |
if realm_admin and realm_passwd:
|
|
|
403b09 |
if 'name' in rd.info:
|
|
|
403b09 |
@@ -1339,12 +1438,14 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
# realm admin is in DOMAIN\user format
|
|
|
403b09 |
# strip DOMAIN part as we'll enforce the one discovered
|
|
|
403b09 |
realm_admin = names[-1]
|
|
|
403b09 |
- auth_string = u"%s\%s%%%s" % (rd.info['name'], realm_admin, realm_passwd)
|
|
|
403b09 |
+ auth_string = u"%s\%s%%%s" \
|
|
|
403b09 |
+ % (rd.info['name'], realm_admin, realm_passwd)
|
|
|
403b09 |
td = get_instance(self)
|
|
|
403b09 |
td.creds.parse_string(auth_string)
|
|
|
403b09 |
td.creds.set_workstation(self.local_domain.hostname)
|
|
|
403b09 |
if realm_server is None:
|
|
|
403b09 |
- # we must have rd.info['dns_hostname'] then, part of anonymous discovery
|
|
|
403b09 |
+ # we must have rd.info['dns_hostname'] then
|
|
|
403b09 |
+ # as it is part of the anonymous discovery
|
|
|
403b09 |
td.retrieve(rd.info['dns_hostname'])
|
|
|
403b09 |
else:
|
|
|
403b09 |
td.retrieve(realm_server)
|
|
|
403b09 |
@@ -1358,8 +1459,8 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
"""
|
|
|
403b09 |
Generate list of records for forest trust information about
|
|
|
403b09 |
our realm domains. Note that the list generated currently
|
|
|
403b09 |
- includes only top level domains, no exclusion domains, and no TDO objects
|
|
|
403b09 |
- as we handle the latter in a separate way
|
|
|
403b09 |
+ includes only top level domains, no exclusion domains, and
|
|
|
403b09 |
+ no TDO objects as we handle the latter in a separate way
|
|
|
403b09 |
"""
|
|
|
403b09 |
if self.local_domain.read_only:
|
|
|
403b09 |
return
|
|
|
403b09 |
@@ -1367,10 +1468,15 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
self.local_domain.ftinfo_records = []
|
|
|
403b09 |
|
|
|
403b09 |
realm_domains = self.api.Command.realmdomains_show()['result']
|
|
|
403b09 |
- # Use realmdomains' modification timestamp to judge records last update time
|
|
|
403b09 |
- entry = self.api.Backend.ldap2.get_entry(realm_domains['dn'], ['modifyTimestamp'])
|
|
|
403b09 |
+ # Use realmdomains' modification timestamp
|
|
|
403b09 |
+ # to judge records' last update time
|
|
|
403b09 |
+ entry = self.api.Backend.ldap2.get_entry(
|
|
|
403b09 |
+ realm_domains['dn'], ['modifyTimestamp'])
|
|
|
403b09 |
# Convert the timestamp to Windows 64-bit timestamp format
|
|
|
403b09 |
- trust_timestamp = long(time.mktime(entry['modifytimestamp'][0].timetuple())*1e7+116444736000000000)
|
|
|
403b09 |
+ trust_timestamp = long(
|
|
|
403b09 |
+ time.mktime(
|
|
|
403b09 |
+ entry.single_value.get('modifytimestamp').timetuple()
|
|
|
403b09 |
+ )*1e7+116444736000000000)
|
|
|
403b09 |
|
|
|
403b09 |
for dom in realm_domains['associateddomain']:
|
|
|
403b09 |
ftinfo = dict()
|
|
|
403b09 |
@@ -1379,7 +1485,8 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
ftinfo['rec_type'] = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME
|
|
|
403b09 |
self.local_domain.ftinfo_records.append(ftinfo)
|
|
|
403b09 |
|
|
|
403b09 |
- def join_ad_full_credentials(self, realm, realm_server, realm_admin, realm_passwd, trust_type):
|
|
|
403b09 |
+ def join_ad_full_credentials(self, realm, realm_server, realm_admin,
|
|
|
403b09 |
+ realm_passwd, trust_type):
|
|
|
403b09 |
if not self.configured:
|
|
|
403b09 |
return None
|
|
|
403b09 |
|
|
|
403b09 |
@@ -1392,24 +1499,33 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
)
|
|
|
403b09 |
|
|
|
403b09 |
trust_external = bool(self.__allow_behavior & TRUST_JOIN_EXTERNAL)
|
|
|
403b09 |
- if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']:
|
|
|
403b09 |
+ if self.remote_domain.info['dns_domain'] != \
|
|
|
403b09 |
+ self.remote_domain.info['dns_forest']:
|
|
|
403b09 |
if not trust_external:
|
|
|
403b09 |
- raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'],
|
|
|
403b09 |
- domain=self.remote_domain.info['dns_domain'])
|
|
|
403b09 |
+ raise errors.NotAForestRootError(
|
|
|
403b09 |
+ forest=self.remote_domain.info['dns_forest'],
|
|
|
403b09 |
+ domain=self.remote_domain.info['dns_domain'])
|
|
|
403b09 |
|
|
|
403b09 |
if not self.remote_domain.read_only:
|
|
|
403b09 |
trustdom_pass = samba.generate_random_password(128, 128)
|
|
|
403b09 |
self.get_realmdomains()
|
|
|
403b09 |
self.remote_domain.establish_trust(self.local_domain,
|
|
|
403b09 |
- trustdom_pass, trust_type, trust_external)
|
|
|
403b09 |
+ trustdom_pass,
|
|
|
403b09 |
+ trust_type, trust_external)
|
|
|
403b09 |
self.local_domain.establish_trust(self.remote_domain,
|
|
|
403b09 |
- trustdom_pass, trust_type, trust_external)
|
|
|
403b09 |
- # if trust is inbound, we don't need to verify it because AD DC will respond
|
|
|
403b09 |
- # with WERR_NO_SUCH_DOMAIN -- in only does verification for outbound trusts.
|
|
|
403b09 |
+ trustdom_pass,
|
|
|
403b09 |
+ trust_type, trust_external)
|
|
|
403b09 |
+ # if trust is inbound, we don't need to verify it because
|
|
|
403b09 |
+ # AD DC will respond with WERR_NO_SUCH_DOMAIN --
|
|
|
403b09 |
+ # it only does verification for outbound trusts.
|
|
|
403b09 |
result = True
|
|
|
403b09 |
if trust_type == TRUST_BIDIRECTIONAL:
|
|
|
403b09 |
result = self.remote_domain.verify_trust(self.local_domain)
|
|
|
403b09 |
- return dict(local=self.local_domain, remote=self.remote_domain, verified=result)
|
|
|
403b09 |
+ return dict(
|
|
|
403b09 |
+ local=self.local_domain,
|
|
|
403b09 |
+ remote=self.remote_domain,
|
|
|
403b09 |
+ verified=result
|
|
|
403b09 |
+ )
|
|
|
403b09 |
return None
|
|
|
403b09 |
|
|
|
403b09 |
def join_ad_ipa_half(self, realm, realm_server, trustdom_passwd, trust_type):
|
|
|
403b09 |
@@ -1420,11 +1536,18 @@ class TrustDomainJoins(object):
|
|
|
403b09 |
self.populate_remote_domain(realm, realm_server, realm_passwd=None)
|
|
|
403b09 |
|
|
|
403b09 |
trust_external = bool(self.__allow_behavior & TRUST_JOIN_EXTERNAL)
|
|
|
403b09 |
- if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']:
|
|
|
403b09 |
+ if self.remote_domain.info['dns_domain'] != \
|
|
|
403b09 |
+ self.remote_domain.info['dns_forest']:
|
|
|
403b09 |
if not trust_external:
|
|
|
403b09 |
- raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'],
|
|
|
403b09 |
- domain=self.remote_domain.info['dns_domain'])
|
|
|
403b09 |
+ raise errors.NotAForestRootError(
|
|
|
403b09 |
+ forest=self.remote_domain.info['dns_forest'],
|
|
|
403b09 |
+ domain=self.remote_domain.info['dns_domain'])
|
|
|
403b09 |
|
|
|
403b09 |
self.local_domain.establish_trust(self.remote_domain,
|
|
|
403b09 |
- trustdom_passwd, trust_type, trust_external)
|
|
|
403b09 |
- return dict(local=self.local_domain, remote=self.remote_domain, verified=False)
|
|
|
403b09 |
+ trustdom_passwd,
|
|
|
403b09 |
+ trust_type, trust_external)
|
|
|
403b09 |
+ return dict(
|
|
|
403b09 |
+ local=self.local_domain,
|
|
|
403b09 |
+ remote=self.remote_domain,
|
|
|
403b09 |
+ verified=False
|
|
|
403b09 |
+ )
|
|
|
403b09 |
--
|
|
|
403b09 |
2.7.4
|
|
|
403b09 |
|