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.fedoradspartitions = os.path.join(paths.ldapdir,
248 "fedorads-partitions.ldif")
249 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
250 "mmr_serverids.conf")
251 paths.olmmrsyncreplconf = 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",
475 "extended_dn_out_ldb"]
476 modules_list2 = ["show_deleted",
479 domaindn_ldb = "users.ldb"
480 if ldap_backend is not None:
481 domaindn_ldb = ldap_backend
482 configdn_ldb = "configuration.ldb"
483 if ldap_backend is not None:
484 configdn_ldb = ldap_backend
485 schemadn_ldb = "schema.ldb"
486 if ldap_backend is not None:
487 schema_ldb = ldap_backend
488 schemadn_ldb = ldap_backend
490 if ldap_backend_type == "fedora-ds":
491 backend_modules = ["nsuniqueid", "paged_searches"]
492 # We can handle linked attributes here, as we don't have directory-side subtree operations
493 tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
494 elif ldap_backend_type == "openldap":
495 backend_modules = ["normalise", "entryuuid", "paged_searches"]
496 # OpenLDAP handles subtree renames, so we don't want to do any of these things
497 tdb_modules_list = ["extended_dn_out_dereference"]
498 elif ldap_backend is not None:
499 raise "LDAP Backend specified, but LDAP Backend Type not specified"
500 elif serverrole == "domain controller":
501 backend_modules = ["repl_meta_data"]
503 backend_modules = ["objectguid"]
505 if tdb_modules_list is None:
506 tdb_modules_list_as_string = ""
508 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
510 samdb.transaction_start()
512 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
513 "SCHEMADN": names.schemadn,
514 "SCHEMADN_LDB": schemadn_ldb,
515 "SCHEMADN_MOD2": ",objectguid",
516 "CONFIGDN": names.configdn,
517 "CONFIGDN_LDB": configdn_ldb,
518 "DOMAINDN": names.domaindn,
519 "DOMAINDN_LDB": domaindn_ldb,
520 "SCHEMADN_MOD": "schema_fsmo,instancetype",
521 "CONFIGDN_MOD": "naming_fsmo,instancetype",
522 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
523 "MODULES_LIST": ",".join(modules_list),
524 "TDB_MODULES_LIST": tdb_modules_list_as_string,
525 "MODULES_LIST2": ",".join(modules_list2),
526 "BACKEND_MOD": ",".join(backend_modules),
530 samdb.transaction_cancel()
533 samdb.transaction_commit()
535 samdb = SamDB(samdb_path, session_info=session_info,
536 credentials=credentials, lp=lp)
538 samdb.transaction_start()
540 message("Setting up sam.ldb attributes")
541 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
543 message("Setting up sam.ldb rootDSE")
544 setup_samdb_rootdse(samdb, setup_path, names)
547 message("Erasing data from partitions")
548 samdb.erase_partitions()
551 samdb.transaction_cancel()
554 samdb.transaction_commit()
559 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
560 netbiosname, domainsid, keytab_path, samdb_url,
561 dns_keytab_path, dnspass, machinepass):
562 """Add DC-specific bits to a secrets database.
564 :param secretsdb: Ldb Handle to the secrets database
565 :param setup_path: Setup path function
566 :param machinepass: Machine password
568 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
569 "MACHINEPASS_B64": b64encode(machinepass),
572 "DNSDOMAIN": dnsdomain,
573 "DOMAINSID": str(domainsid),
574 "SECRETS_KEYTAB": keytab_path,
575 "NETBIOSNAME": netbiosname,
576 "SAM_LDB": samdb_url,
577 "DNS_KEYTAB": dns_keytab_path,
578 "DNSPASS_B64": b64encode(dnspass),
582 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
583 """Setup the secrets database.
585 :param path: Path to the secrets database.
586 :param setup_path: Get the path to a setup file.
587 :param session_info: Session info.
588 :param credentials: Credentials
589 :param lp: Loadparm context
590 :return: LDB handle for the created secrets database
592 if os.path.exists(path):
594 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
597 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
598 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
600 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
602 if credentials is not None and credentials.authentication_requested():
603 if credentials.get_bind_dn() is not None:
604 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
605 "LDAPMANAGERDN": credentials.get_bind_dn(),
606 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
609 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
610 "LDAPADMINUSER": credentials.get_username(),
611 "LDAPADMINREALM": credentials.get_realm(),
612 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
618 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
619 """Setup the templates database.
621 :param path: Path to the database.
622 :param setup_path: Function for obtaining the path to setup files.
623 :param session_info: Session info
624 :param credentials: Credentials
625 :param lp: Loadparm context
627 templates_ldb = SamDB(path, session_info=session_info,
628 credentials=credentials, lp=lp)
631 templates_ldb.erase()
635 templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
637 templates_ldb = SamDB(path, session_info=session_info,
638 credentials=credentials, lp=lp)
640 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
643 def setup_registry(path, setup_path, session_info, credentials, lp):
644 """Setup the registry.
646 :param path: Path to the registry database
647 :param setup_path: Function that returns the path to a setup.
648 :param session_info: Session information
649 :param credentials: Credentials
650 :param lp: Loadparm context
652 reg = registry.Registry()
653 hive = registry.open_ldb(path, session_info=session_info,
654 credentials=credentials, lp_ctx=lp)
655 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
656 provision_reg = setup_path("provision.reg")
657 assert os.path.exists(provision_reg)
658 reg.diff_apply(provision_reg)
661 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
662 """Setup the idmap database.
664 :param path: path to the idmap database
665 :param setup_path: Function that returns a path to a setup file
666 :param session_info: Session information
667 :param credentials: Credentials
668 :param lp: Loadparm context
670 if os.path.exists(path):
673 idmap_ldb = IDmapDB(path, session_info=session_info,
674 credentials=credentials, lp=lp)
677 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
681 def setup_samdb_rootdse(samdb, setup_path, names):
682 """Setup the SamDB rootdse.
684 :param samdb: Sam Database handle
685 :param setup_path: Obtain setup path
687 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
688 "SCHEMADN": names.schemadn,
689 "NETBIOSNAME": names.netbiosname,
690 "DNSDOMAIN": names.dnsdomain,
691 "REALM": names.realm,
692 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
693 "DOMAINDN": names.domaindn,
694 "ROOTDN": names.rootdn,
695 "CONFIGDN": names.configdn,
696 "SERVERDN": names.serverdn,
700 def setup_self_join(samdb, names,
701 machinepass, dnspass,
702 domainsid, invocationid, setup_path,
704 """Join a host to its own domain."""
705 assert isinstance(invocationid, str)
706 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
707 "CONFIGDN": names.configdn,
708 "SCHEMADN": names.schemadn,
709 "DOMAINDN": names.domaindn,
710 "SERVERDN": names.serverdn,
711 "INVOCATIONID": invocationid,
712 "NETBIOSNAME": names.netbiosname,
713 "DEFAULTSITE": names.sitename,
714 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
715 "MACHINEPASS_B64": b64encode(machinepass),
716 "DNSPASS_B64": b64encode(dnspass),
717 "REALM": names.realm,
718 "DOMAIN": names.domain,
719 "DNSDOMAIN": names.dnsdomain})
720 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
721 "POLICYGUID": policyguid,
722 "DNSDOMAIN": names.dnsdomain,
723 "DOMAINSID": str(domainsid),
724 "DOMAINDN": names.domaindn})
727 def setup_samdb(path, setup_path, session_info, credentials, lp,
729 domainsid, aci, domainguid, policyguid,
730 fill, adminpass, krbtgtpass,
731 machinepass, invocationid, dnspass,
732 serverrole, ldap_backend=None,
733 ldap_backend_type=None):
734 """Setup a complete SAM Database.
736 :note: This will wipe the main SAM database file!
739 erase = (fill != FILL_DRS)
741 # Also wipes the database
742 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
743 credentials=credentials, session_info=session_info,
745 ldap_backend=ldap_backend, serverrole=serverrole,
746 ldap_backend_type=ldap_backend_type, erase=erase)
748 samdb = SamDB(path, session_info=session_info,
749 credentials=credentials, lp=lp)
753 message("Pre-loading the Samba 4 and AD schema")
754 samdb.set_domain_sid(domainsid)
755 if serverrole == "domain controller":
756 samdb.set_invocation_id(invocationid)
758 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
759 names.configdn, names.sitename, names.serverdn,
762 samdb.transaction_start()
765 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
766 if serverrole == "domain controller":
767 domain_oc = "domainDNS"
769 domain_oc = "samba4LocalDomain"
771 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
772 "DOMAINDN": names.domaindn,
774 "DOMAIN_OC": domain_oc
777 message("Modifying DomainDN: " + names.domaindn + "")
778 if domainguid is not None:
779 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
783 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
784 "LDAPTIME": timestring(int(time.time())),
785 "DOMAINSID": str(domainsid),
786 "SCHEMADN": names.schemadn,
787 "NETBIOSNAME": names.netbiosname,
788 "DEFAULTSITE": names.sitename,
789 "CONFIGDN": names.configdn,
790 "SERVERDN": names.serverdn,
791 "POLICYGUID": policyguid,
792 "DOMAINDN": names.domaindn,
793 "DOMAINGUID_MOD": domainguid_mod,
796 message("Adding configuration container (permitted to fail)")
797 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
798 "CONFIGDN": names.configdn,
801 message("Modifying configuration container")
802 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
803 "CONFIGDN": names.configdn,
804 "SCHEMADN": names.schemadn,
807 message("Adding schema container (permitted to fail)")
808 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
809 "SCHEMADN": names.schemadn,
812 message("Modifying schema container")
814 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
816 setup_modify_ldif(samdb,
817 setup_path("provision_schema_basedn_modify.ldif"), {
818 "SCHEMADN": names.schemadn,
819 "NETBIOSNAME": names.netbiosname,
820 "DEFAULTSITE": names.sitename,
821 "CONFIGDN": names.configdn,
822 "SERVERDN": names.serverdn,
823 "PREFIXMAP_B64": b64encode(prefixmap)
826 message("Setting up sam.ldb Samba4 schema")
827 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
828 {"SCHEMADN": names.schemadn })
829 message("Setting up sam.ldb AD schema")
830 setup_add_ldif(samdb, setup_path("schema.ldif"),
831 {"SCHEMADN": names.schemadn})
833 message("Setting up sam.ldb configuration data")
834 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
835 "CONFIGDN": names.configdn,
836 "NETBIOSNAME": names.netbiosname,
837 "DEFAULTSITE": names.sitename,
838 "DNSDOMAIN": names.dnsdomain,
839 "DOMAIN": names.domain,
840 "SCHEMADN": names.schemadn,
841 "DOMAINDN": names.domaindn,
842 "SERVERDN": names.serverdn
845 message("Setting up display specifiers")
846 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
847 {"CONFIGDN": names.configdn})
849 message("Adding users container (permitted to fail)")
850 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
851 "DOMAINDN": names.domaindn})
852 message("Modifying users container")
853 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
854 "DOMAINDN": names.domaindn})
855 message("Adding computers container (permitted to fail)")
856 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
857 "DOMAINDN": names.domaindn})
858 message("Modifying computers container")
859 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
860 "DOMAINDN": names.domaindn})
861 message("Setting up sam.ldb data")
862 setup_add_ldif(samdb, setup_path("provision.ldif"), {
863 "DOMAINDN": names.domaindn,
864 "NETBIOSNAME": names.netbiosname,
865 "DEFAULTSITE": names.sitename,
866 "CONFIGDN": names.configdn,
867 "SERVERDN": names.serverdn
870 if fill == FILL_FULL:
871 message("Setting up sam.ldb users and groups")
872 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
873 "DOMAINDN": names.domaindn,
874 "DOMAINSID": str(domainsid),
875 "CONFIGDN": names.configdn,
876 "ADMINPASS_B64": b64encode(adminpass),
877 "KRBTGTPASS_B64": b64encode(krbtgtpass),
880 if serverrole == "domain controller":
881 message("Setting up self join")
882 setup_self_join(samdb, names=names, invocationid=invocationid,
884 machinepass=machinepass,
885 domainsid=domainsid, policyguid=policyguid,
886 setup_path=setup_path)
889 samdb.transaction_cancel()
892 samdb.transaction_commit()
897 FILL_NT4SYNC = "NT4SYNC"
900 def provision(setup_dir, message, session_info,
901 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
902 rootdn=None, domaindn=None, schemadn=None, configdn=None,
904 domain=None, hostname=None, hostip=None, hostip6=None,
905 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
906 policyguid=None, invocationid=None, machinepass=None,
907 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
908 wheel=None, backup=None, aci=None, serverrole=None,
909 ldap_backend=None, ldap_backend_type=None, sitename=None):
912 :note: caution, this wipes all existing data!
915 def setup_path(file):
916 return os.path.join(setup_dir, file)
918 if domainsid is None:
919 domainsid = security.random_sid()
921 domainsid = security.Sid(domainsid)
923 if policyguid is None:
924 policyguid = str(uuid.uuid4())
925 if adminpass is None:
926 adminpass = misc.random_password(12)
927 if krbtgtpass is None:
928 krbtgtpass = misc.random_password(12)
929 if machinepass is None:
930 machinepass = misc.random_password(12)
932 dnspass = misc.random_password(12)
933 root_uid = findnss_uid([root or "root"])
934 nobody_uid = findnss_uid([nobody or "nobody"])
935 users_gid = findnss_gid([users or "users"])
937 wheel_gid = findnss_gid(["wheel", "adm"])
939 wheel_gid = findnss_gid([wheel])
941 aci = "# no aci for local ldb"
943 if targetdir is not None:
944 if (not os.path.exists(os.path.join(targetdir, "etc"))):
945 os.makedirs(os.path.join(targetdir, "etc"))
946 smbconf = os.path.join(targetdir, "etc", "smb.conf")
948 # only install a new smb.conf if there isn't one there already
949 if not os.path.exists(smbconf):
950 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
953 lp = param.LoadParm()
956 names = guess_names(lp=lp, hostname=hostname, domain=domain,
957 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
958 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
961 paths = provision_paths_from_lp(lp, names.dnsdomain)
965 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
966 except socket.gaierror, (socket.EAI_NODATA, msg):
971 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
972 except socket.gaierror, (socket.EAI_NODATA, msg):
975 if serverrole is None:
976 serverrole = lp.get("server role")
978 assert serverrole in ("domain controller", "member server", "standalone")
979 if invocationid is None and serverrole == "domain controller":
980 invocationid = str(uuid.uuid4())
982 if not os.path.exists(paths.private_dir):
983 os.mkdir(paths.private_dir)
985 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
987 if ldap_backend is not None:
988 if ldap_backend == "ldapi":
989 # provision-backend will set this path suggested slapd command line / fedorads.inf
990 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
992 # only install a new shares config db if there is none
993 if not os.path.exists(paths.shareconf):
994 message("Setting up share.ldb")
995 share_ldb = Ldb(paths.shareconf, session_info=session_info,
996 credentials=credentials, lp=lp)
997 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1000 message("Setting up secrets.ldb")
1001 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1002 session_info=session_info,
1003 credentials=credentials, lp=lp)
1005 message("Setting up the registry")
1006 setup_registry(paths.hklm, setup_path, session_info,
1007 credentials=credentials, lp=lp)
1009 message("Setting up templates db")
1010 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
1011 credentials=credentials, lp=lp)
1013 message("Setting up idmap db")
1014 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1015 credentials=credentials, lp=lp)
1017 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1018 credentials=credentials, lp=lp, names=names,
1020 domainsid=domainsid,
1021 aci=aci, domainguid=domainguid, policyguid=policyguid,
1023 adminpass=adminpass, krbtgtpass=krbtgtpass,
1024 invocationid=invocationid,
1025 machinepass=machinepass, dnspass=dnspass,
1026 serverrole=serverrole, ldap_backend=ldap_backend,
1027 ldap_backend_type=ldap_backend_type)
1029 if lp.get("server role") == "domain controller":
1030 if paths.netlogon is None:
1031 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1032 message("Please either remove %s or see the template at %s" %
1033 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1034 assert(paths.netlogon is not None)
1036 if paths.sysvol is None:
1037 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1038 message("Please either remove %s or see the template at %s" %
1039 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1040 assert(paths.sysvol is not None)
1042 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1043 "{" + policyguid + "}")
1044 os.makedirs(policy_path, 0755)
1045 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1046 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1047 os.makedirs(os.path.join(policy_path, "User"), 0755)
1048 if not os.path.isdir(paths.netlogon):
1049 os.makedirs(paths.netlogon, 0755)
1051 if samdb_fill == FILL_FULL:
1052 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1053 root_uid=root_uid, nobody_uid=nobody_uid,
1054 users_gid=users_gid, wheel_gid=wheel_gid)
1056 message("Setting up sam.ldb rootDSE marking as synchronized")
1057 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1059 # Only make a zone file on the first DC, it should be replicated with DNS replication
1060 if serverrole == "domain controller":
1061 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1062 credentials=credentials, lp=lp)
1063 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1064 netbiosname=names.netbiosname, domainsid=domainsid,
1065 keytab_path=paths.keytab, samdb_url=paths.samdb,
1066 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1067 machinepass=machinepass, dnsdomain=names.dnsdomain)
1069 samdb = SamDB(paths.samdb, session_info=session_info,
1070 credentials=credentials, lp=lp)
1072 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1073 assert isinstance(domainguid, str)
1074 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1075 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1076 scope=SCOPE_SUBTREE)
1077 assert isinstance(hostguid, str)
1079 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1080 domaindn=names.domaindn, hostip=hostip,
1081 hostip6=hostip6, hostname=names.hostname,
1082 dnspass=dnspass, realm=names.realm,
1083 domainguid=domainguid, hostguid=hostguid)
1085 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1086 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1088 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1089 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1090 keytab_name=paths.dns_keytab)
1091 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1092 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1094 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1095 hostname=names.hostname, realm=names.realm)
1096 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1098 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1101 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1103 message("Once the above files are installed, your Samba4 server will be ready to use")
1104 message("Server Role: %s" % serverrole)
1105 message("Hostname: %s" % names.hostname)
1106 message("NetBIOS Domain: %s" % names.domain)
1107 message("DNS Domain: %s" % names.dnsdomain)
1108 message("DOMAIN SID: %s" % str(domainsid))
1109 message("Admin password: %s" % adminpass)
1111 result = ProvisionResult()
1112 result.domaindn = domaindn
1113 result.paths = paths
1115 result.samdb = samdb
1119 def provision_become_dc(setup_dir=None,
1120 smbconf=None, targetdir=None, realm=None,
1121 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1123 domain=None, hostname=None, domainsid=None,
1124 adminpass=None, krbtgtpass=None, domainguid=None,
1125 policyguid=None, invocationid=None, machinepass=None,
1126 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1127 wheel=None, backup=None, aci=None, serverrole=None,
1128 ldap_backend=None, ldap_backend_type=None, sitename=None):
1131 """print a message if quiet is not set."""
1134 return provision(setup_dir, message, system_session(), None,
1135 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1136 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1137 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1140 def setup_db_config(setup_path, dbdir):
1141 """Setup a Berkeley database.
1143 :param setup_path: Setup path function.
1144 :param dbdir: Database directory."""
1145 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1146 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1147 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1148 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1150 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1151 {"LDAPDBDIR": dbdir})
1155 def provision_backend(setup_dir=None, message=None,
1156 smbconf=None, targetdir=None, realm=None,
1157 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1158 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1159 ldap_backend_type=None, ldap_backend_port=None,
1162 def setup_path(file):
1163 return os.path.join(setup_dir, file)
1165 if hostname is None:
1166 hostname = socket.gethostname().split(".")[0].lower()
1169 root = findnss(pwd.getpwnam, ["root"])[0]
1171 if adminpass is None:
1172 adminpass = misc.random_password(12)
1174 if targetdir is not None:
1175 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1176 os.makedirs(os.path.join(targetdir, "etc"))
1177 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1179 # only install a new smb.conf if there isn't one there already
1180 if not os.path.exists(smbconf):
1181 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1184 lp = param.LoadParm()
1187 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1188 dnsdomain=realm, serverrole=serverrole,
1189 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1192 paths = provision_paths_from_lp(lp, names.dnsdomain)
1194 if not os.path.isdir(paths.ldapdir):
1195 os.makedirs(paths.ldapdir, 0700)
1196 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1198 os.unlink(schemadb_path)
1202 schemadb = Ldb(schemadb_path, lp=lp)
1204 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1206 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1207 {"SCHEMADN": names.schemadn,
1210 setup_modify_ldif(schemadb,
1211 setup_path("provision_schema_basedn_modify.ldif"), \
1212 {"SCHEMADN": names.schemadn,
1213 "NETBIOSNAME": names.netbiosname,
1214 "DEFAULTSITE": DEFAULTSITE,
1215 "CONFIGDN": names.configdn,
1216 "SERVERDN": names.serverdn,
1217 "PREFIXMAP_B64": b64encode(prefixmap)
1220 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1221 {"SCHEMADN": names.schemadn })
1222 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1223 {"SCHEMADN": names.schemadn})
1225 if ldap_backend_type == "fedora-ds":
1226 if ldap_backend_port is not None:
1227 serverport = "ServerPort=%d" % ldap_backend_port
1231 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1233 "HOSTNAME": hostname,
1234 "DNSDOMAIN": names.dnsdomain,
1235 "LDAPDIR": paths.ldapdir,
1236 "DOMAINDN": names.domaindn,
1237 "LDAPMANAGERDN": names.ldapmanagerdn,
1238 "LDAPMANAGERPASS": adminpass,
1239 "SERVERPORT": serverport})
1241 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1242 {"CONFIGDN": names.configdn,
1243 "SCHEMADN": names.schemadn,
1246 mapping = "schema-map-fedora-ds-1.0"
1247 backend_schema = "99_ad.ldif"
1249 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1251 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1253 elif ldap_backend_type == "openldap":
1254 attrs = ["linkID", "lDAPDisplayName"]
1255 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1257 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1258 refint_attributes = ""
1259 for i in range (0, len(res)):
1260 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1261 target = schemadb.searchone(basedn=names.schemadn,
1262 expression=expression,
1263 attribute="lDAPDisplayName",
1264 scope=SCOPE_SUBTREE)
1265 if target is not None:
1266 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1268 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1269 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1270 "MEMBEROF_ATTR" : str(target) })
1272 refint_config = read_and_sub_file(setup_path("refint.conf"),
1273 { "LINK_ATTRS" : refint_attributes})
1275 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1277 mmr_replicator_acl = ""
1278 mmr_serverids_config = ""
1279 mmr_syncrepl_schema_config = ""
1280 mmr_syncrepl_config_config = ""
1281 mmr_syncrepl_user_config = ""
1283 if ol_mmr_urls is not None:
1284 # For now, make these equal
1285 mmr_pass = adminpass
1287 url_list=filter(None,ol_mmr_urls.split(' '))
1288 if (len(url_list) == 1):
1289 url_list=filter(None,ol_mmr_urls.split(','))
1292 mmr_on_config = "MirrorMode On"
1293 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
1295 for url in url_list:
1297 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1298 { "SERVERID" : str(serverid),
1299 "LDAPSERVER" : url })
1302 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1304 "MMRDN": names.schemadn,
1306 "MMR_PASSWORD": mmr_pass})
1309 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1311 "MMRDN": names.configdn,
1313 "MMR_PASSWORD": mmr_pass})
1316 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1318 "MMRDN": names.domaindn,
1320 "MMR_PASSWORD": mmr_pass })
1323 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1324 {"DNSDOMAIN": names.dnsdomain,
1325 "LDAPDIR": paths.ldapdir,
1326 "DOMAINDN": names.domaindn,
1327 "CONFIGDN": names.configdn,
1328 "SCHEMADN": names.schemadn,
1329 "MEMBEROF_CONFIG": memberof_config,
1330 "MIRRORMODE": mmr_on_config,
1331 "REPLICATOR_ACL": mmr_replicator_acl,
1332 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1333 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1334 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1335 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1336 "REFINT_CONFIG": refint_config})
1337 setup_file(setup_path("modules.conf"), paths.modulesconf,
1338 {"REALM": names.realm})
1340 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1341 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1342 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1344 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1345 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1347 setup_file(setup_path("cn=samba.ldif"),
1348 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1349 { "UUID": str(uuid.uuid4()),
1350 "LDAPTIME": timestring(int(time.time()))} )
1351 setup_file(setup_path("cn=samba-admin.ldif"),
1352 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1353 {"LDAPADMINPASS_B64": b64encode(adminpass),
1354 "UUID": str(uuid.uuid4()),
1355 "LDAPTIME": timestring(int(time.time()))} )
1357 if ol_mmr_urls is not None:
1358 setup_file(setup_path("cn=replicator.ldif"),
1359 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1360 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
1361 "UUID": str(uuid.uuid4()),
1362 "LDAPTIME": timestring(int(time.time()))} )
1366 mapping = "schema-map-openldap-2.3"
1367 backend_schema = "backend-schema.schema"
1369 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1370 if ldap_backend_port is not None:
1371 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1373 server_port_string = ""
1375 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1377 ldapuser = "--username=samba-admin"
1380 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)
1382 os.system(schema_command)
1384 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1385 message("Server Role: %s" % serverrole)
1386 message("Hostname: %s" % names.hostname)
1387 message("DNS Domain: %s" % names.dnsdomain)
1388 message("Base DN: %s" % names.domaindn)
1390 if ldap_backend_type == "openldap":
1391 message("LDAP admin user: samba-admin")
1393 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1395 message("LDAP admin password: %s" % adminpass)
1396 message(slapdcommand)
1397 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1399 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1400 """Create a PHP LDAP admin configuration file.
1402 :param path: Path to write the configuration to.
1403 :param setup_path: Function to generate setup paths.
1405 setup_file(setup_path("phpldapadmin-config.php"), path,
1406 {"S4_LDAPI_URI": ldapi_uri})
1409 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1410 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1411 """Write out a DNS zone file, from the info in the current database.
1413 :param path: Path of the new zone file.
1414 :param setup_path: Setup path function.
1415 :param dnsdomain: DNS Domain name
1416 :param domaindn: DN of the Domain
1417 :param hostip: Local IPv4 IP
1418 :param hostip6: Local IPv6 IP
1419 :param hostname: Local hostname
1420 :param dnspass: Password for DNS
1421 :param realm: Realm name
1422 :param domainguid: GUID of the domain.
1423 :param hostguid: GUID of the host.
1425 assert isinstance(domainguid, str)
1427 if hostip6 is not None:
1428 hostip6_base_line = " IN AAAA " + hostip6
1429 hostip6_host_line = hostname + " IN AAAA " + hostip6
1431 hostip6_base_line = ""
1432 hostip6_host_line = ""
1434 if hostip is not None:
1435 hostip_base_line = " IN A " + hostip
1436 hostip_host_line = hostname + " IN A " + hostip
1438 hostip_base_line = ""
1439 hostip_host_line = ""
1441 setup_file(setup_path("provision.zone"), path, {
1442 "DNSPASS_B64": b64encode(dnspass),
1443 "HOSTNAME": hostname,
1444 "DNSDOMAIN": dnsdomain,
1446 "HOSTIP_BASE_LINE": hostip_base_line,
1447 "HOSTIP_HOST_LINE": hostip_host_line,
1448 "DOMAINGUID": domainguid,
1449 "DATESTRING": time.strftime("%Y%m%d%H"),
1450 "DEFAULTSITE": DEFAULTSITE,
1451 "HOSTGUID": hostguid,
1452 "HOSTIP6_BASE_LINE": hostip6_base_line,
1453 "HOSTIP6_HOST_LINE": hostip6_host_line,
1457 def create_named_conf(path, setup_path, realm, dnsdomain,
1459 """Write out a file containing zone statements suitable for inclusion in a
1460 named.conf file (including GSS-TSIG configuration).
1462 :param path: Path of the new named.conf file.
1463 :param setup_path: Setup path function.
1464 :param realm: Realm name
1465 :param dnsdomain: DNS Domain name
1466 :param private_dir: Path to private directory
1467 :param keytab_name: File name of DNS keytab file
1470 setup_file(setup_path("named.conf"), path, {
1471 "DNSDOMAIN": dnsdomain,
1473 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1474 "PRIVATE_DIR": private_dir
1477 def create_named_txt(path, setup_path, realm, dnsdomain,
1478 private_dir, keytab_name):
1479 """Write out a file containing zone statements suitable for inclusion in a
1480 named.conf file (including GSS-TSIG configuration).
1482 :param path: Path of the new named.conf file.
1483 :param setup_path: Setup path function.
1484 :param realm: Realm name
1485 :param dnsdomain: DNS Domain name
1486 :param private_dir: Path to private directory
1487 :param keytab_name: File name of DNS keytab file
1490 setup_file(setup_path("named.txt"), path, {
1491 "DNSDOMAIN": dnsdomain,
1493 "DNS_KEYTAB": keytab_name,
1494 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1495 "PRIVATE_DIR": private_dir
1498 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1499 """Write out a file containing zone statements suitable for inclusion in a
1500 named.conf file (including GSS-TSIG configuration).
1502 :param path: Path of the new named.conf file.
1503 :param setup_path: Setup path function.
1504 :param dnsdomain: DNS Domain name
1505 :param hostname: Local hostname
1506 :param realm: Realm name
1509 setup_file(setup_path("krb5.conf"), path, {
1510 "DNSDOMAIN": dnsdomain,
1511 "HOSTNAME": hostname,
1516 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
1517 serverdn, servername):
1518 """Load schema for the SamDB.
1520 :param samdb: Load a schema into a SamDB.
1521 :param setup_path: Setup path function.
1522 :param schemadn: DN of the schema
1523 :param netbiosname: NetBIOS name of the host.
1524 :param configdn: DN of the configuration
1525 :param serverdn: DN of the server
1526 :param servername: Host name of the server
1528 schema_data = open(setup_path("schema.ldif"), 'r').read()
1529 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1530 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1531 check_all_substituted(schema_data)
1532 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1533 prefixmap = b64encode(prefixmap)
1535 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1536 head_data = substitute_var(head_data, {
1537 "SCHEMADN": schemadn,
1538 "NETBIOSNAME": netbiosname,
1539 "CONFIGDN": configdn,
1540 "DEFAULTSITE": sitename,
1541 "PREFIXMAP_B64": prefixmap,
1542 "SERVERDN": serverdn,
1543 "SERVERNAME": servername,
1545 check_all_substituted(head_data)
1546 samdb.attach_schema_from_ldif(head_data, schema_data)