9991ea
From 7c4828f3eb0e7b1f246f6263bdf22592d51824df Mon Sep 17 00:00:00 2001
9991ea
From: Alexander Bokovoy <abokovoy@redhat.com>
9991ea
Date: Wed, 27 Nov 2013 12:17:43 +0200
9991ea
Subject: [PATCH 08/10] subdomains: Use AD admin credentials when trust is
9991ea
 being established
9991ea
9991ea
When AD administrator credentials passed, they stored in realm_passwd,
9991ea
not realm_password in the options.
9991ea
9991ea
When passing credentials to ipaserver.dcerpc.fetch_domains(), make sure
9991ea
to normalize them.
9991ea
9991ea
Additionally, force Samba auth module to use NTLMSSP in case we have
9991ea
credentials because at the point when trust is established, KDC is not
9991ea
yet ready to issue tickets to a service in the other realm due to
9991ea
MS-PAC information caching effects. The logic is a bit fuzzy because
9991ea
credentials code makes decisions on what to use based on the smb.conf
9991ea
parameters and Python bindings to set parameters to smb.conf make it so
9991ea
that auth module believes these parameters were overidden by the user
9991ea
through the command line and ignore some of options. We have to do calls
9991ea
in the right order to force NTLMSSP use instead of Kerberos.
9991ea
9991ea
Fixes https://fedorahosted.org/freeipa/ticket/4046
9991ea
---
9991ea
 ipalib/plugins/trust.py | 13 ++++++++++---
9991ea
 ipaserver/dcerpc.py     | 42 ++++++++++++++++++++++++++++--------------
9991ea
 2 files changed, 38 insertions(+), 17 deletions(-)
9991ea
9991ea
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
9991ea
index 5ba0905030c700c7f63003eef25891c52330934b..3b1b2fc67ce333751556a5c3a59a7f89efc608f9 100644
9991ea
--- a/ipalib/plugins/trust.py
9991ea
+++ b/ipalib/plugins/trust.py
9991ea
@@ -1231,10 +1231,17 @@ def execute(self, *keys, **options):
9991ea
 def fetch_domains_from_trust(self, trustinstance, trust_entry, **options):
9991ea
     trust_name = trust_entry['cn'][0]
9991ea
     creds = None
9991ea
-    password = options.get('realm_password', None)
9991ea
+    password = options.get('realm_passwd', None)
9991ea
     if password:
9991ea
-        creds = u"%s%%%s" % (options.get('realm_admin'), password)
9991ea
-    domains = ipaserver.dcerpc.fetch_domains(self.api, trustinstance.local_flatname, trust_name, creds=creds)
9991ea
+        admin_name = options.get('realm_admin')
9991ea
+        sp = admin_name.split('\\')
9991ea
+        if len(sp) == 1:
9991ea
+            sp.insert(0, trustinstance.remote_domain.info['name'])
9991ea
+        creds = u"{name}%{password}".format(name="\\".join(sp),
9991ea
+                                            password=password)
9991ea
+    domains = ipaserver.dcerpc.fetch_domains(self.api,
9991ea
+                                             trustinstance.local_flatname,
9991ea
+                                             trust_name, creds=creds)
9991ea
     result = []
9991ea
     if not domains:
9991ea
         return None
9991ea
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
9991ea
index 0dde3473b12b857ff269a936ad9a07d098405c45..d809c416baac072a2489fbd3c167f08665b7a24e 100644
9991ea
--- a/ipaserver/dcerpc.py
9991ea
+++ b/ipaserver/dcerpc.py
9991ea
@@ -655,7 +655,7 @@ def __gen_lsa_connection(self, binding):
9991ea
        except RuntimeError, (num, message):
9991ea
            raise assess_dcerpc_exception(num=num, message=message)
9991ea
 
9991ea
-    def __init_lsa_pipe(self, remote_host):
9991ea
+    def init_lsa_pipe(self, remote_host):
9991ea
         """
9991ea
         Try to initialize connection to the LSA pipe at remote host.
9991ea
         This method tries consequently all possible transport options
9991ea
@@ -692,7 +692,7 @@ def __gen_lsa_bindings(self, remote_host):
9991ea
         """
