s4: Use SASL authentication against Fedora DS.
authorEndi Sukma Dewata <edewata@redhat.com>
Wed, 9 Sep 2009 16:45:24 +0000 (12:45 -0400)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 9 Sep 2009 23:52:22 +0000 (09:52 +1000)
1. During instance creation the provisioning script will import the SASL
   mapping for samba-admin. It's done here due to missing config schema
   preventing adding the mapping via ldapi.

2. After that it will use ldif2db to import the cn=samba-admin user as
   the target of SASL mapping.

3. Then it will start FDS and continue to do provisioning using the
   Directory Manager with simple bind.

4. The SASL credentials will be stored in secrets.ldb, so when Samba
   server runs later it will use the SASL credentials.

5. After the provisioning is done (just before stopping the slapd)
   it will use the DM over direct ldapi to delete the default SASL
   mappings included automatically by FDS, leaving just the new
   samba-admin mapping.

6. Also before stopping slapd it will use the DM over direct ldapi to
   set the ACL on the root entries of the user, configuration, and
   schema partitions. The ACL will give samba-admin the full access
   to these partitions.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
source4/scripting/python/samba/provision.py
source4/setup/fedorads-partitions.ldif
source4/setup/fedorads-samba.ldif [new file with mode: 0644]
source4/setup/fedorads-sasl.ldif [new file with mode: 0644]
source4/setup/fedorads.inf
source4/setup/schema_samba4.ldif

index 778271f1d5ce520457425533ffbe627d6496a266..e12d63997c93b7966c28fb30afff7cdcff898a26 100644 (file)
@@ -37,6 +37,7 @@ import param
 import registry
 import samba
 import subprocess
+import ldb
 
 import shutil
 from credentials import Credentials, DONT_USE_KERBEROS
@@ -106,6 +107,7 @@ class ProvisionPaths(object):
         self.memberofconf = None
         self.fedoradsinf = None
         self.fedoradspartitions = None
+        self.fedoradssasl = None
         self.olmmron = None
         self.olmmrserveridsconf = None
         self.olmmrsyncreplconf = None
@@ -120,6 +122,7 @@ class ProvisionNames(object):
         self.domaindn = None
         self.configdn = None
         self.schemadn = None
+        self.sambadn = None
         self.ldapmanagerdn = None
         self.dnsdomain = None
         self.realm = None
