[Freeipa-devel] [PATCH] 0128 subdomains: Use AD admin credentials when trust is being established

Alexander Bokovoy abokovoy at redhat.com
Fri Nov 29 11:45:21 UTC 2013


On Fri, 29 Nov 2013, Sumit Bose wrote:
>On Thu, Nov 28, 2013 at 03:04:49PM +0200, Alexander Bokovoy wrote:
>> On Wed, 27 Nov 2013, Alexander Bokovoy wrote:
>> >Hi!
>> >
>> >Attached patch should solve an issue when fetching subdomains fails
>> >shortly after trust has been established due to MS-PAC caching effects
>> >on KDC. We have already made an alternative path to use when AD admin
>> >credentials are available but failed to actually use them here.
>> >
>> >Details in the patch.
>> >
>> >https://fedorahosted.org/freeipa/ticket/4046
>> New version attached. It makes sure we use correct domain name when
>> constructing credentials for NTLMSSP authentication if AD administrator
>> credentials do not include one.
>>
>> Many thanks to Scott Poore who kindly provided Windows Server 2008R2
>> setup which failed for the original case and also for the first version
>> of this patch.
>>
>> --
>> / Alexander Bokovoy
>
>Patch makes sense and is working in my tests, so ACK. There are only two
>cosmetic issues where I leave it up to you if they need fixing, see
>below.
>
>It's a pity that we have to fall back to NTLMSSP, but currently I do not
>see another solution as well. Do you think it would make sense to open a
>ticket as a reminder to do some more research how this can be done with
>Kerberos?
Well, we need to switch DAL driver implementation to syncrepl use,
that would be our best solution for the case. All issues here are not
really issues of communication with AD but the fact that we can't get
MS-PAC to an HTTP service ticket immediately after we established trust
without forcing DAL driver to update its view of the trusts.

Since we have AD administrator credentials at the trust-add point, we simply
use them, as we use them to establish trust. At this point we have
sequence of three NTLMSSP authentication sessions: one for establishing
trust, one for updating trust configuration afterwards, and one to fetch
trust topology information.

For trust-fetch-domains case, where we don't have AD administrator
credentials, we rely on HTTP/ service ticket and that works fine once
DAL driver is able to see newly established trust.

So if we want to open a ticket, it should be a ticket to implement
syncrepl protocol support in the DAL driver rather than any research.

>
>> that auth module believes these parameters were overidden by the user
>> through the command line and ignore some of options. We have to do calls
>> in the right order to forse NTLMSSP use instead of Kerberos.
>
>                        ^^^^^
Thanks, fixed.

>>
>> Fixes https://fedorahosted.org/freeipa/ticket/4046
>> ---
>>  ipalib/plugins/trust.py |  8 ++++++--
>>  ipaserver/dcerpc.py     | 41 +++++++++++++++++++++++++++--------------
>>  2 files changed, 33 insertions(+), 16 deletions(-)
>>
>> +        if len(sp) == 1:
>> +            sp.insert(0, trustinstance.remote_domain.info['name'])
>> +        creds = u"{name}%{password}".format(name="\\".join(sp), password=password)
>                                                                                   ^^
>
>> +    cr.set_workstation(domain_validator.flatname)
>> +    netrc = net.Net(creds=cr, lp=td.parm)
>> +    try:
>> +        result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
>                                                                                   ^^^^^^^^^^^^^^^
>
>I'm not sure about any policy related to long lines in python, but you
>added 2 lines over 80 characters.
Fixed.

-- 
/ Alexander Bokovoy
-------------- next part --------------
>From 71dc3b4ce175ba3803743089b04ec7d3bea48e77 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Wed, 27 Nov 2013 12:17:43 +0200
Subject: [PATCH 2/2] subdomains: Use AD admin credentials when trust is being
 established

When AD administrator credentials passed, they stored in realm_passwd,
not realm_password in the options.

When passing credentials to ipaserver.dcerpc.fetch_domains(), make sure
to normalize them.

Additionally, force Samba auth module to use NTLMSSP in case we have
credentials because at the point when trust is established, KDC is not
yet ready to issue tickets to a service in the other realm due to
MS-PAC information caching effects. The logic is a bit fuzzy because
credentials code makes decisions on what to use based on the smb.conf
parameters and Python bindings to set parameters to smb.conf make it so
that auth module believes these parameters were overidden by the user
through the command line and ignore some of options. We have to do calls
in the right order to force NTLMSSP use instead of Kerberos.

