--- /install/bak/provision.py 2009-07-19 21:36:00.000000000 +0200 +++ scripting/python/samba/provision.py 2009-08-07 00:25:42.000000000 +0200 @@ -36,6 +36,9 @@ import param import registry import samba +import ldap +import subprocess +from ldap.controls import SimplePagedResultsControl from auth import system_session from samba import version, Ldb, substitute_var, valid_netbios_name, check_all_substituted, \ DS_BEHAVIOR_WIN2008 @@ -43,8 +46,9 @@ from samba.idmap import IDmapDB from samba.dcerpc import security import urllib -from ldb import SCOPE_SUBTREE, LdbError, timestring +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, LdbError, timestring from ms_schema import read_ms_schema +from signal import SIGTERM __docformat__ = "restructuredText" @@ -100,7 +104,7 @@ self.olmmrserveridsconf = None self.olmmrsyncreplconf = None self.olcdir = None - self.olslaptest = None + self.olslapd = None self.olcseedldif = None @@ -262,6 +266,8 @@ "ldap") paths.slapdconf = os.path.join(paths.ldapdir, "slapd.conf") + paths.slapdpid = os.path.join(paths.ldapdir, + "slapd.pid") paths.modulesconf = os.path.join(paths.ldapdir, "modules.conf") paths.memberofconf = os.path.join(paths.ldapdir, @@ -935,6 +941,7 @@ FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" + def provision(setup_dir, message, session_info, credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, @@ -1133,6 +1140,60 @@ hostname=names.hostname, realm=names.realm) message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) + # if backend is openldap, terminate slapd after final provison an check its proper termination + if ldap_backend_type == "openldap": + if os.path.exists(paths.slapdpid): + f = open(paths.slapdpid, "r") + p = f.read() + f.close() + os.kill(int(p),SIGTERM) + + # check proper termination of slapd + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + l = ldap.initialize(ldapi_uri) + l.protocol_version = ldap.VERSION3 + baseDN = "" + searchScope = ldap.SCOPE_BASE + retrieveAttributes = None + searchFilter = "(objectClass=OpenLDAProotDSE)" + + try: + ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes) + result_set = [] + result_type, result_data = l.result(ldap_result_id, 0) + if result_type == ldap.RES_SEARCH_ENTRY: + message("LDAP Result Type: " + str(result_type)) + message("LDAP Result Data (rootDSE found): " + str(result_data)) + sys.exit("Warning: slapd not shut down properly. Instance seems still to be running on this host, listening to " + ldapi_uri + ". Please shut it down before you continue.") + except ldap.LDAPError, e: + message("ldap-search Output:") + print e + message("Ok. - Provision-Instance of slapd terminated properly.") + + else: + message(" ") + message("PID-File of slapd could not be located and slapd therefore not be terminated. Check manually.") + if os.path.exists(paths.ldapdir + "/slapd_provision_pid"): + f = open(paths.ldapdir + "/slapd_provision_pid", "r") + p = f.read() + f.close() + message("Check for slapd-Process with PID: " + str(p) + " and terminate it manually.") + else: + message("slapd-Provision-PID File could not be found. Sorry") + # end slapd-termination check + + # now display slapd_command_file.txt to show how slapd must be started next time + if os.path.exists(paths.ldapdir +"/slapd_command_file.txt"): + message("Use the following commandline to start slapd, then Samba:") + f = open(paths.ldapdir +"/slapd_command_file.txt", "r") + x = f.read() + f.close() + message(x) + message("This slapd-Commandline is also stored under: " + str(paths.ldapdir) + "/slapd_command_file.txt") + else: + message("Error. slapd-commandline-File could not be found.") + + create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) @@ -1155,6 +1216,7 @@ return result + def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, @@ -1192,11 +1254,12 @@ def provision_backend(setup_dir=None, message=None, - smbconf=None, targetdir=None, realm=None, + smbconf=None, targetdir=None, realm=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_olc=None,ol_slaptest=None): + ol_mmr_urls=None, ol_olc=None, + ol_slapd=None, nosync=False): def setup_path(file): return os.path.join(setup_dir, file) @@ -1223,17 +1286,18 @@ 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!") - ### - + # if openldap-backend was chosen, check if path to slapd was given and exists + if ldap_backend_type == "openldap" and ol_slapd is None: + sys.exit("Warning: OpenLDAP-Backend must be setup with path to slapd (OpenLDAP-Daemon), e.g. --ol-slapd=\"/usr/local/libexec\"!") + if ldap_backend_type == "openldap" and ol_slapd is not None: + ol_slapd = ol_slapd + "/slapd" + if not os.path.exists(ol_slapd): + message (ol_slapd) + sys.exit("Warning: Given Path to slapd (OpenLDAP-Daemon) does not exist!") + + # openldap-online-configuration: validation of olc and slapd + if ol_olc == "yes" and ol_slapd is None: + sys.exit("Warning: OpenLDAP-Online-Configuration cant be setup without path to slapd!") lp = param.LoadParm() @@ -1314,8 +1378,14 @@ ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn elif ldap_backend_type == "openldap": + #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB + nosync_config = "" + if nosync: + nosync_config = "dbnosync" + + attrs = ["linkID", "lDAPDisplayName"] - 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) + 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_ONELEVEL, attrs=attrs) memberof_config = "# Generated from schema in %s\n" % schemadb_path refint_attributes = "" @@ -1326,7 +1396,7 @@ attribute="lDAPDisplayName", scope=SCOPE_SUBTREE) if target is not None: - refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0] + refint_attributes = refint_attributes + " " + res[i]["lDAPDisplayName"][0] memberof_config += read_and_sub_file(setup_path("memberof.conf"), { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]), @@ -1335,6 +1405,15 @@ refint_config = read_and_sub_file(setup_path("refint.conf"), { "LINK_ATTRS" : refint_attributes}) + res = schemadb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs) + index_config = "" + for i in range (0, len(res)): + index_attr = res[i]["lDAPDisplayName"][0] + if index_attr == "objectGUID": + index_attr = "entryUUID" + + index_config += "index " + index_attr + " eq\n" + # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts mmr_on_config = "" mmr_replicator_acl = "" @@ -1443,7 +1522,9 @@ "OLC_SYNCREPL_CONFIG": olc_syncrepl_config, "OLC_CONFIG_ACL": olc_config_acl, "OLC_MMR_CONFIG": olc_mmr_config, - "REFINT_CONFIG": refint_config}) + "REFINT_CONFIG": refint_config, + "INDEX_CONFIG": index_config, + "NOSYNC": nosync_config}) setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) @@ -1475,24 +1556,36 @@ mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" + # now we generate the needed strings to start slapd automatically, + # first ldapi_uri... ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") if ldap_backend_port is not None: server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port else: server_port_string = "" + # ..and now the slapd-commandline with (optional) mmr and/or olc 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 + slapdcommand_prov=ol_slapd + " -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + slapdcommand=ol_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://:\"" + slapdcommand_prov=ol_slapd + " -F " + paths.olcdir + " -h " + ldapi_uri + slapdcommand=ol_slapd + " -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://" + names.hostname + "." + names.dnsdomain +": 389!)>\"" 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://:\"" + slapdcommand_prov=ol_slapd + " -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + slapdcommand=ol_slapd + " -f " + paths.ldapdir + "/slapd.conf -h \"" + ldapi_uri + " ldap://" + names.hostname + "." + names.dnsdomain +": 389!)>\"" if ol_olc == "yes" and ol_mmr_urls is not None: - slapdcommand="Start slapd with: slapd -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://:\"" + slapdcommand_prov=ol_slapd + " -F " + paths.olcdir + " -h " + ldapi_uri + slapdcommand=ol_slapd + " -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://" + names.hostname + "." + names.dnsdomain +": 389!)>\"" + # now generate file with complete slapd-commandline. + # it is read out later when final provision's done and ol/s4 are ready to be started manually + f = open(paths.ldapdir +"/slapd_command_file.txt", "w") + f.write(str(slapdcommand + "\n")) + f.close() ldapuser = "--username=samba-admin" @@ -1513,9 +1606,59 @@ message("LDAP admin DN: %s" % names.ldapmanagerdn) message("LDAP admin password: %s" % adminpass) - message(slapdcommand) if ol_olc == "yes" or ol_mmr_urls is not None: - message("Attention to slapd-Port: must be different than 389!") + message("Attention to slapd-Port! You are using olc and/or MMR: must be different than 389!") + + # 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.olslapd = str(ol_slapd) + olc_command = paths.olslapd + " -Ttest -f " + paths.slapdconf + " -F " + paths.olcdir + " >/dev/null 2>&1" + os.system(olc_command) + os.remove(paths.slapdconf) + # for debugging purposes, remove: ' + ">/dev/null 2>&1" ' from the line 'olc_command =' above + + + + # start slapd with ldapi for final provisioning. first check, if another instance of slapd is already running + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + + # now we init a rootDSE search to check if a slapd is listening on our ldapi_uri + l = ldap.initialize(ldapi_uri) + l.protocol_version = ldap.VERSION3 + baseDN = "" + searchScope = ldap.SCOPE_BASE + retrieveAttributes = None + searchFilter = "(objectClass=OpenLDAProotDSE)" + + try: + ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes) + result_set = [] + result_type, result_data = l.result(ldap_result_id, 0) + if result_type == ldap.RES_SEARCH_ENTRY: + message("LDAP Result Type: " + str(result_type)) + message("LDAP Result Data (rootDSE found): " + str(result_data)) + sys.exit("Warning: Another slapd Instance seems alread running on this host, listening to " + ldapi_uri + ". Please shut it down before you continue. Exiting now.") + + except ldap.LDAPError, e: + message("ldap-search Output:") + print e + message("Ok. - No other slapd-Instance listening on: " + ldapi_uri + ". Starting slapd now for final provision.") + + p = subprocess.Popen(slapdcommand_prov,shell=True) + message("Started slapd for final provisioning with PID: " + str(p.pid)) + + # proper startup verified, now store slapd-provision-pid. + # this is needed as long as provision/provision-backend are not fully merged + f = open(paths.ldapdir +"/slapd_provision_pid", "w") + f.write(str(p.pid) + "\n") + f.close() + + # done slapd checking + start + + + assert isinstance(ldap_backend_type, str) assert isinstance(ldapuser, str) assert isinstance(adminpass, str) @@ -1529,19 +1672,8 @@ "--realm=" + names.dnsdomain, "--domain=" + names.domain, "--server-role='" + serverrole + "'"] - message("Run provision with: " + " ".join(args)) - + message("Now run final 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):