see commit message for details.

/ Alexander Bokovoy
From 96f4623730f764c73ce4544d0788e8782fecaa99 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Thu, 13 Aug 2015 17:18:57 +0300
Subject: [PATCH] trusts: harden trust-fetch-domains oddjobd-based script

When ipa-getkeytab is used to fetch trusted domain object credentials,
the fetched entry has always kvno 1. ipa-getkeytab always adds a key to
keytab which means older key versions will be in the SSSD keytab and
will confuse libkrb5 ccache initialization code as all kvno values are
equal to 1. Wrong key is picked up then and kinit fails.

To solve this problem, always remove existing
/var/lib/sss/keytabs/forest.keytab before retrieving a new one.

To make sure script's input cannot be used to define what should be
removed (by passing a relative path), make sure we retrieve trusted
forest name from LDAP. If it is not possible to retrieve, the script
will issue an exception and quit. If abrtd is running, this will be
recorded as a 'crash' and an attempt to use script by malicious user
would be recorded as well in the abrtd journal.

Solves https://bugzilla.redhat.com/show_bug.cgi?id=1250190
 install/oddjob/com.redhat.idm.trust-fetch-domains | 29 +++++++++++++++++++----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains 
index e50c81e..6a2171d 100755
--- a/install/oddjob/com.redhat.idm.trust-fetch-domains
+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains
@@ -41,6 +41,9 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, 
                       "-p", oneway_principal,
                       "-k", oneway_keytab_name,
+    if os.path.isfile(oneway_keytab_name):
+        os.unlink(oneway_keytab_name)
     (stdout, stderr, retcode) = ipautil.run(getkeytab_args,
                                             env={'KRB5CCNAME': ccache_name, 
'LANG': 'C'},
@@ -111,7 +114,6 @@ from ipalib.plugins import trust
 # retrieve the keys to oneway_keytab_name.
 keytab_name = '/etc/samba/samba.keytab'
-oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
 principal = str('cifs/' + api.env.host)
@@ -137,10 +139,20 @@ else:
 old_ccache = os.environ.get('KRB5CCNAME')
+# Retrieve own NetBIOS name and trusted forest's name.
+# We use script's input to retrieve the trusted forest's name to sanitize input
+# for file-level access as we might need to wipe out keytab in 
 own_trust_dn = DN(('cn', api.env.domain),('cn','ad'), ('cn', 'etc'), 
 own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ['ipantflatname'])
-own_trust_flatname = own_trust_entry['ipantflatname'][0].upper()
+own_trust_flatname = own_trust_entry.single_value.get('ipantflatname').upper()
+trusted_domain_dn = DN(('cn', trusted_domain.lower()), 
api.env.container_adtrusts, api.env.basedn)
+trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ['cn'])
+trusted_domain = trusted_domain_entry.single_value.get('cn').lower()
+# At this point if we didn't find trusted forest name, an exception will be 
+# and script will quit. This is actually intended.
+oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
 oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
 # If keytab does not exist, retrieve it
@@ -152,11 +164,18 @@ try:
     # The keytab may have stale key material (from older trust-add run)
     if not os.path.isfile(oneway_ccache_name):
         oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, 
+    else:
+        oneway_ccache_check = KRB5_CCache(oneway_ccache_name)
+        if not oneway_ccache_check.credential_is_valid(oneway_principal):
+            # If credentials were invalid, obtain them again
+            oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, 
+        else:
+            oneway_ccache = oneway_ccache_check.ccache
 except krbV.Krb5Error as e:
     # If there was failure on using keytab, assume it is stale and retrieve 
     retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
-if oneway_ccache:
     # There wasn existing ccache, validate its content
     oneway_ccache_check = KRB5_CCache(oneway_ccache_name)
     if not oneway_ccache_check.credential_is_valid(oneway_principal):
@@ -164,7 +183,7 @@ if oneway_ccache:
         oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, 
         oneway_ccache = oneway_ccache_check.ccache
+except krbV.Krb5Error as e:
     oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, 
 # We are done: we have ccache with TDO credentials and can fetch domains
@@ -193,7 +212,7 @@ if domains:
                 dom['range_type'] = u'ipa-ad-trust'
                 # Do not pass ipaserver.dcerpc.TrustInstance to trust.add_range
                 # to force it using existing credentials cache
-                trust.add_range(None, range_name, dom['ipanttrusteddomainsid'],
+                trust.add_range(api, None, range_name, 
                                 trusted_domain, name, **dom)
         except errors.DuplicateEntry:
             # Ignore updating duplicate entries

Manage your subscription for the Freeipa-devel mailing list:
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to