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)
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
86 self.ldapmanagerdn = None
89 self.netbiosname = None
95 class ProvisionResult:
102 def check_install(lp, session_info, credentials):
103 """Check whether the current install seems ok.
105 :param lp: Loadparm context
106 :param session_info: Session information
107 :param credentials: Credentials
109 if lp.get("realm") == "":
110 raise Exception("Realm empty")
111 ldb = Ldb(lp.get("sam database"), session_info=session_info,
112 credentials=credentials, lp=lp)
113 if len(ldb.search("(cn=Administrator)")) != 1:
114 raise "No administrator account found"
117 def findnss(nssfn, names):
118 """Find a user or group from a list of possibilities.
120 :param nssfn: NSS Function to try (should raise KeyError if not found)
121 :param names: Names to check.
122 :return: Value return by first names list.
129 raise KeyError("Unable to find user/group %r" % names)
132 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
133 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
136 def open_ldb(session_info, credentials, lp, dbname):
137 """Open a LDB, thrashing it if it is corrupt.
139 :param session_info: auth session information
140 :param credentials: credentials
141 :param lp: Loadparm context
142 :param dbname: Path of the database to open.
143 :return: a Ldb object
145 assert session_info is not None
147 return Ldb(dbname, session_info=session_info, credentials=credentials,
152 return Ldb(dbname, session_info=session_info, credentials=credentials,
156 def read_and_sub_file(file, subst_vars):
157 """Read a file and sub in variables found in it
159 :param file: File to be read (typically from setup directory)
160 param subst_vars: Optional variables to subsitute in the file.
162 data = open(file, 'r').read()
163 if subst_vars is not None:
164 data = substitute_var(data, subst_vars)
165 check_all_substituted(data)
169 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
170 """Setup a ldb in the private dir.
172 :param ldb: LDB file to import data into
173 :param ldif_path: Path of the LDIF file to load
174 :param subst_vars: Optional variables to subsitute in LDIF.
176 assert isinstance(ldif_path, str)
178 data = read_and_sub_file(ldif_path, subst_vars)
182 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
183 """Modify a ldb in the private dir.
185 :param ldb: LDB object.
186 :param ldif_path: LDIF file path.
187 :param subst_vars: Optional dictionary with substitution variables.
189 data = read_and_sub_file(ldif_path, subst_vars)
191 ldb.modify_ldif(data)
194 def setup_ldb(ldb, ldif_path, subst_vars):
195 """Import a LDIF a file into a LDB handle, optionally substituting variables.
197 :note: Either all LDIF data will be added or none (using transactions).
199 :param ldb: LDB file to import into.
200 :param ldif_path: Path to the LDIF file.
201 :param subst_vars: Dictionary with substitution variables.
203 assert ldb is not None
204 ldb.transaction_start()
206 setup_add_ldif(ldb, ldif_path, subst_vars)
208 ldb.transaction_cancel()
210 ldb.transaction_commit()
213 def setup_file(template, fname, subst_vars):
214 """Setup a file in the private dir.
216 :param template: Path of the template file.
217 :param fname: Path of the file to create.
218 :param subst_vars: Substitution variables.
222 if os.path.exists(f):
225 data = read_and_sub_file(template, subst_vars)
226 open(f, 'w').write(data)
229 def provision_paths_from_lp(lp, dnsdomain):
230 """Set the default paths for provisioning.
232 :param lp: Loadparm context.
233 :param dnsdomain: DNS Domain name
235 paths = ProvisionPaths()
236 paths.private_dir = lp.get("private dir")
237 paths.keytab = "secrets.keytab"
238 paths.dns_keytab = "dns.keytab"
240 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
241 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
242 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
243 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
244 paths.templates = os.path.join(paths.private_dir, "templates.ldb")
245 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
246 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
247 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
248 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
249 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
250 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
251 paths.phpldapadminconfig = os.path.join(paths.private_dir,
252 "phpldapadmin-config.php")
253 paths.ldapdir = os.path.join(paths.private_dir,
255 paths.slapdconf = os.path.join(paths.ldapdir,
257 paths.modulesconf = os.path.join(paths.ldapdir,
259 paths.memberofconf = os.path.join(paths.ldapdir,
261 paths.fedoradsinf = os.path.join(paths.ldapdir,
263 paths.fedoradspartitions = os.path.join(paths.ldapdir,
264 "fedorads-partitions.ldif")
265 paths.hklm = "hklm.ldb"
266 paths.hkcr = "hkcr.ldb"
267 paths.hkcu = "hkcu.ldb"
268 paths.hku = "hku.ldb"
269 paths.hkpd = "hkpd.ldb"
270 paths.hkpt = "hkpt.ldb"
272 paths.sysvol = lp.get("path", "sysvol")
274 paths.netlogon = lp.get("path", "netlogon")
276 paths.smbconf = lp.configfile()
281 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None,
282 rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None,
284 """Guess configuration settings to use."""
287 hostname = socket.gethostname().split(".")[0].lower()
289 netbiosname = hostname.upper()
290 if not valid_netbios_name(netbiosname):
291 raise InvalidNetbiosName(netbiosname)
293 hostname = hostname.lower()
295 if dnsdomain is None:
296 dnsdomain = lp.get("realm")
298 if serverrole is None:
299 serverrole = lp.get("server role")
301 assert dnsdomain is not None
302 realm = dnsdomain.upper()
304 if lp.get("realm").upper() != realm:
305 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
306 (lp.get("realm"), lp.configfile(), realm))
308 dnsdomain = dnsdomain.lower()
310 if serverrole == "domain controller":
312 domain = lp.get("workgroup")
314 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
315 if lp.get("workgroup").upper() != domain.upper():
316 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
317 lp.get("workgroup"), domain)
321 domaindn = "CN=" + netbiosname
323 assert domain is not None
324 domain = domain.upper()
325 if not valid_netbios_name(domain):
326 raise InvalidNetbiosName(domain)
332 configdn = "CN=Configuration," + rootdn
334 schemadn = "CN=Schema," + configdn
339 names = ProvisionNames()
340 names.rootdn = rootdn
341 names.domaindn = domaindn
342 names.configdn = configdn
343 names.schemadn = schemadn
344 names.ldapmanagerdn = "CN=Manager," + rootdn
345 names.dnsdomain = dnsdomain
346 names.domain = domain
348 names.netbiosname = netbiosname
349 names.hostname = hostname
350 names.sitename = sitename
351 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
356 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
359 hostname = socket.gethostname().split(".")[0].lower()
361 if serverrole is None:
362 serverrole = "standalone"
364 assert serverrole in ("domain controller", "member server", "standalone")
365 if serverrole == "domain controller":
367 elif serverrole == "member server":
368 smbconfsuffix = "member"
369 elif serverrole == "standalone":
370 smbconfsuffix = "standalone"
372 assert domain is not None
373 assert realm is not None
375 default_lp = param.LoadParm()
376 #Load non-existant file
377 default_lp.load(smbconf)
379 if targetdir is not None:
380 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
381 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
383 default_lp.set("lock dir", os.path.abspath(targetdir))
388 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
389 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
391 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
393 "HOSTNAME": hostname,
396 "SERVERROLE": serverrole,
397 "NETLOGONPATH": netlogon,
398 "SYSVOLPATH": sysvol,
399 "PRIVATEDIR_LINE": privatedir_line,
400 "LOCKDIR_LINE": lockdir_line
405 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
406 users_gid, wheel_gid):
407 """setup reasonable name mappings for sam names to unix names.
409 :param samdb: SamDB object.
410 :param idmap: IDmap db object.
411 :param sid: The domain sid.
412 :param domaindn: The domain DN.
413 :param root_uid: uid of the UNIX root user.
414 :param nobody_uid: uid of the UNIX nobody user.
415 :param users_gid: gid of the UNIX users group.
416 :param wheel_gid: gid of the UNIX wheel group."""
417 # add some foreign sids if they are not present already
418 samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
419 samdb.add_foreign(domaindn, "S-1-1-0", "World")
420 samdb.add_foreign(domaindn, "S-1-5-2", "Network")
421 samdb.add_foreign(domaindn, "S-1-5-18", "System")
422 samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
424 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
425 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
427 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
428 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
431 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
433 serverrole, ldap_backend=None,
434 ldap_backend_type=None, erase=False):
435 """Setup the partitions for the SAM database.
437 Alternatively, provision() may call this, and then populate the database.
439 :note: This will wipe the Sam Database!
441 :note: This function always removes the local SAM LDB file. The erase
442 parameter controls whether to erase the existing data, which
443 may not be stored locally but in LDAP.
445 assert session_info is not None
447 samdb = SamDB(samdb_path, session_info=session_info,
448 credentials=credentials, lp=lp)
454 os.unlink(samdb_path)
456 samdb = SamDB(samdb_path, session_info=session_info,
457 credentials=credentials, lp=lp)
459 #Add modules to the list to activate them by default
460 #beware often order is important
462 # Some Known ordering constraints:
463 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
464 # - objectclass must be before password_hash, because password_hash checks
465 # that the objectclass is of type person (filled in by objectclass
466 # module when expanding the objectclass list)
467 # - partition must be last
468 # - each partition has its own module list then
469 modules_list = ["rootdse",
485 modules_list2 = ["show_deleted",
488 domaindn_ldb = "users.ldb"
489 if ldap_backend is not None:
490 domaindn_ldb = ldap_backend
491 configdn_ldb = "configuration.ldb"
492 if ldap_backend is not None:
493 configdn_ldb = ldap_backend
494 schemadn_ldb = "schema.ldb"
495 if ldap_backend is not None:
496 schema_ldb = ldap_backend
497 schemadn_ldb = ldap_backend
499 if ldap_backend_type == "fedora-ds":
500 backend_modules = ["nsuniqueid", "paged_searches"]
501 # We can handle linked attributes here, as we don't have directory-side subtree operations
502 tdb_modules_list = ["linked_attributes"]
503 elif ldap_backend_type == "openldap":
504 backend_modules = ["normalise", "entryuuid", "paged_searches"]
505 # OpenLDAP handles subtree renames, so we don't want to do any of these things
506 tdb_modules_list = None
507 elif ldap_backend is not None:
508 raise "LDAP Backend specified, but LDAP Backend Type not specified"
509 elif serverrole == "domain controller":
510 backend_modules = ["repl_meta_data"]
512 backend_modules = ["objectguid"]
514 if tdb_modules_list is None:
515 tdb_modules_list_as_string = ""
517 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
519 samdb.transaction_start()
521 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
522 "SCHEMADN": names.schemadn,
523 "SCHEMADN_LDB": schemadn_ldb,
524 "SCHEMADN_MOD2": ",objectguid",
525 "CONFIGDN": names.configdn,
526 "CONFIGDN_LDB": configdn_ldb,
527 "DOMAINDN": names.domaindn,
528 "DOMAINDN_LDB": domaindn_ldb,
529 "SCHEMADN_MOD": "schema_fsmo,instancetype",
530 "CONFIGDN_MOD": "naming_fsmo,instancetype",
531 "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype",
532 "MODULES_LIST": ",".join(modules_list),
533 "TDB_MODULES_LIST": tdb_modules_list_as_string,
534 "MODULES_LIST2": ",".join(modules_list2),
535 "BACKEND_MOD": ",".join(backend_modules),
539 samdb.transaction_cancel()
542 samdb.transaction_commit()
544 samdb = SamDB(samdb_path, session_info=session_info,
545 credentials=credentials, lp=lp)
547 samdb.transaction_start()
549 message("Setting up sam.ldb attributes")
550 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
552 message("Setting up sam.ldb rootDSE")
553 setup_samdb_rootdse(samdb, setup_path, names)
556 message("Erasing data from partitions")
557 samdb.erase_partitions()
560 samdb.transaction_cancel()
563 samdb.transaction_commit()
568 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
569 netbiosname, domainsid, keytab_path, samdb_url,
570 dns_keytab_path, dnspass, machinepass):
571 """Add DC-specific bits to a secrets database.
573 :param secretsdb: Ldb Handle to the secrets database
574 :param setup_path: Setup path function
575 :param machinepass: Machine password
577 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
578 "MACHINEPASS_B64": b64encode(machinepass),
581 "DNSDOMAIN": dnsdomain,
582 "DOMAINSID": str(domainsid),
583 "SECRETS_KEYTAB": keytab_path,
584 "NETBIOSNAME": netbiosname,
585 "SAM_LDB": samdb_url,
586 "DNS_KEYTAB": dns_keytab_path,
587 "DNSPASS_B64": b64encode(dnspass),
591 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
592 """Setup the secrets database.
594 :param path: Path to the secrets database.
595 :param setup_path: Get the path to a setup file.
596 :param session_info: Session info.
597 :param credentials: Credentials
598 :param lp: Loadparm context
599 :return: LDB handle for the created secrets database
601 if os.path.exists(path):
603 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
606 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
607 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
609 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
611 if credentials is not None and credentials.authentication_requested():
612 if credentials.get_bind_dn() is not None:
613 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
614 "LDAPMANAGERDN": credentials.get_bind_dn(),
615 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
618 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
619 "LDAPADMINUSER": credentials.get_username(),
620 "LDAPADMINREALM": credentials.get_realm(),
621 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
627 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
628 """Setup the templates database.
630 :param path: Path to the database.
631 :param setup_path: Function for obtaining the path to setup files.
632 :param session_info: Session info
633 :param credentials: Credentials
634 :param lp: Loadparm context
636 templates_ldb = SamDB(path, session_info=session_info,
637 credentials=credentials, lp=lp)
638 templates_ldb.erase()
639 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
642 def setup_registry(path, setup_path, session_info, credentials, lp):
643 """Setup the registry.
645 :param path: Path to the registry database
646 :param setup_path: Function that returns the path to a setup.
647 :param session_info: Session information
648 :param credentials: Credentials
649 :param lp: Loadparm context
651 reg = registry.Registry()
652 hive = registry.open_ldb(path, session_info=session_info,
653 credentials=credentials, lp_ctx=lp)
654 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
655 provision_reg = setup_path("provision.reg")
656 assert os.path.exists(provision_reg)
657 reg.diff_apply(provision_reg)
660 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
661 """Setup the idmap database.
663 :param path: path to the idmap database
664 :param setup_path: Function that returns a path to a setup file
665 :param session_info: Session information
666 :param credentials: Credentials
667 :param lp: Loadparm context
669 if os.path.exists(path):
672 idmap_ldb = IDmapDB(path, session_info=session_info,
673 credentials=credentials, lp=lp)
676 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
680 def setup_samdb_rootdse(samdb, setup_path, names):
681 """Setup the SamDB rootdse.
683 :param samdb: Sam Database handle
684 :param setup_path: Obtain setup path
686 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
687 "SCHEMADN": names.schemadn,
688 "NETBIOSNAME": names.netbiosname,
689 "DNSDOMAIN": names.dnsdomain,
690 "REALM": names.realm,
691 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
692 "DOMAINDN": names.domaindn,
693 "ROOTDN": names.rootdn,
694 "CONFIGDN": names.configdn,
695 "SERVERDN": names.serverdn,
699 def setup_self_join(samdb, names,
700 machinepass, dnspass,
701 domainsid, invocationid, setup_path,
703 """Join a host to its own domain."""
704 assert isinstance(invocationid, str)
705 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
706 "CONFIGDN": names.configdn,
707 "SCHEMADN": names.schemadn,
708 "DOMAINDN": names.domaindn,
709 "SERVERDN": names.serverdn,
710 "INVOCATIONID": invocationid,
711 "NETBIOSNAME": names.netbiosname,
712 "DEFAULTSITE": names.sitename,
713 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
714 "MACHINEPASS_B64": b64encode(machinepass),
715 "DNSPASS_B64": b64encode(dnspass),
716 "REALM": names.realm,
717 "DOMAIN": names.domain,
718 "DNSDOMAIN": names.dnsdomain})
719 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
720 "POLICYGUID": policyguid,
721 "DNSDOMAIN": names.dnsdomain,
722 "DOMAINSID": str(domainsid),
723 "DOMAINDN": names.domaindn})
726 def setup_samdb(path, setup_path, session_info, credentials, lp,
728 domainsid, aci, domainguid, policyguid,
729 fill, adminpass, krbtgtpass,
730 machinepass, invocationid, dnspass,
731 serverrole, ldap_backend=None,
732 ldap_backend_type=None):
733 """Setup a complete SAM Database.
735 :note: This will wipe the main SAM database file!
738 erase = (fill != FILL_DRS)
740 # Also wipes the database
741 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
742 credentials=credentials, session_info=session_info,
744 ldap_backend=ldap_backend, serverrole=serverrole,
745 ldap_backend_type=ldap_backend_type, erase=erase)
747 samdb = SamDB(path, session_info=session_info,
748 credentials=credentials, lp=lp)
751 # We want to finish here, but setup the index before we do so
752 message("Setting up sam.ldb index")
753 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
756 message("Pre-loading the Samba 4 and AD schema")
757 samdb.set_domain_sid(domainsid)
758 if serverrole == "domain controller":
759 samdb.set_invocation_id(invocationid)
761 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
762 names.configdn, names.sitename)
764 samdb.transaction_start()
767 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
768 if serverrole == "domain controller":
769 domain_oc = "domainDNS"
771 domain_oc = "samba4LocalDomain"
773 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
774 "DOMAINDN": names.domaindn,
776 "DOMAIN_OC": domain_oc
779 message("Modifying DomainDN: " + names.domaindn + "")
780 if domainguid is not None:
781 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
785 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
786 "LDAPTIME": timestring(int(time.time())),
787 "DOMAINSID": str(domainsid),
788 "SCHEMADN": names.schemadn,
789 "NETBIOSNAME": names.netbiosname,
790 "DEFAULTSITE": names.sitename,
791 "CONFIGDN": names.configdn,
792 "SERVERDN": names.serverdn,
793 "POLICYGUID": policyguid,
794 "DOMAINDN": names.domaindn,
795 "DOMAINGUID_MOD": domainguid_mod,
798 message("Adding configuration container (permitted to fail)")
799 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
800 "CONFIGDN": names.configdn,
802 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
804 message("Modifying configuration container")
805 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
806 "CONFIGDN": names.configdn,
807 "SCHEMADN": names.schemadn,
810 message("Adding schema container (permitted to fail)")
811 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
812 "SCHEMADN": names.schemadn,
814 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
816 message("Modifying schema container")
818 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
820 setup_modify_ldif(samdb,
821 setup_path("provision_schema_basedn_modify.ldif"), {
822 "SCHEMADN": names.schemadn,
823 "NETBIOSNAME": names.netbiosname,
824 "DEFAULTSITE": names.sitename,
825 "CONFIGDN": names.configdn,
826 "SERVERDN": names.serverdn,
827 "PREFIXMAP_B64": b64encode(prefixmap)
830 message("Setting up sam.ldb Samba4 schema")
831 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
832 {"SCHEMADN": names.schemadn })
833 message("Setting up sam.ldb AD schema")
834 setup_add_ldif(samdb, setup_path("schema.ldif"),
835 {"SCHEMADN": names.schemadn})
837 message("Setting up sam.ldb configuration data")
838 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
839 "CONFIGDN": names.configdn,
840 "NETBIOSNAME": names.netbiosname,
841 "DEFAULTSITE": names.sitename,
842 "DNSDOMAIN": names.dnsdomain,
843 "DOMAIN": names.domain,
844 "SCHEMADN": names.schemadn,
845 "DOMAINDN": names.domaindn,
846 "SERVERDN": names.serverdn
849 message("Setting up display specifiers")
850 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
851 {"CONFIGDN": names.configdn})
853 message("Adding users container (permitted to fail)")
854 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
855 "DOMAINDN": names.domaindn})
856 message("Modifying users container")
857 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
858 "DOMAINDN": names.domaindn})
859 message("Adding computers container (permitted to fail)")
860 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
861 "DOMAINDN": names.domaindn})
862 message("Modifying computers container")
863 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
864 "DOMAINDN": names.domaindn})
865 message("Setting up sam.ldb data")
866 setup_add_ldif(samdb, setup_path("provision.ldif"), {
867 "DOMAINDN": names.domaindn,
868 "NETBIOSNAME": names.netbiosname,
869 "DEFAULTSITE": names.sitename,
870 "CONFIGDN": names.configdn,
871 "SERVERDN": names.serverdn
874 if fill == FILL_FULL:
875 message("Setting up sam.ldb users and groups")
876 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
877 "DOMAINDN": names.domaindn,
878 "DOMAINSID": str(domainsid),
879 "CONFIGDN": names.configdn,
880 "ADMINPASS_B64": b64encode(adminpass),
881 "KRBTGTPASS_B64": b64encode(krbtgtpass),
884 if serverrole == "domain controller":
885 message("Setting up self join")
886 setup_self_join(samdb, names=names, invocationid=invocationid,
888 machinepass=machinepass,
889 domainsid=domainsid, policyguid=policyguid,
890 setup_path=setup_path)
892 #We want to setup the index last, as adds are faster unindexed
893 message("Setting up sam.ldb index")
894 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
896 samdb.transaction_cancel()
899 samdb.transaction_commit()
904 FILL_NT4SYNC = "NT4SYNC"
907 def provision(setup_dir, message, session_info,
908 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
909 rootdn=None, domaindn=None, schemadn=None, configdn=None,
911 domain=None, hostname=None, hostip=None, hostip6=None,
912 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
913 policyguid=None, invocationid=None, machinepass=None,
914 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
915 wheel=None, backup=None, aci=None, serverrole=None,
916 ldap_backend=None, ldap_backend_type=None, sitename=None):
919 :note: caution, this wipes all existing data!
922 def setup_path(file):
923 return os.path.join(setup_dir, file)
925 if domainsid is None:
926 domainsid = security.random_sid()
928 domainsid = security.Sid(domainsid)
930 if policyguid is None:
931 policyguid = str(uuid.uuid4())
932 if adminpass is None:
933 adminpass = misc.random_password(12)
934 if krbtgtpass is None:
935 krbtgtpass = misc.random_password(12)
936 if machinepass is None:
937 machinepass = misc.random_password(12)
939 dnspass = misc.random_password(12)
940 root_uid = findnss_uid([root or "root"])
941 nobody_uid = findnss_uid([nobody or "nobody"])
942 users_gid = findnss_gid([users or "users"])
944 wheel_gid = findnss_gid(["wheel", "adm"])
946 wheel_gid = findnss_gid([wheel])
948 aci = "# no aci for local ldb"
950 if targetdir is not None:
951 if (not os.path.exists(os.path.join(targetdir, "etc"))):
952 os.makedirs(os.path.join(targetdir, "etc"))
953 smbconf = os.path.join(targetdir, "etc", "smb.conf")
955 # only install a new smb.conf if there isn't one there already
956 if not os.path.exists(smbconf):
957 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
960 lp = param.LoadParm()
963 names = guess_names(lp=lp, hostname=hostname, domain=domain,
964 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
965 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
968 paths = provision_paths_from_lp(lp, names.dnsdomain)
971 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
975 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
976 except socket.gaierror:
979 if serverrole is None:
980 serverrole = lp.get("server role")
982 assert serverrole in ("domain controller", "member server", "standalone")
983 if invocationid is None and serverrole == "domain controller":
984 invocationid = str(uuid.uuid4())
986 if not os.path.exists(paths.private_dir):
987 os.mkdir(paths.private_dir)
989 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
991 if ldap_backend is not None:
992 if ldap_backend == "ldapi":
993 # provision-backend will set this path suggested slapd command line / fedorads.inf
994 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
996 # only install a new shares config db if there is none
997 if not os.path.exists(paths.shareconf):
998 message("Setting up share.ldb")
999 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1000 credentials=credentials, lp=lp)
1001 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1004 message("Setting up secrets.ldb")
1005 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1006 session_info=session_info,
1007 credentials=credentials, lp=lp)
1009 message("Setting up the registry")
1010 setup_registry(paths.hklm, setup_path, session_info,
1011 credentials=credentials, lp=lp)
1013 message("Setting up templates db")
1014 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
1015 credentials=credentials, lp=lp)
1017 message("Setting up idmap db")
1018 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1019 credentials=credentials, lp=lp)
1021 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1022 credentials=credentials, lp=lp, names=names,
1024 domainsid=domainsid,
1025 aci=aci, domainguid=domainguid, policyguid=policyguid,
1027 adminpass=adminpass, krbtgtpass=krbtgtpass,
1028 invocationid=invocationid,
1029 machinepass=machinepass, dnspass=dnspass,
1030 serverrole=serverrole, ldap_backend=ldap_backend,
1031 ldap_backend_type=ldap_backend_type)
1033 if lp.get("server role") == "domain controller":
1034 if paths.netlogon is None:
1035 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1036 message("Please either remove %s or see the template at %s" %
1037 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1038 assert(paths.netlogon is not None)
1040 if paths.sysvol is None:
1041 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1042 message("Please either remove %s or see the template at %s" %
1043 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1044 assert(paths.sysvol is not None)
1046 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1047 "{" + policyguid + "}")
1048 os.makedirs(policy_path, 0755)
1049 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1050 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1051 os.makedirs(os.path.join(policy_path, "User"), 0755)
1052 if not os.path.isdir(paths.netlogon):
1053 os.makedirs(paths.netlogon, 0755)
1055 if samdb_fill == FILL_FULL:
1056 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1057 root_uid=root_uid, nobody_uid=nobody_uid,
1058 users_gid=users_gid, wheel_gid=wheel_gid)
1060 message("Setting up sam.ldb rootDSE marking as synchronized")
1061 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1063 # Only make a zone file on the first DC, it should be replicated with DNS replication
1064 if serverrole == "domain controller":
1065 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1066 credentials=credentials, lp=lp)
1067 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1068 netbiosname=names.netbiosname, domainsid=domainsid,
1069 keytab_path=paths.keytab, samdb_url=paths.samdb,
1070 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1071 machinepass=machinepass, dnsdomain=names.dnsdomain)
1073 samdb = SamDB(paths.samdb, session_info=session_info,
1074 credentials=credentials, lp=lp)
1076 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1077 assert isinstance(domainguid, str)
1078 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1079 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1080 scope=SCOPE_SUBTREE)
1081 assert isinstance(hostguid, str)
1083 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1084 domaindn=names.domaindn, hostip=hostip,
1085 hostip6=hostip6, hostname=names.hostname,
1086 dnspass=dnspass, realm=names.realm,
1087 domainguid=domainguid, hostguid=hostguid)
1089 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1090 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1092 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1093 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1094 keytab_name=paths.dns_keytab)
1095 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1096 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1098 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1099 hostname=names.hostname, realm=names.realm)
1100 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1102 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1105 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1107 message("Once the above files are installed, your Samba4 server will be ready to use")
1108 message("Server Role: %s" % serverrole)
1109 message("Hostname: %s" % names.hostname)
1110 message("NetBIOS Domain: %s" % names.domain)
1111 message("DNS Domain: %s" % names.dnsdomain)
1112 message("DOMAIN SID: %s" % str(domainsid))
1113 message("Admin password: %s" % adminpass)
1115 result = ProvisionResult()
1116 result.domaindn = domaindn
1117 result.paths = paths
1119 result.samdb = samdb
1123 def provision_become_dc(setup_dir=None,
1124 smbconf=None, targetdir=None, realm=None,
1125 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1127 domain=None, hostname=None, domainsid=None,
1128 adminpass=None, krbtgtpass=None, domainguid=None,
1129 policyguid=None, invocationid=None, machinepass=None,
1130 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1131 wheel=None, backup=None, aci=None, serverrole=None,
1132 ldap_backend=None, ldap_backend_type=None, sitename=None):
1135 """print a message if quiet is not set."""
1138 return provision(setup_dir, message, system_session(), None,
1139 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1140 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1141 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1144 def setup_db_config(setup_path, dbdir):
1145 """Setup a Berkeley database.
1147 :param setup_path: Setup path function.
1148 :param dbdir: Database directory."""
1149 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1150 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1151 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1152 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1154 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1155 {"LDAPDBDIR": dbdir})
1159 def provision_backend(setup_dir=None, message=None,
1160 smbconf=None, targetdir=None, realm=None,
1161 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1162 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1163 ldap_backend_type=None, ldap_backend_port=None):
1165 def setup_path(file):
1166 return os.path.join(setup_dir, file)
1168 if hostname is None:
1169 hostname = socket.gethostname().split(".")[0].lower()
1172 root = findnss(pwd.getpwnam, ["root"])[0]
1174 if adminpass is None:
1175 adminpass = misc.random_password(12)
1177 if targetdir is not None:
1178 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1179 os.makedirs(os.path.join(targetdir, "etc"))
1180 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1182 # only install a new smb.conf if there isn't one there already
1183 if not os.path.exists(smbconf):
1184 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1187 lp = param.LoadParm()
1190 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1191 dnsdomain=realm, serverrole=serverrole,
1192 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1195 paths = provision_paths_from_lp(lp, names.dnsdomain)
1197 if not os.path.isdir(paths.ldapdir):
1198 os.makedirs(paths.ldapdir)
1199 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1201 os.unlink(schemadb_path)
1205 schemadb = Ldb(schemadb_path, lp=lp)
1207 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1209 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1210 {"SCHEMADN": names.schemadn,
1212 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
1214 setup_modify_ldif(schemadb,
1215 setup_path("provision_schema_basedn_modify.ldif"), \
1216 {"SCHEMADN": names.schemadn,
1217 "NETBIOSNAME": names.netbiosname,
1218 "DEFAULTSITE": DEFAULTSITE,
1219 "CONFIGDN": names.configdn,
1220 "SERVERDN": names.serverdn,
1221 "PREFIXMAP_B64": b64encode(prefixmap)
1224 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1225 {"SCHEMADN": names.schemadn })
1226 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1227 {"SCHEMADN": names.schemadn})
1229 if ldap_backend_type == "fedora-ds":
1230 if ldap_backend_port is not None:
1231 serverport = "ServerPort=%d" % ldap_backend_port
1235 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1237 "HOSTNAME": hostname,
1238 "DNSDOMAIN": names.dnsdomain,
1239 "LDAPDIR": paths.ldapdir,
1240 "DOMAINDN": names.domaindn,
1241 "LDAPMANAGERDN": names.ldapmanagerdn,
1242 "LDAPMANAGERPASS": adminpass,
1243 "SERVERPORT": serverport})
1245 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1246 {"CONFIGDN": names.configdn,
1247 "SCHEMADN": names.schemadn,
1250 mapping = "schema-map-fedora-ds-1.0"
1251 backend_schema = "99_ad.ldif"
1253 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1255 elif ldap_backend_type == "openldap":
1256 attrs = ["linkID", "lDAPDisplayName"]
1257 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1259 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1260 refint_attributes = ""
1261 for i in range (0, len(res)):
1262 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1263 target = schemadb.searchone(basedn=names.schemadn,
1264 expression=expression,
1265 attribute="lDAPDisplayName",
1266 scope=SCOPE_SUBTREE)
1267 if target is not None:
1268 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1270 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1271 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1272 "MEMBEROF_ATTR" : str(target) })
1274 refint_config = read_and_sub_file(setup_path("refint.conf"),
1275 { "LINK_ATTRS" : refint_attributes})
1277 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1278 {"DNSDOMAIN": names.dnsdomain,
1279 "LDAPDIR": paths.ldapdir,
1280 "DOMAINDN": names.domaindn,
1281 "CONFIGDN": names.configdn,
1282 "SCHEMADN": names.schemadn,
1283 "MEMBEROF_CONFIG": memberof_config,
1284 "REFINT_CONFIG": refint_config})
1285 setup_file(setup_path("modules.conf"), paths.modulesconf,
1286 {"REALM": names.realm})
1288 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1289 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1290 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1292 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1293 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"))
1295 setup_file(setup_path("cn=samba.ldif"),
1296 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1297 { "UUID": str(uuid.uuid4()),
1298 "LDAPTIME": timestring(int(time.time()))} )
1299 setup_file(setup_path("cn=samba-admin.ldif"),
1300 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1301 {"LDAPADMINPASS_B64": b64encode(adminpass),
1302 "UUID": str(uuid.uuid4()),
1303 "LDAPTIME": timestring(int(time.time()))} )
1305 mapping = "schema-map-openldap-2.3"
1306 backend_schema = "backend-schema.schema"
1308 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1309 if ldap_backend_port is not None:
1310 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1312 server_port_string = ""
1313 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1316 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)
1318 os.system(schema_command)
1320 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1321 message("Server Role: %s" % serverrole)
1322 message("Hostname: %s" % names.hostname)
1323 message("DNS Domain: %s" % names.dnsdomain)
1324 message("Base DN: %s" % names.domaindn)
1326 if ldap_backend_type == "openldap":
1327 message("LDAP admin user: samba-admin")
1329 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1331 message("LDAP admin password: %s" % adminpass)
1332 message(slapdcommand)
1335 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1336 """Create a PHP LDAP admin configuration file.
1338 :param path: Path to write the configuration to.
1339 :param setup_path: Function to generate setup paths.
1341 setup_file(setup_path("phpldapadmin-config.php"), path,
1342 {"S4_LDAPI_URI": ldapi_uri})
1345 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1346 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1347 """Write out a DNS zone file, from the info in the current database.
1349 :param path: Path of the new zone file.
1350 :param setup_path: Setup path function.
1351 :param dnsdomain: DNS Domain name
1352 :param domaindn: DN of the Domain
1353 :param hostip: Local IPv4 IP
1354 :param hostip6: Local IPv6 IP
1355 :param hostname: Local hostname
1356 :param dnspass: Password for DNS
1357 :param realm: Realm name
1358 :param domainguid: GUID of the domain.
1359 :param hostguid: GUID of the host.
1361 assert isinstance(domainguid, str)
1363 if hostip6 is not None:
1364 hostip6_base_line = " IN AAAA " + hostip6
1365 hostip6_host_line = hostname + " IN AAAA " + hostip6
1367 hostip6_base_line = ""
1368 hostip6_host_line = ""
1370 setup_file(setup_path("provision.zone"), path, {
1371 "DNSPASS_B64": b64encode(dnspass),
1372 "HOSTNAME": hostname,
1373 "DNSDOMAIN": dnsdomain,
1376 "DOMAINGUID": domainguid,
1377 "DATESTRING": time.strftime("%Y%m%d%H"),
1378 "DEFAULTSITE": DEFAULTSITE,
1379 "HOSTGUID": hostguid,
1380 "HOSTIP6_BASE_LINE": hostip6_base_line,
1381 "HOSTIP6_HOST_LINE": hostip6_host_line,
1385 def create_named_conf(path, setup_path, realm, dnsdomain,
1387 """Write out a file containing zone statements suitable for inclusion in a
1388 named.conf file (including GSS-TSIG configuration).
1390 :param path: Path of the new named.conf file.
1391 :param setup_path: Setup path function.
1392 :param realm: Realm name
1393 :param dnsdomain: DNS Domain name
1394 :param private_dir: Path to private directory
1395 :param keytab_name: File name of DNS keytab file
1398 setup_file(setup_path("named.conf"), path, {
1399 "DNSDOMAIN": dnsdomain,
1401 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1402 "PRIVATE_DIR": private_dir
1405 def create_named_txt(path, setup_path, realm, dnsdomain,
1406 private_dir, keytab_name):
1407 """Write out a file containing zone statements suitable for inclusion in a
1408 named.conf file (including GSS-TSIG configuration).
1410 :param path: Path of the new named.conf file.
1411 :param setup_path: Setup path function.
1412 :param realm: Realm name
1413 :param dnsdomain: DNS Domain name
1414 :param private_dir: Path to private directory
1415 :param keytab_name: File name of DNS keytab file
1418 setup_file(setup_path("named.txt"), path, {
1419 "DNSDOMAIN": dnsdomain,
1421 "DNS_KEYTAB": keytab_name,
1422 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1423 "PRIVATE_DIR": private_dir
1426 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1427 """Write out a file containing zone statements suitable for inclusion in a
1428 named.conf file (including GSS-TSIG configuration).
1430 :param path: Path of the new named.conf file.
1431 :param setup_path: Setup path function.
1432 :param dnsdomain: DNS Domain name
1433 :param hostname: Local hostname
1434 :param realm: Realm name
1437 setup_file(setup_path("krb5.conf"), path, {
1438 "DNSDOMAIN": dnsdomain,
1439 "HOSTNAME": hostname,
1444 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
1445 """Load schema for the SamDB.
1447 :param samdb: Load a schema into a SamDB.
1448 :param setup_path: Setup path function.
1449 :param schemadn: DN of the schema
1450 :param netbiosname: NetBIOS name of the host.
1451 :param configdn: DN of the configuration
1453 schema_data = open(setup_path("schema.ldif"), 'r').read()
1454 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1455 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1456 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1457 prefixmap = b64encode(prefixmap)
1459 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1460 head_data = substitute_var(head_data, {
1461 "SCHEMADN": schemadn,
1462 "NETBIOSNAME": netbiosname,
1463 "CONFIGDN": configdn,
1464 "DEFAULTSITE":sitename,
1465 "PREFIXMAP_B64":prefixmap
1467 samdb.attach_schema_from_ldif(head_data, schema_data)