s4:provision Rework provision to always have a ProvisionBackend
authorAndrew Bartlett <abartlet@samba.org>
Fri, 30 Oct 2009 02:16:10 +0000 (13:16 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 2 Nov 2009 05:36:54 +0000 (16:36 +1100)
Rather than treat the LDAP backend as a special case, treat all
backends the same, with different callbacks.

Andrew Bartlett

source4/scripting/python/samba/provision.py
source4/setup/provision

index 6c00127bc66e0c2e533012480bd9938fbd2362cc..7558ad3d7c1bfc633f59d3aa51b96770b9cc8b5c 100644 (file)
@@ -184,7 +184,7 @@ class ProvisionResult(object):
         
 class Schema(object):
     def __init__(self, setup_path, domain_sid, schemadn=None,
-                 serverdn=None, sambadn=None, ldap_backend_type=None):
+                 serverdn=None, sambadn=None):
         """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
         
         :param samdb: Load a schema into a SamDB.
@@ -604,8 +604,8 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
     idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
 
 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, 
-                           credentials, names, schema,
-                           serverrole, ldap_backend=None, 
+                           provision_backend, names, schema,
+                           serverrole, 
                            erase=False):
     """Setup the partitions for the SAM database. 
     
@@ -628,7 +628,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
 
     try:
         samdb = Ldb(url=samdb_path, session_info=session_info, 
-                      credentials=credentials, lp=lp, options=["modules:"])
+                      lp=lp, options=["modules:"])
         res = samdb.search(base="@PARTITION", scope=SCOPE_BASE, attrs=["partition"], expression="partition=*")
         if len(res) == 1:
             try:
@@ -651,7 +651,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     except LdbError:
         os.unlink(samdb_path)
         samdb = Ldb(url=samdb_path, session_info=session_info, 
-                      credentials=credentials, lp=lp, options=["modules:"])
+                      lp=lp, options=["modules:"])
          # Wipes the database
         samdb.erase_except_schema_controlled()
 
@@ -693,11 +693,12 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                      "schema_load",
                      "new_partition",
                      "partition"]
+
     ldap_backend_line = "# No LDAP backend"
-    if ldap_backend is not None:
-        ldap_backend_line = "ldapBackend: %s" % ldap_backend.ldapi_uri
+    if provision_backend.type is not "ldb":
+        ldap_backend_line = "ldapBackend: %s" % provision_backend.ldapi_uri
         
-        if ldap_backend.ldap_backend_type == "fedora-ds":
+        if provision_backend.ldap_backend_type == "fedora-ds":
             backend_modules = ["nsuniqueid", "paged_searches"]
             # We can handle linked attributes here, as we don't have directory-side subtree operations
             tdb_modules_list = ["extended_dn_out_fds"]
@@ -837,7 +838,7 @@ def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
             })
 
 
-def setup_secretsdb(path, setup_path, session_info, credentials, lp):
+def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
     """Setup the secrets database.
 
     :param path: Path to the secrets database.
@@ -849,26 +850,26 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp):
     """
     if os.path.exists(path):
         os.unlink(path)
-    secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
+    secrets_ldb = Ldb(path, session_info=session_info, 
                       lp=lp)
     secrets_ldb.erase()
     secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
-    secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
+    secrets_ldb = Ldb(path, session_info=session_info, 
                       lp=lp)
     secrets_ldb.transaction_start()
     secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
 
-    if credentials is not None and credentials.authentication_requested():
-        if credentials.get_bind_dn() is not None:
+    if backend_credentials is not None and backend_credentials.authentication_requested():
+        if backend_credentials.get_bind_dn() is not None:
             setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
-                    "LDAPMANAGERDN": credentials.get_bind_dn(),
-                    "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
+                    "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
+                    "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
                     })
         else:
             setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
-                    "LDAPADMINUSER": credentials.get_username(),
-                    "LDAPADMINREALM": credentials.get_realm(),
-                    "LDAPADMINPASS_B64": b64encode(credentials.get_password())
+                    "LDAPADMINUSER": backend_credentials.get_username(),
+                    "LDAPADMINREALM": backend_credentials.get_realm(),
+                    "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
                     })
 
     return secrets_ldb