Fixes https://fedorahosted.org/freeipa/ticket/4046
---
 ipalib/plugins/trust.py | 13 ++++++++++---
 ipaserver/dcerpc.py     | 42 ++++++++++++++++++++++++++++--------------
 2 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 5ba0905..3b1b2fc 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -1231,10 +1231,17 @@ api.register(trustdomain_del)
 def fetch_domains_from_trust(self, trustinstance, trust_entry, **options):
     trust_name = trust_entry['cn'][0]
     creds = None
-    password = options.get('realm_password', None)
+    password = options.get('realm_passwd', None)
     if password:
-        creds = u"%s%%%s" % (options.get('realm_admin'), password)
-    domains = ipaserver.dcerpc.fetch_domains(self.api, trustinstance.local_flatname, trust_name, creds=creds)
+        admin_name = options.get('realm_admin')
+        sp = admin_name.split('\\')
+        if len(sp) == 1:
+            sp.insert(0, trustinstance.remote_domain.info['name'])
+        creds = u"{name}%{password}".format(name="\\".join(sp),
+                                            password=password)
+    domains = ipaserver.dcerpc.fetch_domains(self.api,
+                                             trustinstance.local_flatname,
+                                             trust_name, creds=creds)
     result = []
     if not domains:
         return None
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index 0dde347..d809c41 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -655,7 +655,7 @@ class TrustDomainInstance(object):
        except RuntimeError, (num, message):
            raise assess_dcerpc_exception(num=num, message=message)
 
-    def __init_lsa_pipe(self, remote_host):
+    def init_lsa_pipe(self, remote_host):
         """
         Try to initialize connection to the LSA pipe at remote host.
         This method tries consequently all possible transport options
@@ -692,7 +692,7 @@ class TrustDomainInstance(object):
         """
         There are multiple transports to issue LSA calls. However, depending on a
         system in use they may be blocked by local operating system policies.
-        Generate all we can use. __init_lsa_pipe() will try them one by one until
+        Generate all we can use. init_lsa_pipe() will try them one by one until
         there is one working.
 
         We try NCACN_NP before NCACN_IP_TCP and signed sessions before unsigned.
@@ -753,7 +753,7 @@ class TrustDomainInstance(object):
         return naming_ref.match(context).group(1)
 
     def retrieve(self, remote_host):
-        self.__init_lsa_pipe(remote_host)
+        self.init_lsa_pipe(remote_host)
 
         objectAttribute = lsa.ObjectAttribute()
         objectAttribute.sec_qos = lsa.QosInfo()
@@ -964,34 +964,48 @@ def fetch_domains(api, mydomain, trustdomain, creds=None):
                 NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL  = 0x00000040)
 
     def communicate(td):
-        td.creds.guess(td.parm)
-        netrc = net.Net(creds=td.creds, lp=td.parm)
-        try:
-            result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
-        except RuntimeError, e:
-            raise assess_dcerpc_exception(message=str(e))
-        if not result:
-            return None
-        td.retrieve(unicode(result.pdc_dns_name))
-
+        td.init_lsa_pipe(td.info['dc'])
         netr_pipe = netlogon.netlogon(td.binding, td.parm, td.creds)
         domains = netr_pipe.netr_DsrEnumerateDomainTrusts(td.binding, 1)
         return domains
 
     domains = None
+    domain_validator = DomainValidator(api)
+    configured = domain_validator.is_configured()
+    if not configured:
+        return None
+
     td = TrustDomainInstance('')
     td.parm.set('workgroup', mydomain)
-    td.creds = credentials.Credentials()
+    cr = credentials.Credentials()
+    cr.set_kerberos_state(credentials.DONT_USE_KERBEROS)
+    cr.guess(td.parm)
+    cr.set_anonymous()
+    cr.set_workstation(domain_validator.flatname)
+    netrc = net.Net(creds=cr, lp=td.parm)
+    try:
+        result = netrc.finddc(domain=trustdomain,
+                              flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
+    except RuntimeError, e:
+        raise assess_dcerpc_exception(message=str(e))
+
+    td.info['dc'] = unicode(result.pdc_dns_name)
     if creds is None:
         domval = DomainValidator(api)
         (ccache_name, principal) = domval.kinit_as_http(trustdomain)
+        td.creds = credentials.Credentials()
         td.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
         if ccache_name:
             with installutils.private_ccache(path=ccache_name):
+                td.creds.guess(td.parm)
+                td.creds.set_workstation(domain_validator.flatname)
                 domains = communicate(td)
     else:
+        td.creds = credentials.Credentials()
         td.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS)
+        td.creds.guess(td.parm)
         td.creds.parse_string(creds)
+        td.creds.set_workstation(domain_validator.flatname)
         domains = communicate(td)
 
     if domains is None:
-- 
1.8.4.2



More information about the Freeipa-devel mailing list