2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 """Functions for setting up a Samba configuration."""
27 from base64 import b64encode
37 from auth import system_session
38 from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
39 from samba.samdb import SamDB
40 from samba.idmap import IDmapDB
43 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
44 LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
46 __docformat__ = "restructuredText"
48 DEFAULTSITE = "Default-First-Site-Name"
50 class InvalidNetbiosName(Exception):
51 """A specified name was not a valid NetBIOS name."""
52 def __init__(self, name):
53 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
56 class ProvisionPaths(object):
69 self.dns_keytab = None
72 self.private_dir = None
75 self.modulesconf = None
76 self.memberofconf = None
77 self.fedoradsinf = None
78 self.fedoradspartitions = None
81 class ProvisionNames(object):
87 self.ldapmanagerdn = None
90 self.netbiosname = None
97 class ProvisionResult(object):
104 def check_install(lp, session_info, credentials):
105 """Check whether the current install seems ok.
107 :param lp: Loadparm context
108 :param session_info: Session information
109 :param credentials: Credentials
111 if lp.get("realm") == "":
112 raise Exception("Realm empty")
113 ldb = Ldb(lp.get("sam database"), session_info=session_info,
114 credentials=credentials, lp=lp)
115 if len(ldb.search("(cn=Administrator)")) != 1:
116 raise "No administrator account found"
119 def findnss(nssfn, names):
120 """Find a user or group from a list of possibilities.
122 :param nssfn: NSS Function to try (should raise KeyError if not found)
123 :param names: Names to check.
124 :return: Value return by first names list.
131 raise KeyError("Unable to find user/group %r" % names)
134 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
135 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
138 def read_and_sub_file(file, subst_vars):
139 """Read a file and sub in variables found in it
141 :param file: File to be read (typically from setup directory)
142 param subst_vars: Optional variables to subsitute in the file.
144 data = open(file, 'r').read()
145 if subst_vars is not None:
146 data = substitute_var(data, subst_vars)
147 check_all_substituted(data)
151 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
152 """Setup a ldb in the private dir.
154 :param ldb: LDB file to import data into
155 :param ldif_path: Path of the LDIF file to load
156 :param subst_vars: Optional variables to subsitute in LDIF.
158 assert isinstance(ldif_path, str)
160 data = read_and_sub_file(ldif_path, subst_vars)
164 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
165 """Modify a ldb in the private dir.
167 :param ldb: LDB object.
168 :param ldif_path: LDIF file path.
169 :param subst_vars: Optional dictionary with substitution variables.
171 data = read_and_sub_file(ldif_path, subst_vars)
173 ldb.modify_ldif(data)
176 def setup_ldb(ldb, ldif_path, subst_vars):
177 """Import a LDIF a file into a LDB handle, optionally substituting variables.
179 :note: Either all LDIF data will be added or none (using transactions).
181 :param ldb: LDB file to import into.
182 :param ldif_path: Path to the LDIF file.
183 :param subst_vars: Dictionary with substitution variables.
185 assert ldb is not None
186 ldb.transaction_start()
188 setup_add_ldif(ldb, ldif_path, subst_vars)
190 ldb.transaction_cancel()
192 ldb.transaction_commit()
195 def setup_file(template, fname, subst_vars):
196 """Setup a file in the private dir.
198 :param template: Path of the template file.
199 :param fname: Path of the file to create.
200 :param subst_vars: Substitution variables.
204 if os.path.exists(f):
207 data = read_and_sub_file(template, subst_vars)
208 open(f, 'w').write(data)
211 def provision_paths_from_lp(lp, dnsdomain):
212 """Set the default paths for provisioning.
214 :param lp: Loadparm context.
215 :param dnsdomain: DNS Domain name
217 paths = ProvisionPaths()
218 paths.private_dir = lp.get("private dir")
219 paths.keytab = "secrets.keytab"
220 paths.dns_keytab = "dns.keytab"
222 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
223 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
224 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
225 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
226 paths.templates = os.path.join(paths.private_dir, "templates.ldb")
227 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
228 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
229 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
230 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
231 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
232 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
233 paths.phpldapadminconfig = os.path.join(paths.private_dir,
234 "phpldapadmin-config.php")
235 paths.ldapdir = os.path.join(paths.private_dir,
237 paths.slapdconf = os.path.join(paths.ldapdir,
239 paths.modulesconf = os.path.join(paths.ldapdir,
241 paths.memberofconf = os.path.join(paths.ldapdir,
243 paths.fedoradsinf = os.path.join(paths.ldapdir,
245 paths.fedoradspartitions = os.path.join(paths.ldapdir,
246 "fedorads-partitions.ldif")
247 paths.hklm = "hklm.ldb"
248 paths.hkcr = "hkcr.ldb"
249 paths.hkcu = "hkcu.ldb"
250 paths.hku = "hku.ldb"
251 paths.hkpd = "hkpd.ldb"
252 paths.hkpt = "hkpt.ldb"
254 paths.sysvol = lp.get("path", "sysvol")
256 paths.netlogon = lp.get("path", "netlogon")
258 paths.smbconf = lp.configfile()
263 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None,
264 rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None,
266 """Guess configuration settings to use."""
269 hostname = socket.gethostname().split(".")[0].lower()
271 netbiosname = hostname.upper()
272 if not valid_netbios_name(netbiosname):
273 raise InvalidNetbiosName(netbiosname)
275 hostname = hostname.lower()
277 if dnsdomain is None:
278 dnsdomain = lp.get("realm")
280 if serverrole is None:
281 serverrole = lp.get("server role")
283 assert dnsdomain is not None
284 realm = dnsdomain.upper()
286 if lp.get("realm").upper() != realm:
287 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
288 (lp.get("realm"), lp.configfile(), realm))
290 dnsdomain = dnsdomain.lower()
292 if serverrole == "domain controller":
294 domain = lp.get("workgroup")
296 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
297 if lp.get("workgroup").upper() != domain.upper():
298 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
299 lp.get("workgroup"), domain)
303 domaindn = "CN=" + netbiosname
305 assert domain is not None
306 domain = domain.upper()
307 if not valid_netbios_name(domain):
308 raise InvalidNetbiosName(domain)
314 configdn = "CN=Configuration," + rootdn
316 schemadn = "CN=Schema," + configdn
321 names = ProvisionNames()
322 names.rootdn = rootdn
323 names.domaindn = domaindn
324 names.configdn = configdn
325 names.schemadn = schemadn
326 names.ldapmanagerdn = "CN=Manager," + rootdn
327 names.dnsdomain = dnsdomain
328 names.domain = domain
330 names.netbiosname = netbiosname
331 names.hostname = hostname
332 names.sitename = sitename
333 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
338 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
341 hostname = socket.gethostname().split(".")[0].lower()
343 if serverrole is None:
344 serverrole = "standalone"
346 assert serverrole in ("domain controller", "member server", "standalone")
347 if serverrole == "domain controller":
349 elif serverrole == "member server":
350 smbconfsuffix = "member"
351 elif serverrole == "standalone":
352 smbconfsuffix = "standalone"
354 assert domain is not None
355 assert realm is not None
357 default_lp = param.LoadParm()
358 #Load non-existant file
359 default_lp.load(smbconf)
361 if targetdir is not None:
362 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
363 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
365 default_lp.set("lock dir", os.path.abspath(targetdir))
370 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
371 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
373 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
375 "HOSTNAME": hostname,
378 "SERVERROLE": serverrole,
379 "NETLOGONPATH": netlogon,
380 "SYSVOLPATH": sysvol,
381 "PRIVATEDIR_LINE": privatedir_line,
382 "LOCKDIR_LINE": lockdir_line
387 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
388 users_gid, wheel_gid):
389 """setup reasonable name mappings for sam names to unix names.
391 :param samdb: SamDB object.
392 :param idmap: IDmap db object.
393 :param sid: The domain sid.
394 :param domaindn: The domain DN.
395 :param root_uid: uid of the UNIX root user.
396 :param nobody_uid: uid of the UNIX nobody user.
397 :param users_gid: gid of the UNIX users group.
398 :param wheel_gid: gid of the UNIX wheel group."""
399 # add some foreign sids if they are not present already
400 samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
401 samdb.add_foreign(domaindn, "S-1-1-0", "World")
402 samdb.add_foreign(domaindn, "S-1-5-2", "Network")
403 samdb.add_foreign(domaindn, "S-1-5-18", "System")
404 samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
406 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
407 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
409 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
410 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
413 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
415 serverrole, ldap_backend=None,
416 ldap_backend_type=None, erase=False):
417 """Setup the partitions for the SAM database.
419 Alternatively, provision() may call this, and then populate the database.
421 :note: This will wipe the Sam Database!
423 :note: This function always removes the local SAM LDB file. The erase
424 parameter controls whether to erase the existing data, which
425 may not be stored locally but in LDAP.
427 assert session_info is not None
429 samdb = SamDB(samdb_path, session_info=session_info,
430 credentials=credentials, lp=lp)
436 os.unlink(samdb_path)
438 samdb = SamDB(samdb_path, session_info=session_info,
439 credentials=credentials, lp=lp)
441 #Add modules to the list to activate them by default
442 #beware often order is important
444 # Some Known ordering constraints:
445 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
446 # - objectclass must be before password_hash, because password_hash checks
447 # that the objectclass is of type person (filled in by objectclass
448 # module when expanding the objectclass list)
449 # - partition must be last
450 # - each partition has its own module list then
451 modules_list = ["rootdse",
467 modules_list2 = ["show_deleted",
470 domaindn_ldb = "users.ldb"
471 if ldap_backend is not None:
472 domaindn_ldb = ldap_backend
473 configdn_ldb = "configuration.ldb"
474 if ldap_backend is not None:
475 configdn_ldb = ldap_backend
476 schemadn_ldb = "schema.ldb"
477 if ldap_backend is not None:
478 schema_ldb = ldap_backend
479 schemadn_ldb = ldap_backend
481 if ldap_backend_type == "fedora-ds":
482 backend_modules = ["nsuniqueid", "paged_searches"]
483 # We can handle linked attributes here, as we don't have directory-side subtree operations
484 tdb_modules_list = ["linked_attributes"]
485 elif ldap_backend_type == "openldap":
486 backend_modules = ["normalise", "entryuuid", "paged_searches"]
487 # OpenLDAP handles subtree renames, so we don't want to do any of these things
488 tdb_modules_list = None
489 elif ldap_backend is not None:
490 raise "LDAP Backend specified, but LDAP Backend Type not specified"
491 elif serverrole == "domain controller":
492 backend_modules = ["repl_meta_data"]
494 backend_modules = ["objectguid"]
496 if tdb_modules_list is None:
497 tdb_modules_list_as_string = ""
499 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
501 samdb.transaction_start()
503 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
504 "SCHEMADN": names.schemadn,
505 "SCHEMADN_LDB": schemadn_ldb,
506 "SCHEMADN_MOD2": ",objectguid",
507 "CONFIGDN": names.configdn,
508 "CONFIGDN_LDB": configdn_ldb,
509 "DOMAINDN": names.domaindn,
510 "DOMAINDN_LDB": domaindn_ldb,
511 "SCHEMADN_MOD": "schema_fsmo,instancetype",
512 "CONFIGDN_MOD": "naming_fsmo,instancetype",
513 "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype",
514 "MODULES_LIST": ",".join(modules_list),
515 "TDB_MODULES_LIST": tdb_modules_list_as_string,
516 "MODULES_LIST2": ",".join(modules_list2),
517 "BACKEND_MOD": ",".join(backend_modules),
521 samdb.transaction_cancel()
524 samdb.transaction_commit()
526 samdb = SamDB(samdb_path, session_info=session_info,
527 credentials=credentials, lp=lp)
529 samdb.transaction_start()
531 message("Setting up sam.ldb attributes")
532 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
534 message("Setting up sam.ldb rootDSE")
535 setup_samdb_rootdse(samdb, setup_path, names)
538 message("Erasing data from partitions")
539 samdb.erase_partitions()
542 samdb.transaction_cancel()
545 samdb.transaction_commit()
550 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
551 netbiosname, domainsid, keytab_path, samdb_url,
552 dns_keytab_path, dnspass, machinepass):
553 """Add DC-specific bits to a secrets database.
555 :param secretsdb: Ldb Handle to the secrets database
556 :param setup_path: Setup path function
557 :param machinepass: Machine password
559 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
560 "MACHINEPASS_B64": b64encode(machinepass),
563 "DNSDOMAIN": dnsdomain,
564 "DOMAINSID": str(domainsid),
565 "SECRETS_KEYTAB": keytab_path,
566 "NETBIOSNAME": netbiosname,
567 "SAM_LDB": samdb_url,
568 "DNS_KEYTAB": dns_keytab_path,
569 "DNSPASS_B64": b64encode(dnspass),
573 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
574 """Setup the secrets database.
576 :param path: Path to the secrets database.
577 :param setup_path: Get the path to a setup file.
578 :param session_info: Session info.
579 :param credentials: Credentials
580 :param lp: Loadparm context
581 :return: LDB handle for the created secrets database
583 if os.path.exists(path):
585 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
588 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
589 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
591 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
593 if credentials is not None and credentials.authentication_requested():
594 if credentials.get_bind_dn() is not None:
595 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
596 "LDAPMANAGERDN": credentials.get_bind_dn(),
597 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
600 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
601 "LDAPADMINUSER": credentials.get_username(),
602 "LDAPADMINREALM": credentials.get_realm(),
603 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
609 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
610 """Setup the templates database.
612 :param path: Path to the database.
613 :param setup_path: Function for obtaining the path to setup files.
614 :param session_info: Session info
615 :param credentials: Credentials
616 :param lp: Loadparm context
618 templates_ldb = SamDB(path, session_info=session_info,
619 credentials=credentials, lp=lp)
620 templates_ldb.erase()
621 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
624 def setup_registry(path, setup_path, session_info, credentials, lp):
625 """Setup the registry.
627 :param path: Path to the registry database
628 :param setup_path: Function that returns the path to a setup.
629 :param session_info: Session information
630 :param credentials: Credentials
631 :param lp: Loadparm context
633 reg = registry.Registry()
634 hive = registry.open_ldb(path, session_info=session_info,
635 credentials=credentials, lp_ctx=lp)
636 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
637 provision_reg = setup_path("provision.reg")
638 assert os.path.exists(provision_reg)
639 reg.diff_apply(provision_reg)
642 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
643 """Setup the idmap database.
645 :param path: path to the idmap database
646 :param setup_path: Function that returns a path to a setup file
647 :param session_info: Session information
648 :param credentials: Credentials
649 :param lp: Loadparm context
651 if os.path.exists(path):
654 idmap_ldb = IDmapDB(path, session_info=session_info,
655 credentials=credentials, lp=lp)
658 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
662 def setup_samdb_rootdse(samdb, setup_path, names):
663 """Setup the SamDB rootdse.
665 :param samdb: Sam Database handle
666 :param setup_path: Obtain setup path
668 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
669 "SCHEMADN": names.schemadn,
670 "NETBIOSNAME": names.netbiosname,
671 "DNSDOMAIN": names.dnsdomain,
672 "REALM": names.realm,
673 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
674 "DOMAINDN": names.domaindn,
675 "ROOTDN": names.rootdn,
676 "CONFIGDN": names.configdn,
677 "SERVERDN": names.serverdn,
681 def setup_self_join(samdb, names,
682 machinepass, dnspass,
683 domainsid, invocationid, setup_path,
685 """Join a host to its own domain."""
686 assert isinstance(invocationid, str)
687 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
688 "CONFIGDN": names.configdn,
689 "SCHEMADN": names.schemadn,
690 "DOMAINDN": names.domaindn,
691 "SERVERDN": names.serverdn,
692 "INVOCATIONID": invocationid,
693 "NETBIOSNAME": names.netbiosname,
694 "DEFAULTSITE": names.sitename,
695 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
696 "MACHINEPASS_B64": b64encode(machinepass),
697 "DNSPASS_B64": b64encode(dnspass),
698 "REALM": names.realm,
699 "DOMAIN": names.domain,
700 "DNSDOMAIN": names.dnsdomain})
701 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
702 "POLICYGUID": policyguid,
703 "DNSDOMAIN": names.dnsdomain,
704 "DOMAINSID": str(domainsid),
705 "DOMAINDN": names.domaindn})
708 def setup_samdb(path, setup_path, session_info, credentials, lp,
710 domainsid, aci, domainguid, policyguid,
711 fill, adminpass, krbtgtpass,
712 machinepass, invocationid, dnspass,
713 serverrole, ldap_backend=None,
714 ldap_backend_type=None):
715 """Setup a complete SAM Database.
717 :note: This will wipe the main SAM database file!
720 erase = (fill != FILL_DRS)
722 # Also wipes the database
723 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
724 credentials=credentials, session_info=session_info,
726 ldap_backend=ldap_backend, serverrole=serverrole,
727 ldap_backend_type=ldap_backend_type, erase=erase)
729 samdb = SamDB(path, session_info=session_info,
730 credentials=credentials, lp=lp)
733 # We want to finish here, but setup the index before we do so
734 message("Setting up sam.ldb index")
735 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
738 message("Pre-loading the Samba 4 and AD schema")
739 samdb.set_domain_sid(domainsid)
740 if serverrole == "domain controller":
741 samdb.set_invocation_id(invocationid)
743 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
744 names.configdn, names.sitename, names.serverdn,
747 samdb.transaction_start()
750 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
751 if serverrole == "domain controller":
752 domain_oc = "domainDNS"
754 domain_oc = "samba4LocalDomain"
756 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
757 "DOMAINDN": names.domaindn,
759 "DOMAIN_OC": domain_oc
762 message("Modifying DomainDN: " + names.domaindn + "")
763 if domainguid is not None:
764 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
768 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
769 "LDAPTIME": timestring(int(time.time())),
770 "DOMAINSID": str(domainsid),
771 "SCHEMADN": names.schemadn,
772 "NETBIOSNAME": names.netbiosname,
773 "DEFAULTSITE": names.sitename,
774 "CONFIGDN": names.configdn,
775 "SERVERDN": names.serverdn,
776 "POLICYGUID": policyguid,
777 "DOMAINDN": names.domaindn,
778 "DOMAINGUID_MOD": domainguid_mod,
781 message("Adding configuration container (permitted to fail)")
782 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
783 "CONFIGDN": names.configdn,
786 message("Modifying configuration container")
787 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
788 "CONFIGDN": names.configdn,
789 "SCHEMADN": names.schemadn,
792 message("Adding schema container (permitted to fail)")
793 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
794 "SCHEMADN": names.schemadn,
797 message("Modifying schema container")
799 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
801 setup_modify_ldif(samdb,
802 setup_path("provision_schema_basedn_modify.ldif"), {
803 "SCHEMADN": names.schemadn,
804 "NETBIOSNAME": names.netbiosname,
805 "DEFAULTSITE": names.sitename,
806 "CONFIGDN": names.configdn,
807 "SERVERDN": names.serverdn,
808 "PREFIXMAP_B64": b64encode(prefixmap)
811 message("Setting up sam.ldb Samba4 schema")
812 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
813 {"SCHEMADN": names.schemadn })
814 message("Setting up sam.ldb AD schema")
815 setup_add_ldif(samdb, setup_path("schema.ldif"),
816 {"SCHEMADN": names.schemadn})
818 message("Setting up sam.ldb configuration data")
819 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
820 "CONFIGDN": names.configdn,
821 "NETBIOSNAME": names.netbiosname,
822 "DEFAULTSITE": names.sitename,
823 "DNSDOMAIN": names.dnsdomain,
824 "DOMAIN": names.domain,
825 "SCHEMADN": names.schemadn,
826 "DOMAINDN": names.domaindn,
827 "SERVERDN": names.serverdn
830 message("Setting up display specifiers")
831 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
832 {"CONFIGDN": names.configdn})
834 message("Adding users container (permitted to fail)")
835 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
836 "DOMAINDN": names.domaindn})
837 message("Modifying users container")
838 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
839 "DOMAINDN": names.domaindn})
840 message("Adding computers container (permitted to fail)")
841 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
842 "DOMAINDN": names.domaindn})
843 message("Modifying computers container")
844 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
845 "DOMAINDN": names.domaindn})
846 message("Setting up sam.ldb data")
847 setup_add_ldif(samdb, setup_path("provision.ldif"), {
848 "DOMAINDN": names.domaindn,
849 "NETBIOSNAME": names.netbiosname,
850 "DEFAULTSITE": names.sitename,
851 "CONFIGDN": names.configdn,
852 "SERVERDN": names.serverdn
855 if fill == FILL_FULL:
856 message("Setting up sam.ldb users and groups")
857 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
858 "DOMAINDN": names.domaindn,
859 "DOMAINSID": str(domainsid),
860 "CONFIGDN": names.configdn,
861 "ADMINPASS_B64": b64encode(adminpass),
862 "KRBTGTPASS_B64": b64encode(krbtgtpass),
865 if serverrole == "domain controller":
866 message("Setting up self join")
867 setup_self_join(samdb, names=names, invocationid=invocationid,
869 machinepass=machinepass,
870 domainsid=domainsid, policyguid=policyguid,
871 setup_path=setup_path)
873 #We want to setup the index last, as adds are faster unindexed
874 message("Setting up sam.ldb index")
875 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
877 samdb.transaction_cancel()
880 samdb.transaction_commit()
885 FILL_NT4SYNC = "NT4SYNC"
888 def provision(setup_dir, message, session_info,
889 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
890 rootdn=None, domaindn=None, schemadn=None, configdn=None,
892 domain=None, hostname=None, hostip=None, hostip6=None,
893 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
894 policyguid=None, invocationid=None, machinepass=None,
895 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
896 wheel=None, backup=None, aci=None, serverrole=None,
897 ldap_backend=None, ldap_backend_type=None, sitename=None):
900 :note: caution, this wipes all existing data!
903 def setup_path(file):
904 return os.path.join(setup_dir, file)
906 if domainsid is None:
907 domainsid = security.random_sid()
909 domainsid = security.Sid(domainsid)
911 if policyguid is None:
912 policyguid = str(uuid.uuid4())
913 if adminpass is None:
914 adminpass = misc.random_password(12)
915 if krbtgtpass is None:
916 krbtgtpass = misc.random_password(12)
917 if machinepass is None:
918 machinepass = misc.random_password(12)
920 dnspass = misc.random_password(12)
921 root_uid = findnss_uid([root or "root"])
922 nobody_uid = findnss_uid([nobody or "nobody"])
923 users_gid = findnss_gid([users or "users"])
925 wheel_gid = findnss_gid(["wheel", "adm"])
927 wheel_gid = findnss_gid([wheel])
929 aci = "# no aci for local ldb"
931 if targetdir is not None:
932 if (not os.path.exists(os.path.join(targetdir, "etc"))):
933 os.makedirs(os.path.join(targetdir, "etc"))
934 smbconf = os.path.join(targetdir, "etc", "smb.conf")
936 # only install a new smb.conf if there isn't one there already
937 if not os.path.exists(smbconf):
938 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
941 lp = param.LoadParm()
944 names = guess_names(lp=lp, hostname=hostname, domain=domain,
945 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
946 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
949 paths = provision_paths_from_lp(lp, names.dnsdomain)
952 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
956 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
957 except socket.gaierror:
960 if serverrole is None:
961 serverrole = lp.get("server role")
963 assert serverrole in ("domain controller", "member server", "standalone")
964 if invocationid is None and serverrole == "domain controller":
965 invocationid = str(uuid.uuid4())
967 if not os.path.exists(paths.private_dir):
968 os.mkdir(paths.private_dir)
970 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
972 if ldap_backend is not None:
973 if ldap_backend == "ldapi":
974 # provision-backend will set this path suggested slapd command line / fedorads.inf
975 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
977 # only install a new shares config db if there is none
978 if not os.path.exists(paths.shareconf):
979 message("Setting up share.ldb")
980 share_ldb = Ldb(paths.shareconf, session_info=session_info,
981 credentials=credentials, lp=lp)
982 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
985 message("Setting up secrets.ldb")
986 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
987 session_info=session_info,
988 credentials=credentials, lp=lp)
990 message("Setting up the registry")
991 setup_registry(paths.hklm, setup_path, session_info,
992 credentials=credentials, lp=lp)
994 message("Setting up templates db")
995 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
996 credentials=credentials, lp=lp)
998 message("Setting up idmap db")
999 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1000 credentials=credentials, lp=lp)
1002 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1003 credentials=credentials, lp=lp, names=names,
1005 domainsid=domainsid,
1006 aci=aci, domainguid=domainguid, policyguid=policyguid,
1008 adminpass=adminpass, krbtgtpass=krbtgtpass,
1009 invocationid=invocationid,
1010 machinepass=machinepass, dnspass=dnspass,
1011 serverrole=serverrole, ldap_backend=ldap_backend,
1012 ldap_backend_type=ldap_backend_type)
1014 if lp.get("server role") == "domain controller":
1015 if paths.netlogon is None:
1016 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1017 message("Please either remove %s or see the template at %s" %
1018 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1019 assert(paths.netlogon is not None)
1021 if paths.sysvol is None:
1022 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1023 message("Please either remove %s or see the template at %s" %
1024 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1025 assert(paths.sysvol is not None)
1027 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1028 "{" + policyguid + "}")
1029 os.makedirs(policy_path, 0755)
1030 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1031 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1032 os.makedirs(os.path.join(policy_path, "User"), 0755)
1033 if not os.path.isdir(paths.netlogon):
1034 os.makedirs(paths.netlogon, 0755)
1036 if samdb_fill == FILL_FULL:
1037 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1038 root_uid=root_uid, nobody_uid=nobody_uid,
1039 users_gid=users_gid, wheel_gid=wheel_gid)
1041 message("Setting up sam.ldb rootDSE marking as synchronized")
1042 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1044 # Only make a zone file on the first DC, it should be replicated with DNS replication
1045 if serverrole == "domain controller":
1046 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1047 credentials=credentials, lp=lp)
1048 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1049 netbiosname=names.netbiosname, domainsid=domainsid,
1050 keytab_path=paths.keytab, samdb_url=paths.samdb,
1051 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1052 machinepass=machinepass, dnsdomain=names.dnsdomain)
1054 samdb = SamDB(paths.samdb, session_info=session_info,
1055 credentials=credentials, lp=lp)
1057 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1058 assert isinstance(domainguid, str)
1059 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1060 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1061 scope=SCOPE_SUBTREE)
1062 assert isinstance(hostguid, str)
1064 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1065 domaindn=names.domaindn, hostip=hostip,
1066 hostip6=hostip6, hostname=names.hostname,
1067 dnspass=dnspass, realm=names.realm,
1068 domainguid=domainguid, hostguid=hostguid)
1070 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1071 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1073 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1074 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1075 keytab_name=paths.dns_keytab)
1076 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1077 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1079 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1080 hostname=names.hostname, realm=names.realm)
1081 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1083 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1086 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1088 message("Once the above files are installed, your Samba4 server will be ready to use")
1089 message("Server Role: %s" % serverrole)
1090 message("Hostname: %s" % names.hostname)
1091 message("NetBIOS Domain: %s" % names.domain)
1092 message("DNS Domain: %s" % names.dnsdomain)
1093 message("DOMAIN SID: %s" % str(domainsid))
1094 message("Admin password: %s" % adminpass)
1096 result = ProvisionResult()
1097 result.domaindn = domaindn
1098 result.paths = paths
1100 result.samdb = samdb
1104 def provision_become_dc(setup_dir=None,
1105 smbconf=None, targetdir=None, realm=None,
1106 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1108 domain=None, hostname=None, domainsid=None,
1109 adminpass=None, krbtgtpass=None, domainguid=None,
1110 policyguid=None, invocationid=None, machinepass=None,
1111 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1112 wheel=None, backup=None, aci=None, serverrole=None,
1113 ldap_backend=None, ldap_backend_type=None, sitename=None):
1116 """print a message if quiet is not set."""
1119 return provision(setup_dir, message, system_session(), None,
1120 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1121 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1122 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1125 def setup_db_config(setup_path, dbdir):
1126 """Setup a Berkeley database.
1128 :param setup_path: Setup path function.
1129 :param dbdir: Database directory."""
1130 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1131 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1132 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1133 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1135 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1136 {"LDAPDBDIR": dbdir})
1140 def provision_backend(setup_dir=None, message=None,
1141 smbconf=None, targetdir=None, realm=None,
1142 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1143 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1144 ldap_backend_type=None, ldap_backend_port=None):
1146 def setup_path(file):
1147 return os.path.join(setup_dir, file)
1149 if hostname is None:
1150 hostname = socket.gethostname().split(".")[0].lower()
1153 root = findnss(pwd.getpwnam, ["root"])[0]
1155 if adminpass is None:
1156 adminpass = misc.random_password(12)
1158 if targetdir is not None:
1159 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1160 os.makedirs(os.path.join(targetdir, "etc"))
1161 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1163 # only install a new smb.conf if there isn't one there already
1164 if not os.path.exists(smbconf):
1165 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1168 lp = param.LoadParm()
1171 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1172 dnsdomain=realm, serverrole=serverrole,
1173 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1176 paths = provision_paths_from_lp(lp, names.dnsdomain)
1178 if not os.path.isdir(paths.ldapdir):
1179 os.makedirs(paths.ldapdir, 0700)
1180 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1182 os.unlink(schemadb_path)
1186 schemadb = Ldb(schemadb_path, lp=lp)
1188 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1190 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1191 {"SCHEMADN": names.schemadn,
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 serverdn, servername):
1431 """Load schema for the SamDB.
1433 :param samdb: Load a schema into a SamDB.
1434 :param setup_path: Setup path function.
1435 :param schemadn: DN of the schema
1436 :param netbiosname: NetBIOS name of the host.
1437 :param configdn: DN of the configuration
1438 :param serverdn: DN of the server
1439 :param servername: Host name of the server
1441 schema_data = open(setup_path("schema.ldif"), 'r').read()
1442 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1443 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1444 check_all_substituted(schema_data)
1445 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1446 prefixmap = b64encode(prefixmap)
1448 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1449 head_data = substitute_var(head_data, {
1450 "SCHEMADN": schemadn,
1451 "NETBIOSNAME": netbiosname,
1452 "CONFIGDN": configdn,
1453 "DEFAULTSITE": sitename,
1454 "PREFIXMAP_B64": prefixmap,
1455 "SERVERDN": serverdn,
1456 "SERVERNAME": servername,
1458 check_all_substituted(head_data)
1459 samdb.attach_schema_from_ldif(head_data, schema_data)