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
436 samdb = SamDB(samdb_path, session_info=session_info,
437 credentials=credentials, lp=lp)
441 os.unlink(samdb_path)
442 samdb = SamDB(samdb_path, session_info=session_info,
443 credentials=credentials, lp=lp)
448 #Add modules to the list to activate them by default
449 #beware often order is important
451 # Some Known ordering constraints:
452 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
453 # - objectclass must be before password_hash, because password_hash checks
454 # that the objectclass is of type person (filled in by objectclass
455 # module when expanding the objectclass list)
456 # - partition must be last
457 # - each partition has its own module list then
458 modules_list = ["rootdse",
476 "extended_dn_out_ldb"]
477 modules_list2 = ["show_deleted",
480 domaindn_ldb = "users.ldb"
481 if ldap_backend is not None:
482 domaindn_ldb = ldap_backend
483 configdn_ldb = "configuration.ldb"
484 if ldap_backend is not None:
485 configdn_ldb = ldap_backend
486 schemadn_ldb = "schema.ldb"
487 if ldap_backend is not None:
488 schema_ldb = ldap_backend
489 schemadn_ldb = ldap_backend
491 if ldap_backend_type == "fedora-ds":
492 backend_modules = ["nsuniqueid", "paged_searches"]
493 # We can handle linked attributes here, as we don't have directory-side subtree operations
494 tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
495 elif ldap_backend_type == "openldap":
496 backend_modules = ["entryuuid", "paged_searches"]
497 # OpenLDAP handles subtree renames, so we don't want to do any of these things
498 tdb_modules_list = ["extended_dn_out_dereference"]
499 elif ldap_backend is not None:
500 raise "LDAP Backend specified, but LDAP Backend Type not specified"
501 elif serverrole == "domain controller":
502 backend_modules = ["repl_meta_data"]
504 backend_modules = ["objectguid"]
506 if tdb_modules_list is None:
507 tdb_modules_list_as_string = ""
509 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
511 samdb.transaction_start()
513 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
514 "SCHEMADN": names.schemadn,
515 "SCHEMADN_LDB": schemadn_ldb,
516 "SCHEMADN_MOD2": ",objectguid",
517 "CONFIGDN": names.configdn,
518 "CONFIGDN_LDB": configdn_ldb,
519 "DOMAINDN": names.domaindn,
520 "DOMAINDN_LDB": domaindn_ldb,
521 "SCHEMADN_MOD": "schema_fsmo,instancetype",
522 "CONFIGDN_MOD": "naming_fsmo,instancetype",
523 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
524 "MODULES_LIST": ",".join(modules_list),
525 "TDB_MODULES_LIST": tdb_modules_list_as_string,
526 "MODULES_LIST2": ",".join(modules_list2),
527 "BACKEND_MOD": ",".join(backend_modules),
531 samdb.transaction_cancel()
534 samdb.transaction_commit()
536 samdb = SamDB(samdb_path, session_info=session_info,
537 credentials=credentials, lp=lp)
539 samdb.transaction_start()
541 message("Setting up sam.ldb attributes")
542 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
544 message("Setting up sam.ldb rootDSE")
545 setup_samdb_rootdse(samdb, setup_path, names)
548 message("Erasing data from partitions")
549 samdb.erase_partitions()
552 samdb.transaction_cancel()
555 samdb.transaction_commit()
560 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
561 netbiosname, domainsid, keytab_path, samdb_url,
562 dns_keytab_path, dnspass, machinepass):
563 """Add DC-specific bits to a secrets database.
565 :param secretsdb: Ldb Handle to the secrets database
566 :param setup_path: Setup path function
567 :param machinepass: Machine password
569 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
570 "MACHINEPASS_B64": b64encode(machinepass),
573 "DNSDOMAIN": dnsdomain,
574 "DOMAINSID": str(domainsid),
575 "SECRETS_KEYTAB": keytab_path,
576 "NETBIOSNAME": netbiosname,
577 "SAM_LDB": samdb_url,
578 "DNS_KEYTAB": dns_keytab_path,
579 "DNSPASS_B64": b64encode(dnspass),
583 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
584 """Setup the secrets database.
586 :param path: Path to the secrets database.
587 :param setup_path: Get the path to a setup file.
588 :param session_info: Session info.
589 :param credentials: Credentials
590 :param lp: Loadparm context
591 :return: LDB handle for the created secrets database
593 if os.path.exists(path):
595 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
598 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
599 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
601 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
603 if credentials is not None and credentials.authentication_requested():
604 if credentials.get_bind_dn() is not None:
605 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
606 "LDAPMANAGERDN": credentials.get_bind_dn(),
607 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
610 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
611 "LDAPADMINUSER": credentials.get_username(),
612 "LDAPADMINREALM": credentials.get_realm(),
613 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
619 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
620 """Setup the templates database.
622 :param path: Path to the database.
623 :param setup_path: Function for obtaining the path to setup files.
624 :param session_info: Session info
625 :param credentials: Credentials
626 :param lp: Loadparm context
628 templates_ldb = SamDB(path, session_info=session_info,
629 credentials=credentials, lp=lp)
632 templates_ldb.erase()
636 templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
638 templates_ldb = SamDB(path, session_info=session_info,
639 credentials=credentials, lp=lp)
641 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
644 def setup_registry(path, setup_path, session_info, credentials, lp):
645 """Setup the registry.
647 :param path: Path to the registry database
648 :param setup_path: Function that returns the path to a setup.
649 :param session_info: Session information
650 :param credentials: Credentials
651 :param lp: Loadparm context
653 reg = registry.Registry()
654 hive = registry.open_ldb(path, session_info=session_info,
655 credentials=credentials, lp_ctx=lp)
656 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
657 provision_reg = setup_path("provision.reg")
658 assert os.path.exists(provision_reg)
659 reg.diff_apply(provision_reg)
662 def setup_idmapdb(path, setup_path, session_info, credentials, lp):
663 """Setup the idmap database.
665 :param path: path to the idmap database
666 :param setup_path: Function that returns a path to a setup file
667 :param session_info: Session information
668 :param credentials: Credentials
669 :param lp: Loadparm context
671 if os.path.exists(path):
674 idmap_ldb = IDmapDB(path, session_info=session_info,
675 credentials=credentials, lp=lp)
678 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
682 def setup_samdb_rootdse(samdb, setup_path, names):
683 """Setup the SamDB rootdse.
685 :param samdb: Sam Database handle
686 :param setup_path: Obtain setup path
688 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
689 "SCHEMADN": names.schemadn,
690 "NETBIOSNAME": names.netbiosname,
691 "DNSDOMAIN": names.dnsdomain,
692 "REALM": names.realm,
693 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
694 "DOMAINDN": names.domaindn,
695 "ROOTDN": names.rootdn,
696 "CONFIGDN": names.configdn,
697 "SERVERDN": names.serverdn,
701 def setup_self_join(samdb, names,
702 machinepass, dnspass,
703 domainsid, invocationid, setup_path,
705 """Join a host to its own domain."""
706 assert isinstance(invocationid, str)
707 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
708 "CONFIGDN": names.configdn,
709 "SCHEMADN": names.schemadn,
710 "DOMAINDN": names.domaindn,
711 "SERVERDN": names.serverdn,
712 "INVOCATIONID": invocationid,
713 "NETBIOSNAME": names.netbiosname,
714 "DEFAULTSITE": names.sitename,
715 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
716 "MACHINEPASS_B64": b64encode(machinepass),
717 "DNSPASS_B64": b64encode(dnspass),
718 "REALM": names.realm,
719 "DOMAIN": names.domain,
720 "DNSDOMAIN": names.dnsdomain})
721 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
722 "POLICYGUID": policyguid,
723 "DNSDOMAIN": names.dnsdomain,
724 "DOMAINSID": str(domainsid),
725 "DOMAINDN": names.domaindn})
728 def setup_samdb(path, setup_path, session_info, credentials, lp,
730 domainsid, aci, domainguid, policyguid,
731 fill, adminpass, krbtgtpass,
732 machinepass, invocationid, dnspass,
733 serverrole, ldap_backend=None,
734 ldap_backend_type=None):
735 """Setup a complete SAM Database.
737 :note: This will wipe the main SAM database file!
740 erase = (fill != FILL_DRS)
742 # Also wipes the database
743 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
744 credentials=credentials, session_info=session_info,
746 ldap_backend=ldap_backend, serverrole=serverrole,
747 ldap_backend_type=ldap_backend_type, erase=erase)
749 samdb = SamDB(path, session_info=session_info,
750 credentials=credentials, lp=lp)
754 message("Pre-loading the Samba 4 and AD schema")
755 samdb.set_domain_sid(domainsid)
756 if serverrole == "domain controller":
757 samdb.set_invocation_id(invocationid)
759 load_schema(setup_path, samdb, names.schemadn, names.netbiosname,
760 names.configdn, names.sitename, names.serverdn,
763 samdb.transaction_start()
766 message("Adding DomainDN: %s (permitted to fail)" % names.domaindn)
767 if serverrole == "domain controller":
768 domain_oc = "domainDNS"
770 domain_oc = "samba4LocalDomain"
772 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
773 "DOMAINDN": names.domaindn,
775 "DOMAIN_OC": domain_oc
778 message("Modifying DomainDN: " + names.domaindn + "")
779 if domainguid is not None:
780 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
784 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
785 "LDAPTIME": timestring(int(time.time())),
786 "DOMAINSID": str(domainsid),
787 "SCHEMADN": names.schemadn,
788 "NETBIOSNAME": names.netbiosname,
789 "DEFAULTSITE": names.sitename,
790 "CONFIGDN": names.configdn,
791 "SERVERDN": names.serverdn,
792 "POLICYGUID": policyguid,
793 "DOMAINDN": names.domaindn,
794 "DOMAINGUID_MOD": domainguid_mod,
797 message("Adding configuration container (permitted to fail)")
798 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
799 "CONFIGDN": names.configdn,
802 message("Modifying configuration container")
803 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
804 "CONFIGDN": names.configdn,
805 "SCHEMADN": names.schemadn,
808 message("Adding schema container (permitted to fail)")
809 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
810 "SCHEMADN": names.schemadn,
813 message("Modifying schema container")
815 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
817 setup_modify_ldif(samdb,
818 setup_path("provision_schema_basedn_modify.ldif"), {
819 "SCHEMADN": names.schemadn,
820 "NETBIOSNAME": names.netbiosname,
821 "DEFAULTSITE": names.sitename,
822 "CONFIGDN": names.configdn,
823 "SERVERDN": names.serverdn,
824 "PREFIXMAP_B64": b64encode(prefixmap)
827 message("Setting up sam.ldb Samba4 schema")
828 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
829 {"SCHEMADN": names.schemadn })
830 message("Setting up sam.ldb AD schema")
831 setup_add_ldif(samdb, setup_path("schema.ldif"),
832 {"SCHEMADN": names.schemadn})
834 message("Setting up sam.ldb configuration data")
835 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
836 "CONFIGDN": names.configdn,
837 "NETBIOSNAME": names.netbiosname,
838 "DEFAULTSITE": names.sitename,
839 "DNSDOMAIN": names.dnsdomain,
840 "DOMAIN": names.domain,
841 "SCHEMADN": names.schemadn,
842 "DOMAINDN": names.domaindn,
843 "SERVERDN": names.serverdn
846 message("Setting up display specifiers")
847 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
848 {"CONFIGDN": names.configdn})
850 message("Adding users container (permitted to fail)")
851 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
852 "DOMAINDN": names.domaindn})
853 message("Modifying users container")
854 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
855 "DOMAINDN": names.domaindn})
856 message("Adding computers container (permitted to fail)")
857 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
858 "DOMAINDN": names.domaindn})
859 message("Modifying computers container")
860 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
861 "DOMAINDN": names.domaindn})
862 message("Setting up sam.ldb data")
863 setup_add_ldif(samdb, setup_path("provision.ldif"), {
864 "DOMAINDN": names.domaindn,
865 "NETBIOSNAME": names.netbiosname,
866 "DEFAULTSITE": names.sitename,
867 "CONFIGDN": names.configdn,
868 "SERVERDN": names.serverdn
871 if fill == FILL_FULL:
872 message("Setting up sam.ldb users and groups")
873 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
874 "DOMAINDN": names.domaindn,
875 "DOMAINSID": str(domainsid),
876 "CONFIGDN": names.configdn,
877 "ADMINPASS_B64": b64encode(adminpass),
878 "KRBTGTPASS_B64": b64encode(krbtgtpass),
881 if serverrole == "domain controller":
882 message("Setting up self join")
883 setup_self_join(samdb, names=names, invocationid=invocationid,
885 machinepass=machinepass,
886 domainsid=domainsid, policyguid=policyguid,
887 setup_path=setup_path)
890 samdb.transaction_cancel()
893 samdb.transaction_commit()
898 FILL_NT4SYNC = "NT4SYNC"
901 def provision(setup_dir, message, session_info,
902 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None,
903 rootdn=None, domaindn=None, schemadn=None, configdn=None,
905 domain=None, hostname=None, hostip=None, hostip6=None,
906 domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None,
907 policyguid=None, invocationid=None, machinepass=None,
908 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
909 wheel=None, backup=None, aci=None, serverrole=None,
910 ldap_backend=None, ldap_backend_type=None, sitename=None):
913 :note: caution, this wipes all existing data!
916 def setup_path(file):
917 return os.path.join(setup_dir, file)
919 if domainsid is None:
920 domainsid = security.random_sid()
922 domainsid = security.Sid(domainsid)
924 if policyguid is None:
925 policyguid = str(uuid.uuid4())
926 if adminpass is None:
927 adminpass = misc.random_password(12)
928 if krbtgtpass is None:
929 krbtgtpass = misc.random_password(12)
930 if machinepass is None:
931 machinepass = misc.random_password(12)
933 dnspass = misc.random_password(12)
934 root_uid = findnss_uid([root or "root"])
935 nobody_uid = findnss_uid([nobody or "nobody"])
936 users_gid = findnss_gid([users or "users"])
938 wheel_gid = findnss_gid(["wheel", "adm"])
940 wheel_gid = findnss_gid([wheel])
942 aci = "# no aci for local ldb"
944 if targetdir is not None:
945 if (not os.path.exists(os.path.join(targetdir, "etc"))):
946 os.makedirs(os.path.join(targetdir, "etc"))
947 smbconf = os.path.join(targetdir, "etc", "smb.conf")
949 # only install a new smb.conf if there isn't one there already
950 if not os.path.exists(smbconf):
951 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
954 lp = param.LoadParm()
957 names = guess_names(lp=lp, hostname=hostname, domain=domain,
958 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
959 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
962 paths = provision_paths_from_lp(lp, names.dnsdomain)
966 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
967 except socket.gaierror, (socket.EAI_NODATA, msg):
972 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
973 except socket.gaierror, (socket.EAI_NODATA, msg):
976 if serverrole is None:
977 serverrole = lp.get("server role")
979 assert serverrole in ("domain controller", "member server", "standalone")
980 if invocationid is None and serverrole == "domain controller":
981 invocationid = str(uuid.uuid4())
983 if not os.path.exists(paths.private_dir):
984 os.mkdir(paths.private_dir)
986 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
988 if ldap_backend is not None:
989 if ldap_backend == "ldapi":
990 # provision-backend will set this path suggested slapd command line / fedorads.inf
991 ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
993 # only install a new shares config db if there is none
994 if not os.path.exists(paths.shareconf):
995 message("Setting up share.ldb")
996 share_ldb = Ldb(paths.shareconf, session_info=session_info,
997 credentials=credentials, lp=lp)
998 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1001 message("Setting up secrets.ldb")
1002 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1003 session_info=session_info,
1004 credentials=credentials, lp=lp)
1006 message("Setting up the registry")
1007 setup_registry(paths.hklm, setup_path, session_info,
1008 credentials=credentials, lp=lp)
1010 message("Setting up templates db")
1011 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
1012 credentials=credentials, lp=lp)
1014 message("Setting up idmap db")
1015 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1016 credentials=credentials, lp=lp)
1018 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1019 credentials=credentials, lp=lp, names=names,
1021 domainsid=domainsid,
1022 aci=aci, domainguid=domainguid, policyguid=policyguid,
1024 adminpass=adminpass, krbtgtpass=krbtgtpass,
1025 invocationid=invocationid,
1026 machinepass=machinepass, dnspass=dnspass,
1027 serverrole=serverrole, ldap_backend=ldap_backend,
1028 ldap_backend_type=ldap_backend_type)
1030 if lp.get("server role") == "domain controller":
1031 if paths.netlogon is None:
1032 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1033 message("Please either remove %s or see the template at %s" %
1034 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1035 assert(paths.netlogon is not None)
1037 if paths.sysvol is None:
1038 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1039 message("Please either remove %s or see the template at %s" %
1040 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1041 assert(paths.sysvol is not None)
1043 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1044 "{" + policyguid + "}")
1045 os.makedirs(policy_path, 0755)
1046 open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
1047 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
1048 os.makedirs(os.path.join(policy_path, "User"), 0755)
1049 if not os.path.isdir(paths.netlogon):
1050 os.makedirs(paths.netlogon, 0755)
1052 if samdb_fill == FILL_FULL:
1053 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1054 root_uid=root_uid, nobody_uid=nobody_uid,
1055 users_gid=users_gid, wheel_gid=wheel_gid)
1057 message("Setting up sam.ldb rootDSE marking as synchronized")
1058 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1060 # Only make a zone file on the first DC, it should be replicated with DNS replication
1061 if serverrole == "domain controller":
1062 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1063 credentials=credentials, lp=lp)
1064 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm,
1065 netbiosname=names.netbiosname, domainsid=domainsid,
1066 keytab_path=paths.keytab, samdb_url=paths.samdb,
1067 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1068 machinepass=machinepass, dnsdomain=names.dnsdomain)
1070 samdb = SamDB(paths.samdb, session_info=session_info,
1071 credentials=credentials, lp=lp)
1073 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1074 assert isinstance(domainguid, str)
1075 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
1076 expression="(&(objectClass=computer)(cn=%s))" % names.hostname,
1077 scope=SCOPE_SUBTREE)
1078 assert isinstance(hostguid, str)
1080 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1081 domaindn=names.domaindn, hostip=hostip,
1082 hostip6=hostip6, hostname=names.hostname,
1083 dnspass=dnspass, realm=names.realm,
1084 domainguid=domainguid, hostguid=hostguid)
1086 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1087 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1089 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1090 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1091 keytab_name=paths.dns_keytab)
1092 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1093 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1095 create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
1096 hostname=names.hostname, realm=names.realm)
1097 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1099 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1102 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1104 message("Once the above files are installed, your Samba4 server will be ready to use")
1105 message("Server Role: %s" % serverrole)
1106 message("Hostname: %s" % names.hostname)
1107 message("NetBIOS Domain: %s" % names.domain)
1108 message("DNS Domain: %s" % names.dnsdomain)
1109 message("DOMAIN SID: %s" % str(domainsid))
1110 message("Admin password: %s" % adminpass)
1112 result = ProvisionResult()
1113 result.domaindn = domaindn
1114 result.paths = paths
1116 result.samdb = samdb
1120 def provision_become_dc(setup_dir=None,
1121 smbconf=None, targetdir=None, realm=None,
1122 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1124 domain=None, hostname=None, domainsid=None,
1125 adminpass=None, krbtgtpass=None, domainguid=None,
1126 policyguid=None, invocationid=None, machinepass=None,
1127 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
1128 wheel=None, backup=None, aci=None, serverrole=None,
1129 ldap_backend=None, ldap_backend_type=None, sitename=None):
1132 """print a message if quiet is not set."""
1135 return provision(setup_dir, message, system_session(), None,
1136 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm,
1137 rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn,
1138 domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename)
1141 def setup_db_config(setup_path, dbdir):
1142 """Setup a Berkeley database.
1144 :param setup_path: Setup path function.
1145 :param dbdir: Database directory."""
1146 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1147 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1148 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1149 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1151 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1152 {"LDAPDBDIR": dbdir})
1156 def provision_backend(setup_dir=None, message=None,
1157 smbconf=None, targetdir=None, realm=None,
1158 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1159 domain=None, hostname=None, adminpass=None, root=None, serverrole=None,
1160 ldap_backend_type=None, ldap_backend_port=None,
1163 def setup_path(file):
1164 return os.path.join(setup_dir, file)
1166 if hostname is None:
1167 hostname = socket.gethostname().split(".")[0].lower()
1170 root = findnss(pwd.getpwnam, ["root"])[0]
1172 if adminpass is None:
1173 adminpass = misc.random_password(12)
1175 if targetdir is not None:
1176 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1177 os.makedirs(os.path.join(targetdir, "etc"))
1178 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1180 # only install a new smb.conf if there isn't one there already
1181 if not os.path.exists(smbconf):
1182 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1185 lp = param.LoadParm()
1188 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1189 dnsdomain=realm, serverrole=serverrole,
1190 rootdn=rootdn, domaindn=domaindn, configdn=configdn,
1193 paths = provision_paths_from_lp(lp, names.dnsdomain)
1195 if not os.path.isdir(paths.ldapdir):
1196 os.makedirs(paths.ldapdir, 0700)
1197 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1199 os.unlink(schemadb_path)
1203 schemadb = Ldb(schemadb_path, lp=lp)
1205 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1207 setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"),
1208 {"SCHEMADN": names.schemadn,
1211 setup_modify_ldif(schemadb,
1212 setup_path("provision_schema_basedn_modify.ldif"), \
1213 {"SCHEMADN": names.schemadn,
1214 "NETBIOSNAME": names.netbiosname,
1215 "DEFAULTSITE": DEFAULTSITE,
1216 "CONFIGDN": names.configdn,
1217 "SERVERDN": names.serverdn,
1218 "PREFIXMAP_B64": b64encode(prefixmap)
1221 setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"),
1222 {"SCHEMADN": names.schemadn })
1223 setup_add_ldif(schemadb, setup_path("schema.ldif"),
1224 {"SCHEMADN": names.schemadn})
1226 if ldap_backend_type == "fedora-ds":
1227 if ldap_backend_port is not None:
1228 serverport = "ServerPort=%d" % ldap_backend_port
1232 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1234 "HOSTNAME": hostname,
1235 "DNSDOMAIN": names.dnsdomain,
1236 "LDAPDIR": paths.ldapdir,
1237 "DOMAINDN": names.domaindn,
1238 "LDAPMANAGERDN": names.ldapmanagerdn,
1239 "LDAPMANAGERPASS": adminpass,
1240 "SERVERPORT": serverport})
1242 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1243 {"CONFIGDN": names.configdn,
1244 "SCHEMADN": names.schemadn,
1247 mapping = "schema-map-fedora-ds-1.0"
1248 backend_schema = "99_ad.ldif"
1250 slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
1252 ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
1254 elif ldap_backend_type == "openldap":
1255 attrs = ["linkID", "lDAPDisplayName"]
1256 res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
1258 memberof_config = "# Generated from schema in %s\n" % schemadb_path
1259 refint_attributes = ""
1260 for i in range (0, len(res)):
1261 expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
1262 target = schemadb.searchone(basedn=names.schemadn,
1263 expression=expression,
1264 attribute="lDAPDisplayName",
1265 scope=SCOPE_SUBTREE)
1266 if target is not None:
1267 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
1269 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1270 { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
1271 "MEMBEROF_ATTR" : str(target) })
1273 refint_config = read_and_sub_file(setup_path("refint.conf"),
1274 { "LINK_ATTRS" : refint_attributes})
1276 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1278 mmr_replicator_acl = ""
1279 mmr_serverids_config = ""
1280 mmr_syncrepl_schema_config = ""
1281 mmr_syncrepl_config_config = ""
1282 mmr_syncrepl_user_config = ""
1284 if ol_mmr_urls is not None:
1285 # For now, make these equal
1286 mmr_pass = adminpass
1288 url_list=filter(None,ol_mmr_urls.split(' '))
1289 if (len(url_list) == 1):
1290 url_list=filter(None,ol_mmr_urls.split(','))
1293 mmr_on_config = "MirrorMode On"
1294 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
1296 for url in url_list:
1298 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1299 { "SERVERID" : str(serverid),
1300 "LDAPSERVER" : url })
1303 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1305 "MMRDN": names.schemadn,
1307 "MMR_PASSWORD": mmr_pass})
1310 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1312 "MMRDN": names.configdn,
1314 "MMR_PASSWORD": mmr_pass})
1317 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1319 "MMRDN": names.domaindn,
1321 "MMR_PASSWORD": mmr_pass })
1324 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1325 {"DNSDOMAIN": names.dnsdomain,
1326 "LDAPDIR": paths.ldapdir,
1327 "DOMAINDN": names.domaindn,
1328 "CONFIGDN": names.configdn,
1329 "SCHEMADN": names.schemadn,
1330 "MEMBEROF_CONFIG": memberof_config,
1331 "MIRRORMODE": mmr_on_config,
1332 "REPLICATOR_ACL": mmr_replicator_acl,
1333 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1334 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1335 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1336 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1337 "REFINT_CONFIG": refint_config})
1338 setup_file(setup_path("modules.conf"), paths.modulesconf,
1339 {"REALM": names.realm})
1341 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1342 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1343 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1345 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1346 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1348 setup_file(setup_path("cn=samba.ldif"),
1349 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1350 { "UUID": str(uuid.uuid4()),
1351 "LDAPTIME": timestring(int(time.time()))} )
1352 setup_file(setup_path("cn=samba-admin.ldif"),
1353 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1354 {"LDAPADMINPASS_B64": b64encode(adminpass),
1355 "UUID": str(uuid.uuid4()),
1356 "LDAPTIME": timestring(int(time.time()))} )
1358 if ol_mmr_urls is not None:
1359 setup_file(setup_path("cn=replicator.ldif"),
1360 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1361 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
1362 "UUID": str(uuid.uuid4()),
1363 "LDAPTIME": timestring(int(time.time()))} )
1367 mapping = "schema-map-openldap-2.3"
1368 backend_schema = "backend-schema.schema"
1370 ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
1371 if ldap_backend_port is not None:
1372 server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
1374 server_port_string = ""
1376 slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
1378 ldapuser = "--username=samba-admin"
1381 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)
1383 os.system(schema_command)
1385 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
1386 message("Server Role: %s" % serverrole)
1387 message("Hostname: %s" % names.hostname)
1388 message("DNS Domain: %s" % names.dnsdomain)
1389 message("Base DN: %s" % names.domaindn)
1391 if ldap_backend_type == "openldap":
1392 message("LDAP admin user: samba-admin")
1394 message("LDAP admin DN: %s" % names.ldapmanagerdn)
1396 message("LDAP admin password: %s" % adminpass)
1397 message(slapdcommand)
1398 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
1400 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1401 """Create a PHP LDAP admin configuration file.
1403 :param path: Path to write the configuration to.
1404 :param setup_path: Function to generate setup paths.
1406 setup_file(setup_path("phpldapadmin-config.php"), path,
1407 {"S4_LDAPI_URI": ldapi_uri})
1410 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1411 hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid):
1412 """Write out a DNS zone file, from the info in the current database.
1414 :param path: Path of the new zone file.
1415 :param setup_path: Setup path function.
1416 :param dnsdomain: DNS Domain name
1417 :param domaindn: DN of the Domain
1418 :param hostip: Local IPv4 IP
1419 :param hostip6: Local IPv6 IP
1420 :param hostname: Local hostname
1421 :param dnspass: Password for DNS
1422 :param realm: Realm name
1423 :param domainguid: GUID of the domain.
1424 :param hostguid: GUID of the host.
1426 assert isinstance(domainguid, str)
1428 if hostip6 is not None:
1429 hostip6_base_line = " IN AAAA " + hostip6
1430 hostip6_host_line = hostname + " IN AAAA " + hostip6
1432 hostip6_base_line = ""
1433 hostip6_host_line = ""
1435 if hostip is not None:
1436 hostip_base_line = " IN A " + hostip
1437 hostip_host_line = hostname + " IN A " + hostip
1439 hostip_base_line = ""
1440 hostip_host_line = ""
1442 setup_file(setup_path("provision.zone"), path, {
1443 "DNSPASS_B64": b64encode(dnspass),
1444 "HOSTNAME": hostname,
1445 "DNSDOMAIN": dnsdomain,
1447 "HOSTIP_BASE_LINE": hostip_base_line,
1448 "HOSTIP_HOST_LINE": hostip_host_line,
1449 "DOMAINGUID": domainguid,
1450 "DATESTRING": time.strftime("%Y%m%d%H"),
1451 "DEFAULTSITE": DEFAULTSITE,
1452 "HOSTGUID": hostguid,
1453 "HOSTIP6_BASE_LINE": hostip6_base_line,
1454 "HOSTIP6_HOST_LINE": hostip6_host_line,
1458 def create_named_conf(path, setup_path, realm, dnsdomain,
1460 """Write out a file containing zone statements suitable for inclusion in a
1461 named.conf file (including GSS-TSIG configuration).
1463 :param path: Path of the new named.conf file.
1464 :param setup_path: Setup path function.
1465 :param realm: Realm name
1466 :param dnsdomain: DNS Domain name
1467 :param private_dir: Path to private directory
1468 :param keytab_name: File name of DNS keytab file
1471 setup_file(setup_path("named.conf"), path, {
1472 "DNSDOMAIN": dnsdomain,
1474 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1475 "PRIVATE_DIR": private_dir
1478 def create_named_txt(path, setup_path, realm, dnsdomain,
1479 private_dir, keytab_name):
1480 """Write out a file containing zone statements suitable for inclusion in a
1481 named.conf file (including GSS-TSIG configuration).
1483 :param path: Path of the new named.conf file.
1484 :param setup_path: Setup path function.
1485 :param realm: Realm name
1486 :param dnsdomain: DNS Domain name
1487 :param private_dir: Path to private directory
1488 :param keytab_name: File name of DNS keytab file
1491 setup_file(setup_path("named.txt"), path, {
1492 "DNSDOMAIN": dnsdomain,
1494 "DNS_KEYTAB": keytab_name,
1495 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1496 "PRIVATE_DIR": private_dir
1499 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1500 """Write out a file containing zone statements suitable for inclusion in a
1501 named.conf file (including GSS-TSIG configuration).
1503 :param path: Path of the new named.conf file.
1504 :param setup_path: Setup path function.
1505 :param dnsdomain: DNS Domain name
1506 :param hostname: Local hostname
1507 :param realm: Realm name
1510 setup_file(setup_path("krb5.conf"), path, {
1511 "DNSDOMAIN": dnsdomain,
1512 "HOSTNAME": hostname,
1517 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
1518 serverdn, servername):
1519 """Load schema for the SamDB.
1521 :param samdb: Load a schema into a SamDB.
1522 :param setup_path: Setup path function.
1523 :param schemadn: DN of the schema
1524 :param netbiosname: NetBIOS name of the host.
1525 :param configdn: DN of the configuration
1526 :param serverdn: DN of the server
1527 :param servername: Host name of the server
1529 schema_data = open(setup_path("schema.ldif"), 'r').read()
1530 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
1531 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
1532 check_all_substituted(schema_data)
1533 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
1534 prefixmap = b64encode(prefixmap)
1536 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1537 head_data = substitute_var(head_data, {
1538 "SCHEMADN": schemadn,
1539 "NETBIOSNAME": netbiosname,
1540 "CONFIGDN": configdn,
1541 "DEFAULTSITE": sitename,
1542 "PREFIXMAP_B64": prefixmap,
1543 "SERVERDN": serverdn,
1544 "SERVERNAME": servername,
1546 check_all_substituted(head_data)
1547 samdb.attach_schema_from_ldif(head_data, schema_data)