@@ -1003,13 +1004,13 @@ def setup_self_join(samdb, names,
               })
 
 
-def setup_samdb(path, setup_path, session_info, credentials, lp, 
+def setup_samdb(path, setup_path, session_info, provision_backend, lp, 
                 names, message, 
                 domainsid, domainguid, policyguid, policyguid_dc,
                 fill, adminpass, krbtgtpass, 
                 machinepass, invocationid, dnspass, ntdsguid,
                 serverrole, dom_for_fun_level=None,
-                schema=None, ldap_backend=None):
+                schema=None):
     """Setup a complete SAM Database.
     
     :note: This will wipe the main SAM database file!
@@ -1032,17 +1033,17 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
 
     # Also wipes the database
     setup_samdb_partitions(path, setup_path, message=message, lp=lp,
-                           credentials=credentials, session_info=session_info,
-                           names=names, ldap_backend=ldap_backend,
+                           provision_backend=provision_backend, session_info=session_info,
+                           names=names, 
                            serverrole=serverrole, schema=schema)
 
     if (schema == None):
         schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
-            sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type)
+                        sambadn=names.sambadn)
 
     # 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, 
-                credentials=credentials, lp=lp)
+                credentials=provision_backend.credentials, lp=lp)
 
     message("Pre-loading the Samba 4 and AD schema")
 
@@ -1222,7 +1223,7 @@ def provision(setup_dir, message, session_info,
               dnspass=None, root=None, nobody=None, users=None, 
               wheel=None, backup=None, aci=None, serverrole=None,
               dom_for_fun_level=None,
-              ldap_backend_extra_port=None, ldap_backend_type=None,
+              ldap_backend_extra_port=None, backend_type=None,
               sitename=None,
               ol_mmr_urls=None, ol_olc=None, 
               setup_ds_path=None, slapd_path=None, nosync=False,
@@ -1260,8 +1261,11 @@ def provision(setup_dir, message, session_info,
         #Make a new, random password between Samba and it's LDAP server
         ldapadminpass=glue.generate_random_str(12)        
 
+    if backend_type is None:
+        backend_type = "ldb"
+
     sid_generator = "internal"
-    if ldap_backend_type == "fedora-ds":
+    if backend_type == "fedora-ds":
         sid_generator = "backend"
 
     root_uid = findnss_uid([root or "root"])
@@ -1319,44 +1323,34 @@ def provision(setup_dir, message, session_info,
     ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
     
     schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
-        sambadn=names.sambadn, ldap_backend_type=ldap_backend_type)
+                    sambadn=names.sambadn)
     
-    secrets_credentials = credentials
-    provision_backend = None
-    if ldap_backend_type:
-        # We only support an LDAP backend over ldapi://
-
-        provision_backend = ProvisionBackend(paths=paths, setup_path=setup_path,
-                                             lp=lp, credentials=credentials, 
-                                             names=names,
-                                             message=message, hostname=hostname,
-                                             root=root, schema=schema,
-                                             ldap_backend_type=ldap_backend_type,
-                                             ldapadminpass=ldapadminpass,
-                                             ldap_backend_extra_port=ldap_backend_extra_port,
-                                             ol_mmr_urls=ol_mmr_urls, 
-                                             slapd_path=slapd_path,
-                                             setup_ds_path=setup_ds_path,
-                                             ldap_dryrun_mode=ldap_dryrun_mode,
-                                             domainsid=domainsid)
-
-        # Now use the backend credentials to access the databases
-        credentials = provision_backend.credentials
-        secrets_credentials = provision_backend.adminCredentials
-        ldapi_url = provision_backend.ldapi_uri
+    provision_backend = ProvisionBackend(backend_type,
+                                         paths=paths, setup_path=setup_path,
+                                         lp=lp, credentials=credentials, 
+                                         names=names,
+                                         message=message, hostname=hostname,
+                                         root=root, schema=schema,
+                                         ldapadminpass=ldapadminpass,
+                                         ldap_backend_extra_port=ldap_backend_extra_port,
+                                         ol_mmr_urls=ol_mmr_urls, 
+                                         slapd_path=slapd_path,
+                                         setup_ds_path=setup_ds_path,
+                                         ldap_dryrun_mode=ldap_dryrun_mode,
+                                         domainsid=domainsid)
 
     # only install a new shares config db if there is none
     if not os.path.exists(paths.shareconf):
         message("Setting up share.ldb")
         share_ldb = Ldb(paths.shareconf, session_info=session_info, 
-                        credentials=credentials, lp=lp)
+                        lp=lp)
         share_ldb.load_ldif_file_add(setup_path("share.ldif"))
 
      
     message("Setting up secrets.ldb")
     secrets_ldb = setup_secretsdb(paths.secrets, setup_path, 
                                   session_info=session_info, 
-                                  credentials=secrets_credentials, lp=lp)
+                                  backend_credentials=provision_backend.secrets_credentials, lp=lp)
 
     message("Setting up the registry")
     setup_registry(paths.hklm, setup_path, session_info, 
@@ -1370,9 +1364,9 @@ def provision(setup_dir, message, session_info,
                           lp=lp)
 
     message("Setting up SAM db")
-    samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info
-                        credentials=credentials, lp=lp, names=names,
-                        message=message
+    samdb = setup_samdb(paths.samdb, setup_path, session_info, 
+                        provision_backend, lp, names,
+                        message, 
                         domainsid=domainsid, 
                         schema=schema, domainguid=domainguid,
                         policyguid=policyguid, policyguid_dc=policyguid_dc,
@@ -1381,8 +1375,7 @@ def provision(setup_dir, message, session_info,
                         invocationid=invocationid, 
                         machinepass=machinepass, dnspass=dnspass, 
                         ntdsguid=ntdsguid, serverrole=serverrole,
-                        dom_for_fun_level=dom_for_fun_level,
-                        ldap_backend=provision_backend)
+                        dom_for_fun_level=dom_for_fun_level)
 
     if serverrole == "domain controller":
         if paths.netlogon is None:
@@ -1464,61 +1457,18 @@ def provision(setup_dir, message, session_info,
                              realm=names.realm)
             message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
 
-    #Now commit the secrets.ldb to disk
-    secrets_ldb.transaction_commit()
-
-    if provision_backend is not None: 
-      if ldap_backend_type == "fedora-ds":
-        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"])
-
-        # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
-        for i in range (0, len(res)):
-          dn = str(res[i]["dn"])
-          ldapi_db.delete(dn)
-
-          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 an LDAP backend is in use, terminate slapd after final provision and check its proper termination
-      if provision_backend.slapd.poll() is None:
-        #Kill the slapd
-        if hasattr(provision_backend.slapd, "terminate"):
-          provision_backend.slapd.terminate()
-        else:
-          # Older python versions don't have .terminate()
-          import signal
-          os.kill(provision_backend.slapd.pid, signal.SIGTERM)
-            
-        #and now wait for it to die
-        provision_backend.slapd.communicate()
-            
-    # now display slapd_command_file.txt to show how slapd must be started next time
-        message("Use later the following commandline to start slapd, then Samba:")
-        slapd_command = "\'" + "\' \'".join(provision_backend.slapd_command) + "\'"
-        message(slapd_command)
-        message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
-
-        setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
-                "SLAPD_COMMAND" : slapd_command})
+    if provision_backend.post_setup is not None:
+        provision_backend.post_setup()
 
+    if provision_backend.shutdown is not None:
+        provision_backend.shutdown()
     
     create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, 
                                ldapi_url)
 
+    #Now commit the secrets.ldb to disk
+    secrets_ldb.transaction_commit()
+
     message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
 
     message("Once the above files are installed, your Samba4 server will be ready to use")
@@ -1529,14 +1479,21 @@ def provision(setup_dir, message, session_info,
     message("DOMAIN SID:            %s" % str(domainsid))
     if samdb_fill == FILL_FULL:
         message("Admin password:    %s" % adminpass)
-    if provision_backend:
+    if provision_backend.type is not "ldb":
         if provision_backend.credentials.get_bind_dn() is not None:
             message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
         else:
             message("LDAP Admin User:       %s" % provision_backend.credentials.get_username())
 
         message("LDAP Admin Password:   %s" % provision_backend.credentials.get_password())
-  
+
+        if provision_backend.slapd_command_escaped is not None:
+            # now display slapd_command_file.txt to show how slapd must be started next time
+            message("Use later the following commandline to start slapd, then Samba:")
+            message(provision_backend.slapd_command_escaped)
+            message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
+
+
     result = ProvisionResult()
     result.domaindn = domaindn
     result.paths = paths
@@ -1586,13 +1543,28 @@ def setup_db_config(setup_path, dbdir):
 
     setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
                {"LDAPDBDIR": dbdir})
-    
+
+def ldap_backend_shutdown(self):
+      # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
+      if self.slapd.poll() is None:
+        #Kill the slapd
+        if hasattr(self.slapd, "terminate"):
+          self.slapd.terminate()
+        else:
+          # Older python versions don't have .terminate()
+          import signal
+          os.kill(self.slapd.pid, signal.SIGTERM)
+            
+        #and now wait for it to die
+        self.slapd.communicate()
+
+
 class ProvisionBackend(object):
-    def __init__(self, paths=None, setup_path=None, lp=None, credentials=None, 
+    def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, 
                  names=None, message=None, 
                  hostname=None, root=None, 
                  schema=None, ldapadminpass=None,
-                 ldap_backend_type=None, ldap_backend_extra_port=None,
+                 ldap_backend_extra_port=None,
                  ol_mmr_urls=None, 
                  setup_ds_path=None, slapd_path=None, 
                  nosync=False, ldap_dryrun_mode=False,
@@ -1601,21 +1573,36 @@ class ProvisionBackend(object):
         
         This works for OpenLDAP and Fedora DS
         """
