2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 """Functions for setting up a Samba configuration."""
27 from base64 import b64encode
37 from auth import system_session
38 from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
39 from samba.samdb import SamDB
40 from samba.idmap import IDmapDB
43 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
44 LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
46 __docformat__ = "restructuredText"
48 DEFAULTSITE = "Default-First-Site-Name"
50 class InvalidNetbiosName(Exception):
51 """A specified name was not a valid NetBIOS name."""
52 def __init__(self, name):
53 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
56 class ProvisionPaths(object):
69 self.dns_keytab = None
72 self.private_dir = None
75 self.modulesconf = None
76 self.memberofconf = None
77 self.fedoradsinf = None
78 self.fedoradspartitions = None
80 self.olmmrserveridsconf = None
81 self.olmmrsyncreplconf = None
83 class ProvisionNames(object):
89 self.ldapmanagerdn = None
92 self.netbiosname = None
99 class ProvisionResult(object):
106 def check_install(lp, session_info, credentials):
107 """Check whether the current install seems ok.
109 :param lp: Loadparm context
110 :param session_info: Session information
111 :param credentials: Credentials
113 if lp.get("realm") == "":
114 raise Exception("Realm empty")
115 ldb = Ldb(lp.get("sam database"), session_info=session_info,
116 credentials=credentials, lp=lp)
117 if len(ldb.search("(cn=Administrator)")) != 1:
118 raise "No administrator account found"
121 def findnss(nssfn, names):
122 """Find a user or group from a list of possibilities.
124 :param nssfn: NSS Function to try (should raise KeyError if not found)
125 :param names: Names to check.
126 :return: Value return by first names list.
133 raise KeyError("Unable to find user/group %r" % names)
136 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
137 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
140 def read_and_sub_file(file, subst_vars):
141 """Read a file and sub in variables found in it
143 :param file: File to be read (typically from setup directory)
144 param subst_vars: Optional variables to subsitute in the file.
146 data = open(file, 'r').read()
147 if subst_vars is not None:
148 data = substitute_var(data, subst_vars)
149 check_all_substituted(data)
153 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
154 """Setup a ldb in the private dir.
156 :param ldb: LDB file to import data into
157 :param ldif_path: Path of the LDIF file to load
158 :param subst_vars: Optional variables to subsitute in LDIF.
160 assert isinstance(ldif_path, str)
162 data = read_and_sub_file(ldif_path, subst_vars)
166 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
167 """Modify a ldb in the private dir.
169 :param ldb: LDB object.
170 :param ldif_path: LDIF file path.
171 :param subst_vars: Optional dictionary with substitution variables.
173 data = read_and_sub_file(ldif_path, subst_vars)
175 ldb.modify_ldif(data)
178 def setup_ldb(ldb, ldif_path, subst_vars):
179 """Import a LDIF a file into a LDB handle, optionally substituting variables.
181 :note: Either all LDIF data will be added or none (using transactions).
183 :param ldb: LDB file to import into.
184 :param ldif_path: Path to the LDIF file.
185 :param subst_vars: Dictionary with substitution variables.
187 assert ldb is not None
188 ldb.transaction_start()
190 setup_add_ldif(ldb, ldif_path, subst_vars)
192 ldb.transaction_cancel()
194 ldb.transaction_commit()
197 def setup_file(template, fname, subst_vars):
198 """Setup a file in the private dir.
200 :param template: Path of the template file.
201 :param fname: Path of the file to create.
202 :param subst_vars: Substitution variables.
206 if os.path.exists(f):
209 data = read_and_sub_file(template, subst_vars)
210 open(f, 'w').write(data)
213 def provision_paths_from_lp(lp, dnsdomain):
214 """Set the default paths for provisioning.
216 :param lp: Loadparm context.
217 :param dnsdomain: DNS Domain name
219 paths = ProvisionPaths()
220 paths.private_dir = lp.get("private dir")
221 paths.keytab = "secrets.keytab"
222 paths.dns_keytab = "dns.keytab"
224 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
225 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
226 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
227 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
228 paths.templates = os.path.join(paths.private_dir, "templates.ldb")
229 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
230 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
231 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
232 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
233 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
234 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
235 paths.phpldapadminconfig = os.path.join(paths.private_dir,
236 "phpldapadmin-config.php")
237 paths.ldapdir = os.path.join(paths.private_dir,
239 paths.slapdconf = os.path.join(paths.ldapdir,
241 paths.modulesconf = os.path.join(paths.ldapdir,
243 paths.memberofconf = os.path.join(paths.ldapdir,
245 paths.fedoradsinf = os.path.join(paths.ldapdir,
247 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
248 "mmr_serverids.conf")
249 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
251 paths.olmmron = os.path.join(paths.ldapdir,
253 paths.hklm = "hklm.ldb"
254 paths.hkcr = "hkcr.ldb"
255 paths.hkcu = "hkcu.ldb"
256 paths.hku = "hku.ldb"
257 paths.hkpd = "hkpd.ldb"
258 paths.hkpt = "hkpt.ldb"
260 paths.sysvol = lp.get("path", "sysvol")
262 paths.netlogon = lp.get("path", "netlogon")
264 paths.smbconf = lp.configfile()
269 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None,
270 rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None,
272 """Guess configuration settings to use."""
275 hostname = socket.gethostname().split(".")[0].lower()
277 netbiosname = hostname.upper()
278 if not valid_netbios_name(netbiosname):
279 raise InvalidNetbiosName(netbiosname)
281 hostname = hostname.lower()
283 if dnsdomain is None:
284 dnsdomain = lp.get("realm")
286 if serverrole is None:
287 serverrole = lp.get("server role")
289 assert dnsdomain is not None
290 realm = dnsdomain.upper()
292 if lp.get("realm").upper() != realm:
293 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
294 (lp.get("realm"), lp.configfile(), realm))
296 dnsdomain = dnsdomain.lower()
298 if serverrole == "domain controller":
300 domain = lp.get("workgroup")
302 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
303 if lp.get("workgroup").upper() != domain.upper():
304 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
305 lp.get("workgroup"), domain)
309 domaindn = "CN=" + netbiosname
311 assert domain is not None
312 domain = domain.upper()
313 if not valid_netbios_name(domain):
314 raise InvalidNetbiosName(domain)
320 configdn = "CN=Configuration," + rootdn
322 schemadn = "CN=Schema," + configdn
327 names = ProvisionNames()
328 names.rootdn = rootdn
329 names.domaindn = domaindn
330 names.configdn = configdn
331 names.schemadn = schemadn
332 names.ldapmanagerdn = "CN=Manager," + rootdn
333 names.dnsdomain = dnsdomain
334 names.domain = domain
336 names.netbiosname = netbiosname
337 names.hostname = hostname
338 names.sitename = sitename
339 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
344 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
347 hostname = socket.gethostname().split(".")[0].lower()
349 if serverrole is None:
350 serverrole = "standalone"
352 assert serverrole in ("domain controller", "member server", "standalone")
353 if serverrole == "domain controller":
355 elif serverrole == "member server":
356 smbconfsuffix = "member"
357 elif serverrole == "standalone":
358 smbconfsuffix = "standalone"
360 assert domain is not None
361 assert realm is not None
363 default_lp = param.LoadParm()
364 #Load non-existant file
365 default_lp.load(smbconf)
367 if targetdir is not None:
368 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
369 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
371 default_lp.set("lock dir", os.path.abspath(targetdir))
376 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
377 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
379 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
381 "HOSTNAME": hostname,
384 "SERVERROLE": serverrole,
385 "NETLOGONPATH": netlogon,
386 "SYSVOLPATH": sysvol,
387 "PRIVATEDIR_LINE": privatedir_line,
388 "LOCKDIR_LINE": lockdir_line
393 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
394 users_gid, wheel_gid):
395 """setup reasonable name mappings for sam names to unix names.
397 :param samdb: SamDB object.
398 :param idmap: IDmap db object.
399 :param sid: The domain sid.
400 :param domaindn: The domain DN.
401 :param root_uid: uid of the UNIX root user.
402 :param nobody_uid: uid of the UNIX nobody user.
403 :param users_gid: gid of the UNIX users group.
404 :param wheel_gid: gid of the UNIX wheel group."""
405 # add some foreign sids if they are not present already
406 samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
407 samdb.add_foreign(domaindn, "S-1-1-0", "World")
408 samdb.add_foreign(domaindn, "S-1-5-2", "Network")
409 samdb.add_foreign(domaindn, "S-1-5-18", "System")
410 samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
412 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
413 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
415 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
416 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
419 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
421 serverrole, ldap_backend=None,
422 ldap_backend_type=None, erase=False):
423 """Setup the partitions for the SAM database.
425 Alternatively, provision() may call this, and then populate the database.
427 :note: This will wipe the Sam Database!
429 :note: This function always removes the local SAM LDB file. The erase
430 parameter controls whether to erase the existing data, which
431 may not be stored locally but in LDAP.
433 assert session_info is not None
435 samdb = SamDB(samdb_path, session_info=session_info,
436 credentials=credentials, lp=lp)
442 os.unlink(samdb_path)
444 samdb = SamDB(samdb_path, session_info=session_info,
445 credentials=credentials, lp=lp)
447 #Add modules to the list to activate them by default
448 #beware often order is important
450 # Some Known ordering constraints:
451 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
452 # - objectclass must be before password_hash, because password_hash checks
453 # that the objectclass is of type person (filled in by objectclass
454 # module when expanding the objectclass list)
455 # - partition must be last
456 # - each partition has its own module list then
457 modules_list = ["rootdse",
473 modules_list2 = ["show_deleted",
476 domaindn_ldb = "users.ldb"
477 if ldap_backend is not None:
478 domaindn_ldb = ldap_backend
479 configdn_ldb = "configuration.ldb"
480 if ldap_backend is not None:
481 configdn_ldb = ldap_backend
482 schemadn_ldb = "schema.ldb"
483 if ldap_backend is not None:
484 schema_ldb = ldap_backend
485 schemadn_ldb = ldap_backend
487 if ldap_backend_type == "fedora-ds":
488 backend_modules = ["nsuniqueid", "paged_searches"]
489 # We can handle linked attributes here, as we don't have directory-side subtree operations
490 tdb_modules_list = ["linked_attributes"]
491 elif ldap_backend_type == "openldap":
492 backend_modules = ["normalise", "entryuuid", "paged_searches"]
493 # OpenLDAP handles subtree renames, so we don't want to do any of these things
494 tdb_modules_list = None
495 elif ldap_backend is not None:
496 raise "LDAP Backend specified, but LDAP Backend Type not specified"
497 elif serverrole == "domain controller":
498 backend_modules = ["repl_meta_data"]
500 backend_modules = ["objectguid"]
502 if tdb_modules_list is None:
503 tdb_modules_list_as_string = ""
505 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
507 samdb.transaction_start()
509 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
510 "SCHEMADN": names.schemadn,
511 "SCHEMADN_LDB": schemadn_ldb,
512 "SCHEMADN_MOD2": ",objectguid",
513 "CONFIGDN": names.configdn,
514 "CONFIGDN_LDB": configdn_ldb,
515 "DOMAINDN": names.domaindn,
516 "DOMAINDN_LDB": domaindn_ldb,
517 "SCHEMADN_MOD": "schema_fsmo,instancetype",
518 "CONFIGDN_MOD": "naming_fsmo,instancetype",
519 "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype",
520 "MODULES_LIST": ",".join(modules_list),
521 "TDB_MODULES_LIST": tdb_modules_list_as_string,
522 "MODULES_LIST2": ",".join(modules_list2),
523 "BACKEND_MOD": ",".join(backend_modules),
527 samdb.transaction_cancel()
530 samdb.transaction_commit()
532 samdb = SamDB(samdb_path, session_info=session_info,
533 credentials=credentials, lp=lp)
535 samdb.transaction_start()
537 message("Setting up sam.ldb attributes")
538 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
540 message("Setting up sam.ldb rootDSE")
541 setup_samdb_rootdse(samdb, setup_path, names)
544 message("Erasing data from partitions")
545 samdb.erase_partitions()
548 samdb.transaction_cancel()
551 samdb.transaction_commit()
556 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
557 netbiosname, domainsid, keytab_path, samdb_url,
558 dns_keytab_path, dnspass, machinepass):
559 """Add DC-specific bits to a secrets database.
561 :param secretsdb: Ldb Handle to the secrets database
562 :param setup_path: Setup path function
563 :param machinepass: Machine password
565 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
566 "MACHINEPASS_B64": b64encode(machinepass),
569 "DNSDOMAIN": dnsdomain,
570 "DOMAINSID": str(domainsid),
571 "SECRETS_KEYTAB": keytab_path,
572 "NETBIOSNAME": netbiosname,
573 "SAM_LDB": samdb_url,
574 "DNS_KEYTAB": dns_keytab_path,
575 "DNSPASS_B64": b64encode(dnspass),
579 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
580 """Setup the secrets database.
582 :param path: Path to the secrets database.
583 :param setup_path: Get the path to a setup file.
584 :param session_info: Session info.
585 :param credentials: Credentials
586 :param lp: Loadparm context
587 :return: LDB handle for the created secrets database
589 if os.path.exists(path):
591 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
594 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
595 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
597 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
599 if credentials is not None and credentials.authentication_requested():
600 if credentials.get_bind_dn() is not None:
601 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
602 "LDAPMANAGERDN": credentials.get_bind_dn(),
603 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
606 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
607 "LDAPADMINUSER": credentials.get_username(),
608 "LDAPADMINREALM": credentials.get_realm(),
609 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
615 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
616 """Setup the templates database.
618 :param path: Path to the database.
619 :param setup_path: Function for obtaining the path to setup files.
620 :param session_info: Session info
621 :param credentials: Credentials
622 :param lp: Loadparm context
624 templates_ldb = SamDB(path, session_info=session_info,
625 credentials=credentials, lp=lp)
626 templates_ldb.erase()
627 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
630 def setup_registry(path, setup_path, session_info, credentials, lp):
631 """Setup the registry.
633 :param path: Path to the registry database
634 :param setup_path: Function that returns the path to a setup.
635 :param session_info: Session information
636 :param credentials: Credentials
637 :param lp: Loadparm context
639 reg = registry.Registry()
640 hive = registry.open_ldb(path, session_info=session_info,
641 credentials=credentials, lp_ctx=lp)
642 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
643 provision_reg = setup_path("provision.reg")
644 assert os.path.exists(provision_reg)
645 reg.diff_apply(provision_reg)
648 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
649 """Setup the idmap database.
651 :param path: path to the idmap database
652 :param setup_path: Function that returns a path to a setup file
653 :param session_info: Session information
654 :param credentials: Credentials
655 :param lp: Loadparm context
657 if os.path.exists(path):
660 idmap_ldb = IDmapDB(path, session_info=session_info,
661 credentials=credentials, lp=lp)
664 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
668 def setup_samdb_rootdse(samdb, setup_path, names):
669 """Setup the SamDB rootdse.
671 :param samdb: Sam Database handle
672 :param setup_path: Obtain setup path
674 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
675 "SCHEMADN": names.schemadn,
676 "NETBIOSNAME": names.netbiosname,
677 "DNSDOMAIN": names.dnsdomain,
678 "REALM": names.realm,
679 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
680 "DOMAINDN": names.domaindn,
681 "ROOTDN": names.rootdn,
682 "CONFIGDN": names.configdn,
683 "SERVERDN": names.serverdn,
687 def setup_self_join(samdb, names,
688 machinepass, dnspass,
689 domainsid, invocationid, setup_path,
691 """Join a host to its own domain."""
692 assert isinstance(invocationid, str)
693 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
694 "CONFIGDN": names.configdn,
695 "SCHEMADN": names.schemadn,
696 "DOMAINDN": names.domaindn,
697 "SERVERDN": names.serverdn,
698 "INVOCATIONID": invocationid,
699 "NETBIOSNAME": names.netbiosname,
700 "DEFAULTSITE": names.sitename,
701 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
702 "MACHINEPASS_B64": b64encode(machinepass),
703 "DNSPASS_B64": b64encode(dnspass),
704 "REALM": names.realm,
705 "DOMAIN": names.domain,
706 "DNSDOMAIN": names.dnsdomain})
707 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
708 "POLICYGUID": policyguid,
709 "DNSDOMAIN": names.dnsdomain,
710 "DOMAINSID": str(domainsid),
711 "DOMAINDN": names.domaindn})
714 def setup_samdb(path, setup_path, session_info, credentials, lp,
716 domainsid, aci, domainguid, policyguid,
717 fill, adminpass, krbtgtpass,
718 machinepass, invocationid, dnspass,
719 serverrole, ldap_backend=None,
720 ldap_backend_type=None):
721 """Setup a complete SAM Database.
723 :note: This will wipe the main SAM database file!
726 erase = (fill != FILL_DRS)
728 # Also wipes the database
729 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
730 credentials=credentials, session_info=session_info,
732 ldap_backend=ldap_backend, serverrole=serverrole,
733 ldap_backend_type=ldap_backend_type, erase=erase)
735 samdb = SamDB(path, session_info=session_info,
736 credentials=credentials, lp=lp)
739 # We want to finish here, but setup the index before we do so
740 message("Setting up sam.ldb index")
741 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
744 message("Pre-loading the Samba 4 and AD schema")
745 samdb.set_domain_sid(domainsid)
746 if serverrole == "domain controller":
747 samdb.set_invocation_id(invocationid)
749 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
750 names.configdn, names.sitename, names.serverdn,
753 samdb.transaction_start()
756 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
757 if serverrole == "domain controller":
758 domain_oc = "domainDNS"
760 domain_oc = "samba4LocalDomain"
762 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
763 "DOMAINDN": names.domaindn,
765 "DOMAIN_OC": domain_oc
768 message("Modifying DomainDN: " + names.domaindn + "")
769 if domainguid is not None:
770 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
774 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
775 "LDAPTIME": timestring(int(time.time())),
776 "DOMAINSID": str(domainsid),
777 "SCHEMADN": names.schemadn,
778 "NETBIOSNAME": names.netbiosname,
779 "DEFAULTSITE": names.sitename,
780 "CONFIGDN": names.configdn,
781 "SERVERDN": names.serverdn,
782 "POLICYGUID": policyguid,
783 "DOMAINDN": names.domaindn,
784 "DOMAINGUID_MOD": domainguid_mod,
787 message("Adding configuration container (permitted to fail)")
788 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
789 "CONFIGDN": names.configdn,
792 message("Modifying configuration container")
793 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
794 "CONFIGDN": names.configdn,
795 "SCHEMADN": names.schemadn,
798 message("Adding schema container (permitted to fail)")
799 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
800 "SCHEMADN": names.schemadn,
803 message("Modifying schema container")
805 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
807 setup_modify_ldif(samdb,
808 setup_path("provision_schema_basedn_modify.ldif"), {
809 "SCHEMADN": names.schemadn,
810 "NETBIOSNAME": names.netbiosname,
811 "DEFAULTSITE": names.sitename,
812 "CONFIGDN": names.configdn,
813 "SERVERDN": names.serverdn,
814 "PREFIXMAP_B64": b64encode(prefixmap)
817 message("Setting up sam.ldb Samba4 schema")
818 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
819 {"SCHEMADN": names.schemadn })
820 message("Setting up sam.ldb AD schema")
821 setup_add_ldif(samdb, setup_path("schema.ldif"),
822 {"SCHEMADN": names.schemadn})
824 message("Setting up sam.ldb configuration data")
825 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
826 "CONFIGDN": names.configdn,
827 "NETBIOSNAME": names.netbiosname,
828 "DEFAULTSITE": names.sitename,
829 "DNSDOMAIN": names.dnsdomain,
830 "DOMAIN": names.domain,
831 "SCHEMADN": names.schemadn,
832 "DOMAINDN": names.domaindn,
833 "SERVERDN": names.serverdn
836 message("Setting up display specifiers")
837 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
838 {"CONFIGDN": names.configdn})
840 message("Adding users container (permitted to fail)")
841 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
842 "DOMAINDN": names.domaindn})
843 message("Modifying users container")
844 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
845 "DOMAINDN": names.domaindn})
846 message("Adding computers container (permitted to fail)")
847 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
848 "DOMAINDN": names.domaindn})
849 message("Modifying computers container")
850 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
851 "DOMAINDN": names.domaindn})
852 message("Setting up sam.ldb data")
853 setup_add_ldif(samdb, setup_path("provision.ldif"), {
854 "DOMAINDN": names.domaindn,
855 "NETBIOSNAME": names.netbiosname,
856 "DEFAULTSITE": names.sitename,
857 "CONFIGDN": names.configdn,
858 "SERVERDN": names.serverdn
861 if fill == FILL_FULL:
862 message("Setting up sam.ldb users and groups")
863 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
864 "DOMAINDN": names.domaindn,
865 "DOMAINSID": str(domainsid),
866 "CONFIGDN": names.configdn,
867 "ADMINPASS_B64": b64encode(adminpass),
868 "KRBTGTPASS_B64": b64encode(krbtgtpass),
871 if serverrole == "domain controller":
872 message("Setting up self join")
873 setup_self_join(samdb, names=names, invocationid=invocationid,
875 machinepass=machinepass,
876 domainsid=domainsid, policyguid=policyguid,
877 setup_path=setup_path)
879 #We want to setup the index last, as adds are faster unindexed
880 message("Setting up sam.ldb index")
881 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
883 samdb.transaction_cancel()
886 samdb.transaction_commit()
891 FILL_NT4SYNC = "NT4SYNC"
894 def provision(setup_dir, message, session_info,
895 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
896 rootdn=None, domaindn=None, schemadn=None, configdn=None,
898 domain=None, hostname=None, hostip=None, hostip6=None,
899 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
900 policyguid=None, invocationid=None, machinepass=None,
901 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
902 wheel=None, backup=None, aci=None, serverrole=None,
903 ldap_backend=None, ldap_backend_type=None, sitename=None):
906 :note: caution, this wipes all existing data!
909 def setup_path(file):
910 return os.path.join(setup_dir, file)
912 if domainsid is None:
913 domainsid = security.random_sid()
915 domainsid = security.Sid(domainsid)
917 if policyguid is None:
918 policyguid = str(uuid.uuid4())
919 if adminpass is None:
920 adminpass = misc.random_password(12)
921 if krbtgtpass is None:
922 krbtgtpass = misc.random_password(12)
923 if machinepass is None:
924 machinepass = misc.random_password(12)
926 dnspass = misc.random_password(12)
927 root_uid = findnss_uid([root or "root"])
928 nobody_uid = findnss_uid([nobody or "nobody"])
929 users_gid = findnss_gid([users or "users"])
931 wheel_gid = findnss_gid(["wheel", "adm"])
933 wheel_gid = findnss_gid([wheel])
935 aci = "# no aci for local ldb"
937 if targetdir is not None:
938 if (not os.path.exists(os.path.join(targetdir, "etc"))):
939 os.makedirs(os.path.join(targetdir, "etc"))
940 smbconf = os.path.join(targetdir, "etc", "smb.conf")
942 # only install a new smb.conf if there isn't one there already
943 if not os.path.exists(smbconf):
944 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
947 lp = param.LoadParm()
950 names = guess_names(lp=lp, hostname=hostname, domain=domain,
951 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
952 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
955 paths = provision_paths_from_lp(lp, names.dnsdomain)
958 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
962 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
963 except socket.gaierror:
966 if serverrole is None:
967 serverrole = lp.get("server role")
969 assert serverrole in ("domain controller", "member server", "standalone")
970 if invocationid is None and serverrole == "domain controller":
971 invocationid = str(uuid.uuid4())
973 if not os.path.exists(paths.private_dir):
974 os.mkdir(paths.private_dir)
976 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
978 if ldap_backend is not None:
979 if ldap_backend == "ldapi":
980 # provision-backend will set this path suggested slapd command line / fedorads.inf
981 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
983 # only install a new shares config db if there is none
984 if not os.path.exists(paths.shareconf):
985 message("Setting up share.ldb")
986 share_ldb = Ldb(paths.shareconf, session_info=session_info,
987 credentials=credentials, lp=lp)
988 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
991 message("Setting up secrets.ldb")
992 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
993 session_info=session_info,
994 credentials=credentials, lp=lp)
996 message("Setting up the registry")
997 setup_registry(paths.hklm, setup_path, session_info,
998 credentials=credentials, lp=lp)
1000 message("Setting up templates db")
1001 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
1002 credentials=credentials, lp=lp)
1004 message("Setting up idmap db")
1005 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1006 credentials=credentials, lp=lp)
1008 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1009 credentials=credentials, lp=lp, names=names,
1011 domainsid=domainsid,
1012 aci=aci, domainguid=domainguid, policyguid=policyguid,
1014 adminpass=adminpass, krbtgtpass=krbtgtpass,
1015 invocationid=invocationid,
1016 machinepass=machinepass, dnspass=dnspass,
1017 serverrole=serverrole, ldap_backend=ldap_backend,
1018 ldap_backend_type=ldap_backend_type)
1020 if lp.get("server role") == "domain controller":
1021 if paths.netlogon is None:
1022 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1023 message("Please either remove %s or see the template at %s" %
1024 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1025 assert(paths.netlogon is not None)
1027 if paths.sysvol is None:
1028 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1029 message("Please either remove %s or see the template at %s" %
1030 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1031 assert(paths.sysvol is not None)
1033 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1034 "{" + policyguid + "}")
1035 os.makedirs(policy_path, 0755)
1036 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1037 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1038 os.makedirs(os.path.join(policy_path, "User"), 0755)
1039 if not os.path.isdir(paths.netlogon):
1040 os.makedirs(paths.netlogon, 0755)
1042 if samdb_fill == FILL_FULL:
1043 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1044 root_uid=root_uid, nobody_uid=nobody_uid,
1045 users_gid=users_gid, wheel_gid=wheel_gid)
1047 message("Setting up sam.ldb rootDSE marking as synchronized")
1048 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1050 # Only make a zone file on the first DC, it should be replicated with DNS replication
1051 if serverrole == "domain controller":
1052 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1053 credentials=credentials, lp=lp)
1054 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1055 netbiosname=names.netbiosname, domainsid=domainsid,
1056 keytab_path=paths.keytab, samdb_url=paths.samdb,
1057 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1058 machinepass=machinepass, dnsdomain=names.dnsdomain)
1060 samdb = SamDB(paths.samdb, session_info=session_info,
1061 credentials=credentials, lp=lp)
1063 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1064 assert isinstance(domainguid, str)
1065 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1066 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1067 scope=SCOPE_SUBTREE)
1068 assert isinstance(hostguid, str)
1070 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1071 domaindn=names.domaindn, hostip=hostip,
1072 hostip6=hostip6, hostname=names.hostname,
1073 dnspass=dnspass, realm=names.realm,
1074 domainguid=domainguid, hostguid=hostguid)
1076 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1077 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1079 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1080 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1081 keytab_name=paths.dns_keytab)
1082 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1083 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1085 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1086 hostname=names.hostname, realm=names.realm)
1087 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1089 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1092 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1094 message("Once the above files are installed, your Samba4 server will be ready to use")
1095 message("Server Role: %s" % serverrole)
1096 message("Hostname: %s" % names.hostname)
1097 message("NetBIOS Domain: %s" % names.domain)
1098 message("DNS Domain: %s" % names.dnsdomain)
1099 message("DOMAIN SID: %s" % str(domainsid))
1100 message("Admin password: %s" % adminpass)
1102 result = ProvisionResult()
1103 result.domaindn = domaindn
1104 result.paths = paths
1106 result.samdb = samdb
1110 def provision_become_dc(setup_dir=None,
1111 smbconf=None, targetdir=None, realm=None,
1112 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1114 domain=None, hostname=None, domainsid=None,
1115 adminpass=None, krbtgtpass=None, domainguid=None,
1116 policyguid=None, invocationid=None, machinepass=None,
1117 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1118 wheel=None, backup=None, aci=None, serverrole=None,
1119 ldap_backend=None, ldap_backend_type=None, sitename=None):
1122 """print a message if quiet is not set."""
1125 return provision(setup_dir, message, system_session(), None,
1126 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1127 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1128 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1131 def setup_db_config(setup_path, dbdir):
1132 """Setup a Berkeley database.
1134 :param setup_path: Setup path function.
1135 :param dbdir: Database directory."""
1136 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1137 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1138 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1139 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1141 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1142 {"LDAPDBDIR": dbdir})
1146 def provision_backend(setup_dir=None, message=None,
1147 smbconf=None, targetdir=None, realm=None,
1148 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1149 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1150 ldap_backend_type=None, ldap_backend_port=None,
1151 ol_mmr_urls=None, mmr_serverids_config=None, mmr_on_config=None,
1152 mmr_syncrepl_schema_config=None,
1153 mmr_syncrepl_config_config=None,
1154 mmr_syncrepl_user_config=None ):
1156 def setup_path(file):
1157 return os.path.join(setup_dir, file)
1159 if hostname is None:
1160 hostname = socket.gethostname().split(".")[0].lower()
1163 root = findnss(pwd.getpwnam, ["root"])[0]
1165 if adminpass is None:
1166 adminpass = misc.random_password(12)
1168 if targetdir is not None:
1169 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1170 os.makedirs(os.path.join(targetdir, "etc"))
1171 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1173 # only install a new smb.conf if there isn't one there already
1174 if not os.path.exists(smbconf):
1175 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1178 lp = param.LoadParm()
1181 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1182 dnsdomain=realm, serverrole=serverrole,
1183 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1186 paths = provision_paths_from_lp(lp, names.dnsdomain)
1188 if not os.path.isdir(paths.ldapdir):
1189 os.makedirs(paths.ldapdir, 0700)
1190 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1192 os.unlink(schemadb_path)
1196 schemadb = Ldb(schemadb_path, lp=lp)
1198 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1200 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1201 {"SCHEMADN": names.schemadn,
1204 setup_modify_ldif(schemadb,
1205 setup_path("provision_schema_basedn_modify.ldif"), \
1206 {"SCHEMADN": names.schemadn,
1207 "NETBIOSNAME": names.netbiosname,
1208 "DEFAULTSITE": DEFAULTSITE,
1209 "CONFIGDN": names.configdn,
1210 "SERVERDN": names.serverdn,
1211 "PREFIXMAP_B64": b64encode(prefixmap)
1214 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1215 {"SCHEMADN": names.schemadn })
1216 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1217 {"SCHEMADN": names.schemadn})
1219 if ldap_backend_type == "fedora-ds":
1220 if ldap_backend_port is not None:
1221 serverport = "ServerPort=%d" % ldap_backend_port
1225 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1227 "HOSTNAME": hostname,
1228 "DNSDOMAIN": names.dnsdomain,
1229 "LDAPDIR": paths.ldapdir,
1230 "DOMAINDN": names.domaindn,
1231 "LDAPMANAGERDN": names.ldapmanagerdn,
1232 "LDAPMANAGERPASS": adminpass,
1233 "SERVERPORT": serverport})
1235 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1236 {"CONFIGDN": names.configdn,
1237 "SCHEMADN": names.schemadn,
1240 mapping = "schema-map-fedora-ds-1.0"
1241 backend_schema = "99_ad.ldif"
1243 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1245 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1247 elif ldap_backend_type == "openldap":
1248 attrs = ["linkID", "lDAPDisplayName"]
1249 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1251 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1252 refint_attributes = ""
1253 for i in range (0, len(res)):
1254 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1255 target = schemadb.searchone(basedn=names.schemadn,
1256 expression=expression,
1257 attribute="lDAPDisplayName",
1258 scope=SCOPE_SUBTREE)
1259 if target is not None:
1260 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1262 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1263 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1264 "MEMBEROF_ATTR" : str(target) })
1266 refint_config = read_and_sub_file(setup_path("refint.conf"),
1267 { "LINK_ATTRS" : refint_attributes})
1269 ########################################################
1270 ### generate serverids and ldap-urls for mmr hosts ###
1271 ########################################################
1274 mmr_serverids_config = " "
1276 if ol_mmr_urls is not None:
1277 mmr_hosts=ol_mmr_urls
1278 mmr_hosts=filter(None,mmr_hosts.split(' '))
1280 mmr_serverids_config = "# Generated from template mmr_serverids.conf\n"
1284 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1285 { "SERVERID" : str(z),
1287 mmr_on_config = "MirrorMode On"
1289 ########################################################
1290 ### generate syncrepl-blocks for mmr hosts ###
1291 ########################################################
1293 mmr_syncrepl_schema_config = " "
1294 mmr_syncrepl_config_config = " "
1295 mmr_syncrepl_user_config = " "
1297 if ol_mmr_urls is not None:
1298 mmr_hosts=ol_mmr_urls
1299 mmr_hosts=filter(None,mmr_hosts.split(' '))
1300 mmr_syncrepl_schema_config = "# Generated from template mmr_syncrepl.conf\n"
1301 mmr_syncrepl_config_config = "# Generated from template mmr_syncrepl.conf\n"
1302 mmr_syncrepl_user_config = "# Generated from template mmr_syncrepl.conf\n"
1306 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1308 "MMRDN": names.schemadn,
1313 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1315 "MMRDN": names.configdn,
1320 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1322 "MMRDN": names.domaindn,
1326 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1327 {"DNSDOMAIN": names.dnsdomain,
1328 "LDAPDIR": paths.ldapdir,
1329 "DOMAINDN": names.domaindn,
1330 "CONFIGDN": names.configdn,
1331 "SCHEMADN": names.schemadn,
1332 "MEMBEROF_CONFIG": memberof_config,
1333 "MIRRORMODE": mmr_on_config,
1334 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1335 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1336 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1337 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1338 "REFINT_CONFIG": refint_config})
1339 setup_file(setup_path("modules.conf"), paths.modulesconf,
1340 {"REALM": names.realm})
1342 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1343 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1344 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1346 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1347 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1349 setup_file(setup_path("cn=samba.ldif"),
1350 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1351 { "UUID": str(uuid.uuid4()),
1352 "LDAPTIME": timestring(int(time.time()))} )
1353 setup_file(setup_path("cn=samba-admin.ldif"),
1354 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1355 {"LDAPADMINPASS_B64": b64encode(adminpass),
1356 "UUID": str(uuid.uuid4()),
1357 "LDAPTIME": timestring(int(time.time()))} )
1359 mapping = "schema-map-openldap-2.3"
1360 backend_schema = "backend-schema.schema"
1362 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1363 if ldap_backend_port is not None:
1364 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1366 server_port_string = ""
1368 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1370 ldapuser = "--username=samba-admin"
1373 schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema)
1375 os.system(schema_command)
1377 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1378 message("Server Role: %s" % serverrole)
1379 message("Hostname: %s" % names.hostname)
1380 message("DNS Domain: %s" % names.dnsdomain)
1381 message("Base DN: %s" % names.domaindn)
1383 if ldap_backend_type == "openldap":
1384 message("LDAP admin user: samba-admin")
1386 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1388 message("LDAP admin password: %s" % adminpass)
1389 message(slapdcommand)
1390 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1392 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1393 """Create a PHP LDAP admin configuration file.
1395 :param path: Path to write the configuration to.
1396 :param setup_path: Function to generate setup paths.
1398 setup_file(setup_path("phpldapadmin-config.php"), path,
1399 {"S4_LDAPI_URI": ldapi_uri})
1402 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1403 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1404 """Write out a DNS zone file, from the info in the current database.
1406 :param path: Path of the new zone file.
1407 :param setup_path: Setup path function.
1408 :param dnsdomain: DNS Domain name
1409 :param domaindn: DN of the Domain
1410 :param hostip: Local IPv4 IP
1411 :param hostip6: Local IPv6 IP
1412 :param hostname: Local hostname
1413 :param dnspass: Password for DNS
1414 :param realm: Realm name
1415 :param domainguid: GUID of the domain.
1416 :param hostguid: GUID of the host.
1418 assert isinstance(domainguid, str)
1420 if hostip6 is not None:
1421 hostip6_base_line = " IN AAAA " + hostip6
1422 hostip6_host_line = hostname + " IN AAAA " + hostip6
1424 hostip6_base_line = ""
1425 hostip6_host_line = ""
1427 setup_file(setup_path("provision.zone"), path, {
1428 "DNSPASS_B64": b64encode(dnspass),
1429 "HOSTNAME": hostname,
1430 "DNSDOMAIN": dnsdomain,
1433 "DOMAINGUID": domainguid,
1434 "DATESTRING": time.strftime("%Y%m%d%H"),
1435 "DEFAULTSITE": DEFAULTSITE,
1436 "HOSTGUID": hostguid,
1437 "HOSTIP6_BASE_LINE": hostip6_base_line,
1438 "HOSTIP6_HOST_LINE": hostip6_host_line,
1442 def create_named_conf(path, setup_path, realm, dnsdomain,
1444 """Write out a file containing zone statements suitable for inclusion in a
1445 named.conf file (including GSS-TSIG configuration).
1447 :param path: Path of the new named.conf file.
1448 :param setup_path: Setup path function.
1449 :param realm: Realm name
1450 :param dnsdomain: DNS Domain name
1451 :param private_dir: Path to private directory
1452 :param keytab_name: File name of DNS keytab file
1455 setup_file(setup_path("named.conf"), path, {
1456 "DNSDOMAIN": dnsdomain,
1458 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1459 "PRIVATE_DIR": private_dir
1462 def create_named_txt(path, setup_path, realm, dnsdomain,
1463 private_dir, keytab_name):
1464 """Write out a file containing zone statements suitable for inclusion in a
1465 named.conf file (including GSS-TSIG configuration).
1467 :param path: Path of the new named.conf file.
1468 :param setup_path: Setup path function.
1469 :param realm: Realm name
1470 :param dnsdomain: DNS Domain name
1471 :param private_dir: Path to private directory
1472 :param keytab_name: File name of DNS keytab file
1475 setup_file(setup_path("named.txt"), path, {
1476 "DNSDOMAIN": dnsdomain,
1478 "DNS_KEYTAB": keytab_name,
1479 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1480 "PRIVATE_DIR": private_dir
1483 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1484 """Write out a file containing zone statements suitable for inclusion in a
1485 named.conf file (including GSS-TSIG configuration).
1487 :param path: Path of the new named.conf file.
1488 :param setup_path: Setup path function.
1489 :param dnsdomain: DNS Domain name
1490 :param hostname: Local hostname
1491 :param realm: Realm name
1494 setup_file(setup_path("krb5.conf"), path, {
1495 "DNSDOMAIN": dnsdomain,
1496 "HOSTNAME": hostname,
1501 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
1502 serverdn, servername):
1503 """Load schema for the SamDB.
1505 :param samdb: Load a schema into a SamDB.
1506 :param setup_path: Setup path function.
1507 :param schemadn: DN of the schema
1508 :param netbiosname: NetBIOS name of the host.
1509 :param configdn: DN of the configuration
1510 :param serverdn: DN of the server
1511 :param servername: Host name of the server
1513 schema_data = open(setup_path("schema.ldif"), 'r').read()
1514 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1515 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1516 check_all_substituted(schema_data)
1517 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1518 prefixmap = b64encode(prefixmap)
1520 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1521 head_data = substitute_var(head_data, {
1522 "SCHEMADN": schemadn,
1523 "NETBIOSNAME": netbiosname,
1524 "CONFIGDN": configdn,
1525 "DEFAULTSITE": sitename,
1526 "PREFIXMAP_B64": prefixmap,
1527 "SERVERDN": serverdn,
1528 "SERVERNAME": servername,
1530 check_all_substituted(head_data)
1531 samdb.attach_schema_from_ldif(head_data, schema_data)