diff options
author | Andrew Bartlett <abartlet@samba.org> | 2009-08-13 17:01:27 +1000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2009-08-17 09:50:58 +1000 |
commit | f87811f6b39bfa8bdef906256cf7752e4a6fd999 (patch) | |
tree | 6b6a36de1546d8cc08074f78eea5279f7dcd7551 | |
parent | 7a9030b7ce164460e662d0798c2490ec5929442d (diff) | |
download | samba-f87811f6b39bfa8bdef906256cf7752e4a6fd999.tar.gz samba-f87811f6b39bfa8bdef906256cf7752e4a6fd999.tar.bz2 samba-f87811f6b39bfa8bdef906256cf7752e4a6fd999.zip |
s4:provision Rework provision-backend into provision
This removes a *lot* of duplicated code and the cause of much
administrator frustration. We now handle starting and stopping the
slapd (at least for the provision), and ensure that there is only one
'right' way to configure the OpenLDAP and Fedora DS backend
We now run OpenLDAP in 'cn=config' mode for online configuration.
To test what was the provision-backend code, a new --ldap-dryrun-mode
option has been added to provision. It quits the provision just
before it would start the LDAP binaries
Andrew Bartlett
-rw-r--r-- | selftest/target/Samba4.pm | 60 | ||||
-rw-r--r-- | source4/scripting/python/samba/provision.py | 1176 | ||||
-rw-r--r-- | source4/setup/ldap_backend_startup.sh | 2 | ||||
-rw-r--r-- | source4/setup/olc_acl.conf | 4 | ||||
-rw-r--r-- | source4/setup/olc_pass.conf | 3 | ||||
-rwxr-xr-x | source4/setup/provision | 35 | ||||
-rwxr-xr-x | source4/setup/provision-backend | 119 | ||||
-rw-r--r-- | source4/setup/slapd.conf | 10 | ||||
-rwxr-xr-x | source4/setup/tests/blackbox_provision-backend.sh | 10 |
9 files changed, 608 insertions, 811 deletions
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index ef553231a0..ab421d586c 100644 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -31,8 +31,6 @@ sub bindir_path($$) { } sub openldap_start($$$) { - my ($slapd_conf, $uri, $logs) = @_; - system("$ENV{OPENLDAP_SLAPD} -d0 -f $slapd_conf -h $uri > $logs 2>&1 &"); } sub slapd_start($$) @@ -47,7 +45,7 @@ sub slapd_start($$) if ($self->{ldap} eq "fedora-ds") { system("$ENV{FEDORA_DS_ROOT}/sbin/ns-slapd -D $env_vars->{FEDORA_DS_DIR} -d0 -i $env_vars->{FEDORA_DS_PIDFILE}> $env_vars->{LDAPDIR}/logs 2>&1 &"); } elsif ($self->{ldap} eq "openldap") { - openldap_start($env_vars->{SLAPD_CONF}, $uri, "$env_vars->{LDAPDIR}/logs"); + system("$ENV{OPENLDAP_SLAPD} -d0 -F $env_vars->{SLAPD_CONF_D} -h $uri > $env_vars->{LDAPDIR}/logs 2>&1 &"); } my $ldbsearch = $self->bindir_path("ldbsearch"); while (system("$ldbsearch -H $uri -s base -b \"\" supportedLDAPVersion > /dev/null") != 0) { @@ -207,37 +205,26 @@ type: 0x3 "); } -sub mk_fedora_ds($$$) +sub mk_fedora_ds($$) { - my ($self, $ldapdir, $configuration) = @_; - - my $fedora_ds_inf = "$ldapdir/fedorads.inf"; - my $fedora_ds_extra_ldif = "$ldapdir/fedorads-partitions.ldif"; + my ($self, $ldapdir) = @_; #Make the subdirectory be as fedora DS would expect my $fedora_ds_dir = "$ldapdir/slapd-samba4"; my $pidfile = "$fedora_ds_dir/logs/slapd-samba4.pid"; -my $dir = getcwd(); -chdir "$ENV{FEDORA_DS_ROOT}/bin" || die; - if (system("perl $ENV{FEDORA_DS_ROOT}/sbin/setup-ds.pl --silent --file=$fedora_ds_inf >&2") != 0) { - chdir $dir; - die("perl $ENV{FEDORA_DS_ROOT}/sbin/setup-ds.pl --silent --file=$fedora_ds_inf FAILED: $?"); - } - chdir $dir || die; - return ($fedora_ds_dir, $pidfile); } -sub mk_openldap($$$) +sub mk_openldap($$) { - my ($self, $ldapdir, $configuration) = @_; + my ($self, $ldapdir) = @_; - my $slapd_conf = "$ldapdir/slapd.conf"; + my $slapd_conf_d = "$ldapdir/slapd.d"; my $pidfile = "$ldapdir/slapd.pid"; - return ($slapd_conf, $pidfile); + return ($slapd_conf_d, $pidfile); } sub mk_keyblobs($$) @@ -792,41 +779,22 @@ sub provision($$$$$$$) my $ret = $self->provision_raw_step1($ctx); if (defined($self->{ldap})) { - my $configuration = "--configfile=$ctx->{smb_conf}"; - - $ret->{LDAP_URI} = $ctx->{ldap_uri}; - push (@{$ctx->{provision_options}},"--ldap-backend=$ctx->{ldap_uri}"); - - push (@{$ctx->{provision_options}}, "--password=$ctx->{password}"); - + $ret->{LDAP_URI} = $ctx->{ldap_uri}; + push (@{$ctx->{provision_options}}, "--ldap-backend-type=" . $self->{ldap}); if ($self->{ldap} eq "openldap") { - push (@{$ctx->{provision_options}}, "--username=samba-admin"); - push (@{$ctx->{provision_options}}, "--ldap-backend-type=openldap"); - - system("$self->{setupdir}/provision-backend $configuration --ldap-admin-pass=$ctx->{password} --root=$ctx->{unix_name} --realm=$ctx->{realm} --domain=$ctx->{domain} --host-name=$ctx->{netbiosname} --ldap-backend-type=$self->{ldap} --nosync --ol-slapd=$ENV{OPENLDAP_SLAPD}>&2") == 0 or die("backend provision failed"); - - ($ret->{SLAPD_CONF}, $ret->{OPENLDAP_PIDFILE}) = $self->mk_openldap($ctx->{ldapdir}, $configuration) or die("Unable to create openldap directories"); + push (@{$ctx->{provision_options}}, "--slapd-path=" . $ENV{OPENLDAP_SLAPD}); + ($ret->{SLAPD_CONF_D}, $ret->{OPENLDAP_PIDFILE}) = $self->mk_openldap($ctx->{ldapdir}) or die("Unable to create openldap directories"); } elsif ($self->{ldap} eq "fedora-ds") { - push (@{$ctx->{provision_options}}, "--simple-bind-dn=cn=Manager,$ctx->{localbasedn}"); - push (@{$ctx->{provision_options}}, "--ldap-backend-type=fedora-ds"); - - system("$self->{setupdir}/provision-backend $configuration --ldap-admin-pass=$ctx->{password} --root=$ctx->{unix_name} --realm=$ctx->{realm} --domain=$ctx->{domain} --host-name=$ctx->{netbiosname} --ldap-backend-type=$self->{ldap}>&2") == 0 or die("backend provision failed"); - - ($ret->{FEDORA_DS_DIR}, $ret->{FEDORA_DS_PIDFILE}) = $self->mk_fedora_ds($ctx->{ldapdir}, $configuration) or die("Unable to create fedora ds directories"); - - $self->slapd_start($ret) or die("couldn't start slapd"); - + push (@{$ctx->{provision_options}}, "--slapd-path=" . "$ENV{FEDORA_DS_ROOT}/sbin/ns-slapd"); + push (@{$ctx->{provision_options}}, "--setup-ds-path=" . "$ENV{FEDORA_DS_ROOT}/sbin/setup-ds.pl"); + ($ret->{FEDORA_DS_DIR}, $ret->{FEDORA_DS_PIDFILE}) = $self->mk_fedora_ds($ctx->{ldapdir}) or die("Unable to create fedora ds directories"); } } $ret = $self->provision_raw_step2($ctx, $ret); - if (defined($self->{ldap}) && ($self->{ldap} eq "fedora-ds")) { - $self->slapd_stop($ret) or die("couldn't stop slapd"); - } - return $ret; } diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 39c3fffce3..253add1205 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -37,6 +37,9 @@ import param import registry import samba import subprocess + +import shutil +from credentials import Credentials from auth import system_session from samba import version, Ldb, substitute_var, valid_netbios_name, check_all_substituted, \ DS_BEHAVIOR_WIN2008 @@ -128,7 +131,40 @@ class ProvisionResult(object): self.domaindn = None self.lp = None self.samdb = None + +class Schema(object): + def __init__(self, setup_path, schemadn=None, + serverdn=None): + """Load schema for the SamDB from the AD schema files and samba4_schema.ldif + + :param samdb: Load a schema into a SamDB. + :param setup_path: Setup path function. + :param schemadn: DN of the schema + :param serverdn: DN of the server + + Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db + """ + + self.ldb = Ldb() + self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'), + setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt')) + self.schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() + self.schema_data = substitute_var(self.schema_data, {"SCHEMADN": schemadn}) + check_all_substituted(self.schema_data) + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + prefixmap = b64encode(prefixmap) + + self.schema_dn_modify = read_and_sub_file(setup_path("provision_schema_basedn_modify.ldif"), + {"SCHEMADN": schemadn, + "PREFIXMAP_B64": prefixmap, + "SERVERDN": serverdn, + }) + self.schema_dn_add = read_and_sub_file(setup_path("provision_schema_basedn.ldif"), + {"SCHEMADN": schemadn + }) + self.ldb.set_schema_from_ldif(self.schema_dn_modify, self.schema_data) + def check_install(lp, session_info, credentials): """Check whether the current install seems ok. @@ -437,8 +473,27 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, :param nobody_uid: uid of the UNIX nobody user. :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_stock_foreign_sids() + + def add_foreign(self, domaindn, sid, desc): + """Add a foreign security principle.""" + add = """ +dn: CN=%s,CN=ForeignSecurityPrincipals,%s +objectClass: top +objectClass: foreignSecurityPrincipal +description: %s +""" % (sid, domaindn, desc) + # deliberately ignore errors from this, as the records may + # already exist + for msg in self.parse_ldif(add): + self.add(msg[1]) + + # add some foreign sids + add_foreign(samdb, domaindn, "S-1-5-7", "Anonymous") + add_foreign(samdb, domaindn, "S-1-1-0", "World") + add_foreign(samdb, domaindn, "S-1-5-2", "Network") + add_foreign(samdb, domaindn, "S-1-5-18", "System") + add_foreign(samdb, domaindn, "S-1-5-11", "Authenticated Users") + 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) @@ -450,7 +505,7 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, names, serverrole, ldap_backend=None, - ldap_backend_type=None, erase=False): + erase=False): """Setup the partitions for the SAM database. Alternatively, provision() may call this, and then populate the database. @@ -463,15 +518,18 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, """ assert session_info is not None + # We use options=["modules:"] to stop the modules loading - we + # just want to wipe and re-initialise the database, not start it up + try: - samdb = SamDB(samdb_path, session_info=session_info, - credentials=credentials, lp=lp) + samdb = Ldb(url=samdb_path, session_info=session_info, + credentials=credentials, lp=lp, options=["modules:"]) # Wipes the database samdb.erase() except LdbError: os.unlink(samdb_path) - samdb = SamDB(samdb_path, session_info=session_info, - credentials=credentials, lp=lp) + samdb = Ldb(url=samdb_path, session_info=session_info, + credentials=credentials, lp=lp, options=["modules:"]) # Wipes the database samdb.erase() @@ -509,26 +567,22 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "partition"] domaindn_ldb = "users.ldb" - if ldap_backend is not None: - domaindn_ldb = ldap_backend configdn_ldb = "configuration.ldb" - if ldap_backend is not None: - configdn_ldb = ldap_backend schemadn_ldb = "schema.ldb" if ldap_backend is not None: - schema_ldb = ldap_backend - schemadn_ldb = ldap_backend + domaindn_ldb = ldap_backend.ldapi_uri + configdn_ldb = ldap_backend.ldapi_uri + schemadn_ldb = ldap_backend.ldapi_uri - 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", "extended_dn_out_dereference"] - elif ldap_backend_type == "openldap": - backend_modules = ["entryuuid", "paged_searches"] - # OpenLDAP handles subtree renames, so we don't want to do any of these things - tdb_modules_list = ["extended_dn_out_dereference"] - elif ldap_backend is not None: - raise "LDAP Backend specified, but LDAP Backend Type not specified" + if ldap_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 = ["linked_attributes", "extended_dn_out_dereference"] + elif ldap_backend.ldap_backend_type == "openldap": + backend_modules = ["entryuuid", "paged_searches"] + # OpenLDAP handles subtree renames, so we don't want to do any of these things + tdb_modules_list = ["extended_dn_out_dereference"] + elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: @@ -541,6 +595,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.transaction_start() try: + message("Setting up sam.ldb partitions and settings") setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { "SCHEMADN": names.schemadn, "SCHEMADN_LDB": schemadn_ldb, @@ -558,34 +613,17 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "BACKEND_MOD": ",".join(backend_modules), }) - except: - samdb.transaction_cancel() - raise - - samdb.transaction_commit() - - samdb = SamDB(samdb_path, session_info=session_info, - credentials=credentials, lp=lp) - - samdb.transaction_start() - try: - message("Setting up sam.ldb attributes") samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") setup_samdb_rootdse(samdb, setup_path, names) - if erase: - message("Erasing data from partitions") - samdb.erase_partitions() - except: samdb.transaction_cancel() raise samdb.transaction_commit() - return samdb def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain, @@ -647,7 +685,7 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): return secrets_ldb -def setup_templatesdb(path, setup_path, session_info, credentials, lp): +def setup_templatesdb(path, setup_path, session_info, lp): """Setup the templates database. :param path: Path to the database. @@ -656,8 +694,8 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): :param credentials: Credentials :param lp: Loadparm context """ - templates_ldb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) + templates_ldb = Ldb(url=path, session_info=session_info, + lp=lp) # Wipes the database try: templates_ldb.erase() @@ -667,13 +705,13 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif")) - templates_ldb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) + templates_ldb = Ldb(url=path, session_info=session_info, + lp=lp) templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) -def setup_registry(path, setup_path, session_info, credentials, lp): +def setup_registry(path, setup_path, session_info, lp): """Setup the registry. :param path: Path to the registry database @@ -684,14 +722,14 @@ 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) + lp_ctx=lp) 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) -def setup_idmapdb(path, setup_path, session_info, credentials, lp): +def setup_idmapdb(path, setup_path, session_info, lp): """Setup the idmap database. :param path: path to the idmap database @@ -704,7 +742,7 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): os.unlink(path) idmap_ldb = IDmapDB(path, session_info=session_info, - credentials=credentials, lp=lp) + lp=lp) idmap_ldb.erase() idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) @@ -761,11 +799,10 @@ def setup_self_join(samdb, names, def setup_samdb(path, setup_path, session_info, credentials, lp, names, message, - domainsid, aci, domainguid, policyguid, + domainsid, domainguid, policyguid, fill, adminpass, krbtgtpass, machinepass, invocationid, dnspass, - serverrole, ldap_backend=None, - ldap_backend_type=None): + serverrole, schema=None, ldap_backend=None): """Setup a complete SAM Database. :note: This will wipe the main SAM database file! @@ -775,22 +812,39 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, forestFunctionality = DS_BEHAVIOR_WIN2008 domainControllerFunctionality = DS_BEHAVIOR_WIN2008 - erase = (fill != FILL_DRS) - # 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, serverrole=serverrole, - ldap_backend_type=ldap_backend_type, erase=erase) + ldap_backend=ldap_backend, serverrole=serverrole) + + # 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) + + message("Pre-loading the Samba 4 and AD schema") + + # Load the schema from the one we computed earlier + samdb.set_schema_from_ldb(schema.ldb) - samdb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) + # And now we can connect to the DB - the schema won't be loaded from the DB + samdb.connect(path) if fill == FILL_DRS: return samdb - message("Pre-loading the Samba 4 and AD schema") + samdb.transaction_start() + try: + message("Erasing data from partitions") + # Load the schema (again). This time it will force a reindex, to make the below computationally sane + samdb.set_schema_from_ldb(schema.ldb) + samdb.erase_partitions() + + except: + samdb.transaction_cancel() + raise + samdb.transaction_commit() + samdb.set_opaque_integer("domainFunctionality", domainFunctionality) samdb.set_opaque_integer("forestFunctionality", forestFunctionality) samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality) @@ -799,12 +853,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if serverrole == "domain controller": samdb.set_invocation_id(invocationid) - schema_data = load_schema(setup_path, samdb, names.schemadn, names.netbiosname, - names.configdn, names.sitename, names.serverdn) samdb.transaction_start() try: - message("Adding DomainDN: %s (permitted to fail)" % names.domaindn) + message("Adding DomainDN: %s" % names.domaindn) if serverrole == "domain controller": domain_oc = "domainDNS" else: @@ -812,7 +864,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": names.domaindn, - "ACI": aci, "DOMAIN_OC": domain_oc }) @@ -836,10 +887,9 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "DOMAIN_FUNCTIONALITY": str(domainFunctionality) }) - message("Adding configuration container (permitted to fail)") + message("Adding configuration container") setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { "CONFIGDN": names.configdn, - "ACI": aci, }) message("Modifying configuration container") setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { @@ -847,27 +897,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "SCHEMADN": names.schemadn, }) - message("Adding schema container (permitted to fail)") - setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { - "SCHEMADN": names.schemadn, - "ACI": aci, - }) - message("Modifying schema container") - - prefixmap = open(setup_path("prefixMap.txt"), 'r').read() - - setup_modify_ldif(samdb, - setup_path("provision_schema_basedn_modify.ldif"), { - "SCHEMADN": names.schemadn, - "NETBIOSNAME": names.netbiosname, - "DEFAULTSITE": names.sitename, - "CONFIGDN": names.configdn, - "SERVERDN": names.serverdn, - "PREFIXMAP_B64": b64encode(prefixmap) - }) - message("Setting up sam.ldb schema") - samdb.add_ldif(schema_data) + samdb.add_ldif(schema.schema_dn_add) + samdb.modify_ldif(schema.schema_dn_modify) + samdb.add_ldif(schema.schema_data) setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"), {"SCHEMADN": names.schemadn}) @@ -888,13 +921,13 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("display_specifiers.ldif"), {"CONFIGDN": names.configdn}) - message("Adding users container (permitted to fail)") + message("Adding users container") setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), { "DOMAINDN": names.domaindn}) message("Modifying users container") setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), { "DOMAINDN": names.domaindn}) - message("Adding computers container (permitted to fail)") + message("Adding computers container") setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), { "DOMAINDN": names.domaindn}) message("Modifying computers container") @@ -947,9 +980,12 @@ def provision(setup_dir, message, session_info, domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, - dnspass=None, root=None, nobody=None, nogroup=None, users=None, + dnspass=None, root=None, nobody=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, - ldap_backend=None, ldap_backend_type=None, sitename=None): + ldap_backend_extra_port=None, ldap_backend_type=None, sitename=None, + ol_mmr_urls=None, ol_olc=None, + setup_ds_path=None, slapd_path=None, nosync=False, + ldap_dryrun_mode=False): """Provision samba4 :note: caution, this wipes all existing data! @@ -978,8 +1014,6 @@ def provision(setup_dir, message, session_info, wheel_gid = findnss_gid(["wheel", "adm"]) else: wheel_gid = findnss_gid([wheel]) - if aci is None: - aci = "# no aci for local ldb" if targetdir is not None: if (not os.path.exists(os.path.join(targetdir, "etc"))): @@ -1027,11 +1061,25 @@ def provision(setup_dir, message, session_info, ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - if ldap_backend is not None: - if ldap_backend == "ldapi": - # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - + schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn) + + 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, + 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) + + # Now use the backend credentials to access the databases + credentials = provision_backend.credentials + # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") @@ -1047,27 +1095,27 @@ def provision(setup_dir, message, session_info, message("Setting up the registry") setup_registry(paths.hklm, setup_path, session_info, - credentials=credentials, lp=lp) + lp=lp) message("Setting up templates db") setup_templatesdb(paths.templates, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + lp=lp) message("Setting up idmap db") idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + 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, domainsid=domainsid, - aci=aci, domainguid=domainguid, policyguid=policyguid, + schema=schema, domainguid=domainguid, policyguid=policyguid, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, invocationid=invocationid, machinepass=machinepass, dnspass=dnspass, - serverrole=serverrole, ldap_backend=ldap_backend, - ldap_backend_type=ldap_backend_type) + serverrole=serverrole, ldap_backend=provision_backend) if serverrole == "domain controller": if paths.netlogon is None: @@ -1109,9 +1157,6 @@ def provision(setup_dir, message, session_info, dns_keytab_path=paths.dns_keytab, dnspass=dnspass, machinepass=machinepass, dnsdomain=names.dnsdomain) - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) - domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") assert isinstance(domainguid, str) hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", @@ -1139,76 +1184,27 @@ def provision(setup_dir, message, session_info, message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) - - # if backend is openldap, terminate slapd after final provision and check its proper termination - if ldap_backend_type == "openldap": + # 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: + #Kill the slapd + if hasattr(provision_backend.slapd, "terminate"): + provision_backend.slapd.terminate() + else: + import signal + os.kill(provision_backend.slapd.pid, signal.SIGTERM) - # We look if our "provision-slapd" is still up and running, - # listening with the stored PID on our ldapi_uri. - # first we check with ldapsearch -> rootDSE via ldapi_uri - # if slapd is running - try: - # in this case we got a running slapd listening on our ldapi_uri - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - ldapi_db = Ldb(ldapi_uri) - search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, - expression="(objectClass=OpenLDAProotDSE)"); - message("LDAP Debug-Output:" + str(search_ol_rootdse)) - - # now we check if slapds PID file exists AND is identical to our stored - if os.path.exists(paths.slapdpid): - f = open(paths.slapdpid, "r") - p1 = f.read() - f.close() - message("slapd-PID-File found. PID is :" + str(p1)) - # validation against stored PID of "provision-slapd". - # is this the slapd we started from provision-backend? - if os.path.exists(paths.ldapdir + "/slapd_provision_pid"): - f = open(paths.ldapdir + "/slapd_provision_pid", "r") - p2 = f.read() - f.close() - message("File from provision-backend with stored PID found. PID is :" + str(p2)) - if int(p1) == int(p2): - message("slapd-Process used for provisioning with PID: " + str(p1) + " will now be shut down.") - os.kill(int(p1),SIGTERM) - else: - message("Warning: PIDs are not identical! Locate the active slapd and shut it down before you continue!") - else: - message("Stored PID File could not be found. Sorry. You have to locate the PID and terminate slapd manually.") - else: - message("slapd-PID File could not be found. Sorry. You have to locate the PID and terminate slapd manually.") - - # Now verify proper slapd-termination... - try: - # in this case we got still a running slapd listening on our ldapi_uri: bad - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - ldapi_db = Ldb(ldapi_uri) - search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, - expression="(objectClass=OpenLDAProotDSE)"); - message("slapd seems still to be running and listening to our "+ ldapi_uri + " -socket. Locate an terminate it manually.") - except LdbError, e: - message("slapd-Process used for final provision was properly shut down.") - # in this case we got no running slapd listening on our ldapi_uri: everythings good - do nothing. - - except LdbError, e: - # in this case we got no running slapd - message("LDAP Debug-Output:") - print e - message("No running slapd on: " + ldapi_uri + " detected. Maybe final provision is incomplete.") - - # 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 later 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.") + #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}) create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) @@ -1240,8 +1236,8 @@ def provision_become_dc(setup_dir=None, domain=None, hostname=None, domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, - dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + dnspass=None, root=None, nobody=None, users=None, + wheel=None, backup=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=None): def message(text): @@ -1261,444 +1257,436 @@ def setup_db_config(setup_path, dbdir): :param dbdir: Database directory.""" if not os.path.isdir(os.path.join(dbdir, "bdb-logs")): os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700) - if not os.path.isdir(os.path.join(dbdir, "tmp")): - os.makedirs(os.path.join(dbdir, "tmp"), 0700) - + if not os.path.isdir(os.path.join(dbdir, "tmp")): + os.makedirs(os.path.join(dbdir, "tmp"), 0700) + setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir}) +class ProvisionBackend(object): + def __init__(self, paths=None, setup_path=None, lp=None, credentials=None, + names=None, message=None, + hostname=None, root=None, + schema=None, + ldap_backend_type=None, ldap_backend_extra_port=None, + ol_mmr_urls=None, + setup_ds_path=None, slapd_path=None, + nosync=False, ldap_dryrun_mode=False): + """Provision an LDAP backend for samba4 + + This works for OpenLDAP and Fedora DS + """ + 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": + #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 + self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP + return + + # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri + # if another instance of slapd is already running + try: + ldapi_db = Ldb(self.ldapi_uri) + search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, + expression="(objectClass=OpenLDAProotDSE)"); + try: + f = open(paths.slapdpid, "r") + p = f.read() + f.close() + message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.") + except: + pass + + raise("Warning: Another slapd Instance seems already running on this host, listening to " + ldapi_uri + ". Please shut it down before you continue. ") + + except LdbError, e: + pass -def provision_backend(setup_dir=None, message=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_slapd=None, nosync=False, testing_mode=False): - - def setup_path(file): - return os.path.join(setup_dir, file) - - if hostname is None: - hostname = socket.gethostname().split(".")[0].lower() - - if root is None: - root = findnss(pwd.getpwnam, ["root"])[0] - - if adminpass is None: - 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): - make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, - targetdir) - - # if openldap-backend was chosen, check if path to slapd was given and exists - if ldap_backend_type == "openldap" and ol_slapd is None and not testing_mode: - sys.exit("Warning: OpenLDAP-Backend must be setup with path to slapd (OpenLDAP-Daemon), e.g. --ol-slapd=\"/usr/local/libexec/slapd\"!") - if ldap_backend_type == "openldap" and ol_slapd is not None: - 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!") - + # Try to print helpful messages when the user has not specified the path to slapd + if slapd_path is None: + raise("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!") + if not os.path.exists(slapd_path): + message (slapd_path) + raise("Warning: Given Path to slapd does not exist!") - lp = param.LoadParm() - lp.load(smbconf) + schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb") + try: + os.unlink(schemadb_path) + except OSError: + pass - 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, - schemadn=schemadn) + # 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 + os.path.join(paths.ldapdir, "schema-tmp.ldb") + schema.ldb.connect(schemadb_path) + schema.ldb.transaction_start() + + # These bits of LDIF are supplied when the Schema object is created + schema.ldb.add_ldif(schema.schema_dn_add) + schema.ldb.modify_ldif(schema.schema_dn_modify) + schema.ldb.add_ldif(schema.schema_data) + schema.ldb.transaction_commit() + + self.credentials = Credentials() + self.credentials.guess(lp) + self.ldap_backend_type = ldap_backend_type + + #Make a new, random password between Samba and it's LDAP server + ldapadminpass=glue.generate_random_str(12) + + if ldap_backend_type == "fedora-ds": + provision_fds_backend(self, paths=paths, setup_path=setup_path, names=names, message=message, + hostname=hostname, ldapadminpass=ldapadminpass, root=root, + schema=schema, ldap_backend_extra_port=ldap_backend_extra_port, + setup_ds_path=setup_ds_path, slapd_path=slapd_path, + nosync=nosync, ldap_dryrun_mode=ldap_dryrun_mode) + + elif ldap_backend_type == "openldap": + provision_openldap_backend(self, paths=paths, setup_path=setup_path, names=names, message=message, + hostname=hostname, ldapadminpass=ldapadminpass, root=root, + schema=schema, ldap_backend_extra_port=ldap_backend_extra_port, + ol_mmr_urls=ol_mmr_urls, + slapd_path=slapd_path, + nosync=nosync, ldap_dryrun_mode=ldap_dryrun_mode) + else: + raise("Unknown LDAP backend type selected") - paths = provision_paths_from_lp(lp, names.dnsdomain) + self.credentials.set_password(ldapadminpass) - 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 + # Now start the slapd, so we can provision onto it. We keep the + # subprocess context around, to kill this off at the successful + # end of the script + self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False) + + while self.slapd.poll() is None: + # Wait until the socket appears + try: + ldapi_db = Ldb(self.ldapi_uri, lp=lp, credentials=self.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! + return + except LdbError, e: + time.sleep(1) + pass + + raise "slapd died before we could make a connection to it" - schemadb = SamDB(schemadb_path, lp=lp) - schemadb.transaction_start() - try: - - prefixmap = open(setup_path("prefixMap.txt"), 'r').read() - setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), - {"SCHEMADN": names.schemadn, - "ACI": "#", - }) - setup_modify_ldif(schemadb, - setup_path("provision_schema_basedn_modify.ldif"), \ - {"SCHEMADN": names.schemadn, - "NETBIOSNAME": names.netbiosname, - "DEFAULTSITE": DEFAULTSITE, - "CONFIGDN": names.configdn, - "SERVERDN": names.serverdn, - "PREFIXMAP_B64": b64encode(prefixmap) - }) - - data = load_schema(setup_path, schemadb, names.schemadn, names.netbiosname, - names.configdn, DEFAULTSITE, names.serverdn) - schemadb.add_ldif(data) - except: - schemadb.transaction_cancel() - raise - schemadb.transaction_commit() +def provision_openldap_backend(result, paths=None, setup_path=None, names=None, message=None, + hostname=None, ldapadminpass=None, root=None, + schema=None, + ldap_backend_extra_port=None, + ol_mmr_urls=None, + slapd_path=None, nosync=False, + ldap_dryrun_mode=False): - if ldap_backend_type == "fedora-ds": - if ldap_backend_port is not None: - serverport = "ServerPort=%d" % ldap_backend_port - else: - serverport = "" - - setup_file(setup_path("fedorads.inf"), paths.fedoradsinf, - {"ROOT": root, - "HOSTNAME": hostname, - "DNSDOMAIN": names.dnsdomain, - "LDAPDIR": paths.ldapdir, - "DOMAINDN": names.domaindn, - "LDAPMANAGERDN": names.ldapmanagerdn, - "LDAPMANAGERPASS": adminpass, - "SERVERPORT": serverport}) + #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB + nosync_config = "" + if nosync: + nosync_config = "dbnosync" - setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, - {"CONFIGDN": names.configdn, - "SCHEMADN": names.schemadn, - }) - - mapping = "schema-map-fedora-ds-1.0" - backend_schema = "99_ad.ldif" - slapdcommand="Initialise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf - - 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_ONELEVEL, 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)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1) - target = schemadb.searchone(basedn=names.schemadn, - expression=expression, - attribute="lDAPDisplayName", - scope=SCOPE_SUBTREE) - if target is not None: - refint_attributes = refint_attributes + " " + res[i]["lDAPDisplayName"][0] + attrs = ["linkID", "lDAPDisplayName"] + res = schema.ldb.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 Samba4 schema\n" + refint_attributes = "" + for i in range (0, len(res)): + expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1) + target = schema.ldb.searchone(basedn=names.schemadn, + expression=expression, + attribute="lDAPDisplayName", + scope=SCOPE_SUBTREE) + if target is not None: + 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]), - "MEMBEROF_ATTR" : str(target) }) - - 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" + memberof_config += read_and_sub_file(setup_path("memberof.conf"), + { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]), + "MEMBEROF_ATTR" : str(target) }) + + refint_config = read_and_sub_file(setup_path("refint.conf"), + { "LINK_ATTRS" : refint_attributes}) + + res = schema.ldb.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 = "" - mmr_serverids_config = "" - mmr_syncrepl_schema_config = "" - mmr_syncrepl_config_config = "" - mmr_syncrepl_user_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: - # For now, make these equal - mmr_pass = adminpass - - url_list=filter(None,ol_mmr_urls.split(' ')) - if (len(url_list) == 1): - url_list=filter(None,ol_mmr_urls.split(',')) + + if ol_mmr_urls is not None: + # For now, make these equal + mmr_pass = ldapadminpass + + 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 }) - 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, - "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, - "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, - "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"),{}) + + 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, + "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, + "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, + "MMR_PASSWORD": mmr_pass }) + # OpenLDAP cn=config initialisation + olc_syncrepl_config = "" + olc_mmr_config = "" + # if mmr = yes, generate cn=config-replication directives + # and olc_seed.lif for the other mmr-servers + if ol_mmr_urls is not None: + serverid=0 + olc_serverids_config = "" + olc_syncrepl_seed_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": mmr_pass}) + + 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": ldapadminpass, + "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config}) + # end olc - # 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}) + setup_file(setup_path("slapd.conf"), paths.slapdconf, + {"DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "MEMBEROF_CONFIG": memberof_config, + "MIRRORMODE": mmr_on_config, + "REPLICATOR_ACL": mmr_replicator_acl, + "MMR_SERVERIDS_CONFIG": mmr_serverids_config, + "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_SYNCREPL_CONFIG": olc_syncrepl_config, + "OLC_MMR_CONFIG": olc_mmr_config, + "REFINT_CONFIG": refint_config, + "INDEX_CONFIG": index_config, + "NOSYNC": nosync_config}) - - # end olc - - setup_file(setup_path("slapd.conf"), paths.slapdconf, - {"DNSDOMAIN": names.dnsdomain, - "LDAPDIR": paths.ldapdir, - "DOMAINDN": names.domaindn, - "CONFIGDN": names.configdn, - "SCHEMADN": names.schemadn, - "MEMBEROF_CONFIG": memberof_config, - "MIRRORMODE": mmr_on_config, - "REPLICATOR_ACL": mmr_replicator_acl, - "MMR_SERVERIDS_CONFIG": mmr_serverids_config, - "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, - "INDEX_CONFIG": index_config, - "NOSYNC": nosync_config}) - setup_file(setup_path("modules.conf"), paths.modulesconf, - {"REALM": names.realm}) + 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")) + + 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) - 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")) - - 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) - - setup_file(setup_path("cn=samba.ldif"), - os.path.join(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"), - {"LDAPADMINPASS_B64": b64encode(adminpass), - "UUID": str(uuid.uuid4()), - "LDAPTIME": timestring(int(time.time()))} ) + setup_file(setup_path("cn=samba.ldif"), + os.path.join(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"), + {"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"), + {"MMR_PASSWORD_B64": b64encode(mmr_pass), + "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"), - {"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" - - # 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 + + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" + + 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) + + # now we generate the needed strings to start slapd automatically, + # first ldapi_uri... + if ldap_backend_extra_port is not None: + # When we use MMR, we can't use 0.0.0.0 as it uses the name + # specified there as part of it's clue as to it's own name, + # and not to replicate to itself + if ol_mmr_urls is None: + server_port_string = "ldap://0.0.0.0:%d" % ldap_backend_extra_port else: - server_port_string = "" + server_port_string = "ldap://" + names.hostname + "." + names.dnsdomain +":%d" % ldap_backend_extra_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_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 + # Prepare the 'result' information - the commands to return in particular + result.slapd_provision_command = [slapd_path] - if ol_olc == "yes" and ol_mmr_urls is None: - slapdcommand_prov=ol_slapd + " -F " + paths.olcdir + " -h " + ldapi_uri - slapdcommand=ol_slapd + " -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://" + names.hostname + "." + names.dnsdomain +":<Chosen PORT (<> 389!)>\"" + result.slapd_provision_command.append("-F" + paths.olcdir) - if ol_olc != "yes" and ol_mmr_urls is not None: - 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 +":<Chosen PORT (<> 389!)>\"" + result.slapd_provision_command.append("-h") - if ol_olc == "yes" and ol_mmr_urls is not None: - slapdcommand_prov=ol_slapd + " -F " + paths.olcdir + " -h " + ldapi_uri - slapdcommand=ol_slapd + " -F " + paths.olcdir + " -h \"" + ldapi_uri + " ldap://" + names.hostname + "." + names.dnsdomain +":<Chosen PORT (<> 389!)>\"" + # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands + result.slapd_command = list(result.slapd_provision_command) + + result.slapd_provision_command.append(result.ldapi_uri) + result.slapd_provision_command.append("-d0") - # 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() + uris = result.ldapi_uri + if server_port_string is not "": + uris = uris + " " + server_port_string - ldapuser = "--username=samba-admin" + result.slapd_command.append(uris) + # Set the username - done here because Fedora DS still uses the admin DN and simple bind + result.credentials.set_username("samba-admin") + + # 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 OpenLDAP on + # this system + if ldap_dryrun_mode: + sys.exit(0) - backend_schema_data = schemadb.convert_schema_to_openldap(ldap_backend_type, 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) + # Finally, convert the configuration into cn=config style! + if not os.path.isdir(paths.olcdir): + os.makedirs(paths.olcdir, 0770) - message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type) - message("Server Role: %s" % serverrole) - message("Hostname: %s" % names.hostname) - message("DNS Domain: %s" % names.dnsdomain) - message("Base DN: %s" % names.domaindn) + retcode = subprocess.call([slapd_path, "-Ttest", "-f", paths.slapdconf, "-F", paths.olcdir], close_fds=True, shell=False) - if ldap_backend_type == "openldap": - message("LDAP admin user: samba-admin") - else: - message("LDAP admin DN: %s" % names.ldapmanagerdn) - - message("LDAP admin password: %s" % adminpass) - if ol_olc == "yes" or ol_mmr_urls is not None: - message("Attention! You are using olc and/or MMR: The slapd-PORT you choose later 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 +# We can't do this, as OpenLDAP is strange. It gives an error +# output to the above, but does the conversion sucessfully... +# +# if retcode != 0: +# raise("conversion from slapd.conf to cn=config failed") + + if not os.path.exists(os.path.join(paths.olcdir, "cn=config.ldif")): + raise("conversion from slapd.conf to cn=config failed") + + # Don't confuse the admin by leaving the slapd.conf around + os.remove(paths.slapdconf) +def provision_fds_backend(result, paths=None, setup_path=None, names=None, message=None, + hostname=None, ldapadminpass=None, root=None, + schema=None, + ldap_backend_extra_port=None, + setup_ds_path=None, + slapd_path=None, + nosync=False, + ldap_dryrun_mode=False): + + if ldap_backend_extra_port is not None: + serverport = "ServerPort=%d" % ldap_backend_extra_port + else: + serverport = "" + + setup_file(setup_path("fedorads.inf"), paths.fedoradsinf, + {"ROOT": root, + "HOSTNAME": hostname, + "DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "LDAPMANAGERDN": names.ldapmanagerdn, + "LDAPMANAGERPASS": ldapadminpass, + "SERVERPORT": serverport}) + + setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, + {"CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + }) - # start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via ldapi_uri - # if another instance of slapd is already running - try: - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - ldapi_db = Ldb(ldapi_uri) - search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, - expression="(objectClass=OpenLDAProotDSE)"); - message("LDAP Debug-Output:" + str(search_ol_rootdse)) - if os.path.exists(paths.slapdpid): - f = open(paths.slapdpid, "r") - p = f.read() - f.close() - message("Check for slapd-Process with PID: " + str(p) + " and terminate it manually.") - else: - message("slapd-PID File could not be found. Sorry. You have to locate the PID manually.") - - sys.exit("Warning: Another slapd Instance seems already running on this host, listening to " + ldapi_uri + ". Please shut it down before you continue. Exiting now.") + mapping = "schema-map-fedora-ds-1.0" + backend_schema = "99_ad.ldif" + + # 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) - except LdbError, e: - message("LDAP Debug-Output:") - print e - message("Ok. - No other slapd-Instance listening on: " + ldapi_uri + ". Starting slapd now for final provision.") + result.credentials.set_bind_dn(names.ldapmanagerdn) - if not testing_mode: - p = subprocess.Popen(slapdcommand_prov, shell=True) - - # after startup: store slapd-provision-pid also in a separate file. - # this is needed as long as provision/provision-backend are not fully merged, - # to compare pids before shutting down - - # wait for pidfile to be created - time.sleep(3) - if os.path.exists(paths.slapdpid): - f = open(paths.slapdpid, "r") - p = f.read() - f.close() - f = open(paths.ldapdir +"/slapd_provision_pid", "w") - f.write(str(p) + "\n") - f.close() - message("Started slapd for final provisioning with PID: "+ str(p)) - else: - message("slapd-PID File could not be found. Sorry") - - # done slapd checking + start + # Destory the target directory, or else setup-ds.pl will complain + fedora_ds_dir = os.path.join(paths.ldapdir, "slapd-samba4") + shutil.rmtree(fedora_ds_dir, True) + result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", paths.slapdpid]; + #In the 'provision' command line, stay in the foreground so we can easily kill it + result.slapd_provision_command.append("-d0") - - 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("Now run final provision with: " + " ".join(args)) + #the command for the final run is the normal script + result.slapd_command = [os.path.join(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 + if ldap_dryrun_mode: + sys.exit(0) + # Try to print helpful messages when the user has not specified the path to the setup-ds tool + if setup_ds_path is None: + raise("Warning: Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!") + if not os.path.exists(setup_ds_path): + message (setup_ds_path) + raise("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) + if retcode != 0: + raise("setup-ds failed") def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. @@ -1817,54 +1805,6 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): }) -def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename, - serverdn): - """Load schema for the SamDB. - - :param samdb: Load a schema into a SamDB. - :param setup_path: Setup path function. - :param schemadn: DN of the schema - :param netbiosname: NetBIOS name of the host. - :param configdn: DN of the configuration - :param serverdn: DN of the server - - Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db - """ - schema_data = get_schema_data(setup_path, {"SCHEMADN": schemadn}) - schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() - schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) - check_all_substituted(schema_data) - prefixmap = open(setup_path("prefixMap.txt"), 'r').read() - prefixmap = b64encode(prefixmap) - - head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read() - head_data = substitute_var(head_data, { - "SCHEMADN": schemadn, - "NETBIOSNAME": netbiosname, - "CONFIGDN": configdn, - "DEFAULTSITE": sitename, - "PREFIXMAP_B64": prefixmap, - "SERVERDN": serverdn, - }) - check_all_substituted(head_data) - samdb.attach_schema_from_ldif(head_data, schema_data) - return schema_data; - -def get_schema_data(setup_path, subst_vars = None): - """Get schema data from the AD schema files instead of schema.ldif. - - :param setup_path: Setup path function. - :param subst_vars: Optional variables to substitute in the file. - Returns the schema data after substitution - """ - - # this data used to be read from schema.ldif - - data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'), - setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt')) + - if subst_vars is not None: - data = substitute_var(data, subst_vars) - check_all_substituted(data) - return data diff --git a/source4/setup/ldap_backend_startup.sh b/source4/setup/ldap_backend_startup.sh new file mode 100644 index 0000000000..4a7c765e36 --- /dev/null +++ b/source4/setup/ldap_backend_startup.sh @@ -0,0 +1,2 @@ +#!/bin/sh +${SLAPD_COMMAND} diff --git a/source4/setup/olc_acl.conf b/source4/setup/olc_acl.conf deleted file mode 100644 index c248b30fb5..0000000000 --- a/source4/setup/olc_acl.conf +++ /dev/null @@ -1,4 +0,0 @@ -access to dn.sub="cn=config" - by dn="cn=samba-admin,cn=samba" write - by dn="cn=replicator,cn=samba" read - diff --git a/source4/setup/olc_pass.conf b/source4/setup/olc_pass.conf deleted file mode 100644 index 4c66c1c43f..0000000000 --- a/source4/setup/olc_pass.conf +++ /dev/null @@ -1,3 +0,0 @@ -database config -rootdn cn=config - diff --git a/source4/setup/provision b/source4/setup/provision index d7fa6aa54f..5686ee0e26 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -74,8 +74,6 @@ parser.add_option("--root", type="string", metavar="USERNAME", help="choose 'root' unix username") parser.add_option("--nobody", type="string", metavar="USERNAME", help="choose 'nobody' user") -parser.add_option("--nogroup", type="string", metavar="GROUPNAME", - help="choose 'nogroup' group") parser.add_option("--wheel", type="string", metavar="GROUPNAME", help="choose 'wheel' privileged group") parser.add_option("--users", type="string", metavar="GROUPNAME", @@ -83,13 +81,12 @@ parser.add_option("--users", type="string", metavar="GROUPNAME", parser.add_option("--quiet", help="Be quiet", action="store_true") parser.add_option("--blank", action="store_true", help="do not add users or groups, just the structure") -parser.add_option("--ldap-backend", type="string", metavar="LDAPSERVER", - help="LDAP server to use for this provision") +parser.add_option("--ldap-backend-extra-port", type="int", metavar="LDAP-BACKEND-EXTRA-PORT", + help="Additional TCP port for LDAP backend server (to use for replication)") parser.add_option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TYPE", - help="LDB mapping module to use for the LDAP backend", + help="LDAP backend type (fedora-ds or openldap)", choices=["fedora-ds", "openldap"]) -parser.add_option("--aci", type="string", metavar="ACI", - help="An arbitary LDIF fragment, particularly useful to loading a backend ACI value into a target LDAP server. You must provide at least a realm and domain") +parser.add_option("--ldap-backend-nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true") parser.add_option("--server-role", type="choice", metavar="ROLE", choices=["domain controller", "dc", "member server", "member", "standalone"], help="Set server role to provision for (default standalone)") @@ -97,6 +94,14 @@ parser.add_option("--partitions-only", help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true") parser.add_option("--targetdir", type="string", metavar="DIR", help="Set target directory") +parser.add_option("--ol-mmr-urls", type="string", metavar="LDAPSERVER", + help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/ (where <PORT> has to be different than 389!) ] separated with whitespaces for use with OpenLDAP-MMR (Multi-Master-Replication)") +parser.add_option("--slapd-path", type="string", metavar="SLAPD-PATH", + help="Path to slapd for LDAP backend [e.g.:'/usr/local/libexec/slapd']. Required for Setup with LDAP-Backend. OpenLDAP Version >= 2.4.17 should be used.") +parser.add_option("--setup-ds-path", type="string", metavar="SETUP_DS-PATH", + help="Path to setup-ds.pl script for Fedora DS LDAP backend [e.g.:'/usr/sbin/setup-ds.pl']. Required for Setup with Fedora DS backend.") +parser.add_option("--nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true") +parser.add_option("--ldap-dryrun-mode", help="Configure LDAP backend, but do not run any binaries and exit early. Used only for the test environment. DO NOT USE", action="store_true") opts = parser.parse_args()[0] @@ -148,9 +153,6 @@ if opts.interactive: lp = sambaopts.get_loadparm() smbconf = lp.configfile -if opts.aci is not None: - print "set ACI: %s" % opts.aci - if opts.server_role == "dc": server_role = "domain controller" elif opts.server_role == "member": @@ -182,7 +184,12 @@ provision(setup_dir, message, invocationid=opts.invocationid, adminpass=opts.adminpass, krbtgtpass=opts.krbtgtpass, machinepass=opts.machinepass, dnspass=opts.dnspass, root=opts.root, nobody=opts.nobody, - nogroup=opts.nogroup, wheel=opts.wheel, users=opts.users, - aci=opts.aci, serverrole=server_role, - ldap_backend=opts.ldap_backend, - ldap_backend_type=opts.ldap_backend_type) + wheel=opts.wheel, users=opts.users, + serverrole=server_role, + ldap_backend_extra_port=opts.ldap_backend_extra_port, + ldap_backend_type=opts.ldap_backend_type, + 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) diff --git a/source4/setup/provision-backend b/source4/setup/provision-backend deleted file mode 100755 index 3da360447f..0000000000 --- a/source4/setup/provision-backend +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/python -# -# Unix SMB/CIFS implementation. -# provision a Samba4 server -# 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 2005 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - -import os, sys - -sys.path.insert(0, "bin/python") - -import getopt -import optparse - -import samba -from samba import param - -from samba.auth import system_session -import samba.getopt as options -from samba.provision import provision_backend, find_setup_dir - -parser = optparse.OptionParser("provision [options]") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("--setupdir", type="string", metavar="DIR", - help="directory with setup files") -parser.add_option("--realm", type="string", metavar="REALM", help="set realm") -parser.add_option("--domain", type="string", metavar="DOMAIN", - help="set domain") -parser.add_option("--host-name", type="string", metavar="HOSTNAME", - help="set hostname") -parser.add_option("--ldap-admin-pass", type="string", metavar="PASSWORD", - help="choose LDAP admin password (otherwise random)") -parser.add_option("--root", type="string", metavar="USERNAME", - help="choose 'root' unix username") -parser.add_option("--quiet", help="Be quiet", action="store_true") -parser.add_option("--nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true") -parser.add_option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TYPE", - help="LDB mapping module to use for the LDAP backend", - choices=["fedora-ds", "openldap"]) -parser.add_option("--ldap-backend-port", type="int", metavar="PORT", - help="TCP Port LDAP server should listen to (default ldapi only)") -parser.add_option("--server-role", type="choice", metavar="ROLE", - choices=["domain controller", "dc", "member server", "member", "standalone"], - help="Set server role to provision for (default standalone)") -parser.add_option("--targetdir", type="string", metavar="DIR", - help="Set target directory") -parser.add_option("--ol-mmr-urls", type="string", metavar="LDAPSERVER", - help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/ (where <PORT> has to be different than 389!) ] separated with whitespaces for use with OpenLDAP-MMR (Multi-Master-Replication)") -parser.add_option("--ol-olc", type="choice", metavar="OPENLDAP-OLC", - help="To setup OpenLDAP-Backend with Online-Configuration [slapd.d] choose 'yes'.", - choices=["yes", "no"]) -parser.add_option("--ol-slapd", type="string", metavar="SLAPD-PATH", - help="Path to OpenLDAP-Daemon (slapd) [e.g.:'/usr/local/libexec/slapd']. Required for Setup with OpenLDAP-Backend. OpenLDAP Version >= 2.4.17 should be used.") -parser.add_option("--testing-mode", type="choice", metavar="TESTING-MODE", - help="Do not select this option, except as part of 'make test' to verify behaviour without a slapd on the system", - choices=["yes", "no"]) - -opts = parser.parse_args()[0] - -def message(text): - """print a message if quiet is not set.""" - if not opts.quiet: - print text - -if opts.realm is None or opts.domain is None: - if opts.realm is None: - print >>sys.stderr, "No realm set" - if opts.domain is None: - print >>sys.stderr, "No domain set" - parser.print_usage() - sys.exit(1) - -smbconf = sambaopts.get_loadparm().configfile - -if opts.server_role == "dc": - server_role = "domain controller" -elif opts.server_role == "member": - server_role = "member server" -else: - server_role = opts.server_role - -setup_dir = opts.setupdir -if setup_dir is None: - setup_dir = find_setup_dir() - -provision_backend(setup_dir=setup_dir, message=message, smbconf=smbconf, targetdir=opts.targetdir, - realm=opts.realm, domain=opts.domain, - hostname=opts.host_name, - adminpass=opts.ldap_admin_pass, - root=opts.root, serverrole=server_role, - ldap_backend_type=opts.ldap_backend_type, - ldap_backend_port=opts.ldap_backend_port, - ol_mmr_urls=opts.ol_mmr_urls, - ol_olc=opts.ol_olc, - ol_slapd=opts.ol_slapd, - nosync=opts.nosync, - testing_mode=opts.testing_mode) diff --git a/source4/setup/slapd.conf b/source4/setup/slapd.conf index 6174121c77..0077a224fb 100644 --- a/source4/setup/slapd.conf +++ b/source4/setup/slapd.conf @@ -61,10 +61,16 @@ rootdn cn=Manager,cn=Samba ######################################## ## olc - configuration ### -${OLC_CONFIG_PASS} +database config +rootdn cn=config + ${OLC_SYNCREPL_CONFIG} ${OLC_MMR_CONFIG} -${OLC_CONFIG_ACL} + +access to dn.sub="cn=config" + by dn="cn=samba-admin,cn=samba" write + by dn="cn=replicator,cn=samba" read + ######################################## ### cn=schema ### diff --git a/source4/setup/tests/blackbox_provision-backend.sh b/source4/setup/tests/blackbox_provision-backend.sh index e1331d62eb..305c87ad36 100755 --- a/source4/setup/tests/blackbox_provision-backend.sh +++ b/source4/setup/tests/blackbox_provision-backend.sh @@ -12,13 +12,13 @@ shift 1 . `dirname $0`/../../../testprogs/blackbox/subunit.sh -testit "openldap-backend" $PYTHON ./setup/provision-backend --domain=FOO --realm=foo.example.com --host-name=samba --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend --testing-mode=yes --ol-slapd=/dev/null -testit "openldap-mmr-backend" $PYTHON ./setup/provision-backend --domain=FOO --realm=foo.example.com --host-name=samba --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-mmr-backend --ol-mmr-urls='ldap://localdc1:9000,ldap://localdc2:9000,ldap://localdc3:9000' --testing-mode=yes --ol-slapd=/dev/null -testit "fedora-ds-backend" $PYTHON ./setup/provision-backend --domain=FOO --realm=foo.example.com --host-name=samba --ldap-backend-type=fedora-ds --targetdir=$PREFIX/fedora-ds-backend --testing-mode=yes --ol-slapd=/dev/null +testit "openldap-backend" $PYTHON ./setup/provision --domain=FOO --realm=foo.example.com --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend --ldap-dryrun-mode --slapd-path=/dev/null +testit "openldap-mmr-backend" $PYTHON ./setup/provision --domain=FOO --realm=foo.example.com --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-mmr-backend --ol-mmr-urls='ldap://localdc1:9000,ldap://localdc2:9000,ldap://localdc3:9000' --ldap-dryrun-mode --slapd-path=/dev/null +testit "fedora-ds-backend" $PYTHON ./setup/provision --domain=FOO --realm=foo.example.com --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend --ldap-dryrun-mode --slapd-path=/dev/null reprovision() { - $PYTHON ./setup/provision-backend --domain=FOO --realm=foo.example.com --host-name=samba --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend-reprovision --testing-mode=yes --ol-slapd=/dev/null - $PYTHON ./setup/provision-backend --domain=FOO --realm=foo.example.com --host-name=samba --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend-reprovision --testing-mode=yes --ol-slapd=/dev/null + $PYTHON ./setup/provision --domain=FOO --realm=foo.example.com --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend-reprovision --ldap-dryrun-mode --slapd-path=/dev/null + $PYTHON ./setup/provision --domain=FOO --realm=foo.example.com --ldap-backend-type=openldap --targetdir=$PREFIX/openldap-backend-reprovision --ldap-dryrun-mode --slapd-path=/dev/null } testit "reprovision-backend" reprovision |