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-2009
7 # Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
9 # Based on the original in EJS:
10 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 3 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 """Functions for setting up a Samba configuration."""
28 from base64 import b64encode
44 from auth import system_session, admin_session
45 from samba import version, Ldb, substitute_var, valid_netbios_name, setup_file
46 from samba import check_all_substituted, read_and_sub_file
47 from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008
48 from samba.samdb import SamDB
49 from samba.idmap import IDmapDB
50 from samba.dcerpc import security
51 from samba.ndr import ndr_pack
53 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
54 from ms_display_specifiers import read_ms_ldif
55 from schema import Schema
56 from provisionbackend import ProvisionBackend
57 from signal import SIGTERM
58 from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
60 __docformat__ = "restructuredText"
63 """Find the setup directory used by provision."""
64 dirname = os.path.dirname(__file__)
65 if "/site-packages/" in dirname:
66 prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
67 for suffix in ["share/setup", "share/samba/setup", "setup"]:
68 ret = os.path.join(prefix, suffix)
69 if os.path.isdir(ret):
72 ret = os.path.join(dirname, "../../../setup")
73 if os.path.isdir(ret):
75 raise Exception("Unable to find setup directory.")
77 def get_config_descriptor(domain_sid):
78 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
79 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
80 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
81 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
82 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
83 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
84 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
85 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
86 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
87 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
88 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
89 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
90 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
91 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
92 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
93 sec = security.descriptor.from_sddl(sddl, domain_sid)
94 return b64encode(ndr_pack(sec))
97 DEFAULTSITE = "Default-First-Site-Name"
101 class ProvisioningError(Exception):
102 """A generic provision error."""
104 class InvalidNetbiosName(Exception):
105 """A specified name was not a valid NetBIOS name."""
106 def __init__(self, name):
107 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
110 class ProvisionPaths(object):
112 self.shareconf = None
123 self.dns_keytab = None
126 self.private_dir = None
128 self.slapdconf = None
129 self.modulesconf = None
130 self.memberofconf = None
131 self.fedoradsinf = None
132 self.fedoradspartitions = None
133 self.fedoradssasl = None
134 self.fedoradsdna = None
135 self.fedoradspam = None
136 self.fedoradsrefint = None
137 self.fedoradslinkedattributes = None
138 self.fedoradsindex = None
139 self.fedoradssamba = None
141 self.olmmrserveridsconf = None
142 self.olmmrsyncreplconf = None
145 self.olcseedldif = None
148 class ProvisionNames(object):
155 self.ldapmanagerdn = None
156 self.dnsdomain = None
158 self.netbiosname = None
165 class ProvisionResult(object):
172 def check_install(lp, session_info, credentials):
173 """Check whether the current install seems ok.
175 :param lp: Loadparm context
176 :param session_info: Session information
177 :param credentials: Credentials
179 if lp.get("realm") == "":
180 raise Exception("Realm empty")
181 ldb = Ldb(lp.get("sam database"), session_info=session_info,
182 credentials=credentials, lp=lp)
183 if len(ldb.search("(cn=Administrator)")) != 1:
184 raise ProvisioningError("No administrator account found")
187 def findnss(nssfn, names):
188 """Find a user or group from a list of possibilities.
190 :param nssfn: NSS Function to try (should raise KeyError if not found)
191 :param names: Names to check.
192 :return: Value return by first names list.
199 raise KeyError("Unable to find user/group %r" % names)
202 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
203 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
206 def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
207 """Setup a ldb in the private dir.
209 :param ldb: LDB file to import data into
210 :param ldif_path: Path of the LDIF file to load
211 :param subst_vars: Optional variables to subsitute in LDIF.
212 :param nocontrols: Optional list of controls, can be None for no controls
214 assert isinstance(ldif_path, str)
215 data = read_and_sub_file(ldif_path, subst_vars)
216 ldb.add_ldif(data,controls)
219 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
220 """Modify a ldb in the private dir.
222 :param ldb: LDB object.
223 :param ldif_path: LDIF file path.
224 :param subst_vars: Optional dictionary with substitution variables.
226 data = read_and_sub_file(ldif_path, subst_vars)
228 ldb.modify_ldif(data)
231 def setup_ldb(ldb, ldif_path, subst_vars):
232 """Import a LDIF a file into a LDB handle, optionally substituting variables.
234 :note: Either all LDIF data will be added or none (using transactions).
236 :param ldb: LDB file to import into.
237 :param ldif_path: Path to the LDIF file.
238 :param subst_vars: Dictionary with substitution variables.
240 assert ldb is not None
241 ldb.transaction_start()
243 setup_add_ldif(ldb, ldif_path, subst_vars)
245 ldb.transaction_cancel()
247 ldb.transaction_commit()
250 def provision_paths_from_lp(lp, dnsdomain):
251 """Set the default paths for provisioning.
253 :param lp: Loadparm context.
254 :param dnsdomain: DNS Domain name
256 paths = ProvisionPaths()
257 paths.private_dir = lp.get("private dir")
258 paths.dns_keytab = "dns.keytab"
260 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
261 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
262 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
263 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
264 paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
265 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
266 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
267 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
268 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
269 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
270 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
271 paths.phpldapadminconfig = os.path.join(paths.private_dir,
272 "phpldapadmin-config.php")
273 paths.ldapdir = os.path.join(paths.private_dir,
275 paths.slapdconf = os.path.join(paths.ldapdir,
277 paths.slapdpid = os.path.join(paths.ldapdir,
279 paths.modulesconf = os.path.join(paths.ldapdir,
281 paths.memberofconf = os.path.join(paths.ldapdir,
283 paths.fedoradsinf = os.path.join(paths.ldapdir,
285 paths.fedoradspartitions = os.path.join(paths.ldapdir,
286 "fedorads-partitions.ldif")
287 paths.fedoradssasl = os.path.join(paths.ldapdir,
288 "fedorads-sasl.ldif")
289 paths.fedoradsdna = os.path.join(paths.ldapdir,
291 paths.fedoradspam = os.path.join(paths.ldapdir,
293 paths.fedoradsrefint = os.path.join(paths.ldapdir,
294 "fedorads-refint.ldif")
295 paths.fedoradslinkedattributes = os.path.join(paths.ldapdir,
296 "fedorads-linked-attributes.ldif")
297 paths.fedoradsindex = os.path.join(paths.ldapdir,
298 "fedorads-index.ldif")
299 paths.fedoradssamba = os.path.join(paths.ldapdir,
300 "fedorads-samba.ldif")
301 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
302 "mmr_serverids.conf")
303 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
305 paths.olcdir = os.path.join(paths.ldapdir,
307 paths.olcseedldif = os.path.join(paths.ldapdir,
309 paths.hklm = "hklm.ldb"
310 paths.hkcr = "hkcr.ldb"
311 paths.hkcu = "hkcu.ldb"
312 paths.hku = "hku.ldb"
313 paths.hkpd = "hkpd.ldb"
314 paths.hkpt = "hkpt.ldb"
316 paths.sysvol = lp.get("path", "sysvol")
318 paths.netlogon = lp.get("path", "netlogon")
320 paths.smbconf = lp.configfile
325 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
326 serverrole=None, rootdn=None, domaindn=None, configdn=None,
327 schemadn=None, serverdn=None, sitename=None, sambadn=None):
328 """Guess configuration settings to use."""
331 hostname = socket.gethostname().split(".")[0]
333 netbiosname = lp.get("netbios name")
334 if netbiosname is None:
335 netbiosname = hostname
336 assert netbiosname is not None
337 netbiosname = netbiosname.upper()
338 if not valid_netbios_name(netbiosname):
339 raise InvalidNetbiosName(netbiosname)
341 if dnsdomain is None:
342 dnsdomain = lp.get("realm")
343 assert dnsdomain is not None
344 dnsdomain = dnsdomain.lower()
346 if serverrole is None:
347 serverrole = lp.get("server role")
348 assert serverrole is not None
349 serverrole = serverrole.lower()
351 realm = dnsdomain.upper()
353 if lp.get("realm").upper() != realm:
354 raise ProvisioningError("guess_names: Realm '%s' in smb.conf must match chosen realm '%s'!", lp.get("realm").upper(), realm)
356 if serverrole == "domain controller":
358 domain = lp.get("workgroup")
359 assert domain is not None
360 domain = domain.upper()
362 if lp.get("workgroup").upper() != domain:
363 raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!", lp.get("workgroup").upper(), domain)
366 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
370 domaindn = "DC=" + netbiosname
372 if not valid_netbios_name(domain):
373 raise InvalidNetbiosName(domain)
375 if hostname.upper() == realm:
376 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!", realm, hostname)
377 if netbiosname == realm:
378 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!", realm, netbiosname)
380 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!", realm, domain)
386 configdn = "CN=Configuration," + rootdn
388 schemadn = "CN=Schema," + configdn
395 names = ProvisionNames()
396 names.rootdn = rootdn
397 names.domaindn = domaindn
398 names.configdn = configdn
399 names.schemadn = schemadn
400 names.sambadn = sambadn
401 names.ldapmanagerdn = "CN=Manager," + rootdn
402 names.dnsdomain = dnsdomain
403 names.domain = domain
405 names.netbiosname = netbiosname
406 names.hostname = hostname
407 names.sitename = sitename
408 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
413 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
414 targetdir, sid_generator):
415 """Create a new smb.conf file based on a couple of basic settings.
417 assert smbconf is not None
419 hostname = socket.gethostname().split(".")[0]
420 netbiosname = hostname.upper()
422 if serverrole is None:
423 serverrole = "standalone"
425 assert serverrole in ("domain controller", "member server", "standalone")
426 if serverrole == "domain controller":
428 elif serverrole == "member server":
429 smbconfsuffix = "member"
430 elif serverrole == "standalone":
431 smbconfsuffix = "standalone"
433 if sid_generator is None:
434 sid_generator = "internal"
436 assert domain is not None
437 domain = domain.upper()
439 assert realm is not None
440 realm = realm.upper()
442 default_lp = param.LoadParm()
443 #Load non-existant file
444 if os.path.exists(smbconf):
445 default_lp.load(smbconf)
447 if targetdir is not None:
448 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
449 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
451 default_lp.set("lock dir", os.path.abspath(targetdir))
456 if sid_generator == "internal":
457 sid_generator_line = ""
459 sid_generator_line = "sid generator = " + sid_generator
461 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
462 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
464 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
466 "NETBIOS_NAME": netbiosname,
469 "SERVERROLE": serverrole,
470 "NETLOGONPATH": netlogon,
471 "SYSVOLPATH": sysvol,
472 "SIDGENERATOR_LINE": sid_generator_line,
473 "PRIVATEDIR_LINE": privatedir_line,
474 "LOCKDIR_LINE": lockdir_line
478 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
479 users_gid, wheel_gid):
480 """setup reasonable name mappings for sam names to unix names.
482 :param samdb: SamDB object.
483 :param idmap: IDmap db object.
484 :param sid: The domain sid.
485 :param domaindn: The domain DN.
486 :param root_uid: uid of the UNIX root user.
487 :param nobody_uid: uid of the UNIX nobody user.
488 :param users_gid: gid of the UNIX users group.
489 :param wheel_gid: gid of the UNIX wheel group."""
491 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
492 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
494 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
495 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
497 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
498 provision_backend, names, schema,
501 """Setup the partitions for the SAM database.
503 Alternatively, provision() may call this, and then populate the database.
505 :note: This will wipe the Sam Database!
507 :note: This function always removes the local SAM LDB file. The erase
508 parameter controls whether to erase the existing data, which
509 may not be stored locally but in LDAP.
512 assert session_info is not None
514 old_partitions = None
515 new_partitions = None
517 # We use options=["modules:"] to stop the modules loading - we
518 # just want to wipe and re-initialise the database, not start it up
521 samdb = Ldb(url=samdb_path, session_info=session_info,
522 lp=lp, options=["modules:"])
523 res = samdb.search(base="@PARTITION", scope=SCOPE_BASE, attrs=["partition"], expression="partition=*")
526 old_partitions = res[0]["partition"]
530 if old_partitions is not None:
532 for old_partition in old_partitions:
533 new_partition = old_partition
534 if old_partition.endswith(".ldb"):
535 p = old_partition.split(":")[0]
536 dn = ldb.Dn(schema.ldb, p)
537 new_partition = dn.get_casefold()
538 new_partitions.append(new_partition)
541 samdb.erase_except_schema_controlled()
543 os.unlink(samdb_path)
544 samdb = Ldb(url=samdb_path, session_info=session_info,
545 lp=lp, options=["modules:"])
547 samdb.erase_except_schema_controlled()
549 #Add modules to the list to activate them by default
550 #beware often order is important
552 # Some Known ordering constraints:
553 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
554 # - objectclass must be before password_hash, because password_hash checks
555 # that the objectclass is of type person (filled in by objectclass
556 # module when expanding the objectclass list)
557 # - partition must be last
558 # - each partition has its own module list then
559 modules_list = ["resolve_oids",
582 "extended_dn_out_ldb"]
583 modules_list2 = ["show_deleted",
588 ldap_backend_line = "# No LDAP backend"
589 if provision_backend.type is not "ldb":
590 ldap_backend_line = "ldapBackend: %s" % provision_backend.ldapi_uri
592 if provision_backend.ldap_backend_type == "fedora-ds":
593 backend_modules = ["nsuniqueid", "paged_searches"]
594 # We can handle linked attributes here, as we don't have directory-side subtree operations
595 tdb_modules_list = ["extended_dn_out_fds"]
596 elif ldap_backend.ldap_backend_type == "openldap":
597 backend_modules = ["entryuuid", "paged_searches"]
598 # OpenLDAP handles subtree renames, so we don't want to do any of these things
599 tdb_modules_list = ["extended_dn_out_openldap"]
601 elif serverrole == "domain controller":
602 tdb_modules_list.insert(0, "repl_meta_data")
605 backend_modules = ["objectguid"]
607 if tdb_modules_list is None:
608 tdb_modules_list_as_string = ""
610 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
612 samdb.transaction_start()
614 message("Setting up sam.ldb partitions and settings")
615 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
616 "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
617 "SCHEMADN_MOD2": ",objectguid",
618 "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
619 "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
620 "SCHEMADN_MOD": "schema_data",
621 "CONFIGDN_MOD": "naming_fsmo",
622 "DOMAINDN_MOD": "pdc_fsmo",
623 "MODULES_LIST": ",".join(modules_list),
624 "TDB_MODULES_LIST": tdb_modules_list_as_string,
625 "MODULES_LIST2": ",".join(modules_list2),
626 "BACKEND_MOD": ",".join(backend_modules),
627 "LDAP_BACKEND_LINE": ldap_backend_line,
631 if new_partitions is not None:
633 m.dn = ldb.Dn(samdb, "@PARTITION")
635 m["partition"] = ldb.MessageElement(new_partitions, ldb.FLAG_MOD_ADD, "partition")
638 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
640 message("Setting up sam.ldb rootDSE")
641 setup_samdb_rootdse(samdb, setup_path, names)
644 samdb.transaction_cancel()
647 samdb.transaction_commit()
650 def secretsdb_self_join(secretsdb, domain,
651 netbiosname, domainsid, machinepass,
652 realm=None, dnsdomain=None,
654 key_version_number=1,
655 secure_channel_type=SEC_CHAN_WKSTA):
656 """Add domain join-specific bits to a secrets database.
658 :param secretsdb: Ldb Handle to the secrets database
659 :param machinepass: Machine password
661 attrs=["whenChanged",
669 msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
670 msg["secureChannelType"] = str(secure_channel_type)
671 msg["flatname"] = [domain]
672 msg["objectClass"] = ["top", "primaryDomain"]
673 if realm is not None:
674 if dnsdomain is None:
675 dnsdomain = realm.lower()
676 msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
678 msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
679 msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
680 msg["privateKeytab"] = ["secrets.keytab"];
683 msg["secret"] = [machinepass]
684 msg["samAccountName"] = ["%s$" % netbiosname]
685 msg["secureChannelType"] = [str(secure_channel_type)]
686 msg["objectSid"] = [ndr_pack(domainsid)]
688 res = secretsdb.search(base="cn=Primary Domains",
690 expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
691 scope=SCOPE_ONELEVEL)
694 if del_msg.dn is not msg.dn:
695 secretsdb.delete(del_msg.dn)
697 res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
700 msg["priorSecret"] = res[0]["secret"]
701 msg["priorWhenChanged"] = res[0]["whenChanged"]
703 if res["privateKeytab"] is not None:
704 msg["privateKeytab"] = res[0]["privateKeytab"]
706 if res["krb5Keytab"] is not None:
707 msg["krb5Keytab"] = res[0]["krb5Keytab"]
710 el.set_flags(ldb.FLAG_MOD_REPLACE)
711 secretsdb.modify(msg)
716 def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
717 dns_keytab_path, dnspass):
718 """Add DNS specific bits to a secrets database.
720 :param secretsdb: Ldb Handle to the secrets database
721 :param setup_path: Setup path function
722 :param machinepass: Machine password
724 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
726 "DNSDOMAIN": dnsdomain,
727 "DNS_KEYTAB": dns_keytab_path,
728 "DNSPASS_B64": b64encode(dnspass),
732 def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
733 """Setup the secrets database.
735 :param path: Path to the secrets database.
736 :param setup_path: Get the path to a setup file.
737 :param session_info: Session info.
738 :param credentials: Credentials
739 :param lp: Loadparm context
740 :return: LDB handle for the created secrets database
742 if os.path.exists(path):
744 secrets_ldb = Ldb(path, session_info=session_info,
747 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
748 secrets_ldb = Ldb(path, session_info=session_info,
750 secrets_ldb.transaction_start()
751 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
753 if backend_credentials is not None and backend_credentials.authentication_requested():
754 if backend_credentials.get_bind_dn() is not None:
755 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
756 "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
757 "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
760 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
761 "LDAPADMINUSER": backend_credentials.get_username(),
762 "LDAPADMINREALM": backend_credentials.get_realm(),
763 "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
768 def setup_privileges(path, setup_path, session_info, lp):
769 """Setup the privileges database.
771 :param path: Path to the privileges database.
772 :param setup_path: Get the path to a setup file.
773 :param session_info: Session info.
774 :param credentials: Credentials
775 :param lp: Loadparm context
776 :return: LDB handle for the created secrets database
778 if os.path.exists(path):
780 privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
781 privilege_ldb.erase()
782 privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
785 def setup_registry(path, setup_path, session_info, lp):
786 """Setup the registry.
788 :param path: Path to the registry database
789 :param setup_path: Function that returns the path to a setup.
790 :param session_info: Session information
791 :param credentials: Credentials
792 :param lp: Loadparm context
794 reg = registry.Registry()
795 hive = registry.open_ldb(path, session_info=session_info,
797 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
798 provision_reg = setup_path("provision.reg")
799 assert os.path.exists(provision_reg)
800 reg.diff_apply(provision_reg)
803 def setup_idmapdb(path, setup_path, session_info, lp):
804 """Setup the idmap database.
806 :param path: path to the idmap database
807 :param setup_path: Function that returns a path to a setup file
808 :param session_info: Session information
809 :param credentials: Credentials
810 :param lp: Loadparm context
812 if os.path.exists(path):
815 idmap_ldb = IDmapDB(path, session_info=session_info,
819 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
823 def setup_samdb_rootdse(samdb, setup_path, names):
824 """Setup the SamDB rootdse.
826 :param samdb: Sam Database handle
827 :param setup_path: Obtain setup path
829 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
830 "SCHEMADN": names.schemadn,
831 "NETBIOSNAME": names.netbiosname,
832 "DNSDOMAIN": names.dnsdomain,
833 "REALM": names.realm,
834 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
835 "DOMAINDN": names.domaindn,
836 "ROOTDN": names.rootdn,
837 "CONFIGDN": names.configdn,
838 "SERVERDN": names.serverdn,
842 def setup_self_join(samdb, names,
843 machinepass, dnspass,
844 domainsid, invocationid, setup_path,
845 policyguid, policyguid_dc, domainControllerFunctionality,
847 """Join a host to its own domain."""
848 assert isinstance(invocationid, str)
849 if ntdsguid is not None:
850 ntdsguid_line = "objectGUID: %s\n"%ntdsguid
853 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
854 "CONFIGDN": names.configdn,
855 "SCHEMADN": names.schemadn,
856 "DOMAINDN": names.domaindn,
857 "SERVERDN": names.serverdn,
858 "INVOCATIONID": invocationid,
859 "NETBIOSNAME": names.netbiosname,
860 "DEFAULTSITE": names.sitename,
861 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
862 "MACHINEPASS_B64": b64encode(machinepass),
863 "DNSPASS_B64": b64encode(dnspass),
864 "REALM": names.realm,
865 "DOMAIN": names.domain,
866 "DNSDOMAIN": names.dnsdomain,
867 "SAMBA_VERSION_STRING": version,
868 "NTDSGUID": ntdsguid_line,
869 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
871 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
872 "POLICYGUID": policyguid,
873 "POLICYGUID_DC": policyguid_dc,
874 "DNSDOMAIN": names.dnsdomain,
875 "DOMAINSID": str(domainsid),
876 "DOMAINDN": names.domaindn})
878 # add the NTDSGUID based SPNs
879 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
880 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
881 expression="", scope=SCOPE_BASE)
882 assert isinstance(names.ntdsguid, str)
884 # Setup fSMORoleOwner entries to point at the newly created DC entry
885 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
886 "DOMAIN": names.domain,
887 "DNSDOMAIN": names.dnsdomain,
888 "DOMAINDN": names.domaindn,
889 "CONFIGDN": names.configdn,
890 "SCHEMADN": names.schemadn,
891 "DEFAULTSITE": names.sitename,
892 "SERVERDN": names.serverdn,
893 "NETBIOSNAME": names.netbiosname,
894 "NTDSGUID": names.ntdsguid
898 def setup_samdb(path, setup_path, session_info, provision_backend, lp,
900 domainsid, domainguid, policyguid, policyguid_dc,
901 fill, adminpass, krbtgtpass,
902 machinepass, invocationid, dnspass, ntdsguid,
903 serverrole, dom_for_fun_level=None,
905 """Setup a complete SAM Database.
907 :note: This will wipe the main SAM database file!
910 # ATTENTION: Do NOT change these default values without discussion with the
911 # team and/or release manager. They have a big impact on the whole program!
912 domainControllerFunctionality = DS_DC_FUNCTION_2008
914 if dom_for_fun_level is None:
915 dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
916 if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003:
917 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!")
919 if dom_for_fun_level > domainControllerFunctionality:
920 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008). This won't work!")
922 domainFunctionality = dom_for_fun_level
923 forestFunctionality = dom_for_fun_level
925 # Also wipes the database
926 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
927 provision_backend=provision_backend, session_info=session_info,
929 serverrole=serverrole, schema=schema)
932 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
933 sambadn=names.sambadn)
935 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
936 samdb = Ldb(session_info=session_info,
937 credentials=provision_backend.credentials, lp=lp)
939 message("Pre-loading the Samba 4 and AD schema")
941 # Load the schema from the one we computed earlier
942 samdb.set_schema_from_ldb(schema.ldb)
944 # And now we can connect to the DB - the schema won't be loaded from the DB
950 samdb.transaction_start()
952 message("Erasing data from partitions")
953 # Load the schema (again). This time it will force a reindex,
954 # and will therefore make the erase_partitions() below
955 # computationally sane
956 samdb.set_schema_from_ldb(schema.ldb)
957 samdb.erase_partitions()
959 # Set the domain functionality levels onto the database.
960 # Various module (the password_hash module in particular) need
961 # to know what level of AD we are emulating.
963 # These will be fixed into the database via the database
964 # modifictions below, but we need them set from the start.
965 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
966 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
967 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
969 samdb.set_domain_sid(str(domainsid))
970 if serverrole == "domain controller":
971 samdb.set_invocation_id(invocationid)
973 message("Adding DomainDN: %s" % names.domaindn)
975 #impersonate domain admin
976 admin_session_info = admin_session(lp, str(domainsid))
977 samdb.set_session_info(admin_session_info)
978 if domainguid is not None:
979 domainguid_line = "objectGUID: %s\n-" % domainguid
982 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
983 "DOMAINDN": names.domaindn,
984 "DOMAINGUID": domainguid_line
988 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
989 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
990 "DOMAINSID": str(domainsid),
991 "SCHEMADN": names.schemadn,
992 "NETBIOSNAME": names.netbiosname,
993 "DEFAULTSITE": names.sitename,
994 "CONFIGDN": names.configdn,
995 "SERVERDN": names.serverdn,
996 "POLICYGUID": policyguid,
997 "DOMAINDN": names.domaindn,
998 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
999 "SAMBA_VERSION_STRING": version
1002 message("Adding configuration container")
1003 descr = get_config_descriptor(domainsid);
1004 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
1005 "CONFIGDN": names.configdn,
1006 "DESCRIPTOR": descr,
1008 message("Modifying configuration container")
1009 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
1010 "CONFIGDN": names.configdn,
1011 "SCHEMADN": names.schemadn,
1014 # The LDIF here was created when the Schema object was constructed
1015 message("Setting up sam.ldb schema")
1016 samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
1017 samdb.modify_ldif(schema.schema_dn_modify)
1018 samdb.write_prefixes_from_schema()
1019 samdb.add_ldif(schema.schema_data, controls=["relax:0"])
1020 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
1021 {"SCHEMADN": names.schemadn})
1023 message("Setting up sam.ldb configuration data")
1024 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
1025 "CONFIGDN": names.configdn,
1026 "NETBIOSNAME": names.netbiosname,
1027 "DEFAULTSITE": names.sitename,
1028 "DNSDOMAIN": names.dnsdomain,
1029 "DOMAIN": names.domain,
1030 "SCHEMADN": names.schemadn,
1031 "DOMAINDN": names.domaindn,
1032 "SERVERDN": names.serverdn,
1033 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
1036 message("Setting up display specifiers")
1037 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1038 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
1039 check_all_substituted(display_specifiers_ldif)
1040 samdb.add_ldif(display_specifiers_ldif)
1042 message("Adding users container")
1043 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1044 "DOMAINDN": names.domaindn})
1045 message("Modifying users container")
1046 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1047 "DOMAINDN": names.domaindn})
1048 message("Adding computers container")
1049 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1050 "DOMAINDN": names.domaindn})
1051 message("Modifying computers container")
1052 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
1053 "DOMAINDN": names.domaindn})
1054 message("Setting up sam.ldb data")
1055 setup_add_ldif(samdb, setup_path("provision.ldif"), {
1056 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
1057 "DOMAINDN": names.domaindn,
1058 "NETBIOSNAME": names.netbiosname,
1059 "DEFAULTSITE": names.sitename,
1060 "CONFIGDN": names.configdn,
1061 "SERVERDN": names.serverdn,
1062 "POLICYGUID_DC": policyguid_dc
1065 if fill == FILL_FULL:
1066 message("Setting up sam.ldb users and groups")
1067 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1068 "DOMAINDN": names.domaindn,
1069 "DOMAINSID": str(domainsid),
1070 "CONFIGDN": names.configdn,
1071 "ADMINPASS_B64": b64encode(adminpass),
1072 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1075 if serverrole == "domain controller":
1076 message("Setting up self join")
1077 setup_self_join(samdb, names=names, invocationid=invocationid,
1079 machinepass=machinepass,
1080 domainsid=domainsid, policyguid=policyguid,
1081 policyguid_dc=policyguid_dc,
1082 setup_path=setup_path,
1083 domainControllerFunctionality=domainControllerFunctionality,
1086 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
1087 names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1088 attribute="objectGUID", expression="", scope=SCOPE_BASE)
1089 assert isinstance(names.ntdsguid, str)
1092 samdb.transaction_cancel()
1095 samdb.transaction_commit()
1100 FILL_NT4SYNC = "NT4SYNC"
1104 def provision(setup_dir, message, session_info,
1105 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
1107 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1109 domain=None, hostname=None, hostip=None, hostip6=None,
1110 domainsid=None, adminpass=None, ldapadminpass=None,
1111 krbtgtpass=None, domainguid=None,
1112 policyguid=None, policyguid_dc=None, invocationid=None,
1113 machinepass=None, ntdsguid=None,
1114 dnspass=None, root=None, nobody=None, users=None,
1115 wheel=None, backup=None, aci=None, serverrole=None,
1116 dom_for_fun_level=None,
1117 ldap_backend_extra_port=None, backend_type=None,
1119 ol_mmr_urls=None, ol_olc=None,
1120 setup_ds_path=None, slapd_path=None, nosync=False,
1121 ldap_dryrun_mode=False):
1124 :note: caution, this wipes all existing data!
1127 def setup_path(file):
1128 return os.path.join(setup_dir, file)
1130 if domainsid is None:
1131 domainsid = security.random_sid()
1133 domainsid = security.dom_sid(domainsid)
1135 # create/adapt the group policy GUIDs
1136 if policyguid is None:
1137 policyguid = str(uuid.uuid4())
1138 policyguid = policyguid.upper()
1139 if policyguid_dc is None:
1140 policyguid_dc = str(uuid.uuid4())
1141 policyguid_dc = policyguid_dc.upper()
1143 if adminpass is None:
1144 adminpass = glue.generate_random_str(12)
1145 if krbtgtpass is None:
1146 krbtgtpass = glue.generate_random_str(12)
1147 if machinepass is None:
1148 machinepass = glue.generate_random_str(12)
1150 dnspass = glue.generate_random_str(12)
1151 if ldapadminpass is None:
1152 #Make a new, random password between Samba and it's LDAP server
1153 ldapadminpass=glue.generate_random_str(12)
1155 if backend_type is None:
1156 backend_type = "ldb"
1158 sid_generator = "internal"
1159 if backend_type == "fedora-ds":
1160 sid_generator = "backend"
1162 root_uid = findnss_uid([root or "root"])
1163 nobody_uid = findnss_uid([nobody or "nobody"])
1164 users_gid = findnss_gid([users or "users"])
1166 wheel_gid = findnss_gid(["wheel", "adm"])
1168 wheel_gid = findnss_gid([wheel])
1170 if targetdir is not None:
1171 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1172 os.makedirs(os.path.join(targetdir, "etc"))
1173 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1174 elif smbconf is None:
1175 smbconf = param.default_path()
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,
1180 targetdir, sid_generator)
1182 lp = param.LoadParm()
1185 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1186 dnsdomain=realm, serverrole=serverrole,
1187 domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1188 serverdn=serverdn, sitename=sitename)
1190 paths = provision_paths_from_lp(lp, names.dnsdomain)
1194 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1195 except socket.gaierror, (socket.EAI_NODATA, msg):
1200 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1201 except socket.gaierror, (socket.EAI_NODATA, msg):
1204 if serverrole is None:
1205 serverrole = lp.get("server role")
1207 assert serverrole in ("domain controller", "member server", "standalone")
1208 if invocationid is None and serverrole == "domain controller":
1209 invocationid = str(uuid.uuid4())
1211 if not os.path.exists(paths.private_dir):
1212 os.mkdir(paths.private_dir)
1214 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1216 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
1217 sambadn=names.sambadn)
1219 provision_backend = ProvisionBackend(backend_type,
1220 paths=paths, setup_path=setup_path,
1221 lp=lp, credentials=credentials,
1223 message=message, hostname=hostname,
1224 root=root, schema=schema,
1225 ldapadminpass=ldapadminpass,
1226 ldap_backend_extra_port=ldap_backend_extra_port,
1227 ol_mmr_urls=ol_mmr_urls,
1228 slapd_path=slapd_path,
1229 setup_ds_path=setup_ds_path,
1230 ldap_dryrun_mode=ldap_dryrun_mode,
1231 domainsid=domainsid)
1233 # only install a new shares config db if there is none
1234 if not os.path.exists(paths.shareconf):
1235 message("Setting up share.ldb")
1236 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1238 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1241 message("Setting up secrets.ldb")
1242 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1243 session_info=session_info,
1244 backend_credentials=provision_backend.secrets_credentials, lp=lp)
1246 message("Setting up the registry")
1247 setup_registry(paths.hklm, setup_path, session_info,
1250 message("Setting up the privileges database")
1251 setup_privileges(paths.privilege, setup_path, session_info, lp=lp)
1253 message("Setting up idmap db")
1254 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1257 message("Setting up SAM db")
1258 samdb = setup_samdb(paths.samdb, setup_path, session_info,
1259 provision_backend, lp, names,
1261 domainsid=domainsid,
1262 schema=schema, domainguid=domainguid,
1263 policyguid=policyguid, policyguid_dc=policyguid_dc,
1265 adminpass=adminpass, krbtgtpass=krbtgtpass,
1266 invocationid=invocationid,
1267 machinepass=machinepass, dnspass=dnspass,
1268 ntdsguid=ntdsguid, serverrole=serverrole,
1269 dom_for_fun_level=dom_for_fun_level)
1271 if serverrole == "domain controller":
1272 if paths.netlogon is None:
1273 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1274 message("Please either remove %s or see the template at %s" %
1275 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1276 assert(paths.netlogon is not None)
1278 if paths.sysvol is None:
1279 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1280 message("Please either remove %s or see the template at %s" %
1281 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1282 assert(paths.sysvol is not None)
1284 # Set up group policies (domain policy and domain controller policy)
1286 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1287 "{" + policyguid + "}")
1288 os.makedirs(policy_path, 0755)
1289 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1290 "[General]\r\nVersion=65543")
1291 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
1292 os.makedirs(os.path.join(policy_path, "USER"), 0755)
1294 policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1295 "{" + policyguid_dc + "}")
1296 os.makedirs(policy_path_dc, 0755)
1297 open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
1298 "[General]\r\nVersion=2")
1299 os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
1300 os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
1302 if not os.path.isdir(paths.netlogon):
1303 os.makedirs(paths.netlogon, 0755)
1305 if samdb_fill == FILL_FULL:
1306 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1307 root_uid=root_uid, nobody_uid=nobody_uid,
1308 users_gid=users_gid, wheel_gid=wheel_gid)
1310 message("Setting up sam.ldb rootDSE marking as synchronized")
1311 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1313 # Only make a zone file on the first DC, it should be replicated with DNS replication
1314 if serverrole == "domain controller":
1315 secretsdb_self_join(secrets_ldb, domain=domain,
1317 dnsdomain=names.dnsdomain,
1318 netbiosname=names.netbiosname,
1319 domainsid=domainsid,
1320 machinepass=machinepass,
1321 secure_channel_type=SEC_CHAN_BDC)
1323 secretsdb_setup_dns(secrets_ldb, setup_path,
1324 realm=names.realm, dnsdomain=names.dnsdomain,
1325 dns_keytab_path=paths.dns_keytab,
1328 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1329 assert isinstance(domainguid, str)
1331 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1333 hostip6=hostip6, hostname=names.hostname,
1335 domainguid=domainguid, ntdsguid=names.ntdsguid)
1337 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1338 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1340 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1341 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1342 keytab_name=paths.dns_keytab)
1343 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1344 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1346 create_krb5_conf(paths.krb5conf, setup_path,
1347 dnsdomain=names.dnsdomain, hostname=names.hostname,
1349 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1351 if provision_backend.post_setup is not None:
1352 provision_backend.post_setup()
1354 if provision_backend.shutdown is not None:
1355 provision_backend.shutdown()
1357 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1360 #Now commit the secrets.ldb to disk
1361 secrets_ldb.transaction_commit()
1363 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1365 message("Once the above files are installed, your Samba4 server will be ready to use")
1366 message("Server Role: %s" % serverrole)
1367 message("Hostname: %s" % names.hostname)
1368 message("NetBIOS Domain: %s" % names.domain)
1369 message("DNS Domain: %s" % names.dnsdomain)
1370 message("DOMAIN SID: %s" % str(domainsid))
1371 if samdb_fill == FILL_FULL:
1372 message("Admin password: %s" % adminpass)
1373 if provision_backend.type is not "ldb":
1374 if provision_backend.credentials.get_bind_dn() is not None:
1375 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1377 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1379 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1381 if provision_backend.slapd_command_escaped is not None:
1382 # now display slapd_command_file.txt to show how slapd must be started next time
1383 message("Use later the following commandline to start slapd, then Samba:")
1384 message(provision_backend.slapd_command_escaped)
1385 message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
1388 result = ProvisionResult()
1389 result.domaindn = domaindn
1390 result.paths = paths
1392 result.samdb = samdb
1397 def provision_become_dc(setup_dir=None,
1398 smbconf=None, targetdir=None, realm=None,
1399 rootdn=None, domaindn=None, schemadn=None,
1400 configdn=None, serverdn=None,
1401 domain=None, hostname=None, domainsid=None,
1402 adminpass=None, krbtgtpass=None, domainguid=None,
1403 policyguid=None, policyguid_dc=None, invocationid=None,
1405 dnspass=None, root=None, nobody=None, users=None,
1406 wheel=None, backup=None, serverrole=None,
1407 ldap_backend=None, ldap_backend_type=None,
1408 sitename=None, debuglevel=1):
1411 """print a message if quiet is not set."""
1414 glue.set_debug_level(debuglevel)
1416 return provision(setup_dir, message, system_session(), None,
1417 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1418 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1419 configdn=configdn, serverdn=serverdn, domain=domain,
1420 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1421 machinepass=machinepass, serverrole="domain controller",
1425 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1426 """Create a PHP LDAP admin configuration file.
1428 :param path: Path to write the configuration to.
1429 :param setup_path: Function to generate setup paths.
1431 setup_file(setup_path("phpldapadmin-config.php"), path,
1432 {"S4_LDAPI_URI": ldapi_uri})
1435 def create_zone_file(path, setup_path, dnsdomain,
1436 hostip, hostip6, hostname, realm, domainguid,
1438 """Write out a DNS zone file, from the info in the current database.
1440 :param path: Path of the new zone file.
1441 :param setup_path: Setup path function.
1442 :param dnsdomain: DNS Domain name
1443 :param domaindn: DN of the Domain
1444 :param hostip: Local IPv4 IP
1445 :param hostip6: Local IPv6 IP
1446 :param hostname: Local hostname
1447 :param realm: Realm name
1448 :param domainguid: GUID of the domain.
1449 :param ntdsguid: GUID of the hosts nTDSDSA record.
1451 assert isinstance(domainguid, str)
1453 if hostip6 is not None:
1454 hostip6_base_line = " IN AAAA " + hostip6
1455 hostip6_host_line = hostname + " IN AAAA " + hostip6
1457 hostip6_base_line = ""
1458 hostip6_host_line = ""
1460 if hostip is not None:
1461 hostip_base_line = " IN A " + hostip
1462 hostip_host_line = hostname + " IN A " + hostip
1464 hostip_base_line = ""
1465 hostip_host_line = ""
1467 setup_file(setup_path("provision.zone"), path, {
1468 "HOSTNAME": hostname,
1469 "DNSDOMAIN": dnsdomain,
1471 "HOSTIP_BASE_LINE": hostip_base_line,
1472 "HOSTIP_HOST_LINE": hostip_host_line,
1473 "DOMAINGUID": domainguid,
1474 "DATESTRING": time.strftime("%Y%m%d%H"),
1475 "DEFAULTSITE": DEFAULTSITE,
1476 "NTDSGUID": ntdsguid,
1477 "HOSTIP6_BASE_LINE": hostip6_base_line,
1478 "HOSTIP6_HOST_LINE": hostip6_host_line,
1482 def create_named_conf(path, setup_path, realm, dnsdomain,
1484 """Write out a file containing zone statements suitable for inclusion in a
1485 named.conf file (including GSS-TSIG configuration).
1487 :param path: Path of the new named.conf file.
1488 :param setup_path: Setup path function.
1489 :param realm: Realm name
1490 :param dnsdomain: DNS Domain name
1491 :param private_dir: Path to private directory
1492 :param keytab_name: File name of DNS keytab file
1495 setup_file(setup_path("named.conf"), path, {
1496 "DNSDOMAIN": dnsdomain,
1498 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1499 "PRIVATE_DIR": private_dir
1502 def create_named_txt(path, setup_path, realm, dnsdomain,
1503 private_dir, keytab_name):
1504 """Write out a file containing zone statements suitable for inclusion in a
1505 named.conf file (including GSS-TSIG configuration).
1507 :param path: Path of the new named.conf file.
1508 :param setup_path: Setup path function.
1509 :param realm: Realm name
1510 :param dnsdomain: DNS Domain name
1511 :param private_dir: Path to private directory
1512 :param keytab_name: File name of DNS keytab file
1515 setup_file(setup_path("named.txt"), path, {
1516 "DNSDOMAIN": dnsdomain,
1518 "DNS_KEYTAB": keytab_name,
1519 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1520 "PRIVATE_DIR": private_dir
1523 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1524 """Write out a file containing zone statements suitable for inclusion in a
1525 named.conf file (including GSS-TSIG configuration).
1527 :param path: Path of the new named.conf file.
1528 :param setup_path: Setup path function.
1529 :param dnsdomain: DNS Domain name
1530 :param hostname: Local hostname
1531 :param realm: Realm name
1534 setup_file(setup_path("krb5.conf"), path, {
1535 "DNSDOMAIN": dnsdomain,
1536 "HOSTNAME": hostname,