Merge branch 'master' of ssh://git.samba.org/data/git/samba
[amitay/samba.git] / source4 / scripting / python / samba / provision.py
index 1da4e885f59291c4a588ef6d48e3763c567afa96..0aa84ec6db7fbe07e2488244c4cec0beee005207 100644 (file)
@@ -4,6 +4,7 @@
 
 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
+# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
 #
 # Based on the original in EJS:
 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
@@ -26,6 +27,7 @@
 
 from base64 import b64encode
 import os
+import sys
 import pwd
 import grp
 import time
@@ -38,13 +40,30 @@ from auth import system_session
 from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
 from samba.samdb import SamDB
 from samba.idmap import IDmapDB
-import security
+from samba.dcerpc import security
 import urllib
 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
         timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
 
 __docformat__ = "restructuredText"
 
+
+def find_setup_dir():
+    """Find the setup directory used by provision."""
+    dirname = os.path.dirname(__file__)
+    if "/site-packages/" in dirname:
+        prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
+        for suffix in ["share/setup", "share/samba/setup", "setup"]:
+            ret = os.path.join(prefix, suffix)
+            if os.path.isdir(ret):
+                return ret
+    # In source tree
+    ret = os.path.join(dirname, "../../../setup")
+    if os.path.isdir(ret):
+        return ret
+    raise Exception("Unable to find setup directory.")
+
+
 DEFAULTSITE = "Default-First-Site-Name"
 
 class InvalidNetbiosName(Exception):
@@ -76,9 +95,13 @@ class ProvisionPaths(object):
         self.memberofconf = None
         self.fedoradsinf = None
         self.fedoradspartitions = None
-       self.olmmron = None
-       self.olmmrserveridsconf = None
-       self.olmmrsyncreplconf = None
+        self.olmmron = None
+        self.olmmrserveridsconf = None
+        self.olmmrsyncreplconf = None
+        self.olcdir = None
+        self.olslaptest = None
+        self.olcseedldif = None
+
 
 class ProvisionNames(object):
     def __init__(self):
@@ -250,6 +273,10 @@ def provision_paths_from_lp(lp, dnsdomain):
                                             "mmr_serverids.conf")
     paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, 
                                            "mmr_syncrepl.conf")
+    paths.olcdir = os.path.join(paths.ldapdir, 
+                                 "slapd.d")
+    paths.olcseedldif = os.path.join(paths.ldapdir, 
+                                 "olc_seed.ldif")
     paths.hklm = "hklm.ldb"
     paths.hkcr = "hkcr.ldb"
     paths.hkcu = "hkcu.ldb"
@@ -261,7 +288,7 @@ def provision_paths_from_lp(lp, dnsdomain):
 
     paths.netlogon = lp.get("path", "netlogon")
 
-    paths.smbconf = lp.configfile()
+    paths.smbconf = lp.configfile
 
     return paths
 
@@ -291,7 +318,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=
 
     if lp.get("realm").upper() != realm:
         raise Exception("realm '%s' in %s must match chosen realm '%s'" %
-                        (lp.get("realm"), lp.configfile(), realm))
+                        (lp.get("realm"), lp.configfile, realm))
     
     dnsdomain = dnsdomain.lower()
 
@@ -343,6 +370,9 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=
 
 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, 
                  targetdir):
+    """Create a new smb.conf file based on a couple of basic settings.
+    """
+    assert smbconf is not None
     if hostname is None:
         hostname = socket.gethostname().split(".")[0].lower()
 
@@ -362,7 +392,8 @@ def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
 
     default_lp = param.LoadParm()
     #Load non-existant file
-    default_lp.load(smbconf)
+    if os.path.exists(smbconf):
+        default_lp.load(smbconf)
     
     if targetdir is not None:
         privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
@@ -389,7 +420,6 @@ def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
             })
 
 
-
 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
                         users_gid, wheel_gid):
     """setup reasonable name mappings for sam names to unix names.
@@ -403,11 +433,7 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
     :param users_gid: gid of the UNIX users group.
     :param wheel_gid: gid of the UNIX wheel group."""
     # add some foreign sids if they are not present already
-    samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
-    samdb.add_foreign(domaindn, "S-1-1-0", "World")
-    samdb.add_foreign(domaindn, "S-1-5-2", "Network")
-    samdb.add_foreign(domaindn, "S-1-5-18", "System")
-    samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
+    samdb.add_stock_foreign_sids()
 
     idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
     idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
