2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 """Functions for setting up a Samba configuration."""
27 from base64 import b64encode
37 from auth import system_session
38 from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
39 from samba.samdb import SamDB
40 from samba.idmap import IDmapDB
43 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
44 LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
46 __docformat__ = "restructuredText"
48 DEFAULTSITE = "Default-First-Site-Name"
50 class InvalidNetbiosName(Exception):
51 """A specified name was not a valid NetBIOS name."""
52 def __init__(self, name):
53 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
56 class ProvisionPaths(object):
69 self.dns_keytab = None
72 self.private_dir = None
75 self.modulesconf = None
76 self.memberofconf = None
77 self.fedoradsinf = None
78 self.fedoradspartitions = None
80 self.olmmrserveridsconf = None
81 self.olmmrsyncreplconf = None
83 class ProvisionNames(object):
89 self.ldapmanagerdn = None
92 self.netbiosname = None
99 class ProvisionResult(object):
106 def check_install(lp, session_info, credentials):
107 """Check whether the current install seems ok.
109 :param lp: Loadparm context
110 :param session_info: Session information
111 :param credentials: Credentials
113 if lp.get("realm") == "":
114 raise Exception("Realm empty")
115 ldb = Ldb(lp.get("sam database"), session_info=session_info,
116 credentials=credentials, lp=lp)
117 if len(ldb.search("(cn=Administrator)")) != 1:
118 raise "No administrator account found"
121 def findnss(nssfn, names):
122 """Find a user or group from a list of possibilities.
124 :param nssfn: NSS Function to try (should raise KeyError if not found)
125 :param names: Names to check.
126 :return: Value return by first names list.
133 raise KeyError("Unable to find user/group %r" % names)
136 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
137 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
140 def read_and_sub_file(file, subst_vars):
141 """Read a file and sub in variables found in it
143 :param file: File to be read (typically from setup directory)
144 param subst_vars: Optional variables to subsitute in the file.
146 data = open(file, 'r').read()
147 if subst_vars is not None:
148 data = substitute_var(data, subst_vars)
149 check_all_substituted(data)
153 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
154 """Setup a ldb in the private dir.
156 :param ldb: LDB file to import data into
157 :param ldif_path: Path of the LDIF file to load
158 :param subst_vars: Optional variables to subsitute in LDIF.
160 assert isinstance(ldif_path, str)
162 data = read_and_sub_file(ldif_path, subst_vars)
166 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
167 """Modify a ldb in the private dir.
169 :param ldb: LDB object.
170 :param ldif_path: LDIF file path.
171 :param subst_vars: Optional dictionary with substitution variables.
173 data = read_and_sub_file(ldif_path, subst_vars)
175 ldb.modify_ldif(data)
178 def setup_ldb(ldb, ldif_path, subst_vars):
179 """Import a LDIF a file into a LDB handle, optionally substituting variables.
181 :note: Either all LDIF data will be added or none (using transactions).
183 :param ldb: LDB file to import into.
184 :param ldif_path: Path to the LDIF file.
185 :param subst_vars: Dictionary with substitution variables.
187 assert ldb is not None
188 ldb.transaction_start()
190 setup_add_ldif(ldb, ldif_path, subst_vars)
192 ldb.transaction_cancel()
194 ldb.transaction_commit()
197 def setup_file(template, fname, subst_vars):
198 """Setup a file in the private dir.
200 :param template: Path of the template file.
201 :param fname: Path of the file to create.
202 :param subst_vars: Substitution variables.
206 if os.path.exists(f):
209 data = read_and_sub_file(template, subst_vars)
210 open(f, 'w').write(data)
213 def provision_paths_from_lp(lp, dnsdomain):
214 """Set the default paths for provisioning.
216 :param lp: Loadparm context.
217 :param dnsdomain: DNS Domain name
219 paths = ProvisionPaths()
220 paths.private_dir = lp.get("private dir")
221 paths.keytab = "secrets.keytab"
222 paths.dns_keytab = "dns.keytab"
224 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
225 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
226 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
227 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
228 paths.templates = os.path.join(paths.private_dir, "templates.ldb")
229 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
230 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
231 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
232 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
233 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
234 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
235 paths.phpldapadminconfig = os.path.join(paths.private_dir,
236 "phpldapadmin-config.php")
237 paths.ldapdir = os.path.join(paths.private_dir,
239 paths.slapdconf = os.path.join(paths.ldapdir,
241 paths.modulesconf = os.path.join(paths.ldapdir,
243 paths.memberofconf = os.path.join(paths.ldapdir,
245 paths.fedoradsinf = os.path.join(paths.ldapdir,
247 paths.fedoradspartitions = os.path.join(paths.ldapdir,
248 "fedorads-partitions.ldif")
249 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
250 "mmr_serverids.conf")
251 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
253 paths.hklm = "hklm.ldb"
254 paths.hkcr = "hkcr.ldb"
255 paths.hkcu = "hkcu.ldb"
256 paths.hku = "hku.ldb"
257 paths.hkpd = "hkpd.ldb"
258 paths.hkpt = "hkpt.ldb"
260 paths.sysvol = lp.get("path", "sysvol")
262 paths.netlogon = lp.get("path", "netlogon")
264 paths.smbconf = lp.configfile()
269 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None,
270 rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None,
272 """Guess configuration settings to use."""
275 hostname = socket.gethostname().split(".")[0].lower()
277 netbiosname = hostname.upper()
278 if not valid_netbios_name(netbiosname):
279 raise InvalidNetbiosName(netbiosname)
281 hostname = hostname.lower()
283 if dnsdomain is None:
284 dnsdomain = lp.get("realm")
286 if serverrole is None:
287 serverrole = lp.get("server role")
289 assert dnsdomain is not None
290 realm = dnsdomain.upper()
292 if lp.get("realm").upper() != realm:
293 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
294 (lp.get("realm"), lp.configfile(), realm))
296 dnsdomain = dnsdomain.lower()
298 if serverrole == "domain controller":
300 domain = lp.get("workgroup")
302 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
303 if lp.get("workgroup").upper() != domain.upper():
304 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
305 lp.get("workgroup"), domain)
309 domaindn = "CN=" + netbiosname
311 assert domain is not None
312 domain = domain.upper()
313 if not valid_netbios_name(domain):
314 raise InvalidNetbiosName(domain)
320 configdn = "CN=Configuration," + rootdn
322 schemadn = "CN=Schema," + configdn
327 names = ProvisionNames()
328 names.rootdn = rootdn
329 names.domaindn = domaindn
330 names.configdn = configdn
331 names.schemadn = schemadn
332 names.ldapmanagerdn = "CN=Manager," + rootdn
333 names.dnsdomain = dnsdomain
334 names.domain = domain
336 names.netbiosname = netbiosname
337 names.hostname = hostname
338 names.sitename = sitename
339 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
344 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
347 hostname = socket.gethostname().split(".")[0].lower()
349 if serverrole is None:
350 serverrole = "standalone"
352 assert serverrole in ("domain controller", "member server", "standalone")
353 if serverrole == "domain controller":
355 elif serverrole == "member server":
356 smbconfsuffix = "member"
357 elif serverrole == "standalone":
358 smbconfsuffix = "standalone"
360 assert domain is not None
361 assert realm is not None
363 default_lp = param.LoadParm()
364 #Load non-existant file
365 default_lp.load(smbconf)
367 if targetdir is not None:
368 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
369 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
371 default_lp.set("lock dir", os.path.abspath(targetdir))
376 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
377 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
379 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
381 "HOSTNAME": hostname,
384 "SERVERROLE": serverrole,
385 "NETLOGONPATH": netlogon,
386 "SYSVOLPATH": sysvol,
387 "PRIVATEDIR_LINE": privatedir_line,
388 "LOCKDIR_LINE": lockdir_line
393 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
394 users_gid, wheel_gid):
395 """setup reasonable name mappings for sam names to unix names.
397 :param samdb: SamDB object.
398 :param idmap: IDmap db object.
399 :param sid: The domain sid.
400 :param domaindn: The domain DN.
401 :param root_uid: uid of the UNIX root user.
402 :param nobody_uid: uid of the UNIX nobody user.
403 :param users_gid: gid of the UNIX users group.
404 :param wheel_gid: gid of the UNIX wheel group."""
405 # add some foreign sids if they are not present already
406 samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
407 samdb.add_foreign(domaindn, "S-1-1-0", "World")
408 samdb.add_foreign(domaindn, "S-1-5-2", "Network")
409 samdb.add_foreign(domaindn, "S-1-5-18", "System")
410 samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
412 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
413 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
415 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
416 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
419 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
421 serverrole, ldap_backend=None,
422 ldap_backend_type=None, erase=False):
423 """Setup the partitions for the SAM database.
425 Alternatively, provision() may call this, and then populate the database.
427 :note: This will wipe the Sam Database!
429 :note: This function always removes the local SAM LDB file. The erase
430 parameter controls whether to erase the existing data, which
431 may not be stored locally but in LDAP.
433 assert session_info is not None
435 samdb = SamDB(samdb_path, session_info=session_info,
436 credentials=credentials, lp=lp)
442 os.unlink(samdb_path)
444 samdb = SamDB(samdb_path, session_info=session_info,
445 credentials=credentials, lp=lp)
447 #Add modules to the list to activate them by default
448 #beware often order is important
450 # Some Known ordering constraints:
451 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
452 # - objectclass must be before password_hash, because password_hash checks
453 # that the objectclass is of type person (filled in by objectclass
454 # module when expanding the objectclass list)
455 # - partition must be last
456 # - each partition has its own module list then
457 modules_list = ["rootdse",
474 modules_list2 = ["show_deleted",
477 domaindn_ldb = "users.ldb"
478 if ldap_backend is not None:
479 domaindn_ldb = ldap_backend
480 configdn_ldb = "configuration.ldb"
481 if ldap_backend is not None:
482 configdn_ldb = ldap_backend
483 schemadn_ldb = "schema.ldb"
484 if ldap_backend is not None:
485 schema_ldb = ldap_backend
486 schemadn_ldb = ldap_backend
488 if ldap_backend_type == "fedora-ds":
489 backend_modules = ["nsuniqueid", "paged_searches"]
490 # We can handle linked attributes here, as we don't have directory-side subtree operations
491 tdb_modules_list = ["linked_attributes"]
492 elif ldap_backend_type == "openldap":
493 backend_modules = ["normalise", "entryuuid", "paged_searches"]
494 # OpenLDAP handles subtree renames, so we don't want to do any of these things
495 tdb_modules_list = None
496 elif ldap_backend is not None:
497 raise "LDAP Backend specified, but LDAP Backend Type not specified"
498 elif serverrole == "domain controller":
499 backend_modules = ["repl_meta_data"]
501 backend_modules = ["objectguid"]
503 if tdb_modules_list is None:
504 tdb_modules_list_as_string = ""
506 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
508 samdb.transaction_start()
510 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
511 "SCHEMADN": names.schemadn,
512 "SCHEMADN_LDB": schemadn_ldb,
513 "SCHEMADN_MOD2": ",objectguid",
514 "CONFIGDN": names.configdn,
515 "CONFIGDN_LDB": configdn_ldb,
516 "DOMAINDN": names.domaindn,
517 "DOMAINDN_LDB": domaindn_ldb,
518 "SCHEMADN_MOD": "schema_fsmo,instancetype",
519 "CONFIGDN_MOD": "naming_fsmo,instancetype",
520 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
521 "MODULES_LIST": ",".join(modules_list),
522 "TDB_MODULES_LIST": tdb_modules_list_as_string,
523 "MODULES_LIST2": ",".join(modules_list2),
524 "BACKEND_MOD": ",".join(backend_modules),
528 samdb.transaction_cancel()
531 samdb.transaction_commit()
533 samdb = SamDB(samdb_path, session_info=session_info,
534 credentials=credentials, lp=lp)
536 samdb.transaction_start()
538 message("Setting up sam.ldb attributes")
539 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
541 message("Setting up sam.ldb rootDSE")
542 setup_samdb_rootdse(samdb, setup_path, names)
545 message("Erasing data from partitions")
546 samdb.erase_partitions()
549 samdb.transaction_cancel()
552 samdb.transaction_commit()
557 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
558 netbiosname, domainsid, keytab_path, samdb_url,
559 dns_keytab_path, dnspass, machinepass):
560 """Add DC-specific bits to a secrets database.
562 :param secretsdb: Ldb Handle to the secrets database
563 :param setup_path: Setup path function
564 :param machinepass: Machine password
566 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
567 "MACHINEPASS_B64": b64encode(machinepass),
570 "DNSDOMAIN": dnsdomain,
571 "DOMAINSID": str(domainsid),
572 "SECRETS_KEYTAB": keytab_path,
573 "NETBIOSNAME": netbiosname,
574 "SAM_LDB": samdb_url,
575 "DNS_KEYTAB": dns_keytab_path,
576 "DNSPASS_B64": b64encode(dnspass),
580 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
581 """Setup the secrets database.
583 :param path: Path to the secrets database.
584 :param setup_path: Get the path to a setup file.
585 :param session_info: Session info.
586 :param credentials: Credentials
587 :param lp: Loadparm context
588 :return: LDB handle for the created secrets database
590 if os.path.exists(path):
592 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
595 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
596 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
598 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
600 if credentials is not None and credentials.authentication_requested():
601 if credentials.get_bind_dn() is not None:
602 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
603 "LDAPMANAGERDN": credentials.get_bind_dn(),
604 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
607 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
608 "LDAPADMINUSER": credentials.get_username(),
609 "LDAPADMINREALM": credentials.get_realm(),
610 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
616 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
617 """Setup the templates database.
619 :param path: Path to the database.
620 :param setup_path: Function for obtaining the path to setup files.
621 :param session_info: Session info
622 :param credentials: Credentials
623 :param lp: Loadparm context
625 templates_ldb = SamDB(path, session_info=session_info,
626 credentials=credentials, lp=lp)
629 templates_ldb.erase()
633 templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
635 templates_ldb = SamDB(path, session_info=session_info,
636 credentials=credentials, lp=lp)
638 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
641 def setup_registry(path, setup_path, session_info, credentials, lp):
642 """Setup the registry.
644 :param path: Path to the registry database
645 :param setup_path: Function that returns the path to a setup.
646 :param session_info: Session information
647 :param credentials: Credentials
648 :param lp: Loadparm context
650 reg = registry.Registry()
651 hive = registry.open_ldb(path, session_info=session_info,
652 credentials=credentials, lp_ctx=lp)
653 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
654 provision_reg = setup_path("provision.reg")
655 assert os.path.exists(provision_reg)
656 reg.diff_apply(provision_reg)
659 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
660 """Setup the idmap database.
662 :param path: path to the idmap database
663 :param setup_path: Function that returns a path to a setup file
664 :param session_info: Session information
665 :param credentials: Credentials
666 :param lp: Loadparm context
668 if os.path.exists(path):
671 idmap_ldb = IDmapDB(path, session_info=session_info,
672 credentials=credentials, lp=lp)
675 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
679 def setup_samdb_rootdse(samdb, setup_path, names):
680 """Setup the SamDB rootdse.
682 :param samdb: Sam Database handle
683 :param setup_path: Obtain setup path
685 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
686 "SCHEMADN": names.schemadn,
687 "NETBIOSNAME": names.netbiosname,
688 "DNSDOMAIN": names.dnsdomain,
689 "REALM": names.realm,
690 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
691 "DOMAINDN": names.domaindn,
692 "ROOTDN": names.rootdn,
693 "CONFIGDN": names.configdn,
694 "SERVERDN": names.serverdn,
698 def setup_self_join(samdb, names,
699 machinepass, dnspass,
700 domainsid, invocationid, setup_path,
702 """Join a host to its own domain."""
703 assert isinstance(invocationid, str)
704 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
705 "CONFIGDN": names.configdn,
706 "SCHEMADN": names.schemadn,
707 "DOMAINDN": names.domaindn,
708 "SERVERDN": names.serverdn,
709 "INVOCATIONID": invocationid,
710 "NETBIOSNAME": names.netbiosname,
711 "DEFAULTSITE": names.sitename,
712 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
713 "MACHINEPASS_B64": b64encode(machinepass),
714 "DNSPASS_B64": b64encode(dnspass),
715 "REALM": names.realm,
716 "DOMAIN": names.domain,
717 "DNSDOMAIN": names.dnsdomain})
718 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
719 "POLICYGUID": policyguid,
720 "DNSDOMAIN": names.dnsdomain,
721 "DOMAINSID": str(domainsid),
722 "DOMAINDN": names.domaindn})
725 def setup_samdb(path, setup_path, session_info, credentials, lp,
727 domainsid, aci, domainguid, policyguid,
728 fill, adminpass, krbtgtpass,
729 machinepass, invocationid, dnspass,
730 serverrole, ldap_backend=None,
731 ldap_backend_type=None):
732 """Setup a complete SAM Database.
734 :note: This will wipe the main SAM database file!
737 erase = (fill != FILL_DRS)
739 # Also wipes the database
740 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
741 credentials=credentials, session_info=session_info,
743 ldap_backend=ldap_backend, serverrole=serverrole,
744 ldap_backend_type=ldap_backend_type, erase=erase)
746 samdb = SamDB(path, session_info=session_info,
747 credentials=credentials, lp=lp)
751 message("Pre-loading the Samba 4 and AD schema")
752 samdb.set_domain_sid(domainsid)
753 if serverrole == "domain controller":
754 samdb.set_invocation_id(invocationid)
756 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
757 names.configdn, names.sitename, names.serverdn,
760 samdb.transaction_start()
763 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
764 if serverrole == "domain controller":
765 domain_oc = "domainDNS"
767 domain_oc = "samba4LocalDomain"
769 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
770 "DOMAINDN": names.domaindn,
772 "DOMAIN_OC": domain_oc
775 message("Modifying DomainDN: " + names.domaindn + "")
776 if domainguid is not None:
777 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
781 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
782 "LDAPTIME": timestring(int(time.time())),
783 "DOMAINSID": str(domainsid),
784 "SCHEMADN": names.schemadn,
785 "NETBIOSNAME": names.netbiosname,
786 "DEFAULTSITE": names.sitename,
787 "CONFIGDN": names.configdn,
788 "SERVERDN": names.serverdn,
789 "POLICYGUID": policyguid,
790 "DOMAINDN": names.domaindn,
791 "DOMAINGUID_MOD": domainguid_mod,
794 message("Adding configuration container (permitted to fail)")
795 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
796 "CONFIGDN": names.configdn,
799 message("Modifying configuration container")
800 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
801 "CONFIGDN": names.configdn,
802 "SCHEMADN": names.schemadn,
805 message("Adding schema container (permitted to fail)")
806 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
807 "SCHEMADN": names.schemadn,
810 message("Modifying schema container")
812 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
814 setup_modify_ldif(samdb,
815 setup_path("provision_schema_basedn_modify.ldif"), {
816 "SCHEMADN": names.schemadn,
817 "NETBIOSNAME": names.netbiosname,
818 "DEFAULTSITE": names.sitename,
819 "CONFIGDN": names.configdn,
820 "SERVERDN": names.serverdn,
821 "PREFIXMAP_B64": b64encode(prefixmap)
824 message("Setting up sam.ldb Samba4 schema")
825 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
826 {"SCHEMADN": names.schemadn })
827 message("Setting up sam.ldb AD schema")
828 setup_add_ldif(samdb, setup_path("schema.ldif"),
829 {"SCHEMADN": names.schemadn})
831 message("Setting up sam.ldb configuration data")
832 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
833 "CONFIGDN": names.configdn,
834 "NETBIOSNAME": names.netbiosname,
835 "DEFAULTSITE": names.sitename,
836 "DNSDOMAIN": names.dnsdomain,
837 "DOMAIN": names.domain,
838 "SCHEMADN": names.schemadn,
839 "DOMAINDN": names.domaindn,
840 "SERVERDN": names.serverdn
843 message("Setting up display specifiers")
844 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
845 {"CONFIGDN": names.configdn})
847 message("Adding users container (permitted to fail)")
848 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
849 "DOMAINDN": names.domaindn})
850 message("Modifying users container")
851 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
852 "DOMAINDN": names.domaindn})
853 message("Adding computers container (permitted to fail)")
854 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
855 "DOMAINDN": names.domaindn})
856 message("Modifying computers container")
857 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
858 "DOMAINDN": names.domaindn})
859 message("Setting up sam.ldb data")
860 setup_add_ldif(samdb, setup_path("provision.ldif"), {
861 "DOMAINDN": names.domaindn,
862 "NETBIOSNAME": names.netbiosname,
863 "DEFAULTSITE": names.sitename,
864 "CONFIGDN": names.configdn,
865 "SERVERDN": names.serverdn
868 if fill == FILL_FULL:
869 message("Setting up sam.ldb users and groups")
870 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
871 "DOMAINDN": names.domaindn,
872 "DOMAINSID": str(domainsid),
873 "CONFIGDN": names.configdn,
874 "ADMINPASS_B64": b64encode(adminpass),
875 "KRBTGTPASS_B64": b64encode(krbtgtpass),
878 if serverrole == "domain controller":
879 message("Setting up self join")
880 setup_self_join(samdb, names=names, invocationid=invocationid,
882 machinepass=machinepass,
883 domainsid=domainsid, policyguid=policyguid,
884 setup_path=setup_path)
887 samdb.transaction_cancel()
890 samdb.transaction_commit()
895 FILL_NT4SYNC = "NT4SYNC"
898 def provision(setup_dir, message, session_info,
899 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
900 rootdn=None, domaindn=None, schemadn=None, configdn=None,
902 domain=None, hostname=None, hostip=None, hostip6=None,
903 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
904 policyguid=None, invocationid=None, machinepass=None,
905 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
906 wheel=None, backup=None, aci=None, serverrole=None,
907 ldap_backend=None, ldap_backend_type=None, sitename=None):
910 :note: caution, this wipes all existing data!
913 def setup_path(file):
914 return os.path.join(setup_dir, file)
916 if domainsid is None:
917 domainsid = security.random_sid()
919 domainsid = security.Sid(domainsid)
921 if policyguid is None:
922 policyguid = str(uuid.uuid4())
923 if adminpass is None:
924 adminpass = misc.random_password(12)
925 if krbtgtpass is None:
926 krbtgtpass = misc.random_password(12)
927 if machinepass is None:
928 machinepass = misc.random_password(12)
930 dnspass = misc.random_password(12)
931 root_uid = findnss_uid([root or "root"])
932 nobody_uid = findnss_uid([nobody or "nobody"])
933 users_gid = findnss_gid([users or "users"])
935 wheel_gid = findnss_gid(["wheel", "adm"])
937 wheel_gid = findnss_gid([wheel])
939 aci = "# no aci for local ldb"
941 if targetdir is not None:
942 if (not os.path.exists(os.path.join(targetdir, "etc"))):
943 os.makedirs(os.path.join(targetdir, "etc"))
944 smbconf = os.path.join(targetdir, "etc", "smb.conf")
946 # only install a new smb.conf if there isn't one there already
947 if not os.path.exists(smbconf):
948 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
951 lp = param.LoadParm()
954 names = guess_names(lp=lp, hostname=hostname, domain=domain,
955 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
956 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
959 paths = provision_paths_from_lp(lp, names.dnsdomain)
963 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
964 except socket.gaierror, (socket.EAI_NODATA, msg):
969 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
970 except socket.gaierror, (socket.EAI_NODATA, msg):
973 if serverrole is None:
974 serverrole = lp.get("server role")
976 assert serverrole in ("domain controller", "member server", "standalone")
977 if invocationid is None and serverrole == "domain controller":
978 invocationid = str(uuid.uuid4())
980 if not os.path.exists(paths.private_dir):
981 os.mkdir(paths.private_dir)
983 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
985 if ldap_backend is not None:
986 if ldap_backend == "ldapi":
987 # provision-backend will set this path suggested slapd command line / fedorads.inf
988 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
990 # only install a new shares config db if there is none
991 if not os.path.exists(paths.shareconf):
992 message("Setting up share.ldb")
993 share_ldb = Ldb(paths.shareconf, session_info=session_info,
994 credentials=credentials, lp=lp)
995 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
998 message("Setting up secrets.ldb")
999 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1000 session_info=session_info,
1001 credentials=credentials, lp=lp)
1003 message("Setting up the registry")
1004 setup_registry(paths.hklm, setup_path, session_info,
1005 credentials=credentials, lp=lp)
1007 message("Setting up templates db")
1008 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
1009 credentials=credentials, lp=lp)
1011 message("Setting up idmap db")
1012 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1013 credentials=credentials, lp=lp)
1015 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1016 credentials=credentials, lp=lp, names=names,
1018 domainsid=domainsid,
1019 aci=aci, domainguid=domainguid, policyguid=policyguid,
1021 adminpass=adminpass, krbtgtpass=krbtgtpass,
1022 invocationid=invocationid,
1023 machinepass=machinepass, dnspass=dnspass,
1024 serverrole=serverrole, ldap_backend=ldap_backend,
1025 ldap_backend_type=ldap_backend_type)
1027 if lp.get("server role") == "domain controller":
1028 if paths.netlogon is None:
1029 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1030 message("Please either remove %s or see the template at %s" %
1031 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1032 assert(paths.netlogon is not None)
1034 if paths.sysvol is None:
1035 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1036 message("Please either remove %s or see the template at %s" %
1037 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1038 assert(paths.sysvol is not None)
1040 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1041 "{" + policyguid + "}")
1042 os.makedirs(policy_path, 0755)
1043 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1044 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1045 os.makedirs(os.path.join(policy_path, "User"), 0755)
1046 if not os.path.isdir(paths.netlogon):
1047 os.makedirs(paths.netlogon, 0755)
1049 if samdb_fill == FILL_FULL:
1050 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1051 root_uid=root_uid, nobody_uid=nobody_uid,
1052 users_gid=users_gid, wheel_gid=wheel_gid)
1054 message("Setting up sam.ldb rootDSE marking as synchronized")
1055 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1057 # Only make a zone file on the first DC, it should be replicated with DNS replication
1058 if serverrole == "domain controller":
1059 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1060 credentials=credentials, lp=lp)
1061 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1062 netbiosname=names.netbiosname, domainsid=domainsid,
1063 keytab_path=paths.keytab, samdb_url=paths.samdb,
1064 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1065 machinepass=machinepass, dnsdomain=names.dnsdomain)
1067 samdb = SamDB(paths.samdb, session_info=session_info,
1068 credentials=credentials, lp=lp)
1070 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1071 assert isinstance(domainguid, str)
1072 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1073 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1074 scope=SCOPE_SUBTREE)
1075 assert isinstance(hostguid, str)
1077 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1078 domaindn=names.domaindn, hostip=hostip,
1079 hostip6=hostip6, hostname=names.hostname,
1080 dnspass=dnspass, realm=names.realm,
1081 domainguid=domainguid, hostguid=hostguid)
1083 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1084 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1086 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1087 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1088 keytab_name=paths.dns_keytab)
1089 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1090 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1092 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1093 hostname=names.hostname, realm=names.realm)
1094 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1096 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1099 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1101 message("Once the above files are installed, your Samba4 server will be ready to use")
1102 message("Server Role: %s" % serverrole)
1103 message("Hostname: %s" % names.hostname)
1104 message("NetBIOS Domain: %s" % names.domain)
1105 message("DNS Domain: %s" % names.dnsdomain)
1106 message("DOMAIN SID: %s" % str(domainsid))
1107 message("Admin password: %s" % adminpass)
1109 result = ProvisionResult()
1110 result.domaindn = domaindn
1111 result.paths = paths
1113 result.samdb = samdb
1117 def provision_become_dc(setup_dir=None,
1118 smbconf=None, targetdir=None, realm=None,
1119 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1121 domain=None, hostname=None, domainsid=None,
1122 adminpass=None, krbtgtpass=None, domainguid=None,
1123 policyguid=None, invocationid=None, machinepass=None,
1124 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1125 wheel=None, backup=None, aci=None, serverrole=None,
1126 ldap_backend=None, ldap_backend_type=None, sitename=None):
1129 """print a message if quiet is not set."""
1132 return provision(setup_dir, message, system_session(), None,
1133 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1134 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1135 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1138 def setup_db_config(setup_path, dbdir):
1139 """Setup a Berkeley database.
1141 :param setup_path: Setup path function.
1142 :param dbdir: Database directory."""
1143 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1144 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1145 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1146 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1148 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1149 {"LDAPDBDIR": dbdir})
1153 def provision_backend(setup_dir=None, message=None,
1154 smbconf=None, targetdir=None, realm=None,
1155 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1156 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1157 ldap_backend_type=None, ldap_backend_port=None,
1160 def setup_path(file):
1161 return os.path.join(setup_dir, file)
1163 if hostname is None:
1164 hostname = socket.gethostname().split(".")[0].lower()
1167 root = findnss(pwd.getpwnam, ["root"])[0]
1169 if adminpass is None:
1170 adminpass = misc.random_password(12)
1172 if targetdir is not None:
1173 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1174 os.makedirs(os.path.join(targetdir, "etc"))
1175 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1177 # only install a new smb.conf if there isn't one there already
1178 if not os.path.exists(smbconf):
1179 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1182 lp = param.LoadParm()
1185 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1186 dnsdomain=realm, serverrole=serverrole,
1187 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1190 paths = provision_paths_from_lp(lp, names.dnsdomain)
1192 if not os.path.isdir(paths.ldapdir):
1193 os.makedirs(paths.ldapdir, 0700)
1194 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1196 os.unlink(schemadb_path)
1200 schemadb = Ldb(schemadb_path, lp=lp)
1202 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1204 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1205 {"SCHEMADN": names.schemadn,
1208 setup_modify_ldif(schemadb,
1209 setup_path("provision_schema_basedn_modify.ldif"), \
1210 {"SCHEMADN": names.schemadn,
1211 "NETBIOSNAME": names.netbiosname,
1212 "DEFAULTSITE": DEFAULTSITE,
1213 "CONFIGDN": names.configdn,
1214 "SERVERDN": names.serverdn,
1215 "PREFIXMAP_B64": b64encode(prefixmap)
1218 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1219 {"SCHEMADN": names.schemadn })
1220 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1221 {"SCHEMADN": names.schemadn})
1223 if ldap_backend_type == "fedora-ds":
1224 if ldap_backend_port is not None:
1225 serverport = "ServerPort=%d" % ldap_backend_port
1229 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1231 "HOSTNAME": hostname,
1232 "DNSDOMAIN": names.dnsdomain,
1233 "LDAPDIR": paths.ldapdir,
1234 "DOMAINDN": names.domaindn,
1235 "LDAPMANAGERDN": names.ldapmanagerdn,
1236 "LDAPMANAGERPASS": adminpass,
1237 "SERVERPORT": serverport})
1239 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1240 {"CONFIGDN": names.configdn,
1241 "SCHEMADN": names.schemadn,
1244 mapping = "schema-map-fedora-ds-1.0"
1245 backend_schema = "99_ad.ldif"
1247 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1249 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1251 elif ldap_backend_type == "openldap":
1252 attrs = ["linkID", "lDAPDisplayName"]
1253 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1255 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1256 refint_attributes = ""
1257 for i in range (0, len(res)):
1258 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1259 target = schemadb.searchone(basedn=names.schemadn,
1260 expression=expression,
1261 attribute="lDAPDisplayName",
1262 scope=SCOPE_SUBTREE)
1263 if target is not None:
1264 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1266 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1267 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1268 "MEMBEROF_ATTR" : str(target) })
1270 refint_config = read_and_sub_file(setup_path("refint.conf"),
1271 { "LINK_ATTRS" : refint_attributes})
1273 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1275 mmr_replicator_acl = ""
1276 mmr_serverids_config = ""
1277 mmr_syncrepl_schema_config = ""
1278 mmr_syncrepl_config_config = ""
1279 mmr_syncrepl_user_config = ""
1281 if ol_mmr_urls is not None:
1282 # For now, make these equal
1283 mmr_pass = adminpass
1285 url_list=filter(None,ol_mmr_urls.split(' '))
1286 if (len(url_list) == 1):
1287 url_list=filter(None,ol_mmr_urls.split(','))
1290 mmr_on_config = "MirrorMode On"
1291 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
1293 for url in url_list:
1295 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1296 { "SERVERID" : str(serverid),
1297 "LDAPSERVER" : url })
1300 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1302 "MMRDN": names.schemadn,
1304 "MMR_PASSWORD": mmr_pass})
1307 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1309 "MMRDN": names.configdn,
1311 "MMR_PASSWORD": mmr_pass})
1314 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1316 "MMRDN": names.domaindn,
1318 "MMR_PASSWORD": mmr_pass })
1321 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1322 {"DNSDOMAIN": names.dnsdomain,
1323 "LDAPDIR": paths.ldapdir,
1324 "DOMAINDN": names.domaindn,
1325 "CONFIGDN": names.configdn,
1326 "SCHEMADN": names.schemadn,
1327 "MEMBEROF_CONFIG": memberof_config,
1328 "MIRRORMODE": mmr_on_config,
1329 "REPLICATOR_ACL": mmr_replicator_acl,
1330 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1331 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1332 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1333 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1334 "REFINT_CONFIG": refint_config})
1335 setup_file(setup_path("modules.conf"), paths.modulesconf,
1336 {"REALM": names.realm})
1338 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1339 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1340 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1342 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1343 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1345 setup_file(setup_path("cn=samba.ldif"),
1346 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1347 { "UUID": str(uuid.uuid4()),
1348 "LDAPTIME": timestring(int(time.time()))} )
1349 setup_file(setup_path("cn=samba-admin.ldif"),
1350 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1351 {"LDAPADMINPASS_B64": b64encode(adminpass),
1352 "UUID": str(uuid.uuid4()),
1353 "LDAPTIME": timestring(int(time.time()))} )
1355 if ol_mmr_urls is not None:
1356 setup_file(setup_path("cn=replicator.ldif"),
1357 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1358 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
1359 "UUID": str(uuid.uuid4()),
1360 "LDAPTIME": timestring(int(time.time()))} )
1364 mapping = "schema-map-openldap-2.3"
1365 backend_schema = "backend-schema.schema"
1367 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1368 if ldap_backend_port is not None:
1369 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1371 server_port_string = ""
1373 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1375 ldapuser = "--username=samba-admin"
1378 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)
1380 os.system(schema_command)
1382 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1383 message("Server Role: %s" % serverrole)
1384 message("Hostname: %s" % names.hostname)
1385 message("DNS Domain: %s" % names.dnsdomain)
1386 message("Base DN: %s" % names.domaindn)
1388 if ldap_backend_type == "openldap":
1389 message("LDAP admin user: samba-admin")
1391 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1393 message("LDAP admin password: %s" % adminpass)
1394 message(slapdcommand)
1395 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1397 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1398 """Create a PHP LDAP admin configuration file.
1400 :param path: Path to write the configuration to.
1401 :param setup_path: Function to generate setup paths.
1403 setup_file(setup_path("phpldapadmin-config.php"), path,
1404 {"S4_LDAPI_URI": ldapi_uri})
1407 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1408 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1409 """Write out a DNS zone file, from the info in the current database.
1411 :param path: Path of the new zone file.
1412 :param setup_path: Setup path function.
1413 :param dnsdomain: DNS Domain name
1414 :param domaindn: DN of the Domain
1415 :param hostip: Local IPv4 IP
1416 :param hostip6: Local IPv6 IP
1417 :param hostname: Local hostname
1418 :param dnspass: Password for DNS
1419 :param realm: Realm name
1420 :param domainguid: GUID of the domain.
1421 :param hostguid: GUID of the host.
1423 assert isinstance(domainguid, str)
1425 if hostip6 is not None:
1426 hostip6_base_line = " IN AAAA " + hostip6
1427 hostip6_host_line = hostname + " IN AAAA " + hostip6
1429 hostip6_base_line = ""
1430 hostip6_host_line = ""
1432 if hostip is not None:
1433 hostip_base_line = " IN A " + hostip
1434 hostip_host_line = hostname + " IN A " + hostip
1436 hostip_base_line = ""
1437 hostip_host_line = ""
1439 setup_file(setup_path("provision.zone"), path, {
1440 "DNSPASS_B64": b64encode(dnspass),
1441 "HOSTNAME": hostname,
1442 "DNSDOMAIN": dnsdomain,
1444 "HOSTIP_BASE_LINE": hostip_base_line,
1445 "HOSTIP_HOST_LINE": hostip_host_line,
1446 "DOMAINGUID": domainguid,
1447 "DATESTRING": time.strftime("%Y%m%d%H"),
1448 "DEFAULTSITE": DEFAULTSITE,
1449 "HOSTGUID": hostguid,
1450 "HOSTIP6_BASE_LINE": hostip6_base_line,
1451 "HOSTIP6_HOST_LINE": hostip6_host_line,
1455 def create_named_conf(path, setup_path, realm, dnsdomain,
1457 """Write out a file containing zone statements suitable for inclusion in a
1458 named.conf file (including GSS-TSIG configuration).
1460 :param path: Path of the new named.conf file.
1461 :param setup_path: Setup path function.
1462 :param realm: Realm name
1463 :param dnsdomain: DNS Domain name
1464 :param private_dir: Path to private directory
1465 :param keytab_name: File name of DNS keytab file
1468 setup_file(setup_path("named.conf"), path, {
1469 "DNSDOMAIN": dnsdomain,
1471 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1472 "PRIVATE_DIR": private_dir
1475 def create_named_txt(path, setup_path, realm, dnsdomain,
1476 private_dir, keytab_name):
1477 """Write out a file containing zone statements suitable for inclusion in a
1478 named.conf file (including GSS-TSIG configuration).
1480 :param path: Path of the new named.conf file.
1481 :param setup_path: Setup path function.
1482 :param realm: Realm name
1483 :param dnsdomain: DNS Domain name
1484 :param private_dir: Path to private directory
1485 :param keytab_name: File name of DNS keytab file
1488 setup_file(setup_path("named.txt"), path, {
1489 "DNSDOMAIN": dnsdomain,
1491 "DNS_KEYTAB": keytab_name,
1492 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1493 "PRIVATE_DIR": private_dir
1496 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1497 """Write out a file containing zone statements suitable for inclusion in a
1498 named.conf file (including GSS-TSIG configuration).
1500 :param path: Path of the new named.conf file.
1501 :param setup_path: Setup path function.
1502 :param dnsdomain: DNS Domain name
1503 :param hostname: Local hostname
1504 :param realm: Realm name
1507 setup_file(setup_path("krb5.conf"), path, {
1508 "DNSDOMAIN": dnsdomain,
1509 "HOSTNAME": hostname,
1514 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
1515 serverdn, servername):
1516 """Load schema for the SamDB.
1518 :param samdb: Load a schema into a SamDB.
1519 :param setup_path: Setup path function.
1520 :param schemadn: DN of the schema
1521 :param netbiosname: NetBIOS name of the host.
1522 :param configdn: DN of the configuration
1523 :param serverdn: DN of the server
1524 :param servername: Host name of the server
1526 schema_data = open(setup_path("schema.ldif"), 'r').read()
1527 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1528 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1529 check_all_substituted(schema_data)
1530 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1531 prefixmap = b64encode(prefixmap)
1533 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1534 head_data = substitute_var(head_data, {
1535 "SCHEMADN": schemadn,
1536 "NETBIOSNAME": netbiosname,
1537 "CONFIGDN": configdn,
1538 "DEFAULTSITE": sitename,
1539 "PREFIXMAP_B64": prefixmap,
1540 "SERVERDN": serverdn,
1541 "SERVERNAME": servername,
1543 check_all_substituted(head_data)
1544 samdb.attach_schema_from_ldif(head_data, schema_data)