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 read_and_sub_file(file, subst_vars):
137 """Read a file and sub in variables found in it
139 :param file: File to be read (typically from setup directory)
140 param subst_vars: Optional variables to subsitute in the file.
142 data = open(file, 'r').read()
143 if subst_vars is not None:
144 data = substitute_var(data, subst_vars)
145 check_all_substituted(data)
149 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
150 """Setup a ldb in the private dir.
152 :param ldb: LDB file to import data into
153 :param ldif_path: Path of the LDIF file to load
154 :param subst_vars: Optional variables to subsitute in LDIF.
156 assert isinstance(ldif_path, str)
158 data = read_and_sub_file(ldif_path, subst_vars)
162 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
163 """Modify a ldb in the private dir.
165 :param ldb: LDB object.
166 :param ldif_path: LDIF file path.
167 :param subst_vars: Optional dictionary with substitution variables.
169 data = read_and_sub_file(ldif_path, subst_vars)
171 ldb.modify_ldif(data)
174 def setup_ldb(ldb, ldif_path, subst_vars):
175 """Import a LDIF a file into a LDB handle, optionally substituting variables.
177 :note: Either all LDIF data will be added or none (using transactions).
179 :param ldb: LDB file to import into.
180 :param ldif_path: Path to the LDIF file.
181 :param subst_vars: Dictionary with substitution variables.
183 assert ldb is not None
184 ldb.transaction_start()
186 setup_add_ldif(ldb, ldif_path, subst_vars)
188 ldb.transaction_cancel()
190 ldb.transaction_commit()
193 def setup_file(template, fname, subst_vars):
194 """Setup a file in the private dir.
196 :param template: Path of the template file.
197 :param fname: Path of the file to create.
198 :param subst_vars: Substitution variables.
202 if os.path.exists(f):
205 data = read_and_sub_file(template, subst_vars)
206 open(f, 'w').write(data)
209 def provision_paths_from_lp(lp, dnsdomain):
210 """Set the default paths for provisioning.
212 :param lp: Loadparm context.
213 :param dnsdomain: DNS Domain name
215 paths = ProvisionPaths()
216 paths.private_dir = lp.get("private dir")
217 paths.keytab = "secrets.keytab"
218 paths.dns_keytab = "dns.keytab"
220 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
221 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
222 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
223 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
224 paths.templates = os.path.join(paths.private_dir, "templates.ldb")
225 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
226 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
227 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
228 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
229 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
230 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
231 paths.phpldapadminconfig = os.path.join(paths.private_dir,
232 "phpldapadmin-config.php")
233 paths.ldapdir = os.path.join(paths.private_dir,
235 paths.slapdconf = os.path.join(paths.ldapdir,
237 paths.modulesconf = os.path.join(paths.ldapdir,
239 paths.memberofconf = os.path.join(paths.ldapdir,
241 paths.fedoradsinf = os.path.join(paths.ldapdir,
243 paths.fedoradspartitions = os.path.join(paths.ldapdir,
244 "fedorads-partitions.ldif")
245 paths.hklm = "hklm.ldb"
246 paths.hkcr = "hkcr.ldb"
247 paths.hkcu = "hkcu.ldb"
248 paths.hku = "hku.ldb"
249 paths.hkpd = "hkpd.ldb"
250 paths.hkpt = "hkpt.ldb"
252 paths.sysvol = lp.get("path", "sysvol")
254 paths.netlogon = lp.get("path", "netlogon")
256 paths.smbconf = lp.configfile()
261 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None,
262 rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None,
264 """Guess configuration settings to use."""
267 hostname = socket.gethostname().split(".")[0].lower()
269 netbiosname = hostname.upper()
270 if not valid_netbios_name(netbiosname):
271 raise InvalidNetbiosName(netbiosname)
273 hostname = hostname.lower()
275 if dnsdomain is None:
276 dnsdomain = lp.get("realm")
278 if serverrole is None:
279 serverrole = lp.get("server role")
281 assert dnsdomain is not None
282 realm = dnsdomain.upper()
284 if lp.get("realm").upper() != realm:
285 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
286 (lp.get("realm"), lp.configfile(), realm))
288 dnsdomain = dnsdomain.lower()
290 if serverrole == "domain controller":
292 domain = lp.get("workgroup")
294 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
295 if lp.get("workgroup").upper() != domain.upper():
296 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
297 lp.get("workgroup"), domain)
301 domaindn = "CN=" + netbiosname
303 assert domain is not None
304 domain = domain.upper()
305 if not valid_netbios_name(domain):
306 raise InvalidNetbiosName(domain)
312 configdn = "CN=Configuration," + rootdn
314 schemadn = "CN=Schema," + configdn
319 names = ProvisionNames()
320 names.rootdn = rootdn
321 names.domaindn = domaindn
322 names.configdn = configdn
323 names.schemadn = schemadn
324 names.ldapmanagerdn = "CN=Manager," + rootdn
325 names.dnsdomain = dnsdomain
326 names.domain = domain
328 names.netbiosname = netbiosname
329 names.hostname = hostname
330 names.sitename = sitename
331 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
336 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
339 hostname = socket.gethostname().split(".")[0].lower()
341 if serverrole is None:
342 serverrole = "standalone"
344 assert serverrole in ("domain controller", "member server", "standalone")
345 if serverrole == "domain controller":
347 elif serverrole == "member server":
348 smbconfsuffix = "member"
349 elif serverrole == "standalone":
350 smbconfsuffix = "standalone"
352 assert domain is not None
353 assert realm is not None
355 default_lp = param.LoadParm()
356 #Load non-existant file
357 default_lp.load(smbconf)
359 if targetdir is not None:
360 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
361 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
363 default_lp.set("lock dir", os.path.abspath(targetdir))
368 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
369 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
371 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
373 "HOSTNAME": hostname,
376 "SERVERROLE": serverrole,
377 "NETLOGONPATH": netlogon,
378 "SYSVOLPATH": sysvol,
379 "PRIVATEDIR_LINE": privatedir_line,
380 "LOCKDIR_LINE": lockdir_line
385 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
386 users_gid, wheel_gid):
387 """setup reasonable name mappings for sam names to unix names.
389 :param samdb: SamDB object.
390 :param idmap: IDmap db object.
391 :param sid: The domain sid.
392 :param domaindn: The domain DN.
393 :param root_uid: uid of the UNIX root user.
394 :param nobody_uid: uid of the UNIX nobody user.
395 :param users_gid: gid of the UNIX users group.
396 :param wheel_gid: gid of the UNIX wheel group."""
397 # add some foreign sids if they are not present already
398 samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
399 samdb.add_foreign(domaindn, "S-1-1-0", "World")
400 samdb.add_foreign(domaindn, "S-1-5-2", "Network")
401 samdb.add_foreign(domaindn, "S-1-5-18", "System")
402 samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
404 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
405 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
407 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
408 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
411 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
413 serverrole, ldap_backend=None,
414 ldap_backend_type=None, erase=False):
415 """Setup the partitions for the SAM database.
417 Alternatively, provision() may call this, and then populate the database.
419 :note: This will wipe the Sam Database!
421 :note: This function always removes the local SAM LDB file. The erase
422 parameter controls whether to erase the existing data, which
423 may not be stored locally but in LDAP.
425 assert session_info is not None
427 samdb = SamDB(samdb_path, session_info=session_info,
428 credentials=credentials, lp=lp)
434 os.unlink(samdb_path)
436 samdb = SamDB(samdb_path, session_info=session_info,
437 credentials=credentials, lp=lp)
439 #Add modules to the list to activate them by default
440 #beware often order is important
442 # Some Known ordering constraints:
443 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
444 # - objectclass must be before password_hash, because password_hash checks
445 # that the objectclass is of type person (filled in by objectclass
446 # module when expanding the objectclass list)
447 # - partition must be last
448 # - each partition has its own module list then
449 modules_list = ["rootdse",
465 modules_list2 = ["show_deleted",
468 domaindn_ldb = "users.ldb"
469 if ldap_backend is not None:
470 domaindn_ldb = ldap_backend
471 configdn_ldb = "configuration.ldb"
472 if ldap_backend is not None:
473 configdn_ldb = ldap_backend
474 schemadn_ldb = "schema.ldb"
475 if ldap_backend is not None:
476 schema_ldb = ldap_backend
477 schemadn_ldb = ldap_backend
479 if ldap_backend_type == "fedora-ds":
480 backend_modules = ["nsuniqueid", "paged_searches"]
481 # We can handle linked attributes here, as we don't have directory-side subtree operations
482 tdb_modules_list = ["linked_attributes"]
483 elif ldap_backend_type == "openldap":
484 backend_modules = ["normalise", "entryuuid", "paged_searches"]
485 # OpenLDAP handles subtree renames, so we don't want to do any of these things
486 tdb_modules_list = None
487 elif ldap_backend is not None:
488 raise "LDAP Backend specified, but LDAP Backend Type not specified"
489 elif serverrole == "domain controller":
490 backend_modules = ["repl_meta_data"]
492 backend_modules = ["objectguid"]
494 if tdb_modules_list is None:
495 tdb_modules_list_as_string = ""
497 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
499 samdb.transaction_start()
501 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
502 "SCHEMADN": names.schemadn,
503 "SCHEMADN_LDB": schemadn_ldb,
504 "SCHEMADN_MOD2": ",objectguid",
505 "CONFIGDN": names.configdn,
506 "CONFIGDN_LDB": configdn_ldb,
507 "DOMAINDN": names.domaindn,
508 "DOMAINDN_LDB": domaindn_ldb,
509 "SCHEMADN_MOD": "schema_fsmo,instancetype",
510 "CONFIGDN_MOD": "naming_fsmo,instancetype",
511 "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype",
512 "MODULES_LIST": ",".join(modules_list),
513 "TDB_MODULES_LIST": tdb_modules_list_as_string,
514 "MODULES_LIST2": ",".join(modules_list2),
515 "BACKEND_MOD": ",".join(backend_modules),
519 samdb.transaction_cancel()
522 samdb.transaction_commit()
524 samdb = SamDB(samdb_path, session_info=session_info,
525 credentials=credentials, lp=lp)
527 samdb.transaction_start()
529 message("Setting up sam.ldb attributes")
530 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
532 message("Setting up sam.ldb rootDSE")
533 setup_samdb_rootdse(samdb, setup_path, names)
536 message("Erasing data from partitions")
537 samdb.erase_partitions()
540 samdb.transaction_cancel()
543 samdb.transaction_commit()
548 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
549 netbiosname, domainsid, keytab_path, samdb_url,
550 dns_keytab_path, dnspass, machinepass):
551 """Add DC-specific bits to a secrets database.
553 :param secretsdb: Ldb Handle to the secrets database
554 :param setup_path: Setup path function
555 :param machinepass: Machine password
557 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
558 "MACHINEPASS_B64": b64encode(machinepass),
561 "DNSDOMAIN": dnsdomain,
562 "DOMAINSID": str(domainsid),
563 "SECRETS_KEYTAB": keytab_path,
564 "NETBIOSNAME": netbiosname,
565 "SAM_LDB": samdb_url,
566 "DNS_KEYTAB": dns_keytab_path,
567 "DNSPASS_B64": b64encode(dnspass),
571 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
572 """Setup the secrets database.
574 :param path: Path to the secrets database.
575 :param setup_path: Get the path to a setup file.
576 :param session_info: Session info.
577 :param credentials: Credentials
578 :param lp: Loadparm context
579 :return: LDB handle for the created secrets database
581 if os.path.exists(path):
583 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
586 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
587 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
589 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
591 if credentials is not None and credentials.authentication_requested():
592 if credentials.get_bind_dn() is not None:
593 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
594 "LDAPMANAGERDN": credentials.get_bind_dn(),
595 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
598 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
599 "LDAPADMINUSER": credentials.get_username(),
600 "LDAPADMINREALM": credentials.get_realm(),
601 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
607 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
608 """Setup the templates database.
610 :param path: Path to the database.
611 :param setup_path: Function for obtaining the path to setup files.
612 :param session_info: Session info
613 :param credentials: Credentials
614 :param lp: Loadparm context
616 templates_ldb = SamDB(path, session_info=session_info,
617 credentials=credentials, lp=lp)
618 templates_ldb.erase()
619 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
622 def setup_registry(path, setup_path, session_info, credentials, lp):
623 """Setup the registry.
625 :param path: Path to the registry database
626 :param setup_path: Function that returns the path to a setup.
627 :param session_info: Session information
628 :param credentials: Credentials
629 :param lp: Loadparm context
631 reg = registry.Registry()
632 hive = registry.open_ldb(path, session_info=session_info,
633 credentials=credentials, lp_ctx=lp)
634 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
635 provision_reg = setup_path("provision.reg")
636 assert os.path.exists(provision_reg)
637 reg.diff_apply(provision_reg)
640 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
641 """Setup the idmap database.
643 :param path: path to the idmap database
644 :param setup_path: Function that returns a path to a setup file
645 :param session_info: Session information
646 :param credentials: Credentials
647 :param lp: Loadparm context
649 if os.path.exists(path):
652 idmap_ldb = IDmapDB(path, session_info=session_info,
653 credentials=credentials, lp=lp)
656 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
660 def setup_samdb_rootdse(samdb, setup_path, names):
661 """Setup the SamDB rootdse.
663 :param samdb: Sam Database handle
664 :param setup_path: Obtain setup path
666 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
667 "SCHEMADN": names.schemadn,
668 "NETBIOSNAME": names.netbiosname,
669 "DNSDOMAIN": names.dnsdomain,
670 "REALM": names.realm,
671 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
672 "DOMAINDN": names.domaindn,
673 "ROOTDN": names.rootdn,
674 "CONFIGDN": names.configdn,
675 "SERVERDN": names.serverdn,
679 def setup_self_join(samdb, names,
680 machinepass, dnspass,
681 domainsid, invocationid, setup_path,
683 """Join a host to its own domain."""
684 assert isinstance(invocationid, str)
685 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
686 "CONFIGDN": names.configdn,
687 "SCHEMADN": names.schemadn,
688 "DOMAINDN": names.domaindn,
689 "SERVERDN": names.serverdn,
690 "INVOCATIONID": invocationid,
691 "NETBIOSNAME": names.netbiosname,
692 "DEFAULTSITE": names.sitename,
693 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
694 "MACHINEPASS_B64": b64encode(machinepass),
695 "DNSPASS_B64": b64encode(dnspass),
696 "REALM": names.realm,
697 "DOMAIN": names.domain,
698 "DNSDOMAIN": names.dnsdomain})
699 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
700 "POLICYGUID": policyguid,
701 "DNSDOMAIN": names.dnsdomain,
702 "DOMAINSID": str(domainsid),
703 "DOMAINDN": names.domaindn})
706 def setup_samdb(path, setup_path, session_info, credentials, lp,
708 domainsid, aci, domainguid, policyguid,
709 fill, adminpass, krbtgtpass,
710 machinepass, invocationid, dnspass,
711 serverrole, ldap_backend=None,
712 ldap_backend_type=None):
713 """Setup a complete SAM Database.
715 :note: This will wipe the main SAM database file!
718 erase = (fill != FILL_DRS)
720 # Also wipes the database
721 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
722 credentials=credentials, session_info=session_info,
724 ldap_backend=ldap_backend, serverrole=serverrole,
725 ldap_backend_type=ldap_backend_type, erase=erase)
727 samdb = SamDB(path, session_info=session_info,
728 credentials=credentials, lp=lp)
731 # We want to finish here, but setup the index before we do so
732 message("Setting up sam.ldb index")
733 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
736 message("Pre-loading the Samba 4 and AD schema")
737 samdb.set_domain_sid(domainsid)
738 if serverrole == "domain controller":
739 samdb.set_invocation_id(invocationid)
741 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
742 names.configdn, names.sitename)
744 samdb.transaction_start()
747 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
748 if serverrole == "domain controller":
749 domain_oc = "domainDNS"
751 domain_oc = "samba4LocalDomain"
753 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
754 "DOMAINDN": names.domaindn,
756 "DOMAIN_OC": domain_oc
759 message("Modifying DomainDN: " + names.domaindn + "")
760 if domainguid is not None:
761 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
765 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
766 "LDAPTIME": timestring(int(time.time())),
767 "DOMAINSID": str(domainsid),
768 "SCHEMADN": names.schemadn,
769 "NETBIOSNAME": names.netbiosname,
770 "DEFAULTSITE": names.sitename,
771 "CONFIGDN": names.configdn,
772 "SERVERDN": names.serverdn,
773 "POLICYGUID": policyguid,
774 "DOMAINDN": names.domaindn,
775 "DOMAINGUID_MOD": domainguid_mod,
778 message("Adding configuration container (permitted to fail)")
779 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
780 "CONFIGDN": names.configdn,
783 message("Modifying configuration container")
784 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
785 "CONFIGDN": names.configdn,
786 "SCHEMADN": names.schemadn,
789 message("Adding schema container (permitted to fail)")
790 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
791 "SCHEMADN": names.schemadn,
794 message("Modifying schema container")
796 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
798 setup_modify_ldif(samdb,
799 setup_path("provision_schema_basedn_modify.ldif"), {
800 "SCHEMADN": names.schemadn,
801 "NETBIOSNAME": names.netbiosname,
802 "DEFAULTSITE": names.sitename,
803 "CONFIGDN": names.configdn,
804 "SERVERDN": names.serverdn,
805 "PREFIXMAP_B64": b64encode(prefixmap)
808 message("Setting up sam.ldb Samba4 schema")
809 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
810 {"SCHEMADN": names.schemadn })
811 message("Setting up sam.ldb AD schema")
812 setup_add_ldif(samdb, setup_path("schema.ldif"),
813 {"SCHEMADN": names.schemadn})
815 message("Setting up sam.ldb configuration data")
816 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
817 "CONFIGDN": names.configdn,
818 "NETBIOSNAME": names.netbiosname,
819 "DEFAULTSITE": names.sitename,
820 "DNSDOMAIN": names.dnsdomain,
821 "DOMAIN": names.domain,
822 "SCHEMADN": names.schemadn,
823 "DOMAINDN": names.domaindn,
824 "SERVERDN": names.serverdn
827 message("Setting up display specifiers")
828 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
829 {"CONFIGDN": names.configdn})
831 message("Adding users container (permitted to fail)")
832 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
833 "DOMAINDN": names.domaindn})
834 message("Modifying users container")
835 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
836 "DOMAINDN": names.domaindn})
837 message("Adding computers container (permitted to fail)")
838 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
839 "DOMAINDN": names.domaindn})
840 message("Modifying computers container")
841 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
842 "DOMAINDN": names.domaindn})
843 message("Setting up sam.ldb data")
844 setup_add_ldif(samdb, setup_path("provision.ldif"), {
845 "DOMAINDN": names.domaindn,
846 "NETBIOSNAME": names.netbiosname,
847 "DEFAULTSITE": names.sitename,
848 "CONFIGDN": names.configdn,
849 "SERVERDN": names.serverdn
852 if fill == FILL_FULL:
853 message("Setting up sam.ldb users and groups")
854 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
855 "DOMAINDN": names.domaindn,
856 "DOMAINSID": str(domainsid),
857 "CONFIGDN": names.configdn,
858 "ADMINPASS_B64": b64encode(adminpass),
859 "KRBTGTPASS_B64": b64encode(krbtgtpass),
862 if serverrole == "domain controller":
863 message("Setting up self join")
864 setup_self_join(samdb, names=names, invocationid=invocationid,
866 machinepass=machinepass,
867 domainsid=domainsid, policyguid=policyguid,
868 setup_path=setup_path)
870 #We want to setup the index last, as adds are faster unindexed
871 message("Setting up sam.ldb index")
872 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
874 samdb.transaction_cancel()
877 samdb.transaction_commit()
882 FILL_NT4SYNC = "NT4SYNC"
885 def provision(setup_dir, message, session_info,
886 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
887 rootdn=None, domaindn=None, schemadn=None, configdn=None,
889 domain=None, hostname=None, hostip=None, hostip6=None,
890 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
891 policyguid=None, invocationid=None, machinepass=None,
892 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
893 wheel=None, backup=None, aci=None, serverrole=None,
894 ldap_backend=None, ldap_backend_type=None, sitename=None):
897 :note: caution, this wipes all existing data!
900 def setup_path(file):
901 return os.path.join(setup_dir, file)
903 if domainsid is None:
904 domainsid = security.random_sid()
906 domainsid = security.Sid(domainsid)
908 if policyguid is None:
909 policyguid = str(uuid.uuid4())
910 if adminpass is None:
911 adminpass = misc.random_password(12)
912 if krbtgtpass is None:
913 krbtgtpass = misc.random_password(12)
914 if machinepass is None:
915 machinepass = misc.random_password(12)
917 dnspass = misc.random_password(12)
918 root_uid = findnss_uid([root or "root"])
919 nobody_uid = findnss_uid([nobody or "nobody"])
920 users_gid = findnss_gid([users or "users"])
922 wheel_gid = findnss_gid(["wheel", "adm"])
924 wheel_gid = findnss_gid([wheel])
926 aci = "# no aci for local ldb"
928 if targetdir is not None:
929 if (not os.path.exists(os.path.join(targetdir, "etc"))):
930 os.makedirs(os.path.join(targetdir, "etc"))
931 smbconf = os.path.join(targetdir, "etc", "smb.conf")
933 # only install a new smb.conf if there isn't one there already
934 if not os.path.exists(smbconf):
935 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
938 lp = param.LoadParm()
941 names = guess_names(lp=lp, hostname=hostname, domain=domain,
942 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
943 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
946 paths = provision_paths_from_lp(lp, names.dnsdomain)
949 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
953 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
954 except socket.gaierror:
957 if serverrole is None:
958 serverrole = lp.get("server role")
960 assert serverrole in ("domain controller", "member server", "standalone")
961 if invocationid is None and serverrole == "domain controller":
962 invocationid = str(uuid.uuid4())
964 if not os.path.exists(paths.private_dir):
965 os.mkdir(paths.private_dir)
967 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
969 if ldap_backend is not None:
970 if ldap_backend == "ldapi":
971 # provision-backend will set this path suggested slapd command line / fedorads.inf
972 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
974 # only install a new shares config db if there is none
975 if not os.path.exists(paths.shareconf):
976 message("Setting up share.ldb")
977 share_ldb = Ldb(paths.shareconf, session_info=session_info,
978 credentials=credentials, lp=lp)
979 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
982 message("Setting up secrets.ldb")
983 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
984 session_info=session_info,
985 credentials=credentials, lp=lp)
987 message("Setting up the registry")
988 setup_registry(paths.hklm, setup_path, session_info,
989 credentials=credentials, lp=lp)
991 message("Setting up templates db")
992 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
993 credentials=credentials, lp=lp)
995 message("Setting up idmap db")
996 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
997 credentials=credentials, lp=lp)
999 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1000 credentials=credentials, lp=lp, names=names,
1002 domainsid=domainsid,
1003 aci=aci, domainguid=domainguid, policyguid=policyguid,
1005 adminpass=adminpass, krbtgtpass=krbtgtpass,
1006 invocationid=invocationid,
1007 machinepass=machinepass, dnspass=dnspass,
1008 serverrole=serverrole, ldap_backend=ldap_backend,
1009 ldap_backend_type=ldap_backend_type)
1011 if lp.get("server role") == "domain controller":
1012 if paths.netlogon is None:
1013 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1014 message("Please either remove %s or see the template at %s" %
1015 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1016 assert(paths.netlogon is not None)
1018 if paths.sysvol is None:
1019 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1020 message("Please either remove %s or see the template at %s" %
1021 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1022 assert(paths.sysvol is not None)
1024 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1025 "{" + policyguid + "}")
1026 os.makedirs(policy_path, 0755)
1027 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1028 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1029 os.makedirs(os.path.join(policy_path, "User"), 0755)
1030 if not os.path.isdir(paths.netlogon):
1031 os.makedirs(paths.netlogon, 0755)
1033 if samdb_fill == FILL_FULL:
1034 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1035 root_uid=root_uid, nobody_uid=nobody_uid,
1036 users_gid=users_gid, wheel_gid=wheel_gid)
1038 message("Setting up sam.ldb rootDSE marking as synchronized")
1039 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1041 # Only make a zone file on the first DC, it should be replicated with DNS replication
1042 if serverrole == "domain controller":
1043 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1044 credentials=credentials, lp=lp)
1045 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1046 netbiosname=names.netbiosname, domainsid=domainsid,
1047 keytab_path=paths.keytab, samdb_url=paths.samdb,
1048 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1049 machinepass=machinepass, dnsdomain=names.dnsdomain)
1051 samdb = SamDB(paths.samdb, session_info=session_info,
1052 credentials=credentials, lp=lp)
1054 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1055 assert isinstance(domainguid, str)
1056 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1057 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1058 scope=SCOPE_SUBTREE)
1059 assert isinstance(hostguid, str)
1061 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1062 domaindn=names.domaindn, hostip=hostip,
1063 hostip6=hostip6, hostname=names.hostname,
1064 dnspass=dnspass, realm=names.realm,
1065 domainguid=domainguid, hostguid=hostguid)
1067 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1068 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1070 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1071 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1072 keytab_name=paths.dns_keytab)
1073 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1074 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1076 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1077 hostname=names.hostname, realm=names.realm)
1078 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1080 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1083 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1085 message("Once the above files are installed, your Samba4 server will be ready to use")
1086 message("Server Role: %s" % serverrole)
1087 message("Hostname: %s" % names.hostname)
1088 message("NetBIOS Domain: %s" % names.domain)
1089 message("DNS Domain: %s" % names.dnsdomain)
1090 message("DOMAIN SID: %s" % str(domainsid))
1091 message("Admin password: %s" % adminpass)
1093 result = ProvisionResult()
1094 result.domaindn = domaindn
1095 result.paths = paths
1097 result.samdb = samdb
1101 def provision_become_dc(setup_dir=None,
1102 smbconf=None, targetdir=None, realm=None,
1103 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1105 domain=None, hostname=None, domainsid=None,
1106 adminpass=None, krbtgtpass=None, domainguid=None,
1107 policyguid=None, invocationid=None, machinepass=None,
1108 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1109 wheel=None, backup=None, aci=None, serverrole=None,
1110 ldap_backend=None, ldap_backend_type=None, sitename=None):
1113 """print a message if quiet is not set."""
1116 return provision(setup_dir, message, system_session(), None,
1117 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1118 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1119 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1122 def setup_db_config(setup_path, dbdir):
1123 """Setup a Berkeley database.
1125 :param setup_path: Setup path function.
1126 :param dbdir: Database directory."""
1127 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1128 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1129 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1130 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1132 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1133 {"LDAPDBDIR": dbdir})
1137 def provision_backend(setup_dir=None, message=None,
1138 smbconf=None, targetdir=None, realm=None,
1139 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1140 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1141 ldap_backend_type=None, ldap_backend_port=None):
1143 def setup_path(file):
1144 return os.path.join(setup_dir, file)
1146 if hostname is None:
1147 hostname = socket.gethostname().split(".")[0].lower()
1150 root = findnss(pwd.getpwnam, ["root"])[0]
1152 if adminpass is None:
1153 adminpass = misc.random_password(12)
1155 if targetdir is not None:
1156 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1157 os.makedirs(os.path.join(targetdir, "etc"))
1158 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1160 # only install a new smb.conf if there isn't one there already
1161 if not os.path.exists(smbconf):
1162 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1165 lp = param.LoadParm()
1168 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1169 dnsdomain=realm, serverrole=serverrole,
1170 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1173 paths = provision_paths_from_lp(lp, names.dnsdomain)
1175 if not os.path.isdir(paths.ldapdir):
1176 os.makedirs(paths.ldapdir, 0700)
1177 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1179 os.unlink(schemadb_path)
1183 schemadb = Ldb(schemadb_path, lp=lp)
1185 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1187 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1188 {"SCHEMADN": names.schemadn,
1191 setup_modify_ldif(schemadb,
1192 setup_path("provision_schema_basedn_modify.ldif"), \
1193 {"SCHEMADN": names.schemadn,
1194 "NETBIOSNAME": names.netbiosname,
1195 "DEFAULTSITE": DEFAULTSITE,
1196 "CONFIGDN": names.configdn,
1197 "SERVERDN": names.serverdn,
1198 "PREFIXMAP_B64": b64encode(prefixmap)
1201 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1202 {"SCHEMADN": names.schemadn })
1203 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1204 {"SCHEMADN": names.schemadn})
1206 if ldap_backend_type == "fedora-ds":
1207 if ldap_backend_port is not None:
1208 serverport = "ServerPort=%d" % ldap_backend_port
1212 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1214 "HOSTNAME": hostname,
1215 "DNSDOMAIN": names.dnsdomain,
1216 "LDAPDIR": paths.ldapdir,
1217 "DOMAINDN": names.domaindn,
1218 "LDAPMANAGERDN": names.ldapmanagerdn,
1219 "LDAPMANAGERPASS": adminpass,
1220 "SERVERPORT": serverport})
1222 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1223 {"CONFIGDN": names.configdn,
1224 "SCHEMADN": names.schemadn,
1227 mapping = "schema-map-fedora-ds-1.0"
1228 backend_schema = "99_ad.ldif"
1230 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1232 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1234 elif ldap_backend_type == "openldap":
1235 attrs = ["linkID", "lDAPDisplayName"]
1236 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1238 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1239 refint_attributes = ""
1240 for i in range (0, len(res)):
1241 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1242 target = schemadb.searchone(basedn=names.schemadn,
1243 expression=expression,
1244 attribute="lDAPDisplayName",
1245 scope=SCOPE_SUBTREE)
1246 if target is not None:
1247 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1249 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1250 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1251 "MEMBEROF_ATTR" : str(target) })
1253 refint_config = read_and_sub_file(setup_path("refint.conf"),
1254 { "LINK_ATTRS" : refint_attributes})
1256 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1257 {"DNSDOMAIN": names.dnsdomain,
1258 "LDAPDIR": paths.ldapdir,
1259 "DOMAINDN": names.domaindn,
1260 "CONFIGDN": names.configdn,
1261 "SCHEMADN": names.schemadn,
1262 "MEMBEROF_CONFIG": memberof_config,
1263 "REFINT_CONFIG": refint_config})
1264 setup_file(setup_path("modules.conf"), paths.modulesconf,
1265 {"REALM": names.realm})
1267 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1268 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1269 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1271 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1272 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1274 setup_file(setup_path("cn=samba.ldif"),
1275 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1276 { "UUID": str(uuid.uuid4()),
1277 "LDAPTIME": timestring(int(time.time()))} )
1278 setup_file(setup_path("cn=samba-admin.ldif"),
1279 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1280 {"LDAPADMINPASS_B64": b64encode(adminpass),
1281 "UUID": str(uuid.uuid4()),
1282 "LDAPTIME": timestring(int(time.time()))} )
1284 mapping = "schema-map-openldap-2.3"
1285 backend_schema = "backend-schema.schema"
1287 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1288 if ldap_backend_port is not None:
1289 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1291 server_port_string = ""
1293 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1295 ldapuser = "--username=samba-admin"
1298 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)
1300 os.system(schema_command)
1302 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1303 message("Server Role: %s" % serverrole)
1304 message("Hostname: %s" % names.hostname)
1305 message("DNS Domain: %s" % names.dnsdomain)
1306 message("Base DN: %s" % names.domaindn)
1308 if ldap_backend_type == "openldap":
1309 message("LDAP admin user: samba-admin")
1311 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1313 message("LDAP admin password: %s" % adminpass)
1314 message(slapdcommand)
1315 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1317 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1318 """Create a PHP LDAP admin configuration file.
1320 :param path: Path to write the configuration to.
1321 :param setup_path: Function to generate setup paths.
1323 setup_file(setup_path("phpldapadmin-config.php"), path,
1324 {"S4_LDAPI_URI": ldapi_uri})
1327 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1328 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1329 """Write out a DNS zone file, from the info in the current database.
1331 :param path: Path of the new zone file.
1332 :param setup_path: Setup path function.
1333 :param dnsdomain: DNS Domain name
1334 :param domaindn: DN of the Domain
1335 :param hostip: Local IPv4 IP
1336 :param hostip6: Local IPv6 IP
1337 :param hostname: Local hostname
1338 :param dnspass: Password for DNS
1339 :param realm: Realm name
1340 :param domainguid: GUID of the domain.
1341 :param hostguid: GUID of the host.
1343 assert isinstance(domainguid, str)
1345 if hostip6 is not None:
1346 hostip6_base_line = " IN AAAA " + hostip6
1347 hostip6_host_line = hostname + " IN AAAA " + hostip6
1349 hostip6_base_line = ""
1350 hostip6_host_line = ""
1352 setup_file(setup_path("provision.zone"), path, {
1353 "DNSPASS_B64": b64encode(dnspass),
1354 "HOSTNAME": hostname,
1355 "DNSDOMAIN": dnsdomain,
1358 "DOMAINGUID": domainguid,
1359 "DATESTRING": time.strftime("%Y%m%d%H"),
1360 "DEFAULTSITE": DEFAULTSITE,
1361 "HOSTGUID": hostguid,
1362 "HOSTIP6_BASE_LINE": hostip6_base_line,
1363 "HOSTIP6_HOST_LINE": hostip6_host_line,
1367 def create_named_conf(path, setup_path, realm, dnsdomain,
1369 """Write out a file containing zone statements suitable for inclusion in a
1370 named.conf file (including GSS-TSIG configuration).
1372 :param path: Path of the new named.conf file.
1373 :param setup_path: Setup path function.
1374 :param realm: Realm name
1375 :param dnsdomain: DNS Domain name
1376 :param private_dir: Path to private directory
1377 :param keytab_name: File name of DNS keytab file
1380 setup_file(setup_path("named.conf"), path, {
1381 "DNSDOMAIN": dnsdomain,
1383 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1384 "PRIVATE_DIR": private_dir
1387 def create_named_txt(path, setup_path, realm, dnsdomain,
1388 private_dir, keytab_name):
1389 """Write out a file containing zone statements suitable for inclusion in a
1390 named.conf file (including GSS-TSIG configuration).
1392 :param path: Path of the new named.conf file.
1393 :param setup_path: Setup path function.
1394 :param realm: Realm name
1395 :param dnsdomain: DNS Domain name
1396 :param private_dir: Path to private directory
1397 :param keytab_name: File name of DNS keytab file
1400 setup_file(setup_path("named.txt"), path, {
1401 "DNSDOMAIN": dnsdomain,
1403 "DNS_KEYTAB": keytab_name,
1404 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1405 "PRIVATE_DIR": private_dir
1408 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1409 """Write out a file containing zone statements suitable for inclusion in a
1410 named.conf file (including GSS-TSIG configuration).
1412 :param path: Path of the new named.conf file.
1413 :param setup_path: Setup path function.
1414 :param dnsdomain: DNS Domain name
1415 :param hostname: Local hostname
1416 :param realm: Realm name
1419 setup_file(setup_path("krb5.conf"), path, {
1420 "DNSDOMAIN": dnsdomain,
1421 "HOSTNAME": hostname,
1426 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
1427 """Load schema for the SamDB.
1429 :param samdb: Load a schema into a SamDB.
1430 :param setup_path: Setup path function.
1431 :param schemadn: DN of the schema
1432 :param netbiosname: NetBIOS name of the host.
1433 :param configdn: DN of the configuration
1435 schema_data = open(setup_path("schema.ldif"), 'r').read()
1436 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1437 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1438 check_all_substituted(schema_data)
1439 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1440 prefixmap = b64encode(prefixmap)
1442 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1443 head_data = substitute_var(head_data, {
1444 "SCHEMADN": schemadn,
1445 "NETBIOSNAME": netbiosname,
1446 "CONFIGDN": configdn,
1447 "DEFAULTSITE":sitename,
1448 "PREFIXMAP_B64":prefixmap
1450 check_all_substituted(head_data)
1451 samdb.attach_schema_from_ldif(head_data, schema_data)