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 credentials import Credentials, DONT_USE_KERBEROS
44 from auth import system_session, admin_session
45 from samba import version, Ldb, substitute_var, valid_netbios_name
46 from samba import check_all_substituted
47 from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008, DS_DC_FUNCTION_2008_R2
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, timestring
54 from ms_schema import read_ms_schema
55 from ms_display_specifiers import read_ms_ldif
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_schema_descriptor(domain_sid):
77 sddl = "O:SAG:SAD:(A;CI;RPLCLORC;;;AU)(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \
78 "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
79 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
80 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
81 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
82 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
83 "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \
84 "(AU;CISA;WP;;;WD)(AU;SA;CR;;;BA)" \
85 "(AU;SA;CR;;;DU)(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \
86 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
87 sec = security.descriptor.from_sddl(sddl, domain_sid)
88 return b64encode(ndr_pack(sec))
90 def get_config_descriptor(domain_sid):
91 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
92 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
93 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
94 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
95 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
96 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
97 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
98 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
99 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
100 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
101 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
102 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
103 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
104 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
105 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
106 sec = security.descriptor.from_sddl(sddl, domain_sid)
107 return b64encode(ndr_pack(sec))
110 DEFAULTSITE = "Default-First-Site-Name"
114 class ProvisioningError(Exception):
115 """A generic provision error."""
117 class InvalidNetbiosName(Exception):
118 """A specified name was not a valid NetBIOS name."""
119 def __init__(self, name):
120 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
123 class ProvisionPaths(object):
125 self.shareconf = None
136 self.dns_keytab = None
139 self.private_dir = None
141 self.slapdconf = None
142 self.modulesconf = None
143 self.memberofconf = None
144 self.fedoradsinf = None
145 self.fedoradspartitions = None
146 self.fedoradssasl = None
148 self.olmmrserveridsconf = None
149 self.olmmrsyncreplconf = None
152 self.olcseedldif = None
155 class ProvisionNames(object):
162 self.ldapmanagerdn = None
163 self.dnsdomain = None
165 self.netbiosname = None
172 class ProvisionResult(object):
179 class Schema(object):
180 def __init__(self, setup_path, domain_sid, schemadn=None,
181 serverdn=None, sambadn=None, ldap_backend_type=None):
182 """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
184 :param samdb: Load a schema into a SamDB.
185 :param setup_path: Setup path function.
186 :param schemadn: DN of the schema
187 :param serverdn: DN of the server
189 Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db
193 self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'),
194 setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt'))
195 self.schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
196 self.schema_data = substitute_var(self.schema_data, {"SCHEMADN": schemadn})
197 check_all_substituted(self.schema_data)
199 self.schema_dn_modify = read_and_sub_file(setup_path("provision_schema_basedn_modify.ldif"),
200 {"SCHEMADN": schemadn,
201 "SERVERDN": serverdn,
204 descr = get_schema_descriptor(domain_sid)
205 self.schema_dn_add = read_and_sub_file(setup_path("provision_schema_basedn.ldif"),
206 {"SCHEMADN": schemadn,
210 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
211 prefixmap = b64encode(prefixmap)
213 # We don't actually add this ldif, just parse it
214 prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % prefixmap
215 self.ldb.set_schema_from_ldif(prefixmap_ldif, self.schema_data)
218 # Return a hash with the forward attribute as a key and the back as the value
219 def get_linked_attributes(schemadn,schemaldb):
220 attrs = ["linkID", "lDAPDisplayName"]
221 res = schemaldb.search(expression="(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
223 for i in range (0, len(res)):
224 expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1)
225 target = schemaldb.searchone(basedn=schemadn,
226 expression=expression,
227 attribute="lDAPDisplayName",
229 if target is not None:
230 attributes[str(res[i]["lDAPDisplayName"])]=str(target)
234 def get_dnsyntax_attributes(schemadn,schemaldb):
235 attrs = ["linkID", "lDAPDisplayName"]
236 res = schemaldb.search(expression="(&(!(linkID=*))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
238 for i in range (0, len(res)):
239 attributes.append(str(res[i]["lDAPDisplayName"]))
244 def check_install(lp, session_info, credentials):
245 """Check whether the current install seems ok.
247 :param lp: Loadparm context
248 :param session_info: Session information
249 :param credentials: Credentials
251 if lp.get("realm") == "":
252 raise Exception("Realm empty")
253 ldb = Ldb(lp.get("sam database"), session_info=session_info,
254 credentials=credentials, lp=lp)
255 if len(ldb.search("(cn=Administrator)")) != 1:
256 raise ProvisioningError("No administrator account found")
259 def findnss(nssfn, names):
260 """Find a user or group from a list of possibilities.
262 :param nssfn: NSS Function to try (should raise KeyError if not found)
263 :param names: Names to check.
264 :return: Value return by first names list.
271 raise KeyError("Unable to find user/group %r" % names)
274 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
275 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
278 def read_and_sub_file(file, subst_vars):
279 """Read a file and sub in variables found in it
281 :param file: File to be read (typically from setup directory)
282 param subst_vars: Optional variables to subsitute in the file.
284 data = open(file, 'r').read()
285 if subst_vars is not None:
286 data = substitute_var(data, subst_vars)
287 check_all_substituted(data)
291 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
292 """Setup a ldb in the private dir.
294 :param ldb: LDB file to import data into
295 :param ldif_path: Path of the LDIF file to load
296 :param subst_vars: Optional variables to subsitute in LDIF.
298 assert isinstance(ldif_path, str)
300 data = read_and_sub_file(ldif_path, subst_vars)
304 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
305 """Modify a ldb in the private dir.
307 :param ldb: LDB object.
308 :param ldif_path: LDIF file path.
309 :param subst_vars: Optional dictionary with substitution variables.
311 data = read_and_sub_file(ldif_path, subst_vars)
313 ldb.modify_ldif(data)
316 def setup_ldb(ldb, ldif_path, subst_vars):
317 """Import a LDIF a file into a LDB handle, optionally substituting variables.
319 :note: Either all LDIF data will be added or none (using transactions).
321 :param ldb: LDB file to import into.
322 :param ldif_path: Path to the LDIF file.
323 :param subst_vars: Dictionary with substitution variables.
325 assert ldb is not None
326 ldb.transaction_start()
328 setup_add_ldif(ldb, ldif_path, subst_vars)
330 ldb.transaction_cancel()
332 ldb.transaction_commit()
335 def setup_file(template, fname, subst_vars):
336 """Setup a file in the private dir.
338 :param template: Path of the template file.
339 :param fname: Path of the file to create.
340 :param subst_vars: Substitution variables.
344 if os.path.exists(f):
347 data = read_and_sub_file(template, subst_vars)
348 open(f, 'w').write(data)
351 def provision_paths_from_lp(lp, dnsdomain):
352 """Set the default paths for provisioning.
354 :param lp: Loadparm context.
355 :param dnsdomain: DNS Domain name
357 paths = ProvisionPaths()
358 paths.private_dir = lp.get("private dir")
359 paths.dns_keytab = "dns.keytab"
361 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
362 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
363 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
364 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
365 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
366 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
367 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
368 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
369 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
370 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
371 paths.phpldapadminconfig = os.path.join(paths.private_dir,
372 "phpldapadmin-config.php")
373 paths.ldapdir = os.path.join(paths.private_dir,
375 paths.slapdconf = os.path.join(paths.ldapdir,
377 paths.slapdpid = os.path.join(paths.ldapdir,
379 paths.modulesconf = os.path.join(paths.ldapdir,
381 paths.memberofconf = os.path.join(paths.ldapdir,
383 paths.fedoradsinf = os.path.join(paths.ldapdir,
385 paths.fedoradspartitions = os.path.join(paths.ldapdir,
386 "fedorads-partitions.ldif")
387 paths.fedoradssasl = os.path.join(paths.ldapdir,
388 "fedorads-sasl.ldif")
389 paths.fedoradssamba = os.path.join(paths.ldapdir,
390 "fedorads-samba.ldif")
391 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
392 "mmr_serverids.conf")
393 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
395 paths.olcdir = os.path.join(paths.ldapdir,
397 paths.olcseedldif = os.path.join(paths.ldapdir,
399 paths.hklm = "hklm.ldb"
400 paths.hkcr = "hkcr.ldb"
401 paths.hkcu = "hkcu.ldb"
402 paths.hku = "hku.ldb"
403 paths.hkpd = "hkpd.ldb"
404 paths.hkpt = "hkpt.ldb"
406 paths.sysvol = lp.get("path", "sysvol")
408 paths.netlogon = lp.get("path", "netlogon")
410 paths.smbconf = lp.configfile
415 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
416 serverrole=None, rootdn=None, domaindn=None, configdn=None,
417 schemadn=None, serverdn=None, sitename=None, sambadn=None):
418 """Guess configuration settings to use."""
421 hostname = socket.gethostname().split(".")[0].lower()
423 netbiosname = hostname.upper()
424 if not valid_netbios_name(netbiosname):
425 raise InvalidNetbiosName(netbiosname)
427 hostname = hostname.lower()
429 if dnsdomain is None:
430 dnsdomain = lp.get("realm")
432 if serverrole is None:
433 serverrole = lp.get("server role")
435 assert dnsdomain is not None
436 realm = dnsdomain.upper()
438 if lp.get("realm").upper() != realm:
439 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
440 (lp.get("realm"), lp.configfile, realm))
442 dnsdomain = dnsdomain.lower()
444 if serverrole == "domain controller":
446 domain = lp.get("workgroup")
448 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
449 if lp.get("workgroup").upper() != domain.upper():
450 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
451 lp.get("workgroup"), domain)
455 domaindn = "CN=" + netbiosname
457 assert domain is not None
458 domain = domain.upper()
459 if not valid_netbios_name(domain):
460 raise InvalidNetbiosName(domain)
462 if netbiosname.upper() == realm.upper():
463 raise Exception("realm %s must not be equal to netbios domain name %s", realm, netbiosname)
465 if hostname.upper() == realm.upper():
466 raise Exception("realm %s must not be equal to hostname %s", realm, hostname)
468 if domain.upper() == realm.upper():
469 raise Exception("realm %s must not be equal to domain name %s", realm, domain)
475 configdn = "CN=Configuration," + rootdn
477 schemadn = "CN=Schema," + configdn
484 names = ProvisionNames()
485 names.rootdn = rootdn
486 names.domaindn = domaindn
487 names.configdn = configdn
488 names.schemadn = schemadn
489 names.sambadn = sambadn
490 names.ldapmanagerdn = "CN=Manager," + rootdn
491 names.dnsdomain = dnsdomain
492 names.domain = domain
494 names.netbiosname = netbiosname
495 names.hostname = hostname
496 names.sitename = sitename
497 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
502 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
504 """Create a new smb.conf file based on a couple of basic settings.
506 assert smbconf is not None
508 hostname = socket.gethostname().split(".")[0].lower()
510 if serverrole is None:
511 serverrole = "standalone"
513 assert serverrole in ("domain controller", "member server", "standalone")
514 if serverrole == "domain controller":
516 elif serverrole == "member server":
517 smbconfsuffix = "member"
518 elif serverrole == "standalone":
519 smbconfsuffix = "standalone"
521 assert domain is not None
522 assert realm is not None
524 default_lp = param.LoadParm()
525 #Load non-existant file
526 if os.path.exists(smbconf):
527 default_lp.load(smbconf)
529 if targetdir is not None:
530 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
531 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
533 default_lp.set("lock dir", os.path.abspath(targetdir))
538 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
539 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
541 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
543 "HOSTNAME": hostname,
546 "SERVERROLE": serverrole,
547 "NETLOGONPATH": netlogon,
548 "SYSVOLPATH": sysvol,
549 "PRIVATEDIR_LINE": privatedir_line,
550 "LOCKDIR_LINE": lockdir_line
554 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
555 users_gid, wheel_gid):
556 """setup reasonable name mappings for sam names to unix names.
558 :param samdb: SamDB object.
559 :param idmap: IDmap db object.
560 :param sid: The domain sid.
561 :param domaindn: The domain DN.
562 :param root_uid: uid of the UNIX root user.
563 :param nobody_uid: uid of the UNIX nobody user.
564 :param users_gid: gid of the UNIX users group.
565 :param wheel_gid: gid of the UNIX wheel group."""
567 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
568 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
570 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
571 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
573 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
575 serverrole, ldap_backend=None,
577 """Setup the partitions for the SAM database.
579 Alternatively, provision() may call this, and then populate the database.
581 :note: This will wipe the Sam Database!
583 :note: This function always removes the local SAM LDB file. The erase
584 parameter controls whether to erase the existing data, which
585 may not be stored locally but in LDAP.
587 assert session_info is not None
589 # We use options=["modules:"] to stop the modules loading - we
590 # just want to wipe and re-initialise the database, not start it up
593 samdb = Ldb(url=samdb_path, session_info=session_info,
594 credentials=credentials, lp=lp, options=["modules:"])
596 samdb.erase_except_schema_controlled()
598 os.unlink(samdb_path)
599 samdb = Ldb(url=samdb_path, session_info=session_info,
600 credentials=credentials, lp=lp, options=["modules:"])
602 samdb.erase_except_schema_controlled()
605 #Add modules to the list to activate them by default
606 #beware often order is important
608 # Some Known ordering constraints:
609 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
610 # - objectclass must be before password_hash, because password_hash checks
611 # that the objectclass is of type person (filled in by objectclass
612 # module when expanding the objectclass list)
613 # - partition must be last
614 # - each partition has its own module list then
615 modules_list = ["resolve_oids",
635 "extended_dn_out_ldb"]
636 modules_list2 = ["show_deleted",
639 domaindn_ldb = "users.ldb"
640 configdn_ldb = "configuration.ldb"
641 schemadn_ldb = "schema.ldb"
642 if ldap_backend is not None:
643 domaindn_ldb = ldap_backend.ldapi_uri
644 configdn_ldb = ldap_backend.ldapi_uri
645 schemadn_ldb = ldap_backend.ldapi_uri
647 if ldap_backend.ldap_backend_type == "fedora-ds":
648 backend_modules = ["nsuniqueid", "paged_searches"]
649 # We can handle linked attributes here, as we don't have directory-side subtree operations
650 tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
651 elif ldap_backend.ldap_backend_type == "openldap":
652 backend_modules = ["entryuuid", "paged_searches"]
653 # OpenLDAP handles subtree renames, so we don't want to do any of these things
654 tdb_modules_list = ["extended_dn_out_dereference"]
656 elif serverrole == "domain controller":
657 tdb_modules_list.insert(0, "repl_meta_data")
660 backend_modules = ["objectguid"]
662 if tdb_modules_list is None:
663 tdb_modules_list_as_string = ""
665 tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
667 samdb.transaction_start()
669 message("Setting up sam.ldb partitions and settings")
670 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
671 "SCHEMADN": names.schemadn,
672 "SCHEMADN_LDB": schemadn_ldb,
673 "SCHEMADN_MOD2": ",objectguid",
674 "CONFIGDN": names.configdn,
675 "CONFIGDN_LDB": configdn_ldb,
676 "DOMAINDN": names.domaindn,
677 "DOMAINDN_LDB": domaindn_ldb,
678 "SCHEMADN_MOD": "schema_fsmo,instancetype",
679 "CONFIGDN_MOD": "naming_fsmo,instancetype",
680 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
681 "MODULES_LIST": ",".join(modules_list),
682 "TDB_MODULES_LIST": tdb_modules_list_as_string,
683 "MODULES_LIST2": ",".join(modules_list2),
684 "BACKEND_MOD": ",".join(backend_modules),
687 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
689 message("Setting up sam.ldb rootDSE")
690 setup_samdb_rootdse(samdb, setup_path, names)
693 samdb.transaction_cancel()
696 samdb.transaction_commit()
698 def secretsdb_self_join(secretsdb, domain,
699 netbiosname, domainsid, machinepass,
700 realm=None, dnsdomain=None,
702 key_version_number=1,
703 secure_channel_type=SEC_CHAN_WKSTA):
704 """Add domain join-specific bits to a secrets database.
706 :param secretsdb: Ldb Handle to the secrets database
707 :param machinepass: Machine password
709 attrs=["whenChanged",
717 msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
718 msg["secureChannelType"] = str(secure_channel_type)
719 msg["flatname"] = [domain]
720 msg["objectClass"] = ["top", "primaryDomain"]
721 if realm is not None:
722 if dnsdomain is None:
723 dnsdomain = realm.lower()
724 msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
726 msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
727 msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
728 msg["privateKeytab"] = ["secrets.keytab"];
731 msg["secret"] = [machinepass]
732 msg["samAccountName"] = ["%s$" % netbiosname]
733 msg["secureChannelType"] = [str(secure_channel_type)]
734 msg["objectSid"] = [ndr_pack(domainsid)]
736 res = secretsdb.search(base="cn=Primary Domains",
738 expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
739 scope=SCOPE_ONELEVEL)
742 if del_msg.dn is not msg.dn:
743 secretsdb.delete(del_msg.dn)
745 res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
748 msg["priorSecret"] = res[0]["secret"]
749 msg["priorWhenChanged"] = res[0]["whenChanged"]
751 if res["privateKeytab"] is not None:
752 msg["privateKeytab"] = res[0]["privateKeytab"]
754 if res["krb5Keytab"] is not None:
755 msg["krb5Keytab"] = res[0]["krb5Keytab"]
758 el.set_flags(ldb.FLAG_MOD_REPLACE)
759 secretsdb.modify(msg)
764 def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
765 dns_keytab_path, dnspass):
766 """Add DNS specific bits to a secrets database.
768 :param secretsdb: Ldb Handle to the secrets database
769 :param setup_path: Setup path function
770 :param machinepass: Machine password
772 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
774 "DNSDOMAIN": dnsdomain,
775 "DNS_KEYTAB": dns_keytab_path,
776 "DNSPASS_B64": b64encode(dnspass),
780 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
781 """Setup the secrets database.
783 :param path: Path to the secrets database.
784 :param setup_path: Get the path to a setup file.
785 :param session_info: Session info.
786 :param credentials: Credentials
787 :param lp: Loadparm context
788 :return: LDB handle for the created secrets database
790 if os.path.exists(path):
792 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
795 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
796 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
798 secrets_ldb.transaction_start()
799 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
801 if credentials is not None and credentials.authentication_requested():
802 if credentials.get_bind_dn() is not None:
803 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
804 "LDAPMANAGERDN": credentials.get_bind_dn(),
805 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
808 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
809 "LDAPADMINUSER": credentials.get_username(),
810 "LDAPADMINREALM": credentials.get_realm(),
811 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
816 def setup_registry(path, setup_path, session_info, lp):
817 """Setup the registry.
819 :param path: Path to the registry database
820 :param setup_path: Function that returns the path to a setup.
821 :param session_info: Session information
822 :param credentials: Credentials
823 :param lp: Loadparm context
825 reg = registry.Registry()
826 hive = registry.open_ldb(path, session_info=session_info,
828 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
829 provision_reg = setup_path("provision.reg")
830 assert os.path.exists(provision_reg)
831 reg.diff_apply(provision_reg)
834 def setup_idmapdb(path, setup_path, session_info, lp):
835 """Setup the idmap database.
837 :param path: path to the idmap database
838 :param setup_path: Function that returns a path to a setup file
839 :param session_info: Session information
840 :param credentials: Credentials
841 :param lp: Loadparm context
843 if os.path.exists(path):
846 idmap_ldb = IDmapDB(path, session_info=session_info,
850 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
854 def setup_samdb_rootdse(samdb, setup_path, names):
855 """Setup the SamDB rootdse.
857 :param samdb: Sam Database handle
858 :param setup_path: Obtain setup path
860 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
861 "SCHEMADN": names.schemadn,
862 "NETBIOSNAME": names.netbiosname,
863 "DNSDOMAIN": names.dnsdomain,
864 "REALM": names.realm,
865 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
866 "DOMAINDN": names.domaindn,
867 "ROOTDN": names.rootdn,
868 "CONFIGDN": names.configdn,
869 "SERVERDN": names.serverdn,
873 def setup_self_join(samdb, names,
874 machinepass, dnspass,
875 domainsid, invocationid, setup_path,
876 policyguid, policyguid_dc, domainControllerFunctionality):
877 """Join a host to its own domain."""
878 assert isinstance(invocationid, str)
879 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
880 "CONFIGDN": names.configdn,
881 "SCHEMADN": names.schemadn,
882 "DOMAINDN": names.domaindn,
883 "SERVERDN": names.serverdn,
884 "INVOCATIONID": invocationid,
885 "NETBIOSNAME": names.netbiosname,
886 "DEFAULTSITE": names.sitename,
887 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
888 "MACHINEPASS_B64": b64encode(machinepass),
889 "DNSPASS_B64": b64encode(dnspass),
890 "REALM": names.realm,
891 "DOMAIN": names.domain,
892 "DNSDOMAIN": names.dnsdomain,
893 "SAMBA_VERSION_STRING": version,
894 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
896 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
897 "POLICYGUID": policyguid,
898 "POLICYGUID_DC": policyguid_dc,
899 "DNSDOMAIN": names.dnsdomain,
900 "DOMAINSID": str(domainsid),
901 "DOMAINDN": names.domaindn})
903 # add the NTDSGUID based SPNs
904 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
905 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
906 expression="", scope=SCOPE_BASE)
907 assert isinstance(names.ntdsguid, str)
909 # Setup fSMORoleOwner entries to point at the newly created DC entry
910 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
911 "DOMAIN": names.domain,
912 "DNSDOMAIN": names.dnsdomain,
913 "DOMAINDN": names.domaindn,
914 "CONFIGDN": names.configdn,
915 "SCHEMADN": names.schemadn,
916 "DEFAULTSITE": names.sitename,
917 "SERVERDN": names.serverdn,
918 "NETBIOSNAME": names.netbiosname,
919 "NTDSGUID": names.ntdsguid
923 def setup_samdb(path, setup_path, session_info, credentials, lp,
925 domainsid, domainguid, policyguid, policyguid_dc,
926 fill, adminpass, krbtgtpass,
927 machinepass, invocationid, dnspass,
928 serverrole, schema=None, ldap_backend=None):
929 """Setup a complete SAM Database.
931 :note: This will wipe the main SAM database file!
934 # Do NOT change these default values without discussion with the team and reslease manager.
935 domainFunctionality = DS_DOMAIN_FUNCTION_2008
936 forestFunctionality = DS_DOMAIN_FUNCTION_2008
937 domainControllerFunctionality = DS_DC_FUNCTION_2008
939 # Also wipes the database
940 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
941 credentials=credentials, session_info=session_info,
943 ldap_backend=ldap_backend, serverrole=serverrole)
946 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
947 sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type)
949 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
950 samdb = Ldb(session_info=session_info,
951 credentials=credentials, lp=lp)
953 message("Pre-loading the Samba 4 and AD schema")
955 # Load the schema from the one we computed earlier
956 samdb.set_schema_from_ldb(schema.ldb)
958 # And now we can connect to the DB - the schema won't be loaded from the DB
962 samdb.load_ldif_file_add(setup_path("provision_options.ldif"))
967 samdb.transaction_start()
969 message("Erasing data from partitions")
970 # Load the schema (again). This time it will force a reindex,
971 # and will therefore make the erase_partitions() below
972 # computationally sane
973 samdb.set_schema_from_ldb(schema.ldb)
974 samdb.erase_partitions()
976 # Set the domain functionality levels onto the database.
977 # Various module (the password_hash module in particular) need
978 # to know what level of AD we are emulating.
980 # These will be fixed into the database via the database
981 # modifictions below, but we need them set from the start.
982 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
983 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
984 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
986 samdb.set_domain_sid(str(domainsid))
987 if serverrole == "domain controller":
988 samdb.set_invocation_id(invocationid)
990 message("Adding DomainDN: %s" % names.domaindn)
991 if serverrole == "domain controller":
992 domain_oc = "domainDNS"
994 domain_oc = "samba4LocalDomain"
996 #impersonate domain admin
997 admin_session_info = admin_session(lp, str(domainsid))
998 samdb.set_session_info(admin_session_info)
1000 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
1001 "DOMAINDN": names.domaindn,
1002 "DOMAIN_OC": domain_oc
1005 message("Modifying DomainDN: " + names.domaindn + "")
1006 if domainguid is not None:
1007 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
1011 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
1012 "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
1013 "DOMAINSID": str(domainsid),
1014 "SCHEMADN": names.schemadn,
1015 "NETBIOSNAME": names.netbiosname,
1016 "DEFAULTSITE": names.sitename,
1017 "CONFIGDN": names.configdn,
1018 "SERVERDN": names.serverdn,
1019 "POLICYGUID": policyguid,
1020 "DOMAINDN": names.domaindn,
1021 "DOMAINGUID_MOD": domainguid_mod,
1022 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
1023 "SAMBA_VERSION_STRING": version
1026 message("Adding configuration container")
1027 descr = get_config_descriptor(domainsid);
1028 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
1029 "CONFIGDN": names.configdn,
1030 "DESCRIPTOR": descr,
1032 message("Modifying configuration container")
1033 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
1034 "CONFIGDN": names.configdn,
1035 "SCHEMADN": names.schemadn,
1038 # The LDIF here was created when the Schema object was constructed
1039 message("Setting up sam.ldb schema")
1040 samdb.add_ldif(schema.schema_dn_add)
1041 samdb.modify_ldif(schema.schema_dn_modify)
1042 samdb.write_prefixes_from_schema()
1043 samdb.add_ldif(schema.schema_data)
1044 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
1045 {"SCHEMADN": names.schemadn})
1047 message("Setting up sam.ldb configuration data")
1048 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
1049 "CONFIGDN": names.configdn,
1050 "NETBIOSNAME": names.netbiosname,
1051 "DEFAULTSITE": names.sitename,
1052 "DNSDOMAIN": names.dnsdomain,
1053 "DOMAIN": names.domain,
1054 "SCHEMADN": names.schemadn,
1055 "DOMAINDN": names.domaindn,
1056 "SERVERDN": names.serverdn,
1057 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
1060 message("Setting up display specifiers")
1061 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1062 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
1063 check_all_substituted(display_specifiers_ldif)
1064 samdb.add_ldif(display_specifiers_ldif)
1066 message("Adding users container")
1067 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1068 "DOMAINDN": names.domaindn})
1069 message("Modifying users container")
1070 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1071 "DOMAINDN": names.domaindn})
1072 message("Adding computers container")
1073 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1074 "DOMAINDN": names.domaindn})
1075 message("Modifying computers container")
1076 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
1077 "DOMAINDN": names.domaindn})
1078 message("Setting up sam.ldb data")
1079 setup_add_ldif(samdb, setup_path("provision.ldif"), {
1080 "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
1081 "DOMAINDN": names.domaindn,
1082 "NETBIOSNAME": names.netbiosname,
1083 "DEFAULTSITE": names.sitename,
1084 "CONFIGDN": names.configdn,
1085 "SERVERDN": names.serverdn,
1086 "POLICYGUID_DC": policyguid_dc
1089 if fill == FILL_FULL:
1090 message("Setting up sam.ldb users and groups")
1091 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1092 "DOMAINDN": names.domaindn,
1093 "DOMAINSID": str(domainsid),
1094 "CONFIGDN": names.configdn,
1095 "ADMINPASS_B64": b64encode(adminpass),
1096 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1099 if serverrole == "domain controller":
1100 message("Setting up self join")
1101 setup_self_join(samdb, names=names, invocationid=invocationid,
1103 machinepass=machinepass,
1104 domainsid=domainsid, policyguid=policyguid,
1105 policyguid_dc=policyguid_dc,
1106 setup_path=setup_path,
1107 domainControllerFunctionality=domainControllerFunctionality)
1109 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
1110 names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1111 attribute="objectGUID", expression="", scope=SCOPE_BASE)
1112 assert isinstance(names.ntdsguid, str)
1115 samdb.transaction_cancel()
1118 samdb.transaction_commit()
1123 FILL_NT4SYNC = "NT4SYNC"
1127 def provision(setup_dir, message, session_info,
1128 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
1130 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1132 domain=None, hostname=None, hostip=None, hostip6=None,
1133 domainsid=None, adminpass=None, ldapadminpass=None,
1134 krbtgtpass=None, domainguid=None,
1135 policyguid=None, policyguid_dc=None, invocationid=None,
1137 dnspass=None, root=None, nobody=None, users=None,
1138 wheel=None, backup=None, aci=None, serverrole=None,
1139 ldap_backend_extra_port=None, ldap_backend_type=None,
1141 ol_mmr_urls=None, ol_olc=None,
1142 setup_ds_path=None, slapd_path=None, nosync=False,
1143 ldap_dryrun_mode=False):
1146 :note: caution, this wipes all existing data!
1149 def setup_path(file):
1150 return os.path.join(setup_dir, file)
1152 if domainsid is None:
1153 domainsid = security.random_sid()
1155 domainsid = security.dom_sid(domainsid)
1158 # create/adapt the group policy GUIDs
1159 if policyguid is None:
1160 policyguid = str(uuid.uuid4())
1161 policyguid = policyguid.upper()
1162 if policyguid_dc is None:
1163 policyguid_dc = str(uuid.uuid4())
1164 policyguid_dc = policyguid_dc.upper()
1166 if adminpass is None:
1167 adminpass = glue.generate_random_str(12)
1168 if krbtgtpass is None:
1169 krbtgtpass = glue.generate_random_str(12)
1170 if machinepass is None:
1171 machinepass = glue.generate_random_str(12)
1173 dnspass = glue.generate_random_str(12)
1174 if ldapadminpass is None:
1175 #Make a new, random password between Samba and it's LDAP server
1176 ldapadminpass=glue.generate_random_str(12)
1179 root_uid = findnss_uid([root or "root"])
1180 nobody_uid = findnss_uid([nobody or "nobody"])
1181 users_gid = findnss_gid([users or "users"])
1183 wheel_gid = findnss_gid(["wheel", "adm"])
1185 wheel_gid = findnss_gid([wheel])
1187 if targetdir is not None:
1188 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1189 os.makedirs(os.path.join(targetdir, "etc"))
1190 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1191 elif smbconf is None:
1192 smbconf = param.default_path()
1194 # only install a new smb.conf if there isn't one there already
1195 if not os.path.exists(smbconf):
1196 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1199 lp = param.LoadParm()
1202 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1203 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
1204 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1207 paths = provision_paths_from_lp(lp, names.dnsdomain)
1211 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1212 except socket.gaierror, (socket.EAI_NODATA, msg):
1217 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1218 except socket.gaierror, (socket.EAI_NODATA, msg):
1221 if serverrole is None:
1222 serverrole = lp.get("server role")
1224 assert serverrole in ("domain controller", "member server", "standalone")
1225 if invocationid is None and serverrole == "domain controller":
1226 invocationid = str(uuid.uuid4())
1228 if not os.path.exists(paths.private_dir):
1229 os.mkdir(paths.private_dir)
1231 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1233 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
1234 sambadn=names.sambadn, ldap_backend_type=ldap_backend_type)
1236 secrets_credentials = credentials
1237 provision_backend = None
1238 if ldap_backend_type:
1239 # We only support an LDAP backend over ldapi://
1241 provision_backend = ProvisionBackend(paths=paths, setup_path=setup_path,
1242 lp=lp, credentials=credentials,
1244 message=message, hostname=hostname,
1245 root=root, schema=schema,
1246 ldap_backend_type=ldap_backend_type,
1247 ldapadminpass=ldapadminpass,
1248 ldap_backend_extra_port=ldap_backend_extra_port,
1249 ol_mmr_urls=ol_mmr_urls,
1250 slapd_path=slapd_path,
1251 setup_ds_path=setup_ds_path,
1252 ldap_dryrun_mode=ldap_dryrun_mode)
1254 # Now use the backend credentials to access the databases
1255 credentials = provision_backend.credentials
1256 secrets_credentials = provision_backend.adminCredentials
1257 ldapi_url = provision_backend.ldapi_uri
1259 # only install a new shares config db if there is none
1260 if not os.path.exists(paths.shareconf):
1261 message("Setting up share.ldb")
1262 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1263 credentials=credentials, lp=lp)
1264 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1267 message("Setting up secrets.ldb")
1268 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1269 session_info=session_info,
1270 credentials=secrets_credentials, lp=lp)
1272 message("Setting up the registry")
1273 setup_registry(paths.hklm, setup_path, session_info,
1276 message("Setting up idmap db")
1277 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1280 message("Setting up SAM db")
1281 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
1282 credentials=credentials, lp=lp, names=names,
1284 domainsid=domainsid,
1285 schema=schema, domainguid=domainguid,
1286 policyguid=policyguid, policyguid_dc=policyguid_dc,
1288 adminpass=adminpass, krbtgtpass=krbtgtpass,
1289 invocationid=invocationid,
1290 machinepass=machinepass, dnspass=dnspass,
1291 serverrole=serverrole, ldap_backend=provision_backend)
1293 if serverrole == "domain controller":
1294 if paths.netlogon is None:
1295 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1296 message("Please either remove %s or see the template at %s" %
1297 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1298 assert(paths.netlogon is not None)
1300 if paths.sysvol is None:
1301 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1302 message("Please either remove %s or see the template at %s" %
1303 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1304 assert(paths.sysvol is not None)
1306 # Set up group policies (domain policy and domain controller policy)
1308 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1309 "{" + policyguid + "}")
1310 os.makedirs(policy_path, 0755)
1311 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1312 "[General]\r\nVersion=65543")
1313 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
1314 os.makedirs(os.path.join(policy_path, "USER"), 0755)
1316 policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1317 "{" + policyguid_dc + "}")
1318 os.makedirs(policy_path_dc, 0755)
1319 open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
1320 "[General]\r\nVersion=2")
1321 os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
1322 os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
1324 if not os.path.isdir(paths.netlogon):
1325 os.makedirs(paths.netlogon, 0755)
1327 if samdb_fill == FILL_FULL:
1328 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1329 root_uid=root_uid, nobody_uid=nobody_uid,
1330 users_gid=users_gid, wheel_gid=wheel_gid)
1332 message("Setting up sam.ldb rootDSE marking as synchronized")
1333 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1335 # Only make a zone file on the first DC, it should be replicated with DNS replication
1336 if serverrole == "domain controller":
1337 secretsdb_self_join(secrets_ldb, domain=domain,
1339 dnsdomain=names.dnsdomain,
1340 netbiosname=names.netbiosname,
1341 domainsid=domainsid,
1342 machinepass=machinepass,
1343 secure_channel_type=SEC_CHAN_BDC)
1345 secretsdb_setup_dns(secrets_ldb, setup_path,
1346 realm=names.realm, dnsdomain=names.dnsdomain,
1347 dns_keytab_path=paths.dns_keytab,
1350 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1351 assert isinstance(domainguid, str)
1353 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1354 domaindn=names.domaindn, hostip=hostip,
1355 hostip6=hostip6, hostname=names.hostname,
1356 dnspass=dnspass, realm=names.realm,
1357 domainguid=domainguid, ntdsguid=names.ntdsguid)
1359 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1360 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1362 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1363 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1364 keytab_name=paths.dns_keytab)
1365 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1366 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1368 create_krb5_conf(paths.krb5conf, setup_path,
1369 dnsdomain=names.dnsdomain, hostname=names.hostname,
1371 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1373 #Now commit the secrets.ldb to disk
1374 secrets_ldb.transaction_commit()
1376 if provision_backend is not None:
1377 if ldap_backend_type == "fedora-ds":
1378 ldapi_db = Ldb(provision_backend.ldapi_uri, lp=lp, credentials=credentials)
1380 # delete default SASL mappings
1381 res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
1383 # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
1384 for i in range (0, len(res)):
1385 dn = str(res[i]["dn"])
1388 aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % names.sambadn
1391 m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
1393 m.dn = ldb.Dn(1, names.domaindn)
1396 m.dn = ldb.Dn(1, names.configdn)
1399 m.dn = ldb.Dn(1, names.schemadn)
1402 # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
1403 if provision_backend.slapd.poll() is None:
1405 if hasattr(provision_backend.slapd, "terminate"):
1406 provision_backend.slapd.terminate()
1408 # Older python versions don't have .terminate()
1410 os.kill(provision_backend.slapd.pid, signal.SIGTERM)
1412 #and now wait for it to die
1413 provision_backend.slapd.communicate()
1415 # now display slapd_command_file.txt to show how slapd must be started next time
1416 message("Use later the following commandline to start slapd, then Samba:")
1417 slapd_command = "\'" + "\' \'".join(provision_backend.slapd_command) + "\'"
1418 message(slapd_command)
1419 message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
1421 setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
1422 "SLAPD_COMMAND" : slapd_command})
1425 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1428 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1430 message("Once the above files are installed, your Samba4 server will be ready to use")
1431 message("Server Role: %s" % serverrole)
1432 message("Hostname: %s" % names.hostname)
1433 message("NetBIOS Domain: %s" % names.domain)
1434 message("DNS Domain: %s" % names.dnsdomain)
1435 message("DOMAIN SID: %s" % str(domainsid))
1436 if samdb_fill == FILL_FULL:
1437 message("Admin password: %s" % adminpass)
1438 if provision_backend:
1439 if provision_backend.credentials.get_bind_dn() is not None:
1440 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1442 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1444 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1446 result = ProvisionResult()
1447 result.domaindn = domaindn
1448 result.paths = paths
1450 result.samdb = samdb
1455 def provision_become_dc(setup_dir=None,
1456 smbconf=None, targetdir=None, realm=None,
1457 rootdn=None, domaindn=None, schemadn=None,
1458 configdn=None, serverdn=None,
1459 domain=None, hostname=None, domainsid=None,
1460 adminpass=None, krbtgtpass=None, domainguid=None,
1461 policyguid=None, policyguid_dc=None, invocationid=None,
1463 dnspass=None, root=None, nobody=None, users=None,
1464 wheel=None, backup=None, serverrole=None,
1465 ldap_backend=None, ldap_backend_type=None,
1466 sitename=None, debuglevel=1):
1469 """print a message if quiet is not set."""
1472 glue.set_debug_level(debuglevel)
1474 return provision(setup_dir, message, system_session(), None,
1475 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1476 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1477 configdn=configdn, serverdn=serverdn, domain=domain,
1478 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1479 machinepass=machinepass, serverrole="domain controller",
1483 def setup_db_config(setup_path, dbdir):
1484 """Setup a Berkeley database.
1486 :param setup_path: Setup path function.
1487 :param dbdir: Database directory."""
1488 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1489 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1490 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1491 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1493 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1494 {"LDAPDBDIR": dbdir})
1496 class ProvisionBackend(object):
1497 def __init__(self, paths=None, setup_path=None, lp=None, credentials=None,
1498 names=None, message=None,
1499 hostname=None, root=None,
1500 schema=None, ldapadminpass=None,
1501 ldap_backend_type=None, ldap_backend_extra_port=None,
1503 setup_ds_path=None, slapd_path=None,
1504 nosync=False, ldap_dryrun_mode=False):
1505 """Provision an LDAP backend for samba4
1507 This works for OpenLDAP and Fedora DS
1510 self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
1512 if not os.path.isdir(paths.ldapdir):
1513 os.makedirs(paths.ldapdir, 0700)
1515 if ldap_backend_type == "existing":
1516 #Check to see that this 'existing' LDAP backend in fact exists
1517 ldapi_db = Ldb(self.ldapi_uri, credentials=credentials)
1518 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1519 expression="(objectClass=OpenLDAProotDSE)")
1521 # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
1522 # This caused them to be set into the long-term database later in the script.
1523 self.credentials = credentials
1524 self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
1527 # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri
1528 # if another instance of slapd is already running
1530 ldapi_db = Ldb(self.ldapi_uri)
1531 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1532 expression="(objectClass=OpenLDAProotDSE)");
1534 f = open(paths.slapdpid, "r")
1537 message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.")
1541 raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ")
1546 # Try to print helpful messages when the user has not specified the path to slapd
1547 if slapd_path is None:
1548 raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
1549 if not os.path.exists(slapd_path):
1550 message (slapd_path)
1551 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
1553 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1555 os.unlink(schemadb_path)
1560 # Put the LDIF of the schema into a database so we can search on
1561 # it to generate schema-dependent configurations in Fedora DS and
1563 os.path.join(paths.ldapdir, "schema-tmp.ldb")
1564 schema.ldb.connect(schemadb_path)
1565 schema.ldb.transaction_start()
1567 # These bits of LDIF are supplied when the Schema object is created
1568 schema.ldb.add_ldif(schema.schema_dn_add)
1569 schema.ldb.modify_ldif(schema.schema_dn_modify)
1570 schema.ldb.add_ldif(schema.schema_data)
1571 schema.ldb.transaction_commit()
1573 self.credentials = Credentials()
1574 self.credentials.guess(lp)
1575 #Kerberos to an ldapi:// backend makes no sense
1576 self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
1578 self.adminCredentials = Credentials()
1579 self.adminCredentials.guess(lp)
1580 #Kerberos to an ldapi:// backend makes no sense
1581 self.adminCredentials.set_kerberos_state(DONT_USE_KERBEROS)
1583 self.ldap_backend_type = ldap_backend_type
1585 if ldap_backend_type == "fedora-ds":
1586 provision_fds_backend(self, paths=paths, setup_path=setup_path,
1587 names=names, message=message,
1589 ldapadminpass=ldapadminpass, root=root,
1591 ldap_backend_extra_port=ldap_backend_extra_port,
1592 setup_ds_path=setup_ds_path,
1593 slapd_path=slapd_path,
1595 ldap_dryrun_mode=ldap_dryrun_mode)
1597 elif ldap_backend_type == "openldap":
1598 provision_openldap_backend(self, paths=paths, setup_path=setup_path,
1599 names=names, message=message,
1601 ldapadminpass=ldapadminpass, root=root,
1603 ldap_backend_extra_port=ldap_backend_extra_port,
1604 ol_mmr_urls=ol_mmr_urls,
1605 slapd_path=slapd_path,
1607 ldap_dryrun_mode=ldap_dryrun_mode)
1609 raise ProvisioningError("Unknown LDAP backend type selected")
1611 self.credentials.set_password(ldapadminpass)
1612 self.adminCredentials.set_username("samba-admin")
1613 self.adminCredentials.set_password(ldapadminpass)
1615 # Now start the slapd, so we can provision onto it. We keep the
1616 # subprocess context around, to kill this off at the successful
1618 self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False)
1620 while self.slapd.poll() is None:
1621 # Wait until the socket appears
1623 ldapi_db = Ldb(self.ldapi_uri, lp=lp, credentials=self.credentials)
1624 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1625 expression="(objectClass=OpenLDAProotDSE)")
1626 # If we have got here, then we must have a valid connection to the LDAP server!
1632 raise ProvisioningError("slapd died before we could make a connection to it")
1635 def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
1637 hostname=None, ldapadminpass=None, root=None,
1639 ldap_backend_extra_port=None,
1641 slapd_path=None, nosync=False,
1642 ldap_dryrun_mode=False):
1644 #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
1647 nosync_config = "dbnosync"
1649 lnkattr = get_linked_attributes(names.schemadn,schema.ldb)
1650 refint_attributes = ""
1651 memberof_config = "# Generated from Samba4 schema\n"
1652 for att in lnkattr.keys():
1653 if lnkattr[att] is not None:
1654 refint_attributes = refint_attributes + " " + att
1656 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1657 { "MEMBER_ATTR" : att ,
1658 "MEMBEROF_ATTR" : lnkattr[att] })
1660 refint_config = read_and_sub_file(setup_path("refint.conf"),
1661 { "LINK_ATTRS" : refint_attributes})
1663 attrs = ["linkID", "lDAPDisplayName"]
1664 res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
1666 for i in range (0, len(res)):
1667 index_attr = res[i]["lDAPDisplayName"][0]
1668 if index_attr == "objectGUID":
1669 index_attr = "entryUUID"
1671 index_config += "index " + index_attr + " eq\n"
1673 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1675 mmr_replicator_acl = ""
1676 mmr_serverids_config = ""
1677 mmr_syncrepl_schema_config = ""
1678 mmr_syncrepl_config_config = ""
1679 mmr_syncrepl_user_config = ""
1682 if ol_mmr_urls is not None:
1683 # For now, make these equal
1684 mmr_pass = ldapadminpass
1686 url_list=filter(None,ol_mmr_urls.split(' '))
1687 if (len(url_list) == 1):
1688 url_list=filter(None,ol_mmr_urls.split(','))
1691 mmr_on_config = "MirrorMode On"
1692 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
1694 for url in url_list:
1696 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1697 { "SERVERID" : str(serverid),
1698 "LDAPSERVER" : url })
1701 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1703 "MMRDN": names.schemadn,
1705 "MMR_PASSWORD": mmr_pass})
1708 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1710 "MMRDN": names.configdn,
1712 "MMR_PASSWORD": mmr_pass})
1715 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1717 "MMRDN": names.domaindn,
1719 "MMR_PASSWORD": mmr_pass })
1720 # OpenLDAP cn=config initialisation
1721 olc_syncrepl_config = ""
1723 # if mmr = yes, generate cn=config-replication directives
1724 # and olc_seed.lif for the other mmr-servers
1725 if ol_mmr_urls is not None:
1727 olc_serverids_config = ""
1728 olc_syncrepl_seed_config = ""
1729 olc_mmr_config += read_and_sub_file(setup_path("olc_mmr.conf"),{})
1731 for url in url_list:
1733 olc_serverids_config += read_and_sub_file(setup_path("olc_serverid.conf"),
1734 { "SERVERID" : str(serverid),
1735 "LDAPSERVER" : url })
1738 olc_syncrepl_config += read_and_sub_file(setup_path("olc_syncrepl.conf"),
1741 "MMR_PASSWORD": mmr_pass})
1743 olc_syncrepl_seed_config += read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
1745 "LDAPSERVER" : url})
1747 setup_file(setup_path("olc_seed.ldif"), paths.olcseedldif,
1748 {"OLC_SERVER_ID_CONF": olc_serverids_config,
1749 "OLC_PW": ldapadminpass,
1750 "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
1753 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1754 {"DNSDOMAIN": names.dnsdomain,
1755 "LDAPDIR": paths.ldapdir,
1756 "DOMAINDN": names.domaindn,
1757 "CONFIGDN": names.configdn,
1758 "SCHEMADN": names.schemadn,
1759 "MEMBEROF_CONFIG": memberof_config,
1760 "MIRRORMODE": mmr_on_config,
1761 "REPLICATOR_ACL": mmr_replicator_acl,
1762 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1763 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1764 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1765 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1766 "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
1767 "OLC_MMR_CONFIG": olc_mmr_config,
1768 "REFINT_CONFIG": refint_config,
1769 "INDEX_CONFIG": index_config,
1770 "NOSYNC": nosync_config})
1772 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1773 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1774 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1776 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1777 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1779 setup_file(setup_path("cn=samba.ldif"),
1780 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1781 { "UUID": str(uuid.uuid4()),
1782 "LDAPTIME": timestring(int(time.time()))} )
1783 setup_file(setup_path("cn=samba-admin.ldif"),
1784 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1785 {"LDAPADMINPASS_B64": b64encode(ldapadminpass),
1786 "UUID": str(uuid.uuid4()),
1787 "LDAPTIME": timestring(int(time.time()))} )
1789 if ol_mmr_urls is not None:
1790 setup_file(setup_path("cn=replicator.ldif"),
1791 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1792 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
1793 "UUID": str(uuid.uuid4()),
1794 "LDAPTIME": timestring(int(time.time()))} )
1797 mapping = "schema-map-openldap-2.3"
1798 backend_schema = "backend-schema.schema"
1800 backend_schema_data = schema.ldb.convert_schema_to_openldap("openldap", open(setup_path(mapping), 'r').read())
1801 assert backend_schema_data is not None
1802 open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
1804 # now we generate the needed strings to start slapd automatically,
1805 # first ldapi_uri...
1806 if ldap_backend_extra_port is not None:
1807 # When we use MMR, we can't use 0.0.0.0 as it uses the name
1808 # specified there as part of it's clue as to it's own name,
1809 # and not to replicate to itself
1810 if ol_mmr_urls is None:
1811 server_port_string = "ldap://0.0.0.0:%d" % ldap_backend_extra_port
1813 server_port_string = "ldap://" + names.hostname + "." + names.dnsdomain +":%d" % ldap_backend_extra_port
1815 server_port_string = ""
1817 # Prepare the 'result' information - the commands to return in particular
1818 result.slapd_provision_command = [slapd_path]
1820 result.slapd_provision_command.append("-F" + paths.olcdir)
1822 result.slapd_provision_command.append("-h")
1824 # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands
1825 result.slapd_command = list(result.slapd_provision_command)
1827 result.slapd_provision_command.append(result.ldapi_uri)
1828 result.slapd_provision_command.append("-d0")
1830 uris = result.ldapi_uri
1831 if server_port_string is not "":
1832 uris = uris + " " + server_port_string
1834 result.slapd_command.append(uris)
1836 # Set the username - done here because Fedora DS still uses the admin DN and simple bind
1837 result.credentials.set_username("samba-admin")
1839 # If we were just looking for crashes up to this point, it's a
1840 # good time to exit before we realise we don't have OpenLDAP on
1842 if ldap_dryrun_mode:
1845 # Finally, convert the configuration into cn=config style!
1846 if not os.path.isdir(paths.olcdir):
1847 os.makedirs(paths.olcdir, 0770)
1849 retcode = subprocess.call([slapd_path, "-Ttest", "-f", paths.slapdconf, "-F", paths.olcdir], close_fds=True, shell=False)
1851 # We can't do this, as OpenLDAP is strange. It gives an error
1852 # output to the above, but does the conversion sucessfully...
1855 # raise ProvisioningError("conversion from slapd.conf to cn=config failed")
1857 if not os.path.exists(os.path.join(paths.olcdir, "cn=config.ldif")):
1858 raise ProvisioningError("conversion from slapd.conf to cn=config failed")
1860 # Don't confuse the admin by leaving the slapd.conf around
1861 os.remove(paths.slapdconf)
1864 def provision_fds_backend(result, paths=None, setup_path=None, names=None,
1866 hostname=None, ldapadminpass=None, root=None,
1868 ldap_backend_extra_port=None,
1872 ldap_dryrun_mode=False):
1874 if ldap_backend_extra_port is not None:
1875 serverport = "ServerPort=%d" % ldap_backend_extra_port
1879 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1881 "HOSTNAME": hostname,
1882 "DNSDOMAIN": names.dnsdomain,
1883 "LDAPDIR": paths.ldapdir,
1884 "DOMAINDN": names.domaindn,
1885 "LDAPMANAGERDN": names.ldapmanagerdn,
1886 "LDAPMANAGERPASS": ldapadminpass,
1887 "SERVERPORT": serverport})
1889 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1890 {"CONFIGDN": names.configdn,
1891 "SCHEMADN": names.schemadn,
1892 "SAMBADN": names.sambadn,
1895 setup_file(setup_path("fedorads-sasl.ldif"), paths.fedoradssasl,
1896 {"SAMBADN": names.sambadn,
1899 setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba,
1900 {"SAMBADN": names.sambadn,
1901 "LDAPADMINPASS": ldapadminpass
1904 mapping = "schema-map-fedora-ds-1.0"
1905 backend_schema = "99_ad.ldif"
1907 # Build a schema file in Fedora DS format
1908 backend_schema_data = schema.ldb.convert_schema_to_openldap("fedora-ds", open(setup_path(mapping), 'r').read())
1909 assert backend_schema_data is not None
1910 open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
1912 result.credentials.set_bind_dn(names.ldapmanagerdn)
1914 # Destory the target directory, or else setup-ds.pl will complain
1915 fedora_ds_dir = os.path.join(paths.ldapdir, "slapd-samba4")
1916 shutil.rmtree(fedora_ds_dir, True)
1918 result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", paths.slapdpid];
1919 #In the 'provision' command line, stay in the foreground so we can easily kill it
1920 result.slapd_provision_command.append("-d0")
1922 #the command for the final run is the normal script
1923 result.slapd_command = [os.path.join(paths.ldapdir, "slapd-samba4", "start-slapd")]
1925 # If we were just looking for crashes up to this point, it's a
1926 # good time to exit before we realise we don't have Fedora DS on
1927 if ldap_dryrun_mode:
1930 # Try to print helpful messages when the user has not specified the path to the setup-ds tool
1931 if setup_ds_path is None:
1932 raise ProvisioningError("Warning: Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
1933 if not os.path.exists(setup_ds_path):
1934 message (setup_ds_path)
1935 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
1937 # Run the Fedora DS setup utility
1938 retcode = subprocess.call([setup_ds_path, "--silent", "--file", paths.fedoradsinf], close_fds=True, shell=False)
1940 raise ProvisioningError("setup-ds failed")
1943 retcode = subprocess.call([
1944 os.path.join(paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", paths.fedoradssamba],
1945 close_fds=True, shell=False)
1947 raise("ldib2db failed")
1949 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1950 """Create a PHP LDAP admin configuration file.
1952 :param path: Path to write the configuration to.
1953 :param setup_path: Function to generate setup paths.
1955 setup_file(setup_path("phpldapadmin-config.php"), path,
1956 {"S4_LDAPI_URI": ldapi_uri})
1959 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1960 hostip, hostip6, hostname, dnspass, realm, domainguid,
1962 """Write out a DNS zone file, from the info in the current database.
1964 :param path: Path of the new zone file.
1965 :param setup_path: Setup path function.
1966 :param dnsdomain: DNS Domain name
1967 :param domaindn: DN of the Domain
1968 :param hostip: Local IPv4 IP
1969 :param hostip6: Local IPv6 IP
1970 :param hostname: Local hostname
1971 :param dnspass: Password for DNS
1972 :param realm: Realm name
1973 :param domainguid: GUID of the domain.
1974 :param ntdsguid: GUID of the hosts nTDSDSA record.
1976 assert isinstance(domainguid, str)
1978 if hostip6 is not None:
1979 hostip6_base_line = " IN AAAA " + hostip6
1980 hostip6_host_line = hostname + " IN AAAA " + hostip6
1982 hostip6_base_line = ""
1983 hostip6_host_line = ""
1985 if hostip is not None:
1986 hostip_base_line = " IN A " + hostip
1987 hostip_host_line = hostname + " IN A " + hostip
1989 hostip_base_line = ""
1990 hostip_host_line = ""
1992 setup_file(setup_path("provision.zone"), path, {
1993 "DNSPASS_B64": b64encode(dnspass),
1994 "HOSTNAME": hostname,
1995 "DNSDOMAIN": dnsdomain,
1997 "HOSTIP_BASE_LINE": hostip_base_line,
1998 "HOSTIP_HOST_LINE": hostip_host_line,
1999 "DOMAINGUID": domainguid,
2000 "DATESTRING": time.strftime("%Y%m%d%H"),
2001 "DEFAULTSITE": DEFAULTSITE,
2002 "NTDSGUID": ntdsguid,
2003 "HOSTIP6_BASE_LINE": hostip6_base_line,
2004 "HOSTIP6_HOST_LINE": hostip6_host_line,
2008 def create_named_conf(path, setup_path, realm, dnsdomain,
2010 """Write out a file containing zone statements suitable for inclusion in a
2011 named.conf file (including GSS-TSIG configuration).
2013 :param path: Path of the new named.conf file.
2014 :param setup_path: Setup path function.
2015 :param realm: Realm name
2016 :param dnsdomain: DNS Domain name
2017 :param private_dir: Path to private directory
2018 :param keytab_name: File name of DNS keytab file
2021 setup_file(setup_path("named.conf"), path, {
2022 "DNSDOMAIN": dnsdomain,
2024 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
2025 "PRIVATE_DIR": private_dir
2028 def create_named_txt(path, setup_path, realm, dnsdomain,
2029 private_dir, keytab_name):
2030 """Write out a file containing zone statements suitable for inclusion in a
2031 named.conf file (including GSS-TSIG configuration).
2033 :param path: Path of the new named.conf file.
2034 :param setup_path: Setup path function.
2035 :param realm: Realm name
2036 :param dnsdomain: DNS Domain name
2037 :param private_dir: Path to private directory
2038 :param keytab_name: File name of DNS keytab file
2041 setup_file(setup_path("named.txt"), path, {
2042 "DNSDOMAIN": dnsdomain,
2044 "DNS_KEYTAB": keytab_name,
2045 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
2046 "PRIVATE_DIR": private_dir
2049 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
2050 """Write out a file containing zone statements suitable for inclusion in a
2051 named.conf file (including GSS-TSIG configuration).
2053 :param path: Path of the new named.conf file.
2054 :param setup_path: Setup path function.
2055 :param dnsdomain: DNS Domain name
2056 :param hostname: Local hostname
2057 :param realm: Realm name
2060 setup_file(setup_path("krb5.conf"), path, {
2061 "DNSDOMAIN": dnsdomain,
2062 "HOSTNAME": hostname,