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,
782 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
784 message("Modifying configuration container")
785 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
786 "CONFIGDN": names.configdn,
787 "SCHEMADN": names.schemadn,
790 message("Adding schema container (permitted to fail)")
791 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
792 "SCHEMADN": names.schemadn,
794 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
796 message("Modifying schema container")
798 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
800 setup_modify_ldif(samdb,
801 setup_path("provision_schema_basedn_modify.ldif"), {
802 "SCHEMADN": names.schemadn,
803 "NETBIOSNAME": names.netbiosname,
804 "DEFAULTSITE": names.sitename,
805 "CONFIGDN": names.configdn,
806 "SERVERDN": names.serverdn,
807 "PREFIXMAP_B64": b64encode(prefixmap)
810 message("Setting up sam.ldb Samba4 schema")
811 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
812 {"SCHEMADN": names.schemadn })
813 message("Setting up sam.ldb AD schema")
814 setup_add_ldif(samdb, setup_path("schema.ldif"),
815 {"SCHEMADN": names.schemadn})
817 message("Setting up sam.ldb configuration data")
818 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
819 "CONFIGDN": names.configdn,
820 "NETBIOSNAME": names.netbiosname,
821 "DEFAULTSITE": names.sitename,
822 "DNSDOMAIN": names.dnsdomain,
823 "DOMAIN": names.domain,
824 "SCHEMADN": names.schemadn,
825 "DOMAINDN": names.domaindn,
826 "SERVERDN": names.serverdn
829 message("Setting up display specifiers")
830 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
831 {"CONFIGDN": names.configdn})
833 message("Adding users container (permitted to fail)")
834 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
835 "DOMAINDN": names.domaindn})
836 message("Modifying users container")
837 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
838 "DOMAINDN": names.domaindn})
839 message("Adding computers container (permitted to fail)")
840 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
841 "DOMAINDN": names.domaindn})
842 message("Modifying computers container")
843 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
844 "DOMAINDN": names.domaindn})
845 message("Setting up sam.ldb data")
846 setup_add_ldif(samdb, setup_path("provision.ldif"), {
847 "DOMAINDN": names.domaindn,
848 "NETBIOSNAME": names.netbiosname,
849 "DEFAULTSITE": names.sitename,
850 "CONFIGDN": names.configdn,
851 "SERVERDN": names.serverdn
854 if fill == FILL_FULL:
855 message("Setting up sam.ldb users and groups")
856 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
857 "DOMAINDN": names.domaindn,
858 "DOMAINSID": str(domainsid),
859 "CONFIGDN": names.configdn,
860 "ADMINPASS_B64": b64encode(adminpass),
861 "KRBTGTPASS_B64": b64encode(krbtgtpass),
864 if serverrole == "domain controller":
865 message("Setting up self join")
866 setup_self_join(samdb, names=names, invocationid=invocationid,
868 machinepass=machinepass,
869 domainsid=domainsid, policyguid=policyguid,
870 setup_path=setup_path)
872 #We want to setup the index last, as adds are faster unindexed
873 message("Setting up sam.ldb index")
874 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
876 samdb.transaction_cancel()
879 samdb.transaction_commit()
884 FILL_NT4SYNC = "NT4SYNC"
887 def provision(setup_dir, message, session_info,
888 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
889 rootdn=None, domaindn=None, schemadn=None, configdn=None,
891 domain=None, hostname=None, hostip=None, hostip6=None,
892 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
893 policyguid=None, invocationid=None, machinepass=None,
894 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
895 wheel=None, backup=None, aci=None, serverrole=None,
896 ldap_backend=None, ldap_backend_type=None, sitename=None):
899 :note: caution, this wipes all existing data!
902 def setup_path(file):
903 return os.path.join(setup_dir, file)
905 if domainsid is None:
906 domainsid = security.random_sid()
908 domainsid = security.Sid(domainsid)
910 if policyguid is None:
911 policyguid = str(uuid.uuid4())
912 if adminpass is None:
913 adminpass = misc.random_password(12)
914 if krbtgtpass is None:
915 krbtgtpass = misc.random_password(12)
916 if machinepass is None:
917 machinepass = misc.random_password(12)
919 dnspass = misc.random_password(12)
920 root_uid = findnss_uid([root or "root"])
921 nobody_uid = findnss_uid([nobody or "nobody"])
922 users_gid = findnss_gid([users or "users"])
924 wheel_gid = findnss_gid(["wheel", "adm"])
926 wheel_gid = findnss_gid([wheel])
928 aci = "# no aci for local ldb"
930 if targetdir is not None:
931 if (not os.path.exists(os.path.join(targetdir, "etc"))):
932 os.makedirs(os.path.join(targetdir, "etc"))
933 smbconf = os.path.join(targetdir, "etc", "smb.conf")
935 # only install a new smb.conf if there isn't one there already
936 if not os.path.exists(smbconf):
937 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
940 lp = param.LoadParm()
943 names = guess_names(lp=lp, hostname=hostname, domain=domain,
944 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
945 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
948 paths = provision_paths_from_lp(lp, names.dnsdomain)
951 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
955 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
956 except socket.gaierror:
959 if serverrole is None:
960 serverrole = lp.get("server role")
962 assert serverrole in ("domain controller", "member server", "standalone")
963 if invocationid is None and serverrole == "domain controller":
964 invocationid = str(uuid.uuid4())
966 if not os.path.exists(paths.private_dir):
967 os.mkdir(paths.private_dir)
969 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
971 if ldap_backend is not None:
972 if ldap_backend == "ldapi":
973 # provision-backend will set this path suggested slapd command line / fedorads.inf
974 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
976 # only install a new shares config db if there is none
977 if not os.path.exists(paths.shareconf):
978 message("Setting up share.ldb")
979 share_ldb = Ldb(paths.shareconf, session_info=session_info,
980 credentials=credentials, lp=lp)
981 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
984 message("Setting up secrets.ldb")
985 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
986 session_info=session_info,
987 credentials=credentials, lp=lp)
989 message("Setting up the registry")
990 setup_registry(paths.hklm, setup_path, session_info,
991 credentials=credentials, lp=lp)
993 message("Setting up templates db")
994 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
995 credentials=credentials, lp=lp)
997 message("Setting up idmap db")
998 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
999 credentials=credentials, lp=lp)
1001 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1002 credentials=credentials, lp=lp, names=names,
1004 domainsid=domainsid,
1005 aci=aci, domainguid=domainguid, policyguid=policyguid,
1007 adminpass=adminpass, krbtgtpass=krbtgtpass,
1008 invocationid=invocationid,
1009 machinepass=machinepass, dnspass=dnspass,
1010 serverrole=serverrole, ldap_backend=ldap_backend,
1011 ldap_backend_type=ldap_backend_type)
1013 if lp.get("server role") == "domain controller":
1014 if paths.netlogon is None:
1015 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1016 message("Please either remove %s or see the template at %s" %
1017 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1018 assert(paths.netlogon is not None)
1020 if paths.sysvol is None:
1021 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1022 message("Please either remove %s or see the template at %s" %
1023 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1024 assert(paths.sysvol is not None)
1026 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1027 "{" + policyguid + "}")
1028 os.makedirs(policy_path, 0755)
1029 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1030 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1031 os.makedirs(os.path.join(policy_path, "User"), 0755)
1032 if not os.path.isdir(paths.netlogon):
1033 os.makedirs(paths.netlogon, 0755)
1035 if samdb_fill == FILL_FULL:
1036 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1037 root_uid=root_uid, nobody_uid=nobody_uid,
1038 users_gid=users_gid, wheel_gid=wheel_gid)
1040 message("Setting up sam.ldb rootDSE marking as synchronized")
1041 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1043 # Only make a zone file on the first DC, it should be replicated with DNS replication
1044 if serverrole == "domain controller":
1045 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1046 credentials=credentials, lp=lp)
1047 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1048 netbiosname=names.netbiosname, domainsid=domainsid,
1049 keytab_path=paths.keytab, samdb_url=paths.samdb,
1050 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1051 machinepass=machinepass, dnsdomain=names.dnsdomain)
1053 samdb = SamDB(paths.samdb, session_info=session_info,
1054 credentials=credentials, lp=lp)
1056 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1057 assert isinstance(domainguid, str)
1058 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1059 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1060 scope=SCOPE_SUBTREE)
1061 assert isinstance(hostguid, str)
1063 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1064 domaindn=names.domaindn, hostip=hostip,
1065 hostip6=hostip6, hostname=names.hostname,
1066 dnspass=dnspass, realm=names.realm,
1067 domainguid=domainguid, hostguid=hostguid)
1069 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1070 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1072 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1073 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1074 keytab_name=paths.dns_keytab)
1075 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1076 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1078 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1079 hostname=names.hostname, realm=names.realm)
1080 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1082 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1085 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1087 message("Once the above files are installed, your Samba4 server will be ready to use")
1088 message("Server Role: %s" % serverrole)
1089 message("Hostname: %s" % names.hostname)
1090 message("NetBIOS Domain: %s" % names.domain)
1091 message("DNS Domain: %s" % names.dnsdomain)
1092 message("DOMAIN SID: %s" % str(domainsid))
1093 message("Admin password: %s" % adminpass)
1095 result = ProvisionResult()
1096 result.domaindn = domaindn
1097 result.paths = paths
1099 result.samdb = samdb
1103 def provision_become_dc(setup_dir=None,
1104 smbconf=None, targetdir=None, realm=None,
1105 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1107 domain=None, hostname=None, domainsid=None,
1108 adminpass=None, krbtgtpass=None, domainguid=None,
1109 policyguid=None, invocationid=None, machinepass=None,
1110 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1111 wheel=None, backup=None, aci=None, serverrole=None,
1112 ldap_backend=None, ldap_backend_type=None, sitename=None):
1115 """print a message if quiet is not set."""
1118 return provision(setup_dir, message, system_session(), None,
1119 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1120 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1121 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1124 def setup_db_config(setup_path, dbdir):
1125 """Setup a Berkeley database.
1127 :param setup_path: Setup path function.
1128 :param dbdir: Database directory."""
1129 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1130 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1131 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1132 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1134 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1135 {"LDAPDBDIR": dbdir})
1139 def provision_backend(setup_dir=None, message=None,
1140 smbconf=None, targetdir=None, realm=None,
1141 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1142 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1143 ldap_backend_type=None, ldap_backend_port=None):
1145 def setup_path(file):
1146 return os.path.join(setup_dir, file)
1148 if hostname is None:
1149 hostname = socket.gethostname().split(".")[0].lower()
1152 root = findnss(pwd.getpwnam, ["root"])[0]
1154 if adminpass is None:
1155 adminpass = misc.random_password(12)
1157 if targetdir is not None:
1158 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1159 os.makedirs(os.path.join(targetdir, "etc"))
1160 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1162 # only install a new smb.conf if there isn't one there already
1163 if not os.path.exists(smbconf):
1164 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1167 lp = param.LoadParm()
1170 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1171 dnsdomain=realm, serverrole=serverrole,
1172 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1175 paths = provision_paths_from_lp(lp, names.dnsdomain)
1177 if not os.path.isdir(paths.ldapdir):
1178 os.makedirs(paths.ldapdir, 0700)
1179 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1181 os.unlink(schemadb_path)
1185 schemadb = Ldb(schemadb_path, lp=lp)
1187 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1189 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1190 {"SCHEMADN": names.schemadn,
1192 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
1194 setup_modify_ldif(schemadb,
1195 setup_path("provision_schema_basedn_modify.ldif"), \
1196 {"SCHEMADN": names.schemadn,
1197 "NETBIOSNAME": names.netbiosname,
1198 "DEFAULTSITE": DEFAULTSITE,
1199 "CONFIGDN": names.configdn,
1200 "SERVERDN": names.serverdn,
1201 "PREFIXMAP_B64": b64encode(prefixmap)
1204 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1205 {"SCHEMADN": names.schemadn })
1206 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1207 {"SCHEMADN": names.schemadn})
1209 if ldap_backend_type == "fedora-ds":
1210 if ldap_backend_port is not None:
1211 serverport = "ServerPort=%d" % ldap_backend_port
1215 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1217 "HOSTNAME": hostname,
1218 "DNSDOMAIN": names.dnsdomain,
1219 "LDAPDIR": paths.ldapdir,
1220 "DOMAINDN": names.domaindn,
1221 "LDAPMANAGERDN": names.ldapmanagerdn,
1222 "LDAPMANAGERPASS": adminpass,
1223 "SERVERPORT": serverport})
1225 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1226 {"CONFIGDN": names.configdn,
1227 "SCHEMADN": names.schemadn,
1230 mapping = "schema-map-fedora-ds-1.0"
1231 backend_schema = "99_ad.ldif"
1233 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1235 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1237 elif ldap_backend_type == "openldap":
1238 attrs = ["linkID", "lDAPDisplayName"]
1239 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1241 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1242 refint_attributes = ""
1243 for i in range (0, len(res)):
1244 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1245 target = schemadb.searchone(basedn=names.schemadn,
1246 expression=expression,
1247 attribute="lDAPDisplayName",
1248 scope=SCOPE_SUBTREE)
1249 if target is not None:
1250 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1252 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1253 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1254 "MEMBEROF_ATTR" : str(target) })
1256 refint_config = read_and_sub_file(setup_path("refint.conf"),
1257 { "LINK_ATTRS" : refint_attributes})
1259 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1260 {"DNSDOMAIN": names.dnsdomain,
1261 "LDAPDIR": paths.ldapdir,
1262 "DOMAINDN": names.domaindn,
1263 "CONFIGDN": names.configdn,
1264 "SCHEMADN": names.schemadn,
1265 "MEMBEROF_CONFIG": memberof_config,
1266 "REFINT_CONFIG": refint_config})
1267 setup_file(setup_path("modules.conf"), paths.modulesconf,
1268 {"REALM": names.realm})
1270 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1271 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1272 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1274 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1275 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1277 setup_file(setup_path("cn=samba.ldif"),
1278 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1279 { "UUID": str(uuid.uuid4()),
1280 "LDAPTIME": timestring(int(time.time()))} )
1281 setup_file(setup_path("cn=samba-admin.ldif"),
1282 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1283 {"LDAPADMINPASS_B64": b64encode(adminpass),
1284 "UUID": str(uuid.uuid4()),
1285 "LDAPTIME": timestring(int(time.time()))} )
1287 mapping = "schema-map-openldap-2.3"
1288 backend_schema = "backend-schema.schema"
1290 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1291 if ldap_backend_port is not None:
1292 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1294 server_port_string = ""
1296 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1298 ldapuser = "--username=samba-admin"
1301 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)
1303 os.system(schema_command)
1305 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1306 message("Server Role: %s" % serverrole)
1307 message("Hostname: %s" % names.hostname)
1308 message("DNS Domain: %s" % names.dnsdomain)
1309 message("Base DN: %s" % names.domaindn)
1311 if ldap_backend_type == "openldap":
1312 message("LDAP admin user: samba-admin")
1314 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1316 message("LDAP admin password: %s" % adminpass)
1317 message(slapdcommand)
1318 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1320 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1321 """Create a PHP LDAP admin configuration file.
1323 :param path: Path to write the configuration to.
1324 :param setup_path: Function to generate setup paths.
1326 setup_file(setup_path("phpldapadmin-config.php"), path,
1327 {"S4_LDAPI_URI": ldapi_uri})
1330 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1331 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1332 """Write out a DNS zone file, from the info in the current database.
1334 :param path: Path of the new zone file.
1335 :param setup_path: Setup path function.
1336 :param dnsdomain: DNS Domain name
1337 :param domaindn: DN of the Domain
1338 :param hostip: Local IPv4 IP
1339 :param hostip6: Local IPv6 IP
1340 :param hostname: Local hostname
1341 :param dnspass: Password for DNS
1342 :param realm: Realm name
1343 :param domainguid: GUID of the domain.
1344 :param hostguid: GUID of the host.
1346 assert isinstance(domainguid, str)
1348 if hostip6 is not None:
1349 hostip6_base_line = " IN AAAA " + hostip6
1350 hostip6_host_line = hostname + " IN AAAA " + hostip6
1352 hostip6_base_line = ""
1353 hostip6_host_line = ""
1355 setup_file(setup_path("provision.zone"), path, {
1356 "DNSPASS_B64": b64encode(dnspass),
1357 "HOSTNAME": hostname,
1358 "DNSDOMAIN": dnsdomain,
1361 "DOMAINGUID": domainguid,
1362 "DATESTRING": time.strftime("%Y%m%d%H"),
1363 "DEFAULTSITE": DEFAULTSITE,
1364 "HOSTGUID": hostguid,
1365 "HOSTIP6_BASE_LINE": hostip6_base_line,
1366 "HOSTIP6_HOST_LINE": hostip6_host_line,
1370 def create_named_conf(path, setup_path, realm, dnsdomain,
1372 """Write out a file containing zone statements suitable for inclusion in a
1373 named.conf file (including GSS-TSIG configuration).
1375 :param path: Path of the new named.conf file.
1376 :param setup_path: Setup path function.
1377 :param realm: Realm name
1378 :param dnsdomain: DNS Domain name
1379 :param private_dir: Path to private directory
1380 :param keytab_name: File name of DNS keytab file
1383 setup_file(setup_path("named.conf"), path, {
1384 "DNSDOMAIN": dnsdomain,
1386 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1387 "PRIVATE_DIR": private_dir
1390 def create_named_txt(path, setup_path, realm, dnsdomain,
1391 private_dir, keytab_name):
1392 """Write out a file containing zone statements suitable for inclusion in a
1393 named.conf file (including GSS-TSIG configuration).
1395 :param path: Path of the new named.conf file.
1396 :param setup_path: Setup path function.
1397 :param realm: Realm name
1398 :param dnsdomain: DNS Domain name
1399 :param private_dir: Path to private directory
1400 :param keytab_name: File name of DNS keytab file
1403 setup_file(setup_path("named.txt"), path, {
1404 "DNSDOMAIN": dnsdomain,
1406 "DNS_KEYTAB": keytab_name,
1407 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1408 "PRIVATE_DIR": private_dir
1411 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1412 """Write out a file containing zone statements suitable for inclusion in a
1413 named.conf file (including GSS-TSIG configuration).
1415 :param path: Path of the new named.conf file.
1416 :param setup_path: Setup path function.
1417 :param dnsdomain: DNS Domain name
1418 :param hostname: Local hostname
1419 :param realm: Realm name
1422 setup_file(setup_path("krb5.conf"), path, {
1423 "DNSDOMAIN": dnsdomain,
1424 "HOSTNAME": hostname,
1429 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
1430 """Load schema for the SamDB.
1432 :param samdb: Load a schema into a SamDB.
1433 :param setup_path: Setup path function.
1434 :param schemadn: DN of the schema
1435 :param netbiosname: NetBIOS name of the host.
1436 :param configdn: DN of the configuration
1438 schema_data = open(setup_path("schema.ldif"), 'r').read()
1439 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1440 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1441 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1442 prefixmap = b64encode(prefixmap)
1444 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1445 head_data = substitute_var(head_data, {
1446 "SCHEMADN": schemadn,
1447 "NETBIOSNAME": netbiosname,
1448 "CONFIGDN": configdn,
1449 "DEFAULTSITE":sitename,
1450 "PREFIXMAP_B64":prefixmap
1452 samdb.attach_schema_from_ldif(head_data, schema_data)