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_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
58 __docformat__ = "restructuredText"
61 class ProvisioningError(ValueError):
66 """Find the setup directory used by provision."""
67 dirname = os.path.dirname(__file__)
68 if "/site-packages/" in dirname:
69 prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
70 for suffix in ["share/setup", "share/samba/setup", "setup"]:
71 ret = os.path.join(prefix, suffix)
72 if os.path.isdir(ret):
75 ret = os.path.join(dirname, "../../../setup")
76 if os.path.isdir(ret):
78 raise Exception("Unable to find setup directory.")
80 def get_schema_descriptor(domain_sid):
81 sddl = "O:SAG:SAD:(A;CI;RPLCLORC;;;AU)(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \
82 "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
83 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
84 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
85 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
86 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
87 "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \
88 "(AU;CISA;WP;;;WD)(AU;SA;CR;;;BA)" \
89 "(AU;SA;CR;;;DU)(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \
90 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
91 sec = security.descriptor.from_sddl(sddl, domain_sid)
92 return b64encode(ndr_pack(sec))
94 def get_config_descriptor(domain_sid):
95 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
96 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
97 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
98 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
99 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
100 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
101 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
102 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
103 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
104 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
105 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
106 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
107 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
108 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
109 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
110 sec = security.descriptor.from_sddl(sddl, domain_sid)
111 return b64encode(ndr_pack(sec))
114 DEFAULTSITE = "Default-First-Site-Name"
116 class InvalidNetbiosName(Exception):
117 """A specified name was not a valid NetBIOS name."""
118 def __init__(self, name):
119 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
122 class ProvisionPaths(object):
124 self.shareconf = None
135 self.dns_keytab = None
138 self.private_dir = None
140 self.slapdconf = None
141 self.modulesconf = None
142 self.memberofconf = None
143 self.fedoradsinf = None
144 self.fedoradspartitions = None
145 self.fedoradssasl = None
147 self.olmmrserveridsconf = None
148 self.olmmrsyncreplconf = None
151 self.olcseedldif = None
154 class ProvisionNames(object):
161 self.ldapmanagerdn = None
162 self.dnsdomain = None
164 self.netbiosname = None
171 class ProvisionResult(object):
178 class Schema(object):
179 def __init__(self, setup_path, domain_sid, schemadn=None,
180 serverdn=None, sambadn=None, ldap_backend_type=None):
181 """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
183 :param samdb: Load a schema into a SamDB.
184 :param setup_path: Setup path function.
185 :param schemadn: DN of the schema
186 :param serverdn: DN of the server
188 Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db
192 self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'),
193 setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt'))
194 self.schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
195 self.schema_data = substitute_var(self.schema_data, {"SCHEMADN": schemadn})
196 check_all_substituted(self.schema_data)
198 self.schema_dn_modify = read_and_sub_file(setup_path("provision_schema_basedn_modify.ldif"),
199 {"SCHEMADN": schemadn,
200 "SERVERDN": serverdn,
203 descr = get_schema_descriptor(domain_sid)
204 self.schema_dn_add = read_and_sub_file(setup_path("provision_schema_basedn.ldif"),
205 {"SCHEMADN": schemadn,
209 prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
210 prefixmap = b64encode(prefixmap)
212 # We don't actually add this ldif, just parse it
213 prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % prefixmap
214 self.ldb.set_schema_from_ldif(prefixmap_ldif, self.schema_data)
217 # Return a hash with the forward attribute as a key and the back as the value
218 def get_linked_attributes(schemadn,schemaldb):
219 attrs = ["linkID", "lDAPDisplayName"]
220 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)
222 for i in range (0, len(res)):
223 expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1)
224 target = schemaldb.searchone(basedn=schemadn,
225 expression=expression,
226 attribute="lDAPDisplayName",
228 if target is not None:
229 attributes[str(res[i]["lDAPDisplayName"])]=str(target)
233 def get_dnsyntax_attributes(schemadn,schemaldb):
234 attrs = ["linkID", "lDAPDisplayName"]
235 res = schemaldb.search(expression="(&(!(linkID=*))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
237 for i in range (0, len(res)):
238 attributes.append(str(res[i]["lDAPDisplayName"]))
243 def check_install(lp, session_info, credentials):
244 """Check whether the current install seems ok.
246 :param lp: Loadparm context
247 :param session_info: Session information
248 :param credentials: Credentials
250 if lp.get("realm") == "":
251 raise Exception("Realm empty")
252 ldb = Ldb(lp.get("sam database"), session_info=session_info,
253 credentials=credentials, lp=lp)
254 if len(ldb.search("(cn=Administrator)")) != 1:
255 raise ProvisioningError("No administrator account found")
258 def findnss(nssfn, names):
259 """Find a user or group from a list of possibilities.
261 :param nssfn: NSS Function to try (should raise KeyError if not found)
262 :param names: Names to check.
263 :return: Value return by first names list.
270 raise KeyError("Unable to find user/group %r" % names)
273 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
274 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
277 def read_and_sub_file(file, subst_vars):
278 """Read a file and sub in variables found in it
280 :param file: File to be read (typically from setup directory)
281 param subst_vars: Optional variables to subsitute in the file.
283 data = open(file, 'r').read()
284 if subst_vars is not None:
285 data = substitute_var(data, subst_vars)
286 check_all_substituted(data)
290 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
291 """Setup a ldb in the private dir.
293 :param ldb: LDB file to import data into
294 :param ldif_path: Path of the LDIF file to load
295 :param subst_vars: Optional variables to subsitute in LDIF.
297 assert isinstance(ldif_path, str)
299 data = read_and_sub_file(ldif_path, subst_vars)
303 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
304 """Modify a ldb in the private dir.
306 :param ldb: LDB object.
307 :param ldif_path: LDIF file path.
308 :param subst_vars: Optional dictionary with substitution variables.
310 data = read_and_sub_file(ldif_path, subst_vars)
312 ldb.modify_ldif(data)
315 def setup_ldb(ldb, ldif_path, subst_vars):
316 """Import a LDIF a file into a LDB handle, optionally substituting variables.
318 :note: Either all LDIF data will be added or none (using transactions).
320 :param ldb: LDB file to import into.
321 :param ldif_path: Path to the LDIF file.
322 :param subst_vars: Dictionary with substitution variables.
324 assert ldb is not None
325 ldb.transaction_start()
327 setup_add_ldif(ldb, ldif_path, subst_vars)
329 ldb.transaction_cancel()
331 ldb.transaction_commit()
334 def setup_file(template, fname, subst_vars):
335 """Setup a file in the private dir.
337 :param template: Path of the template file.
338 :param fname: Path of the file to create.
339 :param subst_vars: Substitution variables.
343 if os.path.exists(f):
346 data = read_and_sub_file(template, subst_vars)
347 open(f, 'w').write(data)
350 def provision_paths_from_lp(lp, dnsdomain):
351 """Set the default paths for provisioning.
353 :param lp: Loadparm context.
354 :param dnsdomain: DNS Domain name
356 paths = ProvisionPaths()
357 paths.private_dir = lp.get("private dir")
358 paths.keytab = "secrets.keytab"
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()
700 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
701 netbiosname, domainsid, keytab_path, samdb_url,
702 dns_keytab_path, dnspass, machinepass):
703 """Add DC-specific bits to a secrets database.
705 :param secretsdb: Ldb Handle to the secrets database
706 :param setup_path: Setup path function
707 :param machinepass: Machine password
709 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
710 "MACHINEPASS_B64": b64encode(machinepass),
713 "DNSDOMAIN": dnsdomain,
714 "DOMAINSID": str(domainsid),
715 "SECRETS_KEYTAB": keytab_path,
716 "NETBIOSNAME": netbiosname,
717 "SAM_LDB": samdb_url,
718 "DNS_KEYTAB": dns_keytab_path,
719 "DNSPASS_B64": b64encode(dnspass),
723 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
724 """Setup the secrets database.
726 :param path: Path to the secrets database.
727 :param setup_path: Get the path to a setup file.
728 :param session_info: Session info.
729 :param credentials: Credentials
730 :param lp: Loadparm context
731 :return: LDB handle for the created secrets database
733 if os.path.exists(path):
735 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
738 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
739 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
741 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
743 if credentials is not None and credentials.authentication_requested():
744 if credentials.get_bind_dn() is not None:
745 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
746 "LDAPMANAGERDN": credentials.get_bind_dn(),
747 "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
750 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
751 "LDAPADMINUSER": credentials.get_username(),
752 "LDAPADMINREALM": credentials.get_realm(),
753 "LDAPADMINPASS_B64": b64encode(credentials.get_password())
758 def setup_registry(path, setup_path, session_info, lp):
759 """Setup the registry.
761 :param path: Path to the registry database
762 :param setup_path: Function that returns the path to a setup.
763 :param session_info: Session information
764 :param credentials: Credentials
765 :param lp: Loadparm context
767 reg = registry.Registry()
768 hive = registry.open_ldb(path, session_info=session_info,
770 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
771 provision_reg = setup_path("provision.reg")
772 assert os.path.exists(provision_reg)
773 reg.diff_apply(provision_reg)
776 def setup_idmapdb(path, setup_path, session_info, lp):
777 """Setup the idmap database.
779 :param path: path to the idmap database
780 :param setup_path: Function that returns a path to a setup file
781 :param session_info: Session information
782 :param credentials: Credentials
783 :param lp: Loadparm context
785 if os.path.exists(path):
788 idmap_ldb = IDmapDB(path, session_info=session_info,
792 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
796 def setup_samdb_rootdse(samdb, setup_path, names):
797 """Setup the SamDB rootdse.
799 :param samdb: Sam Database handle
800 :param setup_path: Obtain setup path
802 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
803 "SCHEMADN": names.schemadn,
804 "NETBIOSNAME": names.netbiosname,
805 "DNSDOMAIN": names.dnsdomain,
806 "REALM": names.realm,
807 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
808 "DOMAINDN": names.domaindn,
809 "ROOTDN": names.rootdn,
810 "CONFIGDN": names.configdn,
811 "SERVERDN": names.serverdn,
815 def setup_self_join(samdb, names,
816 machinepass, dnspass,
817 domainsid, invocationid, setup_path,
818 policyguid, policyguid_dc, domainControllerFunctionality):
819 """Join a host to its own domain."""
820 assert isinstance(invocationid, str)
821 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
822 "CONFIGDN": names.configdn,
823 "SCHEMADN": names.schemadn,
824 "DOMAINDN": names.domaindn,
825 "SERVERDN": names.serverdn,
826 "INVOCATIONID": invocationid,
827 "NETBIOSNAME": names.netbiosname,
828 "DEFAULTSITE": names.sitename,
829 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
830 "MACHINEPASS_B64": b64encode(machinepass),
831 "DNSPASS_B64": b64encode(dnspass),
832 "REALM": names.realm,
833 "DOMAIN": names.domain,
834 "DNSDOMAIN": names.dnsdomain,
835 "SAMBA_VERSION_STRING": version,
836 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
838 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
839 "POLICYGUID": policyguid,
840 "POLICYGUID_DC": policyguid_dc,
841 "DNSDOMAIN": names.dnsdomain,
842 "DOMAINSID": str(domainsid),
843 "DOMAINDN": names.domaindn})
845 # add the NTDSGUID based SPNs
846 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
847 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
848 expression="", scope=SCOPE_BASE)
849 assert isinstance(names.ntdsguid, str)
851 # Setup fSMORoleOwner entries to point at the newly created DC entry
852 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
853 "DOMAIN": names.domain,
854 "DNSDOMAIN": names.dnsdomain,
855 "DOMAINDN": names.domaindn,
856 "CONFIGDN": names.configdn,
857 "SCHEMADN": names.schemadn,
858 "DEFAULTSITE": names.sitename,
859 "SERVERDN": names.serverdn,
860 "NETBIOSNAME": names.netbiosname,
861 "NTDSGUID": names.ntdsguid
865 def setup_samdb(path, setup_path, session_info, credentials, lp,
867 domainsid, domainguid, policyguid, policyguid_dc,
868 fill, adminpass, krbtgtpass,
869 machinepass, invocationid, dnspass,
870 serverrole, schema=None, ldap_backend=None):
871 """Setup a complete SAM Database.
873 :note: This will wipe the main SAM database file!
876 domainFunctionality = DS_DOMAIN_FUNCTION_2000
877 forestFunctionality = DS_DOMAIN_FUNCTION_2000
878 domainControllerFunctionality = DS_DC_FUNCTION_2008_R2
880 # Also wipes the database
881 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
882 credentials=credentials, session_info=session_info,
884 ldap_backend=ldap_backend, serverrole=serverrole)
887 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
888 sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type)
890 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
891 samdb = Ldb(session_info=session_info,
892 credentials=credentials, lp=lp)
894 message("Pre-loading the Samba 4 and AD schema")
896 # Load the schema from the one we computed earlier
897 samdb.set_schema_from_ldb(schema.ldb)
899 # And now we can connect to the DB - the schema won't be loaded from the DB
903 samdb.load_ldif_file_add(setup_path("provision_options.ldif"))
908 samdb.transaction_start()
910 message("Erasing data from partitions")
911 # Load the schema (again). This time it will force a reindex,
912 # and will therefore make the erase_partitions() below
913 # computationally sane
914 samdb.set_schema_from_ldb(schema.ldb)
915 samdb.erase_partitions()
917 # Set the domain functionality levels onto the database.
918 # Various module (the password_hash module in particular) need
919 # to know what level of AD we are emulating.
921 # These will be fixed into the database via the database
922 # modifictions below, but we need them set from the start.
923 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
924 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
925 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
927 samdb.set_domain_sid(str(domainsid))
928 if serverrole == "domain controller":
929 samdb.set_invocation_id(invocationid)
931 message("Adding DomainDN: %s" % names.domaindn)
932 if serverrole == "domain controller":
933 domain_oc = "domainDNS"
935 domain_oc = "samba4LocalDomain"
937 #impersonate domain admin
938 admin_session_info = admin_session(lp, str(domainsid))
939 samdb.set_session_info(admin_session_info)
941 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
942 "DOMAINDN": names.domaindn,
943 "DOMAIN_OC": domain_oc
946 message("Modifying DomainDN: " + names.domaindn + "")
947 if domainguid is not None:
948 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
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 "DOMAINGUID_MOD": domainguid_mod,
963 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
964 "SAMBA_VERSION_STRING": version
967 message("Adding configuration container")
968 descr = get_config_descriptor(domainsid);
969 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
970 "CONFIGDN": names.configdn,
973 message("Modifying configuration container")
974 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
975 "CONFIGDN": names.configdn,
976 "SCHEMADN": names.schemadn,
979 # The LDIF here was created when the Schema object was constructed
980 message("Setting up sam.ldb schema")
981 samdb.add_ldif(schema.schema_dn_add)
982 samdb.modify_ldif(schema.schema_dn_modify)
983 samdb.write_prefixes_from_schema()
984 samdb.add_ldif(schema.schema_data)
985 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
986 {"SCHEMADN": names.schemadn})
988 message("Setting up sam.ldb configuration data")
989 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
990 "CONFIGDN": names.configdn,
991 "NETBIOSNAME": names.netbiosname,
992 "DEFAULTSITE": names.sitename,
993 "DNSDOMAIN": names.dnsdomain,
994 "DOMAIN": names.domain,
995 "SCHEMADN": names.schemadn,
996 "DOMAINDN": names.domaindn,
997 "SERVERDN": names.serverdn,
998 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
1001 message("Setting up display specifiers")
1002 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1003 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
1004 check_all_substituted(display_specifiers_ldif)
1005 samdb.add_ldif(display_specifiers_ldif)
1007 message("Adding users container")
1008 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1009 "DOMAINDN": names.domaindn})
1010 message("Modifying users container")
1011 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1012 "DOMAINDN": names.domaindn})
1013 message("Adding computers container")
1014 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1015 "DOMAINDN": names.domaindn})
1016 message("Modifying computers container")
1017 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
1018 "DOMAINDN": names.domaindn})
1019 message("Setting up sam.ldb data")
1020 setup_add_ldif(samdb, setup_path("provision.ldif"), {
1021 "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
1022 "DOMAINDN": names.domaindn,
1023 "NETBIOSNAME": names.netbiosname,
1024 "DEFAULTSITE": names.sitename,
1025 "CONFIGDN": names.configdn,
1026 "SERVERDN": names.serverdn,
1027 "POLICYGUID_DC": policyguid_dc
1030 if fill == FILL_FULL:
1031 message("Setting up sam.ldb users and groups")
1032 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1033 "DOMAINDN": names.domaindn,
1034 "DOMAINSID": str(domainsid),
1035 "CONFIGDN": names.configdn,
1036 "ADMINPASS_B64": b64encode(adminpass),
1037 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1040 if serverrole == "domain controller":
1041 message("Setting up self join")
1042 setup_self_join(samdb, names=names, invocationid=invocationid,
1044 machinepass=machinepass,
1045 domainsid=domainsid, policyguid=policyguid,
1046 policyguid_dc=policyguid_dc,
1047 setup_path=setup_path,
1048 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,
1078 dnspass=None, root=None, nobody=None, users=None,
1079 wheel=None, backup=None, aci=None, serverrole=None,
1080 ldap_backend_extra_port=None, ldap_backend_type=None,
1082 ol_mmr_urls=None, ol_olc=None,
1083 setup_ds_path=None, slapd_path=None, nosync=False,
1084 ldap_dryrun_mode=False):
1087 :note: caution, this wipes all existing data!
1090 def setup_path(file):
1091 return os.path.join(setup_dir, file)
1093 if domainsid is None:
1094 domainsid = security.random_sid()
1096 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)
1120 root_uid = findnss_uid([root or "root"])
1121 nobody_uid = findnss_uid([nobody or "nobody"])
1122 users_gid = findnss_gid([users or "users"])
1124 wheel_gid = findnss_gid(["wheel", "adm"])
1126 wheel_gid = findnss_gid([wheel])
1128 if targetdir is not None:
1129 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1130 os.makedirs(os.path.join(targetdir, "etc"))
1131 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1132 elif smbconf is None:
1133 smbconf = param.default_path()
1135 # only install a new smb.conf if there isn't one there already
1136 if not os.path.exists(smbconf):
1137 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1140 lp = param.LoadParm()
1143 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1144 dnsdomain=realm, serverrole=serverrole, sitename=sitename,
1145 rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1148 paths = provision_paths_from_lp(lp, names.dnsdomain)
1152 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1153 except socket.gaierror, (socket.EAI_NODATA, msg):
1158 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1159 except socket.gaierror, (socket.EAI_NODATA, msg):
1162 if serverrole is None:
1163 serverrole = lp.get("server role")
1165 assert serverrole in ("domain controller", "member server", "standalone")
1166 if invocationid is None and serverrole == "domain controller":
1167 invocationid = str(uuid.uuid4())
1169 if not os.path.exists(paths.private_dir):
1170 os.mkdir(paths.private_dir)
1172 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1174 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
1175 sambadn=names.sambadn, ldap_backend_type=ldap_backend_type)
1177 secrets_credentials = credentials
1178 provision_backend = None
1179 if ldap_backend_type:
1180 # We only support an LDAP backend over ldapi://
1182 provision_backend = ProvisionBackend(paths=paths, setup_path=setup_path,
1183 lp=lp, credentials=credentials,
1185 message=message, hostname=hostname,
1186 root=root, schema=schema,
1187 ldap_backend_type=ldap_backend_type,
1188 ldapadminpass=ldapadminpass,
1189 ldap_backend_extra_port=ldap_backend_extra_port,
1190 ol_mmr_urls=ol_mmr_urls,
1191 slapd_path=slapd_path,
1192 setup_ds_path=setup_ds_path,
1193 ldap_dryrun_mode=ldap_dryrun_mode)
1195 # Now use the backend credentials to access the databases
1196 credentials = provision_backend.credentials
1197 secrets_credentials = provision_backend.adminCredentials
1198 ldapi_url = provision_backend.ldapi_uri
1200 # only install a new shares config db if there is none
1201 if not os.path.exists(paths.shareconf):
1202 message("Setting up share.ldb")
1203 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1204 credentials=credentials, lp=lp)
1205 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1208 message("Setting up secrets.ldb")
1209 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1210 session_info=session_info,
1211 credentials=secrets_credentials, lp=lp)
1213 message("Setting up the registry")
1214 setup_registry(paths.hklm, setup_path, session_info,
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=session_info,
1223 credentials=credentials, lp=lp, names=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 serverrole=serverrole, ldap_backend=provision_backend)
1234 if serverrole == "domain controller":
1235 if paths.netlogon is None:
1236 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1237 message("Please either remove %s or see the template at %s" %
1238 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1239 assert(paths.netlogon is not None)
1241 if paths.sysvol is None:
1242 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1243 message("Please either remove %s or see the template at %s" %
1244 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1245 assert(paths.sysvol is not None)
1247 # Set up group policies (domain policy and domain controller policy)
1249 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1250 "{" + policyguid + "}")
1251 os.makedirs(policy_path, 0755)
1252 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1253 "[General]\r\nVersion=65543")
1254 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
1255 os.makedirs(os.path.join(policy_path, "USER"), 0755)
1257 policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1258 "{" + policyguid_dc + "}")
1259 os.makedirs(policy_path_dc, 0755)
1260 open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
1261 "[General]\r\nVersion=2")
1262 os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
1263 os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
1265 if not os.path.isdir(paths.netlogon):
1266 os.makedirs(paths.netlogon, 0755)
1268 if samdb_fill == FILL_FULL:
1269 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1270 root_uid=root_uid, nobody_uid=nobody_uid,
1271 users_gid=users_gid, wheel_gid=wheel_gid)
1273 message("Setting up sam.ldb rootDSE marking as synchronized")
1274 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1276 # Only make a zone file on the first DC, it should be replicated with DNS replication
1277 if serverrole == "domain controller":
1278 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
1279 credentials=credentials, lp=lp)
1280 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain,
1282 netbiosname=names.netbiosname,
1283 domainsid=domainsid,
1284 keytab_path=paths.keytab, samdb_url=paths.samdb,
1285 dns_keytab_path=paths.dns_keytab,
1286 dnspass=dnspass, machinepass=machinepass,
1287 dnsdomain=names.dnsdomain)
1289 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1290 assert isinstance(domainguid, str)
1292 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1293 domaindn=names.domaindn, hostip=hostip,
1294 hostip6=hostip6, hostname=names.hostname,
1295 dnspass=dnspass, realm=names.realm,
1296 domainguid=domainguid, ntdsguid=names.ntdsguid)
1298 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1299 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1301 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1302 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1303 keytab_name=paths.dns_keytab)
1304 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1305 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1307 create_krb5_conf(paths.krb5conf, setup_path,
1308 dnsdomain=names.dnsdomain, hostname=names.hostname,
1310 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1313 if provision_backend is not None:
1314 if ldap_backend_type == "fedora-ds":
1315 ldapi_db = Ldb(provision_backend.ldapi_uri, lp=lp, credentials=credentials)
1317 # delete default SASL mappings
1318 res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
1320 # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
1321 for i in range (0, len(res)):
1322 dn = str(res[i]["dn"])
1325 aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % names.sambadn
1328 m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
1330 m.dn = ldb.Dn(1, names.domaindn)
1333 m.dn = ldb.Dn(1, names.configdn)
1336 m.dn = ldb.Dn(1, names.schemadn)
1339 # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
1340 if provision_backend.slapd.poll() is None:
1342 if hasattr(provision_backend.slapd, "terminate"):
1343 provision_backend.slapd.terminate()
1345 # Older python versions don't have .terminate()
1347 os.kill(provision_backend.slapd.pid, signal.SIGTERM)
1349 #and now wait for it to die
1350 provision_backend.slapd.communicate()
1352 # now display slapd_command_file.txt to show how slapd must be started next time
1353 message("Use later the following commandline to start slapd, then Samba:")
1354 slapd_command = "\'" + "\' \'".join(provision_backend.slapd_command) + "\'"
1355 message(slapd_command)
1356 message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
1358 setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
1359 "SLAPD_COMMAND" : slapd_command})
1362 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1365 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1367 message("Once the above files are installed, your Samba4 server will be ready to use")
1368 message("Server Role: %s" % serverrole)
1369 message("Hostname: %s" % names.hostname)
1370 message("NetBIOS Domain: %s" % names.domain)
1371 message("DNS Domain: %s" % names.dnsdomain)
1372 message("DOMAIN SID: %s" % str(domainsid))
1373 if samdb_fill == FILL_FULL:
1374 message("Admin password: %s" % adminpass)
1375 if provision_backend:
1376 if provision_backend.credentials.get_bind_dn() is not None:
1377 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1379 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1381 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1383 result = ProvisionResult()
1384 result.domaindn = domaindn
1385 result.paths = paths
1387 result.samdb = samdb
1392 def provision_become_dc(setup_dir=None,
1393 smbconf=None, targetdir=None, realm=None,
1394 rootdn=None, domaindn=None, schemadn=None,
1395 configdn=None, serverdn=None,
1396 domain=None, hostname=None, domainsid=None,
1397 adminpass=None, krbtgtpass=None, domainguid=None,
1398 policyguid=None, policyguid_dc=None, invocationid=None,
1400 dnspass=None, root=None, nobody=None, users=None,
1401 wheel=None, backup=None, serverrole=None,
1402 ldap_backend=None, ldap_backend_type=None,
1403 sitename=None, debuglevel=1):
1406 """print a message if quiet is not set."""
1409 glue.set_debug_level(debuglevel)
1411 return provision(setup_dir, message, system_session(), None,
1412 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1413 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1414 configdn=configdn, serverdn=serverdn, domain=domain,
1415 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1416 machinepass=machinepass, serverrole="domain controller",
1420 def setup_db_config(setup_path, dbdir):
1421 """Setup a Berkeley database.
1423 :param setup_path: Setup path function.
1424 :param dbdir: Database directory."""
1425 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
1426 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
1427 if not os.path.isdir(os.path.join(dbdir, "tmp")):
1428 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
1430 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
1431 {"LDAPDBDIR": dbdir})
1433 class ProvisionBackend(object):
1434 def __init__(self, paths=None, setup_path=None, lp=None, credentials=None,
1435 names=None, message=None,
1436 hostname=None, root=None,
1437 schema=None, ldapadminpass=None,
1438 ldap_backend_type=None, ldap_backend_extra_port=None,
1440 setup_ds_path=None, slapd_path=None,
1441 nosync=False, ldap_dryrun_mode=False):
1442 """Provision an LDAP backend for samba4
1444 This works for OpenLDAP and Fedora DS
1447 self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
1449 if not os.path.isdir(paths.ldapdir):
1450 os.makedirs(paths.ldapdir, 0700)
1452 if ldap_backend_type == "existing":
1453 #Check to see that this 'existing' LDAP backend in fact exists
1454 ldapi_db = Ldb(self.ldapi_uri, credentials=credentials)
1455 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1456 expression="(objectClass=OpenLDAProotDSE)")
1458 # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
1459 # This caused them to be set into the long-term database later in the script.
1460 self.credentials = credentials
1461 self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
1464 # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri
1465 # if another instance of slapd is already running
1467 ldapi_db = Ldb(self.ldapi_uri)
1468 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1469 expression="(objectClass=OpenLDAProotDSE)");
1471 f = open(paths.slapdpid, "r")
1474 message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.")
1478 raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ")
1483 # Try to print helpful messages when the user has not specified the path to slapd
1484 if slapd_path is None:
1485 raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
1486 if not os.path.exists(slapd_path):
1487 message (slapd_path)
1488 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
1490 schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
1492 os.unlink(schemadb_path)
1497 # Put the LDIF of the schema into a database so we can search on
1498 # it to generate schema-dependent configurations in Fedora DS and
1500 os.path.join(paths.ldapdir, "schema-tmp.ldb")
1501 schema.ldb.connect(schemadb_path)
1502 schema.ldb.transaction_start()
1504 # These bits of LDIF are supplied when the Schema object is created
1505 schema.ldb.add_ldif(schema.schema_dn_add)
1506 schema.ldb.modify_ldif(schema.schema_dn_modify)
1507 schema.ldb.add_ldif(schema.schema_data)
1508 schema.ldb.transaction_commit()
1510 self.credentials = Credentials()
1511 self.credentials.guess(lp)
1512 #Kerberos to an ldapi:// backend makes no sense
1513 self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
1515 self.adminCredentials = Credentials()
1516 self.adminCredentials.guess(lp)
1517 #Kerberos to an ldapi:// backend makes no sense
1518 self.adminCredentials.set_kerberos_state(DONT_USE_KERBEROS)
1520 self.ldap_backend_type = ldap_backend_type
1522 if ldap_backend_type == "fedora-ds":
1523 provision_fds_backend(self, paths=paths, setup_path=setup_path,
1524 names=names, message=message,
1526 ldapadminpass=ldapadminpass, root=root,
1528 ldap_backend_extra_port=ldap_backend_extra_port,
1529 setup_ds_path=setup_ds_path,
1530 slapd_path=slapd_path,
1532 ldap_dryrun_mode=ldap_dryrun_mode)
1534 elif ldap_backend_type == "openldap":
1535 provision_openldap_backend(self, paths=paths, setup_path=setup_path,
1536 names=names, message=message,
1538 ldapadminpass=ldapadminpass, root=root,
1540 ldap_backend_extra_port=ldap_backend_extra_port,
1541 ol_mmr_urls=ol_mmr_urls,
1542 slapd_path=slapd_path,
1544 ldap_dryrun_mode=ldap_dryrun_mode)
1546 raise ProvisioningError("Unknown LDAP backend type selected")
1548 self.credentials.set_password(ldapadminpass)
1549 self.adminCredentials.set_username("samba-admin")
1550 self.adminCredentials.set_password(ldapadminpass)
1552 # Now start the slapd, so we can provision onto it. We keep the
1553 # subprocess context around, to kill this off at the successful
1555 self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False)
1557 while self.slapd.poll() is None:
1558 # Wait until the socket appears
1560 ldapi_db = Ldb(self.ldapi_uri, lp=lp, credentials=self.credentials)
1561 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
1562 expression="(objectClass=OpenLDAProotDSE)")
1563 # If we have got here, then we must have a valid connection to the LDAP server!
1569 raise ProvisioningError("slapd died before we could make a connection to it")
1572 def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
1574 hostname=None, ldapadminpass=None, root=None,
1576 ldap_backend_extra_port=None,
1578 slapd_path=None, nosync=False,
1579 ldap_dryrun_mode=False):
1581 #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
1584 nosync_config = "dbnosync"
1586 lnkattr = get_linked_attributes(names.schemadn,schema.ldb)
1587 refint_attributes = ""
1588 memberof_config = "# Generated from Samba4 schema\n"
1589 for att in lnkattr.keys():
1590 if lnkattr[att] is not None:
1591 refint_attributes = refint_attributes + " " + att
1593 memberof_config += read_and_sub_file(setup_path("memberof.conf"),
1594 { "MEMBER_ATTR" : att ,
1595 "MEMBEROF_ATTR" : lnkattr[att] })
1597 refint_config = read_and_sub_file(setup_path("refint.conf"),
1598 { "LINK_ATTRS" : refint_attributes})
1600 attrs = ["linkID", "lDAPDisplayName"]
1601 res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
1603 for i in range (0, len(res)):
1604 index_attr = res[i]["lDAPDisplayName"][0]
1605 if index_attr == "objectGUID":
1606 index_attr = "entryUUID"
1608 index_config += "index " + index_attr + " eq\n"
1610 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1612 mmr_replicator_acl = ""
1613 mmr_serverids_config = ""
1614 mmr_syncrepl_schema_config = ""
1615 mmr_syncrepl_config_config = ""
1616 mmr_syncrepl_user_config = ""
1619 if ol_mmr_urls is not None:
1620 # For now, make these equal
1621 mmr_pass = ldapadminpass
1623 url_list=filter(None,ol_mmr_urls.split(' '))
1624 if (len(url_list) == 1):
1625 url_list=filter(None,ol_mmr_urls.split(','))
1628 mmr_on_config = "MirrorMode On"
1629 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
1631 for url in url_list:
1633 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
1634 { "SERVERID" : str(serverid),
1635 "LDAPSERVER" : url })
1638 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1640 "MMRDN": names.schemadn,
1642 "MMR_PASSWORD": mmr_pass})
1645 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1647 "MMRDN": names.configdn,
1649 "MMR_PASSWORD": mmr_pass})
1652 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1654 "MMRDN": names.domaindn,
1656 "MMR_PASSWORD": mmr_pass })
1657 # OpenLDAP cn=config initialisation
1658 olc_syncrepl_config = ""
1660 # if mmr = yes, generate cn=config-replication directives
1661 # and olc_seed.lif for the other mmr-servers
1662 if ol_mmr_urls is not None:
1664 olc_serverids_config = ""
1665 olc_syncrepl_seed_config = ""
1666 olc_mmr_config += read_and_sub_file(setup_path("olc_mmr.conf"),{})
1668 for url in url_list:
1670 olc_serverids_config += read_and_sub_file(setup_path("olc_serverid.conf"),
1671 { "SERVERID" : str(serverid),
1672 "LDAPSERVER" : url })
1675 olc_syncrepl_config += read_and_sub_file(setup_path("olc_syncrepl.conf"),
1678 "MMR_PASSWORD": mmr_pass})
1680 olc_syncrepl_seed_config += read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
1682 "LDAPSERVER" : url})
1684 setup_file(setup_path("olc_seed.ldif"), paths.olcseedldif,
1685 {"OLC_SERVER_ID_CONF": olc_serverids_config,
1686 "OLC_PW": ldapadminpass,
1687 "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
1690 setup_file(setup_path("slapd.conf"), paths.slapdconf,
1691 {"DNSDOMAIN": names.dnsdomain,
1692 "LDAPDIR": paths.ldapdir,
1693 "DOMAINDN": names.domaindn,
1694 "CONFIGDN": names.configdn,
1695 "SCHEMADN": names.schemadn,
1696 "MEMBEROF_CONFIG": memberof_config,
1697 "MIRRORMODE": mmr_on_config,
1698 "REPLICATOR_ACL": mmr_replicator_acl,
1699 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
1700 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
1701 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
1702 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
1703 "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
1704 "OLC_MMR_CONFIG": olc_mmr_config,
1705 "REFINT_CONFIG": refint_config,
1706 "INDEX_CONFIG": index_config,
1707 "NOSYNC": nosync_config})
1709 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
1710 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
1711 setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
1713 if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
1714 os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
1716 setup_file(setup_path("cn=samba.ldif"),
1717 os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
1718 { "UUID": str(uuid.uuid4()),
1719 "LDAPTIME": timestring(int(time.time()))} )
1720 setup_file(setup_path("cn=samba-admin.ldif"),
1721 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1722 {"LDAPADMINPASS_B64": b64encode(ldapadminpass),
1723 "UUID": str(uuid.uuid4()),
1724 "LDAPTIME": timestring(int(time.time()))} )
1726 if ol_mmr_urls is not None:
1727 setup_file(setup_path("cn=replicator.ldif"),
1728 os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1729 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
1730 "UUID": str(uuid.uuid4()),
1731 "LDAPTIME": timestring(int(time.time()))} )
1734 mapping = "schema-map-openldap-2.3"
1735 backend_schema = "backend-schema.schema"
1737 backend_schema_data = schema.ldb.convert_schema_to_openldap("openldap", open(setup_path(mapping), 'r').read())
1738 assert backend_schema_data is not None
1739 open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
1741 # now we generate the needed strings to start slapd automatically,
1742 # first ldapi_uri...
1743 if ldap_backend_extra_port is not None:
1744 # When we use MMR, we can't use 0.0.0.0 as it uses the name
1745 # specified there as part of it's clue as to it's own name,
1746 # and not to replicate to itself
1747 if ol_mmr_urls is None:
1748 server_port_string = "ldap://0.0.0.0:%d" % ldap_backend_extra_port
1750 server_port_string = "ldap://" + names.hostname + "." + names.dnsdomain +":%d" % ldap_backend_extra_port
1752 server_port_string = ""
1754 # Prepare the 'result' information - the commands to return in particular
1755 result.slapd_provision_command = [slapd_path]
1757 result.slapd_provision_command.append("-F" + paths.olcdir)
1759 result.slapd_provision_command.append("-h")
1761 # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands
1762 result.slapd_command = list(result.slapd_provision_command)
1764 result.slapd_provision_command.append(result.ldapi_uri)
1765 result.slapd_provision_command.append("-d0")
1767 uris = result.ldapi_uri
1768 if server_port_string is not "":
1769 uris = uris + " " + server_port_string
1771 result.slapd_command.append(uris)
1773 # Set the username - done here because Fedora DS still uses the admin DN and simple bind
1774 result.credentials.set_username("samba-admin")
1776 # If we were just looking for crashes up to this point, it's a
1777 # good time to exit before we realise we don't have OpenLDAP on
1779 if ldap_dryrun_mode:
1782 # Finally, convert the configuration into cn=config style!
1783 if not os.path.isdir(paths.olcdir):
1784 os.makedirs(paths.olcdir, 0770)
1786 retcode = subprocess.call([slapd_path, "-Ttest", "-f", paths.slapdconf, "-F", paths.olcdir], close_fds=True, shell=False)
1788 # We can't do this, as OpenLDAP is strange. It gives an error
1789 # output to the above, but does the conversion sucessfully...
1792 # raise ProvisioningError("conversion from slapd.conf to cn=config failed")
1794 if not os.path.exists(os.path.join(paths.olcdir, "cn=config.ldif")):
1795 raise ProvisioningError("conversion from slapd.conf to cn=config failed")
1797 # Don't confuse the admin by leaving the slapd.conf around
1798 os.remove(paths.slapdconf)
1801 def provision_fds_backend(result, paths=None, setup_path=None, names=None,
1803 hostname=None, ldapadminpass=None, root=None,
1805 ldap_backend_extra_port=None,
1809 ldap_dryrun_mode=False):
1811 if ldap_backend_extra_port is not None:
1812 serverport = "ServerPort=%d" % ldap_backend_extra_port
1816 setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
1818 "HOSTNAME": hostname,
1819 "DNSDOMAIN": names.dnsdomain,
1820 "LDAPDIR": paths.ldapdir,
1821 "DOMAINDN": names.domaindn,
1822 "LDAPMANAGERDN": names.ldapmanagerdn,
1823 "LDAPMANAGERPASS": ldapadminpass,
1824 "SERVERPORT": serverport})
1826 setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
1827 {"CONFIGDN": names.configdn,
1828 "SCHEMADN": names.schemadn,
1829 "SAMBADN": names.sambadn,
1832 setup_file(setup_path("fedorads-sasl.ldif"), paths.fedoradssasl,
1833 {"SAMBADN": names.sambadn,
1836 setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba,
1837 {"SAMBADN": names.sambadn,
1838 "LDAPADMINPASS": ldapadminpass
1841 mapping = "schema-map-fedora-ds-1.0"
1842 backend_schema = "99_ad.ldif"
1844 # Build a schema file in Fedora DS format
1845 backend_schema_data = schema.ldb.convert_schema_to_openldap("fedora-ds", open(setup_path(mapping), 'r').read())
1846 assert backend_schema_data is not None
1847 open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
1849 result.credentials.set_bind_dn(names.ldapmanagerdn)
1851 # Destory the target directory, or else setup-ds.pl will complain
1852 fedora_ds_dir = os.path.join(paths.ldapdir, "slapd-samba4")
1853 shutil.rmtree(fedora_ds_dir, True)
1855 result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", paths.slapdpid];
1856 #In the 'provision' command line, stay in the foreground so we can easily kill it
1857 result.slapd_provision_command.append("-d0")
1859 #the command for the final run is the normal script
1860 result.slapd_command = [os.path.join(paths.ldapdir, "slapd-samba4", "start-slapd")]
1862 # If we were just looking for crashes up to this point, it's a
1863 # good time to exit before we realise we don't have Fedora DS on
1864 if ldap_dryrun_mode:
1867 # Try to print helpful messages when the user has not specified the path to the setup-ds tool
1868 if setup_ds_path is None:
1869 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\"!")
1870 if not os.path.exists(setup_ds_path):
1871 message (setup_ds_path)
1872 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
1874 # Run the Fedora DS setup utility
1875 retcode = subprocess.call([setup_ds_path, "--silent", "--file", paths.fedoradsinf], close_fds=True, shell=False)
1877 raise ProvisioningError("setup-ds failed")
1880 retcode = subprocess.call([
1881 os.path.join(paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", paths.fedoradssamba],
1882 close_fds=True, shell=False)
1884 raise("ldib2db failed")
1886 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1887 """Create a PHP LDAP admin configuration file.
1889 :param path: Path to write the configuration to.
1890 :param setup_path: Function to generate setup paths.
1892 setup_file(setup_path("phpldapadmin-config.php"), path,
1893 {"S4_LDAPI_URI": ldapi_uri})
1896 def create_zone_file(path, setup_path, dnsdomain, domaindn,
1897 hostip, hostip6, hostname, dnspass, realm, domainguid,
1899 """Write out a DNS zone file, from the info in the current database.
1901 :param path: Path of the new zone file.
1902 :param setup_path: Setup path function.
1903 :param dnsdomain: DNS Domain name
1904 :param domaindn: DN of the Domain
1905 :param hostip: Local IPv4 IP
1906 :param hostip6: Local IPv6 IP
1907 :param hostname: Local hostname
1908 :param dnspass: Password for DNS
1909 :param realm: Realm name
1910 :param domainguid: GUID of the domain.
1911 :param ntdsguid: GUID of the hosts nTDSDSA record.
1913 assert isinstance(domainguid, str)
1915 if hostip6 is not None:
1916 hostip6_base_line = " IN AAAA " + hostip6
1917 hostip6_host_line = hostname + " IN AAAA " + hostip6
1919 hostip6_base_line = ""
1920 hostip6_host_line = ""
1922 if hostip is not None:
1923 hostip_base_line = " IN A " + hostip
1924 hostip_host_line = hostname + " IN A " + hostip
1926 hostip_base_line = ""
1927 hostip_host_line = ""
1929 setup_file(setup_path("provision.zone"), path, {
1930 "DNSPASS_B64": b64encode(dnspass),
1931 "HOSTNAME": hostname,
1932 "DNSDOMAIN": dnsdomain,
1934 "HOSTIP_BASE_LINE": hostip_base_line,
1935 "HOSTIP_HOST_LINE": hostip_host_line,
1936 "DOMAINGUID": domainguid,
1937 "DATESTRING": time.strftime("%Y%m%d%H"),
1938 "DEFAULTSITE": DEFAULTSITE,
1939 "NTDSGUID": ntdsguid,
1940 "HOSTIP6_BASE_LINE": hostip6_base_line,
1941 "HOSTIP6_HOST_LINE": hostip6_host_line,
1945 def create_named_conf(path, setup_path, realm, dnsdomain,
1947 """Write out a file containing zone statements suitable for inclusion in a
1948 named.conf file (including GSS-TSIG configuration).
1950 :param path: Path of the new named.conf file.
1951 :param setup_path: Setup path function.
1952 :param realm: Realm name
1953 :param dnsdomain: DNS Domain name
1954 :param private_dir: Path to private directory
1955 :param keytab_name: File name of DNS keytab file
1958 setup_file(setup_path("named.conf"), path, {
1959 "DNSDOMAIN": dnsdomain,
1961 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1962 "PRIVATE_DIR": private_dir
1965 def create_named_txt(path, setup_path, realm, dnsdomain,
1966 private_dir, keytab_name):
1967 """Write out a file containing zone statements suitable for inclusion in a
1968 named.conf file (including GSS-TSIG configuration).
1970 :param path: Path of the new named.conf file.
1971 :param setup_path: Setup path function.
1972 :param realm: Realm name
1973 :param dnsdomain: DNS Domain name
1974 :param private_dir: Path to private directory
1975 :param keytab_name: File name of DNS keytab file
1978 setup_file(setup_path("named.txt"), path, {
1979 "DNSDOMAIN": dnsdomain,
1981 "DNS_KEYTAB": keytab_name,
1982 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1983 "PRIVATE_DIR": private_dir
1986 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1987 """Write out a file containing zone statements suitable for inclusion in a
1988 named.conf file (including GSS-TSIG configuration).
1990 :param path: Path of the new named.conf file.
1991 :param setup_path: Setup path function.
1992 :param dnsdomain: DNS Domain name
1993 :param hostname: Local hostname
1994 :param realm: Realm name
1997 setup_file(setup_path("krb5.conf"), path, {
1998 "DNSDOMAIN": dnsdomain,
1999 "HOSTNAME": hostname,