+        self.paths = paths
+        self.slapd_command = None
+        self.slapd_command_escaped = None
+
+        self.type = backend_type
+        
+        # Set a default - the code for "existing" below replaces this
+        self.ldap_backend_type = backend_type
+
+        self.post_setup = None
+        self.shutdown = None
+
+        if self.type is "ldb":
+            self.credentials = None
+            self.secrets_credentials = None
+            return
 
         self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
         
-        if not os.path.isdir(paths.ldapdir):
-            os.makedirs(paths.ldapdir, 0700)
-            
-        if ldap_backend_type == "existing":
+        if self.type == "existing":
             #Check to see that this 'existing' LDAP backend in fact exists
             ldapi_db = Ldb(self.ldapi_uri, credentials=credentials)
             search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
                                                 expression="(objectClass=OpenLDAProotDSE)")
 
             # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
-            # This caused them to be set into the long-term database later in the script.
             self.credentials = credentials
+            # This caused them to be set into the long-term database later in the script.
+            self.secrets_credentials = credentials
+
             self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
             return
     
@@ -1645,13 +1632,16 @@ class ProvisionBackend(object):
             message (slapd_path)
             raise ProvisioningError("Warning: Given Path to slapd does not exist!")
 
+
+        if not os.path.isdir(paths.ldapdir):
+            os.makedirs(paths.ldapdir, 0700)
+
         schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
         try:
             os.unlink(schemadb_path)
         except OSError:
             pass
 