@@ -139,7 +142,7 @@ class ProvisionResult(object):
         
 class Schema(object):
     def __init__(self, setup_path, schemadn=None, 
-                 serverdn=None):
+                 serverdn=None, sambadn=None, ldap_backend_type=None):
         """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
         
         :param samdb: Load a schema into a SamDB.
@@ -343,6 +346,10 @@ def provision_paths_from_lp(lp, dnsdomain):
                                      "fedorads.inf")
     paths.fedoradspartitions = os.path.join(paths.ldapdir, 
                                             "fedorads-partitions.ldif")
+    paths.fedoradssasl = os.path.join(paths.ldapdir, 
+                                      "fedorads-sasl.ldif")
+    paths.fedoradssamba = os.path.join(paths.ldapdir, 
+                                        "fedorads-samba.ldif")
     paths.olmmrserveridsconf = os.path.join(paths.ldapdir, 
                                             "mmr_serverids.conf")
     paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, 
@@ -369,7 +376,7 @@ def provision_paths_from_lp(lp, dnsdomain):
 
 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
                 serverrole=None, rootdn=None, domaindn=None, configdn=None,
-                schemadn=None, serverdn=None, sitename=None):
+                schemadn=None, serverdn=None, sitename=None, sambadn=None):
     """Guess configuration settings to use."""
 
     if hostname is None:
@@ -421,6 +428,8 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
         configdn = "CN=Configuration," + rootdn
     if schemadn is None:
         schemadn = "CN=Schema," + configdn
+    if sambadn is None:
+        sambadn = "CN=Samba"
 
     if sitename is None:
         sitename=DEFAULTSITE
@@ -430,6 +439,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
     names.domaindn = domaindn
     names.configdn = configdn
     names.schemadn = schemadn
+    names.sambadn = sambadn
     names.ldapmanagerdn = "CN=Manager," + rootdn
     names.dnsdomain = dnsdomain
     names.domain = domain
@@ -814,7 +824,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
                            ldap_backend=ldap_backend, serverrole=serverrole)
 
     if (schema == None):
-        schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn)
+        schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn,
+            sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type)
 
     # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
     samdb = Ldb(session_info=session_info, 
@@ -1079,7 +1090,8 @@ def provision(setup_dir, message, session_info,
 
     ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
     
-    schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn)
+    schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn,
+        sambadn=names.sambadn, ldap_backend_type=ldap_backend_type)
     
     provision_backend = None
     if ldap_backend_type:
@@ -1112,7 +1124,7 @@ def provision(setup_dir, message, session_info,
     message("Setting up secrets.ldb")
     secrets_ldb = setup_secretsdb(paths.secrets, setup_path, 
                                   session_info=session_info, 
-                                  credentials=credentials, lp=lp)
+                                  credentials=provision_backend.adminCredentials, lp=lp)
 
     message("Setting up the registry")
     setup_registry(paths.hklm, setup_path, session_info, 
@@ -1205,6 +1217,32 @@ def provision(setup_dir, message, session_info,
             message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
 
 
+    ldapi_db = Ldb(provision_backend.ldapi_uri, lp=lp, credentials=credentials)
+
+    # delete default SASL mappings
+    res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
+
+    for i in range (0, len(res)):
+        dn = str(res[i]["dn"])
+        ldapi_db.delete(dn)
+
+    # configure aci
+    if ldap_backend_type == "fedora-ds":
+
+        aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % names.sambadn
+
+        m = ldb.Message()
+        m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
+
+        m.dn = ldb.Dn(1, names.domaindn)
+        ldapi_db.modify(m)
+
+        m.dn = ldb.Dn(1, names.configdn)
+        ldapi_db.modify(m)
+
+        m.dn = ldb.Dn(1, names.schemadn)
+        ldapi_db.modify(m)
+
     # if backend is openldap, terminate slapd after final provision and check its proper termination
     if provision_backend is not None and provision_backend.slapd is not None:
         if provision_backend.slapd.poll() is None:
@@ -1379,6 +1417,12 @@ class ProvisionBackend(object):
         self.credentials.guess(lp)
         #Kerberos to an ldapi:// backend makes no sense
         self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
+
+        self.adminCredentials = Credentials()
+        self.adminCredentials.guess(lp)
+        #Kerberos to an ldapi:// backend makes no sense
+        self.adminCredentials.set_kerberos_state(DONT_USE_KERBEROS)
+
         self.ldap_backend_type = ldap_backend_type
 
         if ldap_backend_type == "fedora-ds":
@@ -1408,6 +1452,8 @@ class ProvisionBackend(object):
             raise ProvisioningError("Unknown LDAP backend type selected")
 
         self.credentials.set_password(ldapadminpass)
+        self.adminCredentials.set_username("samba-admin")
+        self.adminCredentials.set_password(ldapadminpass)
 
         # Now start the slapd, so we can provision onto it.  We keep the
         # subprocess context around, to kill this off at the successful
@@ -1686,6 +1732,16 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
     setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, 
                {"CONFIGDN": names.configdn,
                 "SCHEMADN": names.schemadn,
+                "SAMBADN": names.sambadn,
+                })
+
+    setup_file(setup_path("fedorads-sasl.ldif"), paths.fedoradssasl, 
+               {"SAMBADN": names.sambadn,
+                })
+
+    setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba,
+                {"SAMBADN": names.sambadn, 
+                 "LDAPADMINPASS": ldapadminpass
                 })
 
     mapping = "schema-map-fedora-ds-1.0"
@@ -1726,6 +1782,13 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
     if retcode != 0:
         raise ProvisioningError("setup-ds failed")
 
+    # Load samba-admin
+    retcode = subprocess.call([
+        os.path.join(paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", paths.fedoradssamba],
+        close_fds=True, shell=False)
+    if retcode != 0:
+        raise("ldib2db failed")
+
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
     """Create a PHP LDAP admin configuration file.
 