9991ea
         There are multiple transports to issue LSA calls. However, depending on a
9991ea
         system in use they may be blocked by local operating system policies.
9991ea
-        Generate all we can use. __init_lsa_pipe() will try them one by one until
9991ea
+        Generate all we can use. init_lsa_pipe() will try them one by one until
9991ea
         there is one working.
9991ea
 
9991ea
         We try NCACN_NP before NCACN_IP_TCP and signed sessions before unsigned.
9991ea
@@ -753,7 +753,7 @@ def parse_naming_context(self, context):
9991ea
         return naming_ref.match(context).group(1)
9991ea
 
9991ea
     def retrieve(self, remote_host):
9991ea
-        self.__init_lsa_pipe(remote_host)
9991ea
+        self.init_lsa_pipe(remote_host)
9991ea
 
9991ea
         objectAttribute = lsa.ObjectAttribute()
9991ea
         objectAttribute.sec_qos = lsa.QosInfo()
9991ea
@@ -964,34 +964,48 @@ def fetch_domains(api, mydomain, trustdomain, creds=None):
9991ea
                 NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL  = 0x00000040)
9991ea
 
9991ea
     def communicate(td):
9991ea
-        td.creds.guess(td.parm)
9991ea
-        netrc = net.Net(creds=td.creds, lp=td.parm)
9991ea
-        try:
9991ea
-            result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
9991ea
-        except RuntimeError, e:
9991ea
-            raise assess_dcerpc_exception(message=str(e))
9991ea
-        if not result:
9991ea
-            return None
9991ea
-        td.retrieve(unicode(result.pdc_dns_name))
9991ea
-
9991ea
+        td.init_lsa_pipe(td.info['dc'])
9991ea
         netr_pipe = netlogon.netlogon(td.binding, td.parm, td.creds)
9991ea
         domains = netr_pipe.netr_DsrEnumerateDomainTrusts(td.binding, 1)
9991ea
         return domains
9991ea
 
9991ea
     domains = None
9991ea
+    domain_validator = DomainValidator(api)
9991ea
+    configured = domain_validator.is_configured()
9991ea
+    if not configured:
9991ea
+        return None
9991ea
+
9991ea
     td = TrustDomainInstance('')
9991ea
     td.parm.set('workgroup', mydomain)
9991ea
-    td.creds = credentials.Credentials()
9991ea
+    cr = credentials.Credentials()
9991ea
+    cr.set_kerberos_state(credentials.DONT_USE_KERBEROS)
9991ea
+    cr.guess(td.parm)
9991ea
+    cr.set_anonymous()
9991ea
+    cr.set_workstation(domain_validator.flatname)
9991ea
+    netrc = net.Net(creds=cr, lp=td.parm)
9991ea
+    try:
9991ea
+        result = netrc.finddc(domain=trustdomain,
9991ea
+                              flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
9991ea
+    except RuntimeError, e:
9991ea
+        raise assess_dcerpc_exception(message=str(e))
9991ea
+
9991ea
+    td.info['dc'] = unicode(result.pdc_dns_name)
9991ea
     if creds is None:
9991ea
         domval = DomainValidator(api)
9991ea
         (ccache_name, principal) = domval.kinit_as_http(trustdomain)
9991ea
+        td.creds = credentials.Credentials()
9991ea
         td.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
9991ea
         if ccache_name:
9991ea
             with installutils.private_ccache(path=ccache_name):
9991ea
+                td.creds.guess(td.parm)
9991ea
+                td.creds.set_workstation(domain_validator.flatname)
9991ea
                 domains = communicate(td)
9991ea
     else:
9991ea
+        td.creds = credentials.Credentials()
9991ea
         td.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS)
9991ea
+        td.creds.guess(td.parm)
9991ea
         td.creds.parse_string(creds)
9991ea
+        td.creds.set_workstation(domain_validator.flatname)
9991ea
         domains = communicate(td)
9991ea
 
9991ea
     if domains is None:
9991ea
-- 
9991ea
1.8.3.1
9991ea