-
         # Put the LDIF of the schema into a database so we can search on
         # it to generate schema-dependent configurations in Fedora DS and
         # OpenLDAP
@@ -1670,15 +1660,15 @@ class ProvisionBackend(object):
         #Kerberos to an ldapi:// backend makes no sense
         self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
 
-        self.adminCredentials = Credentials()
-        self.adminCredentials.guess(lp)
+        self.secrets_credentials = Credentials()
+        self.secrets_credentials.guess(lp)
         #Kerberos to an ldapi:// backend makes no sense
-        self.adminCredentials.set_kerberos_state(DONT_USE_KERBEROS)
+        self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
 
-        self.ldap_backend_type = ldap_backend_type
+        self.shutdown = ldap_backend_shutdown
 
-        if ldap_backend_type == "fedora-ds":
-            provision_fds_backend(self, paths=paths, setup_path=setup_path,
+        if self.type == "fedora-ds":
+            provision_fds_backend(self, setup_path=setup_path,
                                   names=names, message=message, 
                                   hostname=hostname,
                                   ldapadminpass=ldapadminpass, root=root, 
@@ -1690,8 +1680,8 @@ class ProvisionBackend(object):
                                   ldap_dryrun_mode=ldap_dryrun_mode,
                                   domainsid=domainsid)
             
-        elif ldap_backend_type == "openldap":
-            provision_openldap_backend(self, paths=paths, setup_path=setup_path,
+        elif self.type == "openldap":
+            provision_openldap_backend(self, setup_path=setup_path,
                                        names=names, message=message, 
                                        hostname=hostname,
                                        ldapadminpass=ldapadminpass, root=root, 
@@ -1705,8 +1695,12 @@ 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)
+        self.secrets_credentials.set_username("samba-admin")
+        self.secrets_credentials.set_password(ldapadminpass)
+
+        self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
+        setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
+                "SLAPD_COMMAND" : slapd_command})
 
         # Now start the slapd, so we can provision onto it.  We keep the
         # subprocess context around, to kill this off at the successful