@@ -437,7 +463,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                       credentials=credentials, lp=lp)
         # Wipes the database
         samdb.erase()
-    except:
+    except LdbError:
         os.unlink(samdb_path)
         samdb = SamDB(samdb_path, session_info=session_info, 
                       credentials=credentials, lp=lp)
@@ -630,6 +656,7 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp):
     # Wipes the database
     try:
         templates_ldb.erase()
+    # This should be 'except LdbError', but on a re-provision the assert in ldb.erase fires, and we need to catch that too
     except:
         os.unlink(path)
 
@@ -920,8 +947,6 @@ def provision(setup_dir, message, session_info,
 
     if domainsid is None:
         domainsid = security.random_sid()
-    else:
-        domainsid = security.Sid(domainsid)
 
     if policyguid is None:
         policyguid = str(uuid.uuid4())
@@ -947,6 +972,8 @@ def provision(setup_dir, message, session_info,
         if (not os.path.exists(os.path.join(targetdir, "etc"))):
             os.makedirs(os.path.join(targetdir, "etc"))
         smbconf = os.path.join(targetdir, "etc", "smb.conf")
+    elif smbconf is None:
+        smbconf = param.default_path()
 
     # only install a new smb.conf if there isn't one there already
     if not os.path.exists(smbconf):
@@ -1160,7 +1187,7 @@ def provision_backend(setup_dir=None, message=None,
                       rootdn=None, domaindn=None, schemadn=None, configdn=None,
                       domain=None, hostname=None, adminpass=None, root=None, serverrole=None, 
                       ldap_backend_type=None, ldap_backend_port=None,
-                     ol_mmr_urls=None):
+                      ol_mmr_urls=None,ol_olc=None,ol_slaptest=None):
 
     def setup_path(file):
         return os.path.join(setup_dir, file)
@@ -1178,15 +1205,34 @@ def provision_backend(setup_dir=None, message=None,
         if (not os.path.exists(os.path.join(targetdir, "etc"))):
             os.makedirs(os.path.join(targetdir, "etc"))
         smbconf = os.path.join(targetdir, "etc", "smb.conf")
+    elif smbconf is None:
+        smbconf = param.default_path()
+        assert smbconf is not None
 
     # only install a new smb.conf if there isn't one there already
     if not os.path.exists(smbconf):
         make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, 
                      targetdir)
 
+    # openldap-online-configuration: validation of olc and slaptest
+    if ol_olc == "yes" and ol_slaptest is None: 
+        sys.exit("Warning: OpenLDAP-Online-Configuration cant be setup without path to slaptest-Binary!")
+
+    if ol_olc == "yes" and ol_slaptest is not None:
+        ol_slaptest = ol_slaptest + "/slaptest"
+        if not os.path.exists(ol_slaptest):
+            message (ol_slaptest)
+            sys.exit("Warning: Given Path to slaptest-Binary does not exist!")
+    ###
+
+
+
     lp = param.LoadParm()
     lp.load(smbconf)
 
+    if serverrole is None:
+        serverrole = lp.get("server role")
+
     names = guess_names(lp=lp, hostname=hostname, domain=domain, 
                         dnsdomain=realm, serverrole=serverrole, 
                         rootdn=rootdn, domaindn=domaindn, configdn=configdn, 
@@ -1199,7 +1245,7 @@ def provision_backend(setup_dir=None, message=None,
     schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
     try:
         os.unlink(schemadb_path)
-    except:
+    except OSError:
         pass
 
     schemadb = Ldb(schemadb_path, lp=lp)
@@ -1249,18 +1295,18 @@ def provision_backend(setup_dir=None, message=None,
         mapping = "schema-map-fedora-ds-1.0"
         backend_schema = "99_ad.ldif"
         
-        slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
+        slapdcommand="Initialise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
        
         ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
 
     elif ldap_backend_type == "openldap":
         attrs = ["linkID", "lDAPDisplayName"]
-        res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
+        res = schemadb.search(expression="(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
 
         memberof_config = "# Generated from schema in %s\n" % schemadb_path
         refint_attributes = ""
         for i in range (0, len(res)):
-            expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
+            expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1)
             target = schemadb.searchone(basedn=names.schemadn, 
                                         expression=expression, 
                                         attribute="lDAPDisplayName", 
@@ -1276,52 +1322,95 @@ def provision_backend(setup_dir=None, message=None,
                                             { "LINK_ATTRS" : refint_attributes})
 
 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
-       mmr_on_config = ""
-       mmr_replicator_acl = ""
-       mmr_serverids_config = ""
+        mmr_on_config = ""
+        mmr_replicator_acl = ""
+        mmr_serverids_config = ""
         mmr_syncrepl_schema_config = "" 
-       mmr_syncrepl_config_config = "" 
-       mmr_syncrepl_user_config = "" 
-       
-       if ol_mmr_urls is not None:
+        mmr_syncrepl_config_config = "" 
+        mmr_syncrepl_user_config = "" 
+       
+        if ol_mmr_urls is not None:
                 # For now, make these equal
                 mmr_pass = adminpass
 
-               url_list=filter(None,ol_mmr_urls.split(' ')) 
+                url_list=filter(None,ol_mmr_urls.split(' ')) 
                 if (len(url_list) == 1):
                     url_list=filter(None,ol_mmr_urls.split(',')) 
                      
 
-               mmr_on_config = "MirrorMode On"
-               mmr_replicator_acl = "  by dn=cn=replicator,cn=samba read"
-               serverid=0
-               for url in url_list:
-                       serverid=serverid+1
-                       mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
-                                                                    { "SERVERID" : str(serverid),
-                                                                      "LDAPSERVER" : url })
+                mmr_on_config = "MirrorMode On"
+                mmr_replicator_acl = "  by dn=cn=replicator,cn=samba read"
+                serverid=0
+                for url in url_list:
+                        serverid=serverid+1
+                        mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
+                                                                     { "SERVERID" : str(serverid),
+                                                                       "LDAPSERVER" : url })
                         rid=serverid*10
-                       rid=rid+1
-                       mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
-                                                                    {  "RID" : str(rid),
-                                                                       "MMRDN": names.schemadn,
-                                                                       "LDAPSERVER" : url,
+                        rid=rid+1
+                        mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                     {  "RID" : str(rid),
+                                                                        "MMRDN": names.schemadn,
+                                                                        "LDAPSERVER" : url,
                                                                         "MMR_PASSWORD": mmr_pass})
 
-                       rid=rid+1
-                       mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
-                                                                    {  "RID" : str(rid),
-                                                                       "MMRDN": names.configdn,
-                                                                       "LDAPSERVER" : url,
+                        rid=rid+1
+                        mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                     {  "RID" : str(rid),
+                                                                        "MMRDN": names.configdn,
+                                                                        "LDAPSERVER" : url,
                                                                         "MMR_PASSWORD": mmr_pass})
 
-                       rid=rid+1
-                       mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
-                                                                    {  "RID" : str(rid),
-                                                                       "MMRDN": names.domaindn,
-                                                                       "LDAPSERVER" : url,
+                        rid=rid+1
+                        mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                     {  "RID" : str(rid),
+                                                                        "MMRDN": names.domaindn,
+                                                                        "LDAPSERVER" : url,
                                                                         "MMR_PASSWORD": mmr_pass })
+        # olc = yes?
+        olc_config_pass = ""
+        olc_config_acl = ""
+        olc_syncrepl_config = ""
+        olc_mmr_config = "" 
+        if ol_olc == "yes":
+                olc_config_pass += read_and_sub_file(setup_path("olc_pass.conf"),
+                                                                { "OLC_PW": adminpass })
+                olc_config_acl += read_and_sub_file(setup_path("olc_acl.conf"),{})
+                
+            # if olc = yes + mmr = yes, generate cn=config-replication directives
+            # and  olc_seed.lif for the other mmr-servers
+                if ol_olc == "yes" and ol_mmr_urls is not None:
+                        serverid=0
+                        olc_serverids_config = ""
+                        olc_syncrepl_config = ""
+                        olc_syncrepl_seed_config = ""
+                        olc_mmr_config = "" 
+                        olc_mmr_config += read_and_sub_file(setup_path("olc_mmr.conf"),{})
+                        rid=1000
+                        for url in url_list:
+                                serverid=serverid+1
+                                olc_serverids_config += read_and_sub_file(setup_path("olc_serverid.conf"),
+                                                                     { "SERVERID" : str(serverid),
+                                                                       "LDAPSERVER" : url })
+                        
+                                rid=rid+1
+                                olc_syncrepl_config += read_and_sub_file(setup_path("olc_syncrepl.conf"),
+                                                                     {  "RID" : str(rid),
+                                                                        "LDAPSERVER" : url,
+                                                                        "MMR_PASSWORD": adminpass})
+
+                                olc_syncrepl_seed_config += read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
+                                                                     {  "RID" : str(rid),
+                                                                        "LDAPSERVER" : url})
+
+                                setup_file(setup_path("olc_seed.ldif"), paths.olcseedldif,
+                                                                     {"OLC_SERVER_ID_CONF": olc_serverids_config,
+                                                                      "OLC_PW": adminpass,
+                                                                      "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
+        
 
+                # end olc
 
         setup_file(setup_path("slapd.conf"), paths.slapdconf,
                    {"DNSDOMAIN": names.dnsdomain,
@@ -1336,8 +1425,12 @@ def provision_backend(setup_dir=None, message=None,
                     "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
                     "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
                     "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
+                    "OLC_CONFIG_PASS": olc_config_pass,
+                    "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
+                    "OLC_CONFIG_ACL": olc_config_acl,
+                    "OLC_MMR_CONFIG": olc_mmr_config,
                     "REFINT_CONFIG": refint_config})
-       setup_file(setup_path("modules.conf"), paths.modulesconf,
+        setup_file(setup_path("modules.conf"), paths.modulesconf,
                    {"REALM": names.realm})
         
         setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
@@ -1356,16 +1449,15 @@ def provision_backend(setup_dir=None, message=None,
                               {"LDAPADMINPASS_B64": b64encode(adminpass),
                                "UUID": str(uuid.uuid4()), 
                                "LDAPTIME": timestring(int(time.time()))} )
-       
-       if ol_mmr_urls is not None:
-          setup_file(setup_path("cn=replicator.ldif"),
+        
+        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"),
                               {"MMR_PASSWORD_B64": b64encode(mmr_pass),
                                "UUID": str(uuid.uuid4()),
                                "LDAPTIME": timestring(int(time.time()))} )
 
 
-
         mapping = "schema-map-openldap-2.3"
         backend_schema = "backend-schema.schema"
 
@@ -1375,7 +1467,18 @@ def provision_backend(setup_dir=None, message=None,
         else:
             server_port_string = ""
 
-        slapdcommand="Start slapd with:    slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
+        if ol_olc != "yes" and ol_mmr_urls is None:
+          slapdcommand="Start slapd with:    slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
+
+        if ol_olc == "yes" and ol_mmr_urls is None:
+          slapdcommand="Start slapd with:    slapd -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://<FQHN>:<PORT>\"" 
+
+        if ol_olc != "yes" and ol_mmr_urls is not None:
+          slapdcommand="Start slapd with:    slapd -f " + paths.ldapdir + "/slapd.conf -h \"" + ldapi_uri + " ldap://<FQHN>:<PORT>\""
+
+        if ol_olc == "yes" and ol_mmr_urls is not None:
+          slapdcommand="Start slapd with:    slapd -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://<FQHN>:<PORT>\""
+
 
         ldapuser = "--username=samba-admin"
 
@@ -1397,7 +1500,35 @@ def provision_backend(setup_dir=None, message=None,
 
     message("LDAP admin password: %s" % adminpass)
     message(slapdcommand)
-    message("Run provision with:  --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
+    if ol_olc == "yes" or ol_mmr_urls is not None:
+        message("Attention to slapd-Port: <PORT> must be different than 389!")
+    assert isinstance(ldap_backend_type, str)
+    assert isinstance(ldapuser, str)
+    assert isinstance(adminpass, str)
+    assert isinstance(names.dnsdomain, str)
+    assert isinstance(names.domain, str)
+    assert isinstance(serverrole, str)
+    args = ["--ldap-backend=ldapi",
+            "--ldap-backend-type=" + ldap_backend_type,
+            "--password=" + adminpass,
+            ldapuser,
+            "--realm=" + names.dnsdomain,
+            "--domain=" + names.domain,
+            "--server-role='" + serverrole + "'"]
+    message("Run provision with: " + " ".join(args))
+
+
+    # if --ol-olc=yes, generate online-configuration in ../private/ldap/slapd.d 
+    if ol_olc == "yes":
+          if not os.path.isdir(paths.olcdir):
+             os.makedirs(paths.olcdir, 0770)
+          paths.olslaptest = str(ol_slaptest)
+          olc_command = paths.olslaptest + " -f" + paths.slapdconf + " -F" +  paths.olcdir + " >/dev/null 2>&1"
+          os.system(olc_command)
+          os.remove(paths.slapdconf)        
+          # use line below for debugging during olc-conversion with slaptest, instead of olc_command above 
+          #olc_command = paths.olslaptest + " -f" + paths.slapdconf + " -F" +  paths.olcdir"
+
 
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
     """Create a PHP LDAP admin configuration file.