Move some samdb-specific code out of provision.
[amitay/samba.git] / source4 / scripting / python / samba / provision.py
index 4764d0cafa6b3c7c074d09ccf0db4eb024196428..1d7011d305c0a297e312c5adcabc92c8cacd5fab 100644 (file)
@@ -29,7 +29,7 @@ import os
 import pwd
 import grp
 import time
-import uuid, misc
+import uuid, glue
 import socket
 import param
 import registry
@@ -38,10 +38,10 @@ 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, \
-        LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
+        timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
 
 __docformat__ = "restructuredText"
 
@@ -80,6 +80,7 @@ class ProvisionPaths(object):
        self.olmmrserveridsconf = None
        self.olmmrsyncreplconf = None
 
+
 class ProvisionNames(object):
     def __init__(self):
         self.rootdn = None
@@ -261,7 +262,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 +292,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 +344,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 +366,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 +394,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 +407,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)
@@ -432,17 +432,18 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     """
     assert session_info is not None
 
-    samdb = SamDB(samdb_path, session_info=session_info, 
-                  credentials=credentials, lp=lp)
-
-    # Wipes the database
     try:
+        samdb = SamDB(samdb_path, session_info=session_info, 
+                      credentials=credentials, lp=lp)
+        # Wipes the database
         samdb.erase()
     except:
         os.unlink(samdb_path)
-
-    samdb = SamDB(samdb_path, session_info=session_info, 
-                  credentials=credentials, lp=lp)
+        samdb = SamDB(samdb_path, session_info=session_info, 
+                      credentials=credentials, lp=lp)
+         # Wipes the database
+        samdb.erase()
+        
 
     #Add modules to the list to activate them by default
     #beware often order is important
@@ -459,8 +460,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                     "ranged_results",
                     "anr",
                     "server_sort",
-                    "extended_dn",
                     "asq",
+                    "extended_dn_store",
+                    "extended_dn_in",
                     "rdn_name",
                     "objectclass",
                     "samldb",
@@ -470,7 +472,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     tdb_modules_list = [
                     "subtree_rename",
                     "subtree_delete",
-                    "linked_attributes"]
+                    "linked_attributes",
+                    "extended_dn_out_ldb"]
     modules_list2 = ["show_deleted",
                     "partition"]
  
@@ -488,11 +491,11 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     if 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 = ["linked_attributes"]
+        tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
     elif ldap_backend_type == "openldap":
-        backend_modules = ["normalise", "entryuuid", "paged_searches"]
+        backend_modules = ["entryuuid", "paged_searches"]
         # OpenLDAP handles subtree renames, so we don't want to do any of these things
-        tdb_modules_list = None
+        tdb_modules_list = ["extended_dn_out_dereference"]
     elif ldap_backend is not None:
         raise "LDAP Backend specified, but LDAP Backend Type not specified"
     elif serverrole == "domain controller":
@@ -650,7 +653,7 @@ def setup_registry(path, setup_path, session_info, credentials, lp):
     reg = registry.Registry()
     hive = registry.open_ldb(path, session_info=session_info, 
                          credentials=credentials, lp_ctx=lp)
-    reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
+    reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
     provision_reg = setup_path("provision.reg")
     assert os.path.exists(provision_reg)
     reg.diff_apply(provision_reg)
@@ -749,7 +752,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
         return samdb
 
     message("Pre-loading the Samba 4 and AD schema")
-    samdb.set_domain_sid(domainsid)
+    samdb.set_domain_sid(str(domainsid))
     if serverrole == "domain controller":
         samdb.set_invocation_id(invocationid)
 
@@ -827,6 +830,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
         message("Setting up sam.ldb AD schema")
         setup_add_ldif(samdb, setup_path("schema.ldif"), 
                        {"SCHEMADN": names.schemadn})
+        setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"), 
+                       {"SCHEMADN": names.schemadn})
 
         message("Setting up sam.ldb configuration data")
         setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
@@ -915,19 +920,17 @@ 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())
     if adminpass is None:
-        adminpass = misc.random_password(12)
+        adminpass = glue.generate_random_str(12)
     if krbtgtpass is None:
-        krbtgtpass = misc.random_password(12)
+        krbtgtpass = glue.generate_random_str(12)
     if machinepass is None:
-        machinepass  = misc.random_password(12)
+        machinepass  = glue.generate_random_str(12)
     if dnspass is None:
-        dnspass = misc.random_password(12)
+        dnspass = glue.generate_random_str(12)
     root_uid = findnss_uid([root or "root"])
     nobody_uid = findnss_uid([nobody or "nobody"])
     users_gid = findnss_gid([users or "users"])
@@ -942,6 +945,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):
@@ -959,13 +964,16 @@ def provision(setup_dir, message, session_info,
     paths = provision_paths_from_lp(lp, names.dnsdomain)
 
     if hostip is None:
-        hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
+        try:
+            hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
+        except socket.gaierror, (socket.EAI_NODATA, msg):
+            hostip = None
 
     if hostip6 is None:
         try:
             hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
-        except socket.gaierror: 
-            pass
+        except socket.gaierror, (socket.EAI_NODATA, msg)
+            hostip6 = None
 
     if serverrole is None:
         serverrole = lp.get("server role")
@@ -1164,12 +1172,15 @@ def provision_backend(setup_dir=None, message=None,
         root = findnss(pwd.getpwnam, ["root"])[0]
 
     if adminpass is None:
-        adminpass = misc.random_password(12)
+        adminpass = glue.generate_random_str(12)
 
     if targetdir is not 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):
@@ -1179,6 +1190,9 @@ def provision_backend(setup_dir=None, message=None,
     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, 
@@ -1241,18 +1255,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", 
@@ -1389,7 +1403,21 @@ 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)
+    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))
+
 
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
     """Create a PHP LDAP admin configuration file.
@@ -1426,12 +1454,20 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn,
         hostip6_base_line = ""
         hostip6_host_line = ""
 
+    if hostip is not None:
+        hostip_base_line = "            IN A    " + hostip
+        hostip_host_line = hostname + "        IN A    " + hostip
+    else:
+        hostip_base_line = ""
+        hostip_host_line = ""
+
     setup_file(setup_path("provision.zone"), path, {
             "DNSPASS_B64": b64encode(dnspass),
             "HOSTNAME": hostname,
             "DNSDOMAIN": dnsdomain,
             "REALM": realm,
-            "HOSTIP": hostip,
+            "HOSTIP_BASE_LINE": hostip_base_line,
+            "HOSTIP_HOST_LINE": hostip_host_line,
             "DOMAINGUID": domainguid,
             "DATESTRING": time.strftime("%Y%m%d%H"),
             "DEFAULTSITE": DEFAULTSITE,