[Freeipa-devel] [PATCH] 0073 Add trust verification code

Alexander Bokovoy abokovoy at redhat.com
Mon Sep 17 15:44:36 UTC 2012


Hi,

Following patch adds trust verification sequence to the case when we
establish trust with knowledge of AD administrative credentials.

As we found out, in order to validate/verify trust, one has to have
administrative credentials for the trusted domain, since there are
few RPCs that should be performed against trusted domain's DC's LSA
and NetLogon pipes and these are protected by administrative credentials.

Thus, when we know admin credentials for the remote domain, we can
perform the trust validation.

https://fedorahosted.org/freeipa/ticket/2763


-- 
/ Alexander Bokovoy
-------------- next part --------------
>From ddf4205c8b3182cbb19328dc9f8b21ede5de3c65 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Thu, 13 Sep 2012 20:01:55 +0300
Subject: [PATCH] Add verification of the AD trust

Since we only can perform verification when AD admin credentials are available,
report that trust should be verified from the AD side in other cases,
including unsuccessful verification.

Once trust is added, status of it is never stored anywhere.

https://fedorahosted.org/freeipa/ticket/2763
---
 ipalib/plugins/trust.py | 12 +++++++-----
 ipaserver/dcerpc.py     | 31 ++++++++++++++++++++++++++++---
 2 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 074560dc27eb121b5035ba9a8260e5ab24b2b4b5..2e20725e6343dfd7ea602dd7903745cd0a0e0c62 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -60,8 +60,8 @@ _trust_type_dict = {1 : _('Non-Active Directory domain'),
 _trust_direction_dict = {1 : _('Trusting forest'),
                          2 : _('Trusted forest'),
                          3 : _('Two-way trust')}
-_trust_status = {1 : _('Established and verified'),
-                 2 : _('Waiting for confirmation by remote side')}
+_trust_status_dict = {True : _('Established and verified'),
+                 False : _('Waiting for confirmation by remote side')}
 _trust_type_dict_unknown = _('Unknown')
 
 def trust_type_string(level):
@@ -84,7 +84,7 @@ def trust_direction_string(level):
     return unicode(string)
 
 def trust_status_string(level):
-    string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown)
+    string = _trust_status_dict.get(level, _trust_type_dict_unknown)
     return unicode(string)
 
 class trust(LDAPObject):
@@ -190,6 +190,8 @@ class trust_add(LDAPCreate):
         result['result'] = trusts[0][1]
         result['result']['trusttype'] = [trust_type_string(result['result']['ipanttrusttype'][0])]
         result['result']['trustdirection'] = [trust_direction_string(result['result']['ipanttrustdirection'][0])]
+        result['result']['truststatus'] = [trust_status_string(result['verified'])]
+        del result['verified']
 
         return result
 
@@ -272,14 +274,14 @@ class trust_add(LDAPCreate):
             if result is None:
                 raise errors.ValidationError(name=_('AD Trust setup'), error=_('Unable to verify write permissions to the AD'))
 
-            return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
+            return dict(value=trustinstance.remote_domain.info['dns_domain'], verified=result['verified'])
 
         # 2. We don't have access to the remote domain and trustdom password
         # is provided. Do the work on our side and inform what to do on remote
         # side.
         if 'trust_secret' in options:
             result = trustinstance.join_ad_ipa_half(keys[-1], realm_server, options['trust_secret'])
-            return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
+            return dict(value=trustinstance.remote_domain.info['dns_domain'], verified=result['verified'])
         raise errors.ValidationError(name=_('AD Trust setup'), error=_('Not enough arguments specified to perform trust setup'))
 
 class trust_del(LDAPDelete):
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index b7ccd15d3e9008fddb6dc5419fc05c50ede39d26..86cf01dbac9aca21c35d2db65ef4d4c56e313709 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -35,7 +35,7 @@ import os, string, struct, copy
 import uuid
 from samba import param
 from samba import credentials
-from samba.dcerpc import security, lsa, drsblobs, nbt
+from samba.dcerpc import security, lsa, drsblobs, nbt, netlogon
 from samba.ndr import ndr_pack
 from samba import net
 import samba
@@ -217,6 +217,7 @@ class TrustDomainInstance(object):
         if self._pipe is None:
             raise errors.RemoteRetrieveError(
                 reason=_('Cannot establish LSA connection to %(host)s. Is CIFS server running?') % dict(host=remote_host))
+        self.binding = binding
 
     def __gen_lsa_bindings(self, remote_host):
         """
@@ -251,6 +252,7 @@ class TrustDomainInstance(object):
         self.info['dns_domain'] = unicode(result.dns_domain)
         self.info['dns_forest'] = unicode(result.forest)
         self.info['guid'] = unicode(result.domain_uuid)
+        self.info['dc'] = unicode(result.pdc_dns_name)
 
         # Netlogon response doesn't contain SID of the domain.
         # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID control to reveal the SID
@@ -291,6 +293,7 @@ class TrustDomainInstance(object):
         self.info['dns_forest'] = unicode(result.dns_forest.string)
         self.info['guid'] = unicode(result.domain_guid)
         self.info['sid'] = unicode(result.sid)
+        self.info['dc'] = remote_host
 
     def generate_auth(self, trustdom_secret):
         def arcfour_encrypt(key, data):
@@ -374,6 +377,27 @@ class TrustDomainInstance(object):
         except RuntimeError, (num, message):
             raise assess_dcerpc_exception(num=num, message=message)
 
+    def verify_trust(self, another_domain):
+        def retrieve_netlogon_info_2(domain, function_code, data):
+            try:
+                netr_pipe = netlogon.netlogon(domain.binding, domain.parm, domain.creds)
+                result = netr_pipe.netr_LogonControl2Ex(logon_server=None,
+                                           function_code=function_code,
+                                           level=2,
+                                           data=data
+                                           )
+                return result
+            except RuntimeError, (num, message):
+                raise assess_dcerpc_exception(num=num, message=message)
+
+        result = retrieve_netlogon_info_2(self,
+                                          netlogon.NETLOGON_CONTROL_TC_VERIFY,
+                                          another_domain.info['dns_domain'])
+        if (unicode(result.trusted_dc_name)[2:] == another_domain.info['dc'] and
+            result.tc_connection_status == (0, 'WERR_OK')):
+            return True
+        return False
+
 class TrustDomainJoins(object):
     def __init__(self, api):
         self.api = api
@@ -447,7 +471,8 @@ class TrustDomainJoins(object):
             trustdom_pass = samba.generate_random_password(128, 128)
             self.remote_domain.establish_trust(self.local_domain, trustdom_pass)
             self.local_domain.establish_trust(self.remote_domain, trustdom_pass)
-            return dict(local=self.local_domain, remote=self.remote_domain)
+            result = self.remote_domain.verify_trust(self.local_domain)
+            return dict(local=self.local_domain, remote=self.remote_domain, verified=result)
         return None
 
     def join_ad_ipa_half(self, realm, realm_server, trustdom_passwd):
@@ -456,4 +481,4 @@ class TrustDomainJoins(object):
 
         self.__populate_remote_domain(realm, realm_server, realm_passwd=None)
         self.local_domain.establish_trust(self.remote_domain, trustdom_passwd)
-        return dict(local=self.local_domain, remote=self.remote_domain)
+        return dict(local=self.local_domain, remote=self.remote_domain, verified=False)
-- 
1.7.12



More information about the Freeipa-devel mailing list