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
43 from auth import system_session, admin_session
44 from samba import version, Ldb, substitute_var, valid_netbios_name, setup_file
45 from samba import check_all_substituted, read_and_sub_file
46 from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008
47 from samba.samdb import SamDB
48 from samba.idmap import IDmapDB
49 from samba.dcerpc import security
50 from samba.ndr import ndr_pack
52 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
53 from ms_display_specifiers import read_ms_ldif
54 from schema import Schema
55 from provisionbackend import ProvisionBackend
56 from signal import SIGTERM
57 from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
59 __docformat__ = "restructuredText"
62 """Find the setup directory used by provision."""
63 dirname = os.path.dirname(__file__)
64 if "/site-packages/" in dirname:
65 prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
66 for suffix in ["share/setup", "share/samba/setup", "setup"]:
67 ret = os.path.join(prefix, suffix)
68 if os.path.isdir(ret):
71 ret = os.path.join(dirname, "../../../setup")
72 if os.path.isdir(ret):
74 raise Exception("Unable to find setup directory.")
76 def get_config_descriptor(domain_sid):
77 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
78 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
79 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
80 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
81 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
82 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
83 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
84 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
85 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
86 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
87 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
88 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
89 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
90 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
91 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
92 sec = security.descriptor.from_sddl(sddl, domain_sid)
93 return b64encode(ndr_pack(sec))
96 DEFAULTSITE = "Default-First-Site-Name"
100 class ProvisioningError(Exception):
101 """A generic provision error."""
103 class InvalidNetbiosName(Exception):
104 """A specified name was not a valid NetBIOS name."""
105 def __init__(self, name):
106 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
109 class ProvisionPaths(object):
111 self.shareconf = None
122 self.dns_keytab = None
125 self.private_dir = None
127 self.slapdconf = None
128 self.modulesconf = None
129 self.memberofconf = None
130 self.fedoradsinf = None
131 self.fedoradspartitions = None
132 self.fedoradssasl = None
133 self.fedoradsdna = None
134 self.fedoradspam = None
135 self.fedoradsrefint = None
136 self.fedoradslinkedattributes = None
137 self.fedoradsindex = None
138 self.fedoradssamba = None
140 self.olmmrserveridsconf = None
141 self.olmmrsyncreplconf = None
144 self.olcseedldif = None
147 class ProvisionNames(object):
154 self.ldapmanagerdn = None
155 self.dnsdomain = None
157 self.netbiosname = None
164 class ProvisionResult(object):
171 def check_install(lp, session_info, credentials):
172 """Check whether the current install seems ok.
174 :param lp: Loadparm context
175 :param session_info: Session information
176 :param credentials: Credentials
178 if lp.get("realm") == "":
179 raise Exception("Realm empty")
180 ldb = Ldb(lp.get("sam database"), session_info=session_info,
181 credentials=credentials, lp=lp)
182 if len(ldb.search("(cn=Administrator)")) != 1:
183 raise ProvisioningError("No administrator account found")
186 def findnss(nssfn, names):
187 """Find a user or group from a list of possibilities.
189 :param nssfn: NSS Function to try (should raise KeyError if not found)
190 :param names: Names to check.
191 :return: Value return by first names list.
198 raise KeyError("Unable to find user/group %r" % names)
201 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
202 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
205 def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
206 """Setup a ldb in the private dir.
208 :param ldb: LDB file to import data into
209 :param ldif_path: Path of the LDIF file to load
210 :param subst_vars: Optional variables to subsitute in LDIF.
211 :param nocontrols: Optional list of controls, can be None for no controls
213 assert isinstance(ldif_path, str)
214 data = read_and_sub_file(ldif_path, subst_vars)
215 ldb.add_ldif(data,controls)
218 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
219 """Modify a ldb in the private dir.
221 :param ldb: LDB object.
222 :param ldif_path: LDIF file path.
223 :param subst_vars: Optional dictionary with substitution variables.
225 data = read_and_sub_file(ldif_path, subst_vars)
227 ldb.modify_ldif(data)
230 def setup_ldb(ldb, ldif_path, subst_vars):
231 """Import a LDIF a file into a LDB handle, optionally substituting variables.
233 :note: Either all LDIF data will be added or none (using transactions).
235 :param ldb: LDB file to import into.
236 :param ldif_path: Path to the LDIF file.
237 :param subst_vars: Dictionary with substitution variables.
239 assert ldb is not None
240 ldb.transaction_start()
242 setup_add_ldif(ldb, ldif_path, subst_vars)
244 ldb.transaction_cancel()
246 ldb.transaction_commit()
249 def provision_paths_from_lp(lp, dnsdomain):
250 """Set the default paths for provisioning.
252 :param lp: Loadparm context.
253 :param dnsdomain: DNS Domain name
255 paths = ProvisionPaths()
256 paths.private_dir = lp.get("private dir")
257 paths.dns_keytab = "dns.keytab"
259 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
260 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
261 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
262 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
263 paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
264 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
265 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
266 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
267 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
268 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
269 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
270 paths.phpldapadminconfig = os.path.join(paths.private_dir,
271 "phpldapadmin-config.php")
272 paths.ldapdir = os.path.join(paths.private_dir,
274 paths.slapdconf = os.path.join(paths.ldapdir,
276 paths.slapdpid = os.path.join(paths.ldapdir,
278 paths.modulesconf = os.path.join(paths.ldapdir,
280 paths.memberofconf = os.path.join(paths.ldapdir,
282 paths.fedoradsinf = os.path.join(paths.ldapdir,
284 paths.fedoradspartitions = os.path.join(paths.ldapdir,
285 "fedorads-partitions.ldif")
286 paths.fedoradssasl = os.path.join(paths.ldapdir,
287 "fedorads-sasl.ldif")
288 paths.fedoradsdna = os.path.join(paths.ldapdir,
290 paths.fedoradspam = os.path.join(paths.ldapdir,
292 paths.fedoradsrefint = os.path.join(paths.ldapdir,
293 "fedorads-refint.ldif")
294 paths.fedoradslinkedattributes = os.path.join(paths.ldapdir,
295 "fedorads-linked-attributes.ldif")
296 paths.fedoradsindex = os.path.join(paths.ldapdir,
297 "fedorads-index.ldif")
298 paths.fedoradssamba = os.path.join(paths.ldapdir,
299 "fedorads-samba.ldif")
300 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
301 "mmr_serverids.conf")
302 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
304 paths.olcdir = os.path.join(paths.ldapdir,
306 paths.olcseedldif = os.path.join(paths.ldapdir,
308 paths.hklm = "hklm.ldb"
309 paths.hkcr = "hkcr.ldb"
310 paths.hkcu = "hkcu.ldb"
311 paths.hku = "hku.ldb"
312 paths.hkpd = "hkpd.ldb"
313 paths.hkpt = "hkpt.ldb"
315 paths.sysvol = lp.get("path", "sysvol")
317 paths.netlogon = lp.get("path", "netlogon")
319 paths.smbconf = lp.configfile
324 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
325 serverrole=None, rootdn=None, domaindn=None, configdn=None,
326 schemadn=None, serverdn=None, sitename=None, sambadn=None):
327 """Guess configuration settings to use."""
330 hostname = socket.gethostname().split(".")[0]
332 netbiosname = lp.get("netbios name")
333 if netbiosname is None:
334 netbiosname = hostname
335 assert netbiosname is not None
336 netbiosname = netbiosname.upper()
337 if not valid_netbios_name(netbiosname):
338 raise InvalidNetbiosName(netbiosname)
340 if dnsdomain is None:
341 dnsdomain = lp.get("realm")
342 assert dnsdomain is not None
343 dnsdomain = dnsdomain.lower()
345 if serverrole is None:
346 serverrole = lp.get("server role")
347 assert serverrole is not None
348 serverrole = serverrole.lower()
350 realm = dnsdomain.upper()
352 if lp.get("realm").upper() != realm:
353 raise ProvisioningError("guess_names: Realm '%s' in smb.conf must match chosen realm '%s'!", lp.get("realm").upper(), realm)
355 if serverrole == "domain controller":
357 domain = lp.get("workgroup")
358 assert domain is not None
359 domain = domain.upper()
361 if lp.get("workgroup").upper() != domain:
362 raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!", lp.get("workgroup").upper(), domain)
365 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
369 domaindn = "DC=" + netbiosname
371 if not valid_netbios_name(domain):
372 raise InvalidNetbiosName(domain)
374 if hostname.upper() == realm:
375 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!", realm, hostname)
376 if netbiosname == realm:
377 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!", realm, netbiosname)
379 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!", realm, domain)
385 configdn = "CN=Configuration," + rootdn
387 schemadn = "CN=Schema," + configdn
394 names = ProvisionNames()
395 names.rootdn = rootdn
396 names.domaindn = domaindn
397 names.configdn = configdn
398 names.schemadn = schemadn
399 names.sambadn = sambadn
400 names.ldapmanagerdn = "CN=Manager," + rootdn
401 names.dnsdomain = dnsdomain
402 names.domain = domain
404 names.netbiosname = netbiosname
405 names.hostname = hostname
406 names.sitename = sitename
407 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
412 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
413 targetdir, sid_generator):
414 """Create a new smb.conf file based on a couple of basic settings.
416 assert smbconf is not None
418 hostname = socket.gethostname().split(".")[0]
419 netbiosname = hostname.upper()
421 if serverrole is None:
422 serverrole = "standalone"
424 assert serverrole in ("domain controller", "member server", "standalone")
425 if serverrole == "domain controller":
427 elif serverrole == "member server":
428 smbconfsuffix = "member"
429 elif serverrole == "standalone":
430 smbconfsuffix = "standalone"
432 if sid_generator is None:
433 sid_generator = "internal"
435 assert domain is not None
436 domain = domain.upper()
438 assert realm is not None
439 realm = realm.upper()
441 default_lp = param.LoadParm()
442 #Load non-existant file
443 if os.path.exists(smbconf):
444 default_lp.load(smbconf)
446 if targetdir is not None:
447 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
448 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
450 default_lp.set("lock dir", os.path.abspath(targetdir))
455 if sid_generator == "internal":
456 sid_generator_line = ""
458 sid_generator_line = "sid generator = " + sid_generator
460 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
461 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
463 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
465 "NETBIOS_NAME": netbiosname,
468 "SERVERROLE": serverrole,
469 "NETLOGONPATH": netlogon,
470 "SYSVOLPATH": sysvol,
471 "SIDGENERATOR_LINE": sid_generator_line,
472 "PRIVATEDIR_LINE": privatedir_line,
473 "LOCKDIR_LINE": lockdir_line
477 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
478 users_gid, wheel_gid):
479 """setup reasonable name mappings for sam names to unix names.
481 :param samdb: SamDB object.
482 :param idmap: IDmap db object.
483 :param sid: The domain sid.
484 :param domaindn: The domain DN.
485 :param root_uid: uid of the UNIX root user.
486 :param nobody_uid: uid of the UNIX nobody user.
487 :param users_gid: gid of the UNIX users group.
488 :param wheel_gid: gid of the UNIX wheel group."""
490 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
491 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
493 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
494 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
496 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
497 provision_backend, names, schema,
500 """Setup the partitions for the SAM database.
502 Alternatively, provision() may call this, and then populate the database.
504 :note: This will wipe the Sam Database!
506 :note: This function always removes the local SAM LDB file. The erase
507 parameter controls whether to erase the existing data, which
508 may not be stored locally but in LDAP.
511 assert session_info is not None
513 old_partitions = None
514 new_partitions = None
516 # We use options=["modules:"] to stop the modules loading - we
517 # just want to wipe and re-initialise the database, not start it up
520 os.unlink(samdb_path)
524 samdb = Ldb(url=samdb_path, session_info=session_info,
525 lp=lp, options=["modules:"])
527 #Add modules to the list to activate them by default
528 #beware often order is important
530 # Some Known ordering constraints:
531 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
532 # - objectclass must be before password_hash, because password_hash checks
533 # that the objectclass is of type person (filled in by objectclass
534 # module when expanding the objectclass list)
535 # - partition must be last
536 # - each partition has its own module list then
537 modules_list = ["resolve_oids",
560 "extended_dn_out_ldb"]
561 modules_list2 = ["show_deleted",
566 ldap_backend_line = "# No LDAP backend"
567 if provision_backend.type is not "ldb":
568 ldap_backend_line = "ldapBackend: %s" % provision_backend.ldapi_uri
570 if provision_backend.ldap_backend_type == "fedora-ds":
571 backend_modules = ["nsuniqueid", "paged_searches"]
572 # We can handle linked attributes here, as we don't have directory-side subtree operations
573 tdb_modules_list = ["extended_dn_out_fds"]
574 elif ldap_backend.ldap_backend_type == "openldap":
575 backend_modules = ["entryuuid", "paged_searches"]
576 # OpenLDAP handles subtree renames, so we don't want to do any of these things
577 tdb_modules_list = ["extended_dn_out_openldap"]
579 elif serverrole == "domain controller":
580 tdb_modules_list.insert(0, "repl_meta_data")
583 backend_modules = ["objectguid"]
585 if tdb_modules_list is None:
586 tdb_modules_list_as_string = ""
588 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
590 samdb.transaction_start()
592 message("Setting up sam.ldb partitions and settings")
593 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
594 "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
595 "SCHEMADN_MOD2": ",objectguid",
596 "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
597 "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
598 "SCHEMADN_MOD": "schema_data",
599 "CONFIGDN_MOD": "naming_fsmo",
600 "DOMAINDN_MOD": "pdc_fsmo",
601 "MODULES_LIST": ",".join(modules_list),
602 "TDB_MODULES_LIST": tdb_modules_list_as_string,
603 "MODULES_LIST2": ",".join(modules_list2),
604 "BACKEND_MOD": ",".join(backend_modules),
605 "LDAP_BACKEND_LINE": ldap_backend_line,
609 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
611 message("Setting up sam.ldb rootDSE")
612 setup_samdb_rootdse(samdb, setup_path, names)
615 samdb.transaction_cancel()
618 samdb.transaction_commit()
621 def secretsdb_self_join(secretsdb, domain,
622 netbiosname, domainsid, machinepass,
623 realm=None, dnsdomain=None,
625 key_version_number=1,
626 secure_channel_type=SEC_CHAN_WKSTA):
627 """Add domain join-specific bits to a secrets database.
629 :param secretsdb: Ldb Handle to the secrets database
630 :param machinepass: Machine password
632 attrs=["whenChanged",
640 msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
641 msg["secureChannelType"] = str(secure_channel_type)
642 msg["flatname"] = [domain]
643 msg["objectClass"] = ["top", "primaryDomain"]
644 if realm is not None:
645 if dnsdomain is None:
646 dnsdomain = realm.lower()
647 msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
649 msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
650 msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
651 msg["privateKeytab"] = ["secrets.keytab"];
654 msg["secret"] = [machinepass]
655 msg["samAccountName"] = ["%s$" % netbiosname]
656 msg["secureChannelType"] = [str(secure_channel_type)]
657 msg["objectSid"] = [ndr_pack(domainsid)]
659 res = secretsdb.search(base="cn=Primary Domains",
661 expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
662 scope=SCOPE_ONELEVEL)
665 if del_msg.dn is not msg.dn:
666 secretsdb.delete(del_msg.dn)
668 res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
671 msg["priorSecret"] = res[0]["secret"]
672 msg["priorWhenChanged"] = res[0]["whenChanged"]
674 if res["privateKeytab"] is not None:
675 msg["privateKeytab"] = res[0]["privateKeytab"]
677 if res["krb5Keytab"] is not None:
678 msg["krb5Keytab"] = res[0]["krb5Keytab"]
681 el.set_flags(ldb.FLAG_MOD_REPLACE)
682 secretsdb.modify(msg)
687 def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
688 dns_keytab_path, dnspass):
689 """Add DNS specific bits to a secrets database.
691 :param secretsdb: Ldb Handle to the secrets database
692 :param setup_path: Setup path function
693 :param machinepass: Machine password
695 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
697 "DNSDOMAIN": dnsdomain,
698 "DNS_KEYTAB": dns_keytab_path,
699 "DNSPASS_B64": b64encode(dnspass),
703 def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
704 """Setup the secrets database.
706 :param path: Path to the secrets database.
707 :param setup_path: Get the path to a setup file.
708 :param session_info: Session info.
709 :param credentials: Credentials
710 :param lp: Loadparm context
711 :return: LDB handle for the created secrets database
713 if os.path.exists(path):
715 secrets_ldb = Ldb(path, session_info=session_info,
718 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
719 secrets_ldb = Ldb(path, session_info=session_info,
721 secrets_ldb.transaction_start()
722 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
724 if backend_credentials is not None and backend_credentials.authentication_requested():
725 if backend_credentials.get_bind_dn() is not None:
726 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
727 "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
728 "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
731 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
732 "LDAPADMINUSER": backend_credentials.get_username(),
733 "LDAPADMINREALM": backend_credentials.get_realm(),
734 "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
739 def setup_privileges(path, setup_path, session_info, lp):
740 """Setup the privileges database.
742 :param path: Path to the privileges database.
743 :param setup_path: Get the path to a setup file.
744 :param session_info: Session info.
745 :param credentials: Credentials
746 :param lp: Loadparm context
747 :return: LDB handle for the created secrets database
749 if os.path.exists(path):
751 privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
752 privilege_ldb.erase()
753 privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
756 def setup_registry(path, setup_path, session_info, lp):
757 """Setup the registry.
759 :param path: Path to the registry database
760 :param setup_path: Function that returns the path to a setup.
761 :param session_info: Session information
762 :param credentials: Credentials
763 :param lp: Loadparm context
765 reg = registry.Registry()
766 hive = registry.open_ldb(path, session_info=session_info,
768 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
769 provision_reg = setup_path("provision.reg")
770 assert os.path.exists(provision_reg)
771 reg.diff_apply(provision_reg)
774 def setup_idmapdb(path, setup_path, session_info, lp):
775 """Setup the idmap database.
777 :param path: path to the idmap database
778 :param setup_path: Function that returns a path to a setup file
779 :param session_info: Session information
780 :param credentials: Credentials
781 :param lp: Loadparm context
783 if os.path.exists(path):
786 idmap_ldb = IDmapDB(path, session_info=session_info,
790 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
794 def setup_samdb_rootdse(samdb, setup_path, names):
795 """Setup the SamDB rootdse.
797 :param samdb: Sam Database handle
798 :param setup_path: Obtain setup path
800 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
801 "SCHEMADN": names.schemadn,
802 "NETBIOSNAME": names.netbiosname,
803 "DNSDOMAIN": names.dnsdomain,
804 "REALM": names.realm,
805 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
806 "DOMAINDN": names.domaindn,
807 "ROOTDN": names.rootdn,
808 "CONFIGDN": names.configdn,
809 "SERVERDN": names.serverdn,
813 def setup_self_join(samdb, names,
814 machinepass, dnspass,
815 domainsid, invocationid, setup_path,
816 policyguid, policyguid_dc, domainControllerFunctionality,
818 """Join a host to its own domain."""
819 assert isinstance(invocationid, str)
820 if ntdsguid is not None:
821 ntdsguid_line = "objectGUID: %s\n"%ntdsguid
824 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
825 "CONFIGDN": names.configdn,
826 "SCHEMADN": names.schemadn,
827 "DOMAINDN": names.domaindn,
828 "SERVERDN": names.serverdn,
829 "INVOCATIONID": invocationid,
830 "NETBIOSNAME": names.netbiosname,
831 "DEFAULTSITE": names.sitename,
832 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
833 "MACHINEPASS_B64": b64encode(machinepass),
834 "DNSPASS_B64": b64encode(dnspass),
835 "REALM": names.realm,
836 "DOMAIN": names.domain,
837 "DNSDOMAIN": names.dnsdomain,
838 "SAMBA_VERSION_STRING": version,
839 "NTDSGUID": ntdsguid_line,
840 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
842 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
843 "POLICYGUID": policyguid,
844 "POLICYGUID_DC": policyguid_dc,
845 "DNSDOMAIN": names.dnsdomain,
846 "DOMAINSID": str(domainsid),
847 "DOMAINDN": names.domaindn})
849 # add the NTDSGUID based SPNs
850 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
851 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
852 expression="", scope=SCOPE_BASE)
853 assert isinstance(names.ntdsguid, str)
855 # Setup fSMORoleOwner entries to point at the newly created DC entry
856 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
857 "DOMAIN": names.domain,
858 "DNSDOMAIN": names.dnsdomain,
859 "DOMAINDN": names.domaindn,
860 "CONFIGDN": names.configdn,
861 "SCHEMADN": names.schemadn,
862 "DEFAULTSITE": names.sitename,
863 "SERVERDN": names.serverdn,
864 "NETBIOSNAME": names.netbiosname,
865 "NTDSGUID": names.ntdsguid
869 def setup_samdb(path, setup_path, session_info, provision_backend, lp,
871 domainsid, domainguid, policyguid, policyguid_dc,
872 fill, adminpass, krbtgtpass,
873 machinepass, invocationid, dnspass, ntdsguid,
874 serverrole, dom_for_fun_level=None,
876 """Setup a complete SAM Database.
878 :note: This will wipe the main SAM database file!
881 # ATTENTION: Do NOT change these default values without discussion with the
882 # team and/or release manager. They have a big impact on the whole program!
883 domainControllerFunctionality = DS_DC_FUNCTION_2008
885 if dom_for_fun_level is None:
886 dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
887 if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003:
888 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!")
890 if dom_for_fun_level > domainControllerFunctionality:
891 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!")
893 domainFunctionality = dom_for_fun_level
894 forestFunctionality = dom_for_fun_level
896 # Also wipes the database
897 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
898 provision_backend=provision_backend, session_info=session_info,
900 serverrole=serverrole, schema=schema)
903 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
904 sambadn=names.sambadn)
906 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
907 samdb = Ldb(session_info=session_info,
908 credentials=provision_backend.credentials, lp=lp)
910 message("Pre-loading the Samba 4 and AD schema")
912 # Load the schema from the one we computed earlier
913 samdb.set_schema_from_ldb(schema.ldb)
915 # And now we can connect to the DB - the schema won't be loaded from the DB
921 samdb.transaction_start()
923 # Set the domain functionality levels onto the database.
924 # Various module (the password_hash module in particular) need
925 # to know what level of AD we are emulating.
927 # These will be fixed into the database via the database
928 # modifictions below, but we need them set from the start.
929 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
930 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
931 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
933 samdb.set_domain_sid(str(domainsid))
934 if serverrole == "domain controller":
935 samdb.set_invocation_id(invocationid)
937 message("Adding DomainDN: %s" % names.domaindn)
939 #impersonate domain admin
940 admin_session_info = admin_session(lp, str(domainsid))
941 samdb.set_session_info(admin_session_info)
942 if domainguid is not None:
943 domainguid_line = "objectGUID: %s\n-" % domainguid
946 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
947 "DOMAINDN": names.domaindn,
948 "DOMAINGUID": domainguid_line
952 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
953 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
954 "DOMAINSID": str(domainsid),
955 "SCHEMADN": names.schemadn,
956 "NETBIOSNAME": names.netbiosname,
957 "DEFAULTSITE": names.sitename,
958 "CONFIGDN": names.configdn,
959 "SERVERDN": names.serverdn,
960 "POLICYGUID": policyguid,
961 "DOMAINDN": names.domaindn,
962 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
963 "SAMBA_VERSION_STRING": version
966 message("Adding configuration container")
967 descr = get_config_descriptor(domainsid);
968 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
969 "CONFIGDN": names.configdn,
972 message("Modifying configuration container")
973 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
974 "CONFIGDN": names.configdn,
975 "SCHEMADN": names.schemadn,
978 # The LDIF here was created when the Schema object was constructed
979 message("Setting up sam.ldb schema")
980 samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
981 samdb.modify_ldif(schema.schema_dn_modify)
982 samdb.write_prefixes_from_schema()
983 samdb.add_ldif(schema.schema_data, controls=["relax:0"])
984 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
985 {"SCHEMADN": names.schemadn})
987 message("Setting up sam.ldb configuration data")
988 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
989 "CONFIGDN": names.configdn,
990 "NETBIOSNAME": names.netbiosname,
991 "DEFAULTSITE": names.sitename,
992 "DNSDOMAIN": names.dnsdomain,
993 "DOMAIN": names.domain,
994 "SCHEMADN": names.schemadn,
995 "DOMAINDN": names.domaindn,
996 "SERVERDN": names.serverdn,
997 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
1000 message("Setting up display specifiers")
1001 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1002 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
1003 check_all_substituted(display_specifiers_ldif)
1004 samdb.add_ldif(display_specifiers_ldif)
1006 message("Adding users container")
1007 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1008 "DOMAINDN": names.domaindn})
1009 message("Modifying users container")
1010 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1011 "DOMAINDN": names.domaindn})
1012 message("Adding computers container")
1013 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1014 "DOMAINDN": names.domaindn})
1015 message("Modifying computers container")
1016 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
1017 "DOMAINDN": names.domaindn})
1018 message("Setting up sam.ldb data")
1019 setup_add_ldif(samdb, setup_path("provision.ldif"), {
1020 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
1021 "DOMAINDN": names.domaindn,
1022 "NETBIOSNAME": names.netbiosname,
1023 "DEFAULTSITE": names.sitename,
1024 "CONFIGDN": names.configdn,
1025 "SERVERDN": names.serverdn,
1026 "POLICYGUID_DC": policyguid_dc
1029 if fill == FILL_FULL:
1030 message("Setting up sam.ldb users and groups")
1031 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1032 "DOMAINDN": names.domaindn,
1033 "DOMAINSID": str(domainsid),
1034 "CONFIGDN": names.configdn,
1035 "ADMINPASS_B64": b64encode(adminpass),
1036 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1039 if serverrole == "domain controller":
1040 message("Setting up self join")
1041 setup_self_join(samdb, names=names, invocationid=invocationid,
1043 machinepass=machinepass,
1044 domainsid=domainsid, policyguid=policyguid,
1045 policyguid_dc=policyguid_dc,
1046 setup_path=setup_path,
1047 domainControllerFunctionality=domainControllerFunctionality,
1050 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
1051 names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1052 attribute="objectGUID", expression="", scope=SCOPE_BASE)
1053 assert isinstance(names.ntdsguid, str)
1056 samdb.transaction_cancel()
1059 samdb.transaction_commit()
1064 FILL_NT4SYNC = "NT4SYNC"
1068 def provision(setup_dir, message, session_info,
1069 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
1071 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1073 domain=None, hostname=None, hostip=None, hostip6=None,
1074 domainsid=None, adminpass=None, ldapadminpass=None,
1075 krbtgtpass=None, domainguid=None,
1076 policyguid=None, policyguid_dc=None, invocationid=None,
1077 machinepass=None, ntdsguid=None,
1078 dnspass=None, root=None, nobody=None, users=None,
1079 wheel=None, backup=None, aci=None, serverrole=None,
1080 dom_for_fun_level=None,
1081 ldap_backend_extra_port=None, backend_type=None,
1083 ol_mmr_urls=None, ol_olc=None,
1084 setup_ds_path=None, slapd_path=None, nosync=False,
1085 ldap_dryrun_mode=False):
1088 :note: caution, this wipes all existing data!
1091 def setup_path(file):
1092 return os.path.join(setup_dir, file)
1094 if domainsid is None:
1095 domainsid = security.random_sid()
1097 domainsid = security.dom_sid(domainsid)
1099 # create/adapt the group policy GUIDs
1100 if policyguid is None:
1101 policyguid = str(uuid.uuid4())
1102 policyguid = policyguid.upper()
1103 if policyguid_dc is None:
1104 policyguid_dc = str(uuid.uuid4())
1105 policyguid_dc = policyguid_dc.upper()
1107 if adminpass is None:
1108 adminpass = glue.generate_random_str(12)
1109 if krbtgtpass is None:
1110 krbtgtpass = glue.generate_random_str(12)
1111 if machinepass is None:
1112 machinepass = glue.generate_random_str(12)
1114 dnspass = glue.generate_random_str(12)
1115 if ldapadminpass is None:
1116 #Make a new, random password between Samba and it's LDAP server
1117 ldapadminpass=glue.generate_random_str(12)
1119 if backend_type is None:
1120 backend_type = "ldb"
1122 sid_generator = "internal"
1123 if backend_type == "fedora-ds":
1124 sid_generator = "backend"
1126 root_uid = findnss_uid([root or "root"])
1127 nobody_uid = findnss_uid([nobody or "nobody"])
1128 users_gid = findnss_gid([users or "users"])
1130 wheel_gid = findnss_gid(["wheel", "adm"])
1132 wheel_gid = findnss_gid([wheel])
1134 if targetdir is not None:
1135 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1136 os.makedirs(os.path.join(targetdir, "etc"))
1137 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1138 elif smbconf is None:
1139 smbconf = param.default_path()
1141 # only install a new smb.conf if there isn't one there already
1142 if not os.path.exists(smbconf):
1143 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1144 targetdir, sid_generator)
1146 lp = param.LoadParm()
1149 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1150 dnsdomain=realm, serverrole=serverrole,
1151 domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1152 serverdn=serverdn, sitename=sitename)
1154 paths = provision_paths_from_lp(lp, names.dnsdomain)
1158 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1159 except socket.gaierror, (socket.EAI_NODATA, msg):
1164 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1165 except socket.gaierror, (socket.EAI_NODATA, msg):
1168 if serverrole is None:
1169 serverrole = lp.get("server role")
1171 assert serverrole in ("domain controller", "member server", "standalone")
1172 if invocationid is None and serverrole == "domain controller":
1173 invocationid = str(uuid.uuid4())
1175 if not os.path.exists(paths.private_dir):
1176 os.mkdir(paths.private_dir)
1178 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1180 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
1181 sambadn=names.sambadn)
1183 provision_backend = ProvisionBackend(backend_type,
1184 paths=paths, setup_path=setup_path,
1185 lp=lp, credentials=credentials,
1187 message=message, hostname=hostname,
1188 root=root, schema=schema,
1189 ldapadminpass=ldapadminpass,
1190 ldap_backend_extra_port=ldap_backend_extra_port,
1191 ol_mmr_urls=ol_mmr_urls,
1192 slapd_path=slapd_path,
1193 setup_ds_path=setup_ds_path,
1194 ldap_dryrun_mode=ldap_dryrun_mode,
1195 domainsid=domainsid)
1197 # only install a new shares config db if there is none
1198 if not os.path.exists(paths.shareconf):
1199 message("Setting up share.ldb")
1200 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1202 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1205 message("Setting up secrets.ldb")
1206 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1207 session_info=session_info,
1208 backend_credentials=provision_backend.secrets_credentials, lp=lp)
1210 message("Setting up the registry")
1211 setup_registry(paths.hklm, setup_path, session_info,
1214 message("Setting up the privileges database")
1215 setup_privileges(paths.privilege, setup_path, session_info, lp=lp)
1217 message("Setting up idmap db")
1218 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1221 message("Setting up SAM db")
1222 samdb = setup_samdb(paths.samdb, setup_path, session_info,
1223 provision_backend, lp, names,
1225 domainsid=domainsid,
1226 schema=schema, domainguid=domainguid,
1227 policyguid=policyguid, policyguid_dc=policyguid_dc,
1229 adminpass=adminpass, krbtgtpass=krbtgtpass,
1230 invocationid=invocationid,
1231 machinepass=machinepass, dnspass=dnspass,
1232 ntdsguid=ntdsguid, serverrole=serverrole,
1233 dom_for_fun_level=dom_for_fun_level)
1235 if serverrole == "domain controller":
1236 if paths.netlogon is None:
1237 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1238 message("Please either remove %s or see the template at %s" %
1239 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1240 assert(paths.netlogon is not None)
1242 if paths.sysvol is None:
1243 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1244 message("Please either remove %s or see the template at %s" %
1245 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1246 assert(paths.sysvol is not None)
1248 # Set up group policies (domain policy and domain controller policy)
1250 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1251 "{" + policyguid + "}")
1252 os.makedirs(policy_path, 0755)
1253 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1254 "[General]\r\nVersion=65543")
1255 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
1256 os.makedirs(os.path.join(policy_path, "USER"), 0755)
1258 policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1259 "{" + policyguid_dc + "}")
1260 os.makedirs(policy_path_dc, 0755)
1261 open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
1262 "[General]\r\nVersion=2")
1263 os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
1264 os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
1266 if not os.path.isdir(paths.netlogon):
1267 os.makedirs(paths.netlogon, 0755)
1269 if samdb_fill == FILL_FULL:
1270 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1271 root_uid=root_uid, nobody_uid=nobody_uid,
1272 users_gid=users_gid, wheel_gid=wheel_gid)
1274 message("Setting up sam.ldb rootDSE marking as synchronized")
1275 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1277 # Only make a zone file on the first DC, it should be replicated with DNS replication
1278 if serverrole == "domain controller":
1279 secretsdb_self_join(secrets_ldb, domain=domain,
1281 dnsdomain=names.dnsdomain,
1282 netbiosname=names.netbiosname,
1283 domainsid=domainsid,
1284 machinepass=machinepass,
1285 secure_channel_type=SEC_CHAN_BDC)
1287 secretsdb_setup_dns(secrets_ldb, setup_path,
1288 realm=names.realm, dnsdomain=names.dnsdomain,
1289 dns_keytab_path=paths.dns_keytab,
1292 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1293 assert isinstance(domainguid, str)
1295 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1297 hostip6=hostip6, hostname=names.hostname,
1299 domainguid=domainguid, ntdsguid=names.ntdsguid)
1301 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1302 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1304 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1305 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1306 keytab_name=paths.dns_keytab)
1307 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1308 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1310 create_krb5_conf(paths.krb5conf, setup_path,
1311 dnsdomain=names.dnsdomain, hostname=names.hostname,
1313 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1315 if provision_backend.post_setup is not None:
1316 provision_backend.post_setup()
1318 if provision_backend.shutdown is not None:
1319 provision_backend.shutdown()
1321 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1324 #Now commit the secrets.ldb to disk
1325 secrets_ldb.transaction_commit()
1327 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1329 message("Once the above files are installed, your Samba4 server will be ready to use")
1330 message("Server Role: %s" % serverrole)
1331 message("Hostname: %s" % names.hostname)
1332 message("NetBIOS Domain: %s" % names.domain)
1333 message("DNS Domain: %s" % names.dnsdomain)
1334 message("DOMAIN SID: %s" % str(domainsid))
1335 if samdb_fill == FILL_FULL:
1336 message("Admin password: %s" % adminpass)
1337 if provision_backend.type is not "ldb":
1338 if provision_backend.credentials.get_bind_dn() is not None:
1339 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1341 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1343 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1345 if provision_backend.slapd_command_escaped is not None:
1346 # now display slapd_command_file.txt to show how slapd must be started next time
1347 message("Use later the following commandline to start slapd, then Samba:")
1348 message(provision_backend.slapd_command_escaped)
1349 message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
1352 result = ProvisionResult()
1353 result.domaindn = domaindn
1354 result.paths = paths
1356 result.samdb = samdb
1361 def provision_become_dc(setup_dir=None,
1362 smbconf=None, targetdir=None, realm=None,
1363 rootdn=None, domaindn=None, schemadn=None,
1364 configdn=None, serverdn=None,
1365 domain=None, hostname=None, domainsid=None,
1366 adminpass=None, krbtgtpass=None, domainguid=None,
1367 policyguid=None, policyguid_dc=None, invocationid=None,
1369 dnspass=None, root=None, nobody=None, users=None,
1370 wheel=None, backup=None, serverrole=None,
1371 ldap_backend=None, ldap_backend_type=None,
1372 sitename=None, debuglevel=1):
1375 """print a message if quiet is not set."""
1378 glue.set_debug_level(debuglevel)
1380 return provision(setup_dir, message, system_session(), None,
1381 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1382 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1383 configdn=configdn, serverdn=serverdn, domain=domain,
1384 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1385 machinepass=machinepass, serverrole="domain controller",
1389 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1390 """Create a PHP LDAP admin configuration file.
1392 :param path: Path to write the configuration to.
1393 :param setup_path: Function to generate setup paths.
1395 setup_file(setup_path("phpldapadmin-config.php"), path,
1396 {"S4_LDAPI_URI": ldapi_uri})
1399 def create_zone_file(path, setup_path, dnsdomain,
1400 hostip, hostip6, hostname, realm, domainguid,
1402 """Write out a DNS zone file, from the info in the current database.
1404 :param path: Path of the new zone file.
1405 :param setup_path: Setup path function.
1406 :param dnsdomain: DNS Domain name
1407 :param domaindn: DN of the Domain
1408 :param hostip: Local IPv4 IP
1409 :param hostip6: Local IPv6 IP
1410 :param hostname: Local hostname
1411 :param realm: Realm name
1412 :param domainguid: GUID of the domain.
1413 :param ntdsguid: GUID of the hosts nTDSDSA record.
1415 assert isinstance(domainguid, str)
1417 if hostip6 is not None:
1418 hostip6_base_line = " IN AAAA " + hostip6
1419 hostip6_host_line = hostname + " IN AAAA " + hostip6
1421 hostip6_base_line = ""
1422 hostip6_host_line = ""
1424 if hostip is not None:
1425 hostip_base_line = " IN A " + hostip
1426 hostip_host_line = hostname + " IN A " + hostip
1428 hostip_base_line = ""
1429 hostip_host_line = ""
1431 setup_file(setup_path("provision.zone"), path, {
1432 "HOSTNAME": hostname,
1433 "DNSDOMAIN": dnsdomain,
1435 "HOSTIP_BASE_LINE": hostip_base_line,
1436 "HOSTIP_HOST_LINE": hostip_host_line,
1437 "DOMAINGUID": domainguid,
1438 "DATESTRING": time.strftime("%Y%m%d%H"),
1439 "DEFAULTSITE": DEFAULTSITE,
1440 "NTDSGUID": ntdsguid,
1441 "HOSTIP6_BASE_LINE": hostip6_base_line,
1442 "HOSTIP6_HOST_LINE": hostip6_host_line,
1446 def create_named_conf(path, setup_path, realm, dnsdomain,
1448 """Write out a file containing zone statements suitable for inclusion in a
1449 named.conf file (including GSS-TSIG configuration).
1451 :param path: Path of the new named.conf file.
1452 :param setup_path: Setup path function.
1453 :param realm: Realm name
1454 :param dnsdomain: DNS Domain name
1455 :param private_dir: Path to private directory
1456 :param keytab_name: File name of DNS keytab file
1459 setup_file(setup_path("named.conf"), path, {
1460 "DNSDOMAIN": dnsdomain,
1462 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1463 "PRIVATE_DIR": private_dir
1466 def create_named_txt(path, setup_path, realm, dnsdomain,
1467 private_dir, keytab_name):
1468 """Write out a file containing zone statements suitable for inclusion in a
1469 named.conf file (including GSS-TSIG configuration).
1471 :param path: Path of the new named.conf file.
1472 :param setup_path: Setup path function.
1473 :param realm: Realm name
1474 :param dnsdomain: DNS Domain name
1475 :param private_dir: Path to private directory
1476 :param keytab_name: File name of DNS keytab file
1479 setup_file(setup_path("named.txt"), path, {
1480 "DNSDOMAIN": dnsdomain,
1482 "DNS_KEYTAB": keytab_name,
1483 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1484 "PRIVATE_DIR": private_dir
1487 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1488 """Write out a file containing zone statements suitable for inclusion in a
1489 named.conf file (including GSS-TSIG configuration).
1491 :param path: Path of the new named.conf file.
1492 :param setup_path: Setup path function.
1493 :param dnsdomain: DNS Domain name
1494 :param hostname: Local hostname
1495 :param realm: Realm name
1498 setup_file(setup_path("krb5.conf"), path, {
1499 "DNSDOMAIN": dnsdomain,
1500 "HOSTNAME": hostname,