index 571fb599b9a8fa60c7e537f8ec3882e75360a363..04528cb07e6f9d938fd24a99478351feae8a6286 100644 (file)
@@ -28,3 +28,18 @@ objectclass: nsBackendInstance
 nsslapd-suffix: ${SCHEMADN}
 cn: schemaData
 
+dn: cn="${SAMBADN}",cn=mapping tree,cn=config
+objectclass: top
+objectclass: extensibleObject
+objectclass: nsMappingTree
+nsslapd-state: backend
+nsslapd-backend: sambaData
+cn: ${SAMBADN}
+
+dn: cn=sambaData,cn=ldbm database,cn=plugins,cn=config
+objectclass: top
+objectclass: extensibleObject
+objectclass: nsBackendInstance
+nsslapd-suffix: ${SAMBADN}
+cn: sambaData
+
diff --git a/source4/setup/fedorads-samba.ldif b/source4/setup/fedorads-samba.ldif
new file mode 100644 (file)
index 0000000..2d77ada
--- /dev/null
@@ -0,0 +1,10 @@
+dn: ${SAMBADN}
+objectClass: top
+objectClass: container
+cn: Samba
+
+dn: CN=samba-admin,${SAMBADN}
+objectClass: top
+objectClass: person
+cn: samba-admin
+userPassword: {CLEAR}${LDAPADMINPASS}
diff --git a/source4/setup/fedorads-sasl.ldif b/source4/setup/fedorads-sasl.ldif
new file mode 100644 (file)
index 0000000..99bb6a7
--- /dev/null
@@ -0,0 +1,9 @@
+# Map samba-admin to CN=samba-admin,${SAMBADN}
+dn: cn=samba-admin mapping,cn=mapping,cn=sasl,cn=config
+objectClass: top
+objectClass: nsSaslMapping
+cn: samba-admin mapping
+nsSaslMapRegexString: ^samba-admin$
+nsSaslMapBaseDNTemplate: CN=samba-admin,${SAMBADN}
+nsSaslMapFilterTemplate: (objectclass=*)
+
index fe51d01db1a0c18e8b78115406a04ef6e0f525d3..90ebe6a9a5ec0694bbd7631a4efe68650b89dab1 100644 (file)
@@ -27,3 +27,4 @@ start_server= 0
 install_full_schema= 0
 SchemaFile=${LDAPDIR}/99_ad.ldif
 ConfigFile = ${LDAPDIR}/fedorads-partitions.ldif
+ConfigFile = ${LDAPDIR}/fedorads-sasl.ldif
index d5d35af7d5188b21877ba4b254eabcbc62907ba0..f447bf5617f784a0c67643e7f9285891e3c43a2f 100644 (file)
@@ -193,24 +193,6 @@ oMSyntax: 20
 #Allocated: (dynamicObject) samba4DynamicObject: 1.3.6.1.4.1.7165.4.255.8
 #Allocated: (entryTTL) samba4EntryTTL: 1.3.6.1.4.1.7165.4.255.9
 
-#
-# Fedora DS uses this attribute, and we need to set it via our module stack
-#
-#dn: CN=aci,${SCHEMADN}
-#cn: aci
-#name: aci
-#objectClass: top
-#objectClass: attributeSchema
-#lDAPDisplayName: aci
-#isSingleValued: TRUE
-#systemFlags: 16
-#systemOnly: FALSE
-#schemaIDGUID: d8e6c1fa-db08-4f26-a53b-23c414aac92d
-#adminDisplayName: aci
-#attributeID: 1.3.6.1.4.1.7165.4.1.11
-#attributeSyntax: 2.5.5.4
-#oMSyntax: 20
-
 #
 # Based on domainDNS, but without the DNS bits.
 #