From f832d83ea07fa3e5cd9ec2138b02549ea5cba5a0 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 17 Mar 2010 10:01:24 -0400
Subject: [PATCH] Retrieve the LDAP schema using kerberos credentials.

This is required so we can disable anonymous access in 389-ds.
---
 install/tools/ipa-server-install |    1 +
 ipalib/plugins/migration.py      |    3 +-
 ipaserver/plugins/ldap2.py       |   45 ++++++++++++++++++++++++++++++++------
 3 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 3157622..5eb956b 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -452,6 +452,7 @@ def main():
     # Configuration for ipalib, we will bootstrap and finalize later, after
     # we are sure we have the configuration file ready.
     cfg = dict(
+        context='installer',
         in_server=True,
         debug=options.debug
     )
diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py
index d64aeac..55a2157 100644
--- a/ipalib/plugins/migration.py
+++ b/ipalib/plugins/migration.py
@@ -30,7 +30,8 @@ import re
 from ipalib import api, errors, output, uuid
 from ipalib import Command, List, Password, Str
 from ipalib.cli import to_cli
-from ipaserver.plugins.ldap2 import ldap2
+if api.env.in_server and api.env.context in ['lite', 'server']:
+    from ipaserver.plugins.ldap2 import ldap2
 from ipalib import _
 from ipalib.text import Gettext # FIXME: remove once the other Gettext FIXME is removed
 
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index a026f0e..84a9178 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -30,6 +30,8 @@ import copy
 import os
 import socket
 import string
+import shutil
+import tempfile
 
 import krbV
 import ldap as _ldap
@@ -47,6 +49,9 @@ from ipalib.encoder import Encoder, encode_args, decode_retval
 from ipalib.request import context
 
 
+# SASL authentication mechanism
+SASL_AUTH = _ldap_sasl.sasl({}, 'GSSAPI')
+
 # universal LDAPError handler
 def _handle_errors(e, **kw):
     """
@@ -98,12 +103,38 @@ def _handle_errors(e, **kw):
         raise errors.DatabaseError(desc=desc, info=info)
 
 
-# retrieves LDAP schema from server
 def load_schema(url):
+    """
+    Retrieve the LDAP schema from the provided url.
+
+    Bind using kerberos credentials. If in the context of the
+    in-tree "lite" server then use the current ccache. If in the context of
+    Apache then create a new ccache and bind using the Apache HTTP service
+    principal.
+    """
+    tmpdir = None
+
+    if not api.env.in_server or api.env.context not in ['lite', 'server']:
+        # The schema is only needed on the server side
+        return
+
     try:
+        if api.env.context == 'server':
+            # Create a new credentials cache for this Apache process
+            tmpdir = tempfile.mkdtemp(prefix = "tmp-")
+            ccache_file = 'FILE:%s/ccache' % tmpdir
+            krbcontext = krbV.default_context()
+            principal = str('HTTP/%s@%s' % (api.env.host, api.env.realm))
+            keytab = krbV.Keytab(name='/etc/httpd/conf/ipa.keytab', context=krbcontext)
+            principal = krbV.Principal(name=principal, context=krbcontext)
+            os.environ['KRB5CCNAME'] = ccache_file
+            ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=principal)
+            ccache.init(principal)
+            ccache.init_creds_keytab(keytab=keytab, principal=principal)
+
         conn = _ldap.initialize(url)
-        # assume anonymous access is enabled
-        conn.simple_bind_s('', '')
+        conn.sasl_interactive_bind_s('', SASL_AUTH)
+
         schema_entry = conn.search_s(
             'cn=schema', _ldap.SCOPE_BASE,
             attrlist=['attributetypes', 'objectclasses']
@@ -119,6 +150,9 @@ def load_schema(url):
         # TODO: DS uses 'cn=schema', support for other server?
         #       raise a more appropriate exception
         raise
+    finally:
+        if tmpdir:
+            shutil.rmtree(tmpdir)
 
     return _ldap.schema.SubSchema(schema_entry[1])
 
@@ -165,9 +199,6 @@ class ldap2(CrudBackend, Encoder):
     # only MOD_REPLACE operations are generated for them
     _FORCE_REPLACE_ON_UPDATE_ATTRS = []
 
-    # SASL authentication mechanism
-    _SASL_AUTH = _ldap_sasl.sasl({}, 'GSSAPI')
-
     # rules for generating filters from entries
     MATCH_ANY = '|'   # (|(filter1)(filter2))
     MATCH_ALL = '&'   # (&(filter1)(filter2))
@@ -239,7 +270,7 @@ class ldap2(CrudBackend, Encoder):
         if ccache is not None:
             try:
                 os.environ['KRB5CCNAME'] = ccache
-                conn.sasl_interactive_bind_s('', self._SASL_AUTH)
+                conn.sasl_interactive_bind_s('', SASL_AUTH)
                 principal = krbV.CCache(name=ccache,
                             context=krbV.default_context()).principal().name
                 setattr(context, 'principal', principal)
-- 
1.6.2.5