@@ -1728,7 +1722,7 @@ class ProvisionBackend(object):
         raise ProvisioningError("slapd died before we could make a connection to it")
 
 
-def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
+def provision_openldap_backend(result, setup_path=None, names=None,
                                message=None, 
                                hostname=None, ldapadminpass=None, root=None, 
                                schema=None, 
@@ -1840,15 +1834,15 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
                                                           {  "RID" : str(rid),
                                                              "LDAPSERVER" : url})
                 
-        setup_file(setup_path("olc_seed.ldif"), paths.olcseedldif,
+        setup_file(setup_path("olc_seed.ldif"), result.paths.olcseedldif,
                    {"OLC_SERVER_ID_CONF": olc_serverids_config,
                     "OLC_PW": ldapadminpass,
                     "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
     # end olc
                 
-    setup_file(setup_path("slapd.conf"), paths.slapdconf,
+    setup_file(setup_path("slapd.conf"), result.paths.slapdconf,
                {"DNSDOMAIN": names.dnsdomain,
-                "LDAPDIR": paths.ldapdir,
+                "LDAPDIR": result.paths.ldapdir,
                 "DOMAINDN": names.domaindn,
                 "CONFIGDN": names.configdn,
                 "SCHEMADN": names.schemadn,
@@ -1865,26 +1859,26 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
                 "INDEX_CONFIG": index_config,
                 "NOSYNC": nosync_config})
         
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
+    setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "user"))
+    setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "config"))
+    setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "schema"))
     
-    if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba",  "cn=samba")):
-        os.makedirs(os.path.join(paths.ldapdir, "db", "samba",  "cn=samba"), 0700)
+    if not os.path.exists(os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba")):
+        os.makedirs(os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba"), 0700)
         
     setup_file(setup_path("cn=samba.ldif"), 
-               os.path.join(paths.ldapdir, "db", "samba",  "cn=samba.ldif"),
+               os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba.ldif"),
                { "UUID": str(uuid.uuid4()), 
                  "LDAPTIME": timestring(int(time.time()))} )
     setup_file(setup_path("cn=samba-admin.ldif"), 
-               os.path.join(paths.ldapdir, "db", "samba",  "cn=samba", "cn=samba-admin.ldif"),
+               os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba", "cn=samba-admin.ldif"),
                {"LDAPADMINPASS_B64": b64encode(ldapadminpass),
                 "UUID": str(uuid.uuid4()), 
                 "LDAPTIME": timestring(int(time.time()))} )
     
     if ol_mmr_urls is not None:
         setup_file(setup_path("cn=replicator.ldif"),
-                   os.path.join(paths.ldapdir, "db", "samba",  "cn=samba", "cn=replicator.ldif"),
+                   os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba", "cn=replicator.ldif"),
                    {"MMR_PASSWORD_B64": b64encode(mmr_pass),
                     "UUID": str(uuid.uuid4()),
                     "LDAPTIME": timestring(int(time.time()))} )
@@ -1895,7 +1889,7 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
 
     backend_schema_data = schema.ldb.convert_schema_to_openldap("openldap", open(setup_path(mapping), 'r').read())
     assert backend_schema_data is not None
-    open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
+    open(os.path.join(result.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
 
     # now we generate the needed strings to start slapd automatically,
     # first ldapi_uri...
@@ -1913,7 +1907,7 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
     # Prepare the 'result' information - the commands to return in particular
     result.slapd_provision_command = [slapd_path]
 
-    result.slapd_provision_command.append("-F" + paths.olcdir)
+    result.slapd_provision_command.append("-F" + result.paths.olcdir)
 
     result.slapd_provision_command.append("-h")
 
@@ -1939,10 +1933,10 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
         sys.exit(0)
 
     # Finally, convert the configuration into cn=config style!
-    if not os.path.isdir(paths.olcdir):
-        os.makedirs(paths.olcdir, 0770)
+    if not os.path.isdir(result.paths.olcdir):
+        os.makedirs(result.paths.olcdir, 0770)
 
-        retcode = subprocess.call([slapd_path, "-Ttest", "-f", paths.slapdconf, "-F", paths.olcdir], close_fds=True, shell=False)
+        retcode = subprocess.call([slapd_path, "-Ttest", "-f", result.paths.slapdconf, "-F", result.paths.olcdir], close_fds=True, shell=False)
 
 #        We can't do this, as OpenLDAP is strange.  It gives an error
 #        output to the above, but does the conversion sucessfully...
@@ -1950,14 +1944,14 @@ def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
 #        if retcode != 0:
 #            raise ProvisioningError("conversion from slapd.conf to cn=config failed")
 
-        if not os.path.exists(os.path.join(paths.olcdir, "cn=config.ldif")):
+        if not os.path.exists(os.path.join(result.paths.olcdir, "cn=config.ldif")):
             raise ProvisioningError("conversion from slapd.conf to cn=config failed")
 
         # Don't confuse the admin by leaving the slapd.conf around
-        os.remove(paths.slapdconf)        
-          
+        os.remove(result.paths.slapdconf)        
+
 
-def provision_fds_backend(result, paths=None, setup_path=None, names=None,
+def provision_fds_backend(result, setup_path=None, names=None,
                           message=None, 
                           hostname=None, ldapadminpass=None, root=None, 
                           schema=None,
@@ -1973,33 +1967,33 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
     else:
         serverport = ""
         
-    setup_file(setup_path("fedorads.inf"), paths.fedoradsinf, 
+    setup_file(setup_path("fedorads.inf"), result.paths.fedoradsinf, 
                {"ROOT": root,
                 "HOSTNAME": hostname,
                 "DNSDOMAIN": names.dnsdomain,
-                "LDAPDIR": paths.ldapdir,
+                "LDAPDIR": result.paths.ldapdir,
                 "DOMAINDN": names.domaindn,
                 "LDAPMANAGERDN": names.ldapmanagerdn,
                 "LDAPMANAGERPASS": ldapadminpass, 
                 "SERVERPORT": serverport})
 
-    setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, 
+    setup_file(setup_path("fedorads-partitions.ldif"), result.paths.fedoradspartitions, 
                {"CONFIGDN": names.configdn,
                 "SCHEMADN": names.schemadn,
                 "SAMBADN": names.sambadn,
                 })
 
-    setup_file(setup_path("fedorads-sasl.ldif"), paths.fedoradssasl, 
+    setup_file(setup_path("fedorads-sasl.ldif"), result.paths.fedoradssasl, 
                {"SAMBADN": names.sambadn,
                 })
 
-    setup_file(setup_path("fedorads-dna.ldif"), paths.fedoradsdna, 
+    setup_file(setup_path("fedorads-dna.ldif"), result.paths.fedoradsdna, 
                {"DOMAINDN": names.domaindn,
                 "SAMBADN": names.sambadn,
                 "DOMAINSID": str(domainsid),
                 })
 
-    setup_file(setup_path("fedorads-pam.ldif"), paths.fedoradspam)
+    setup_file(setup_path("fedorads-pam.ldif"), result.paths.fedoradspam)
 
     lnkattr = get_linked_attributes(names.schemadn,schema.ldb)
 
@@ -2020,8 +2014,8 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
                                                  { "ATTR" : attr })
             argnum += 1
 
-    open(paths.fedoradsrefint, 'w').write(refint_config)
-    open(paths.fedoradslinkedattributes, 'w').write(memberof_config)
+    open(result.paths.fedoradsrefint, 'w').write(refint_config)
+    open(result.paths.fedoradslinkedattributes, 'w').write(memberof_config)
 
     attrs = ["lDAPDisplayName"]
     res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
@@ -2035,9 +2029,9 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
         index_config += read_and_sub_file(setup_path("fedorads-index.ldif"),
                                              { "ATTR" : attr })
 
-    open(paths.fedoradsindex, 'w').write(index_config)
+    open(result.paths.fedoradsindex, 'w').write(index_config)
 
-    setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba,
+    setup_file(setup_path("fedorads-samba.ldif"), result.paths.fedoradssamba,
                 {"SAMBADN": names.sambadn, 
                  "LDAPADMINPASS": ldapadminpass
                 })
@@ -2048,20 +2042,20 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
     # Build a schema file in Fedora DS format
     backend_schema_data = schema.ldb.convert_schema_to_openldap("fedora-ds", open(setup_path(mapping), 'r').read())
     assert backend_schema_data is not None
-    open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
+    open(os.path.join(result.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
 
     result.credentials.set_bind_dn(names.ldapmanagerdn)
 
     # Destory the target directory, or else setup-ds.pl will complain
-    fedora_ds_dir = os.path.join(paths.ldapdir, "slapd-samba4")
+    fedora_ds_dir = os.path.join(result.paths.ldapdir, "slapd-samba4")
     shutil.rmtree(fedora_ds_dir, True)
 
-    result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", paths.slapdpid];
+    result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", result.paths.slapdpid];
     #In the 'provision' command line, stay in the foreground so we can easily kill it
     result.slapd_provision_command.append("-d0")
 
     #the command for the final run is the normal script
-    result.slapd_command = [os.path.join(paths.ldapdir, "slapd-samba4", "start-slapd")]
+    result.slapd_command = [os.path.join(result.paths.ldapdir, "slapd-samba4", "start-slapd")]
 
     # If we were just looking for crashes up to this point, it's a
     # good time to exit before we realise we don't have Fedora DS on
@@ -2076,17 +2070,46 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None,
         raise ProvisioningError("Warning: Given Path to slapd does not exist!")
 
     # Run the Fedora DS setup utility
-    retcode = subprocess.call([setup_ds_path, "--silent", "--file", paths.fedoradsinf], close_fds=True, shell=False)
+    retcode = subprocess.call([setup_ds_path, "--silent", "--file", result.paths.fedoradsinf], close_fds=True, shell=False)
     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],
+        os.path.join(result.paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", result.paths.fedoradssamba],
         close_fds=True, shell=False)
     if retcode != 0:
         raise("ldib2db failed")
 
+    # Leave a hook to do the 'post initilisation' setup
+    def fds_post_setup(self):
+        ldapi_db = Ldb(self.ldapi_uri, credentials=self.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"])
+    
+        # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
+        for i in range (0, len(res)):
+            dn = str(res[i]["dn"])
+            ldapi_db.delete(dn)
+            
+            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)
+            
+    result.post_setup = fds_post_setup
+    
+
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
     """Create a PHP LDAP admin configuration file.
 
index ddcf1cffb2eb168ced9ca5be9948d4392bf27cca..ed350dd46a89552a05eb7cc62276f3898ab94020 100755 (executable)
@@ -207,7 +207,7 @@ provision(setup_dir, message,
           wheel=opts.wheel, users=opts.users,
           serverrole=server_role, dom_for_fun_level=dom_for_fun_level,
           ldap_backend_extra_port=opts.ldap_backend_extra_port, 
-          ldap_backend_type=opts.ldap_backend_type,
+          backend_type=opts.ldap_backend_type,
           ldapadminpass=opts.ldapadminpass, ol_mmr_urls=opts.ol_mmr_urls,
           slapd_path=opts.slapd_path, setup_ds_path=opts.setup_ds_path,
           nosync=opts.nosync,ldap_dryrun_mode=opts.ldap_dryrun_mode)