2 # backend code for provisioning a Samba4 server
3 # Released under the GNU GPL v3 or later
4 # Copyright Jelmer Vernooij 2007
6 # Based on the original in EJS:
7 # Copyright Andrew Tridgell 2005
10 from base64 import b64encode
16 from socket import gethostname, gethostbyname
20 from samba import Ldb, substitute_var, valid_netbios_name
21 from samba.samdb import SamDB
23 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
24 LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
26 """Functions for setting up a Samba configuration."""
28 DEFAULTSITE = "Default-First-Site-Name"
30 class InvalidNetbiosName(Exception):
31 def __init__(self, name):
32 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
48 self.dns_keytab = None
51 self.ldap_basedn_ldif = None
52 self.ldap_config_basedn_ldif = None
53 self.ldap_schema_basedn_ldif = None
56 def install_ok(lp, session_info, credentials):
57 """Check whether the current install seems ok.
59 :param lp: Loadparm context
60 :param session_info: Session information
61 :param credentials: Credentials
63 if lp.get("realm") == "":
65 ldb = Ldb(lp.get("sam database"), session_info=session_info,
66 credentials=credentials, lp=lp)
67 if len(ldb.search("(cn=Administrator)")) != 1:
72 def findnss(nssfn, *names):
73 """Find a user or group from a list of possibilities."""
79 raise Exception("Unable to find user/group for %s" % arguments[1])
82 def open_ldb(session_info, credentials, lp, dbname):
83 """Open a LDB, thrashing it if it is corrupt.
85 :param session_info: auth session information
86 :param credentials: credentials
87 :param lp: Loadparm context
88 :param dbname: Path of the database to open.
91 assert session_info is not None
93 return Ldb(dbname, session_info=session_info, credentials=credentials,
98 return Ldb(dbname, session_info=session_info, credentials=credentials,
102 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
103 """Setup a ldb in the private dir.
105 :param ldb: LDB file to import data into
106 :param ldif_path: Path of the LDIF file to load
107 :param subst_vars: Optional variables to subsitute in LDIF.
109 assert isinstance(ldif_path, str)
111 data = open(ldif_path, 'r').read()
112 if subst_vars is not None:
113 data = substitute_var(data, subst_vars)
115 assert "${" not in data
120 def setup_modify_ldif(ldb, ldif_path, substvars=None):
121 """Modify a ldb in the private dir.
123 :param ldb: LDB object.
124 :param ldif_path: LDIF file path.
125 :param substvars: Optional dictionary with substitution variables.
127 data = open(ldif_path, 'r').read()
128 if substvars is not None:
129 data = substitute_var(data, substvars)
131 assert "${" not in data
133 ldb.modify_ldif(data)
136 def setup_ldb(ldb, ldif_path, subst_vars):
137 assert ldb is not None
138 ldb.transaction_start()
140 setup_add_ldif(ldb, ldif_path, subst_vars)
142 ldb.transaction_cancel()
144 ldb.transaction_commit()
147 def setup_file(template, fname, substvars):
148 """Setup a file in the private dir.
150 :param template: Path of the template file.
151 :param fname: Path of the file to create.
152 :param substvars: Substitution variables.
156 if os.path.exists(f):
159 data = open(template, 'r').read()
161 data = substitute_var(data, substvars)
162 assert not "${" in data
164 open(f, 'w').write(data)
167 def provision_paths_from_lp(lp, dnsdomain):
168 """Set the default paths for provisioning.
170 :param lp: Loadparm context.
171 :param dnsdomain: DNS Domain name
173 paths = ProvisionPaths()
174 private_dir = lp.get("private dir")
175 paths.shareconf = os.path.join(private_dir, "share.ldb")
176 paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb")
177 paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb")
178 paths.templates = os.path.join(private_dir, "templates.ldb")
179 paths.keytab = os.path.join(private_dir, "secrets.keytab")
180 paths.dns_keytab = os.path.join(private_dir, "dns.keytab")
181 paths.dns = os.path.join(private_dir, dnsdomain + ".zone")
182 paths.winsdb = os.path.join(private_dir, "wins.ldb")
183 paths.s4_ldapi_path = os.path.join(private_dir, "ldapi")
184 paths.phpldapadminconfig = os.path.join(private_dir,
185 "phpldapadmin-config.php")
186 paths.hklm = os.path.join(private_dir, "hklm.ldb")
187 paths.sysvol = lp.get("sysvol", "path")
188 if paths.sysvol is None:
189 paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol")
191 paths.netlogon = lp.get("netlogon", "path")
192 if paths.netlogon is None:
193 paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts"))
198 def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users,
200 """setup reasonable name mappings for sam names to unix names.
202 :param ldb: SamDB object.
203 :param sid: The domain sid.
204 :param domaindn: The domain DN.
205 :param root: Name of the UNIX root user.
206 :param nobody: Name of the UNIX nobody user.
207 :param nogroup: Name of the unix nobody group.
208 :param users: Name of the unix users group.
209 :param wheel: Name of the wheel group (users that can become root).
210 :param backup: Name of the backup group."""
211 # add some foreign sids if they are not present already
212 ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
213 ldb.add_foreign(domaindn, "S-1-1-0", "World")
214 ldb.add_foreign(domaindn, "S-1-5-2", "Network")
215 ldb.add_foreign(domaindn, "S-1-5-18", "System")
216 ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
218 # some well known sids
219 ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody)
220 ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup)
221 ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup)
222 ldb.setup_name_mapping(domaindn, "S-1-5-18", root)
223 ldb.setup_name_mapping(domaindn, "S-1-5-11", users)
224 ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel)
225 ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users)
226 ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup)
227 ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup)
229 # and some well known domain rids
230 ldb.setup_name_mapping(domaindn, sid + "-500", root)
231 ldb.setup_name_mapping(domaindn, sid + "-518", wheel)
232 ldb.setup_name_mapping(domaindn, sid + "-519", wheel)
233 ldb.setup_name_mapping(domaindn, sid + "-512", wheel)
234 ldb.setup_name_mapping(domaindn, sid + "-513", users)
235 ldb.setup_name_mapping(domaindn, sid + "-520", wheel)
238 def provision_become_dc(setup_dir, message, paths, lp, session_info,
240 assert session_info is not None
243 def setup_path(file):
244 return os.path.join(setup_dir, file)
245 os.path.unlink(paths.samdb)
247 message("Setting up templates db")
248 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
249 credentials=credentials, lp=lp)
251 # Also wipes the database
252 message("Setting up sam.ldb")
253 samdb = SamDB(paths.samdb, session_info=session_info,
254 credentials=credentials, lp=lp)
256 message("Setting up sam.ldb partitions")
257 setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn)
259 samdb = SamDB(paths.samdb, session_info=session_info,
260 credentials=credentials, lp=lp)
262 ldb.transaction_start()
264 message("Setting up sam.ldb attributes")
265 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
267 message("Setting up sam.ldb rootDSE")
268 setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn,
269 hostname, dnsdomain, realm, rootdn, configdn,
273 message("Erasing data from partitions")
274 samdb.erase_partitions()
276 message("Setting up sam.ldb indexes")
277 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
279 samdb.transaction_cancel()
282 samdb.transaction_commit()
284 message("Setting up %s" % paths.secrets)
285 secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info,
287 setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"),
288 { "MACHINEPASS_B64": b64encode(machinepass) })
291 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
292 if os.path.exists(path):
294 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp)
296 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
297 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
301 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
302 templates_ldb = SamDB(path, session_info=session_info,
303 credentials=credentials, lp=lp)
304 templates_ldb.erase()
305 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
308 def setup_registry(path, setup_path, session_info, credentials, lp):
309 reg = registry.Registry()
310 hive = registry.open_ldb(path, session_info=session_info,
311 credentials=credentials, lp_ctx=lp)
312 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
313 provision_reg = setup_path("provision.reg")
314 assert os.path.exists(provision_reg)
315 reg.diff_apply(provision_reg)
318 def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname,
319 dnsdomain, realm, rootdn, configdn, netbiosname):
320 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
321 "SCHEMADN": schemadn,
322 "NETBIOSNAME": netbiosname,
323 "DNSDOMAIN": dnsdomain,
324 "DEFAULTSITE": DEFAULTSITE,
326 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
327 "DOMAINDN": domaindn,
329 "CONFIGDN": configdn,
330 "VERSION": samba.version(),
334 def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn):
335 #Add modules to the list to activate them by default
336 #beware often order is important
338 # Some Known ordering constraints:
339 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
340 # - objectclass must be before password_hash, because password_hash checks
341 # that the objectclass is of type person (filled in by objectclass
342 # module when expanding the objectclass list)
343 # - partition must be last
344 # - each partition has its own module list then
345 modules_list = ["rootdse",
361 modules_list2 = ["show_deleted",
364 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
365 "SCHEMADN": schemadn,
366 "SCHEMADN_LDB": "schema.ldb",
367 "SCHEMADN_MOD2": ",objectguid",
368 "CONFIGDN": configdn,
369 "CONFIGDN_LDB": "configuration.ldb",
370 "DOMAINDN": domaindn,
371 "DOMAINDN_LDB": "users.ldb",
372 "SCHEMADN_MOD": "schema_fsmo",
373 "CONFIGDN_MOD": "naming_fsmo",
374 "CONFIGDN_MOD2": ",objectguid",
375 "DOMAINDN_MOD": "pdc_fsmo,password_hash",
376 "DOMAINDN_MOD2": ",objectguid",
377 "MODULES_LIST": ",".join(modules_list),
378 "TDB_MODULES_LIST": ","+",".join(tdb_modules_list),
379 "MODULES_LIST2": ",".join(modules_list2),
383 def setup_self_join(samdb, configdn, schemadn, domaindn,
384 netbiosname, hostname, dnsdomain, machinepass, dnspass,
385 realm, domainname, domainsid, invocationid, setup_path,
386 policyguid, hostguid=None):
387 if hostguid is not None:
388 hostguid_add = "objectGUID: %s" % hostguid
392 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
393 "CONFIGDN": configdn,
394 "SCHEMADN": schemadn,
395 "DOMAINDN": domaindn,
396 "INVOCATIONID": invocationid,
397 "NETBIOSNAME": netbiosname,
398 "DEFAULTSITE": DEFAULTSITE,
399 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
400 "MACHINEPASS_B64": b64encode(machinepass),
401 "DNSPASS_B64": b64encode(dnspass),
403 "DOMAIN": domainname,
404 "HOSTGUID_ADD": hostguid_add,
405 "DNSDOMAIN": dnsdomain})
406 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
407 "POLICYGUID": policyguid,
408 "DNSDOMAIN": dnsdomain,
409 "DOMAINSID": str(domainsid),
410 "DOMAINDN": domaindn})
413 def setup_samdb(path, setup_path, session_info, credentials, lp,
414 schemadn, configdn, domaindn, dnsdomain, realm,
415 netbiosname, message, hostname, rootdn, erase,
416 domainsid, aci, rdn_dc, domainguid, policyguid,
417 domainname, blank, adminpass, krbtgtpass,
418 machinepass, hostguid, invocationid, dnspass):
419 # Also wipes the database
420 message("Setting up sam.ldb")
421 samdb = SamDB(path, session_info=session_info,
422 credentials=credentials, lp=lp)
424 message("Setting up sam.ldb partitions")
425 setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn)
427 samdb = SamDB(path, session_info=session_info,
428 credentials=credentials, lp=lp)
430 samdb.transaction_start()
432 message("Setting up sam.ldb attributes")
433 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
435 message("Setting up sam.ldb rootDSE")
436 setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn,
437 hostname, dnsdomain, realm, rootdn, configdn,
441 message("Erasing data from partitions")
442 samdb.erase_partitions()
444 samdb.transaction_cancel()
447 samdb.transaction_commit()
449 message("Pre-loading the Samba 4 and AD schema")
450 samdb = SamDB(path, session_info=session_info,
451 credentials=credentials, lp=lp)
452 samdb.set_domain_sid(domainsid)
453 load_schema(setup_path, samdb, schemadn, netbiosname, configdn)
455 samdb.transaction_start()
458 message("Adding DomainDN: %s (permitted to fail)" % domaindn)
459 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
460 "DOMAINDN": domaindn,
465 message("Modifying DomainDN: " + domaindn + "")
466 if domainguid is not None:
467 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
471 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
473 "LDAPTIME": timestring(int(time.time())),
474 "DOMAINSID": str(domainsid),
475 "SCHEMADN": schemadn,
476 "NETBIOSNAME": netbiosname,
477 "DEFAULTSITE": DEFAULTSITE,
478 "CONFIGDN": configdn,
479 "POLICYGUID": policyguid,
480 "DOMAINDN": domaindn,
481 "DOMAINGUID_MOD": domainguid_mod,
484 message("Adding configuration container (permitted to fail)")
485 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
486 "CONFIGDN": configdn,
488 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
490 message("Modifying configuration container")
491 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
492 "CONFIGDN": configdn,
493 "SCHEMADN": schemadn,
496 message("Adding schema container (permitted to fail)")
497 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
498 "SCHEMADN": schemadn,
500 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
502 message("Modifying schema container")
503 setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), {
504 "SCHEMADN": schemadn,
505 "NETBIOSNAME": netbiosname,
506 "DEFAULTSITE": DEFAULTSITE,
507 "CONFIGDN": configdn,
510 message("Setting up sam.ldb Samba4 schema")
511 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
512 {"SCHEMADN": schemadn })
513 message("Setting up sam.ldb AD schema")
514 setup_add_ldif(samdb, setup_path("schema.ldif"),
515 {"SCHEMADN": schemadn})
517 message("Setting up sam.ldb configuration data")
518 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
519 "CONFIGDN": configdn,
520 "NETBIOSNAME": netbiosname,
521 "DEFAULTSITE": DEFAULTSITE,
522 "DNSDOMAIN": dnsdomain,
523 "DOMAIN": domainname,
524 "SCHEMADN": schemadn,
525 "DOMAINDN": domaindn,
528 message("Setting up display specifiers")
529 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
530 {"CONFIGDN": configdn})
532 message("Adding users container (permitted to fail)")
533 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
534 "DOMAINDN": domaindn})
535 message("Modifying users container")
536 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
537 "DOMAINDN": domaindn})
538 message("Adding computers container (permitted to fail)")
539 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
540 "DOMAINDN": domaindn})
541 message("Modifying computers container")
542 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
543 "DOMAINDN": domaindn})
544 message("Setting up sam.ldb data")
545 setup_add_ldif(samdb, setup_path("provision.ldif"), {
546 "DOMAINDN": domaindn,
547 "NETBIOSNAME": netbiosname,
548 "DEFAULTSITE": DEFAULTSITE,
549 "CONFIGDN": configdn,
553 message("Setting up sam.ldb users and groups")
554 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
555 "DOMAINDN": domaindn,
556 "DOMAINSID": str(domainsid),
557 "CONFIGDN": configdn,
558 "ADMINPASS_B64": b64encode(adminpass),
559 "KRBTGTPASS_B64": b64encode(krbtgtpass),
562 if lp.get("server role") == "domain controller":
563 message("Setting up self join")
564 setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn,
565 invocationid=invocationid, dnspass=dnspass, netbiosname=netbiosname,
566 dnsdomain=dnsdomain, realm=realm, machinepass=machinepass,
567 domainname=domainname, domainsid=domainsid, policyguid=policyguid,
568 hostname=hostname, hostguid=hostguid, setup_path=setup_path)
570 message("Setting up sam.ldb index")
571 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
573 message("Setting up sam.ldb rootDSE marking as synchronized")
574 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
576 samdb.transaction_cancel()
579 samdb.transaction_commit()
583 def provision(lp, setup_dir, message, blank, paths, session_info,
584 credentials, ldapbackend, realm=None, domain=None, hostname=None,
585 hostip=None, domainsid=None, hostguid=None, adminpass=None,
586 krbtgtpass=None, domainguid=None, policyguid=None,
587 invocationid=None, machinepass=None, dnspass=None, root=None,
588 nobody=None, nogroup=None, users=None, wheel=None, backup=None,
589 aci=None, serverrole=None):
592 :note: caution, this wipes all existing data!
595 def setup_path(file):
596 return os.path.join(setup_dir, file)
600 if domainsid is None:
601 domainsid = security.random_sid()
602 if policyguid is None:
603 policyguid = uuid.random()
604 if invocationid is None:
605 invocationid = uuid.random()
606 if adminpass is None:
607 adminpass = misc.random_password(12)
608 if krbtgtpass is None:
609 krbtgtpass = misc.random_password(12)
610 if machinepass is None:
611 machinepass = misc.random_password(12)
613 dnspass = misc.random_password(12)
615 root = findnss(pwd.getpwnam, "root")[4]
617 nobody = findnss(pwd.getpwnam, "nobody")[4]
619 nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2]
621 users = findnss(grp.getgrnam, "users", "guest", "other", "unknown",
624 wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2]
626 backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2]
628 aci = "# no aci for local ldb"
629 if serverrole is None:
630 serverrole = lp.get("server role")
633 realm = lp.get("realm")
635 if lp.get("realm").upper() != realm.upper():
636 raise Exception("realm '%s' in smb.conf must match chosen realm '%s'\n" %
637 (lp.get("realm"), realm))
639 assert realm is not None
640 realm = realm.upper()
643 domain = lp.get("workgroup")
645 if lp.get("workgroup").upper() != domain.upper():
646 raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n",
647 lp.get("workgroup"), domain)
649 assert domain is not None
650 domain = domain.upper()
651 if not valid_netbios_name(domain):
652 raise InvalidNetbiosName(domain)
655 hostname = gethostname().split(".")[0].lower()
658 hostip = gethostbyname(hostname)
660 netbiosname = hostname.upper()
661 if not valid_netbios_name(netbiosname):
662 raise InvalidNetbiosName(netbiosname)
664 dnsdomain = realm.lower()
665 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
667 configdn = "CN=Configuration," + rootdn
668 schemadn = "CN=Schema," + configdn
670 rdn_dc = domaindn.split(",")[0][len("DC="):]
672 message("set DOMAIN SID: %s" % str(domainsid))
673 message("Provisioning for %s in realm %s" % (domain, realm))
674 message("Using administrator password: %s" % adminpass)
676 assert paths.smbconf is not None
678 # only install a new smb.conf if there isn't one there already
679 if not os.path.exists(paths.smbconf):
680 message("Setting up smb.conf")
681 if serverrole == "domain controller":
683 elif serverrole == "member":
684 smbconfsuffix = "member"
686 assert "Invalid server role setting: %s" % serverrole
687 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, {
688 "HOSTNAME": hostname,
689 "DOMAIN_CONF": domain,
691 "SERVERROLE": serverrole,
692 "NETLOGONPATH": paths.netlogon,
693 "SYSVOLPATH": paths.sysvol,
697 # only install a new shares config db if there is none
698 if not os.path.exists(paths.shareconf):
699 message("Setting up share.ldb")
700 share_ldb = Ldb(paths.shareconf, session_info=session_info,
701 credentials=credentials, lp=lp)
702 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
704 message("Setting up secrets.ldb")
705 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
706 session_info=session_info,
707 credentials=credentials, lp=lp)
709 message("Setting up the registry")
710 setup_registry(paths.hklm, setup_path, session_info,
711 credentials=credentials, lp=lp)
713 message("Setting up templates db")
714 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
715 credentials=credentials, lp=lp)
717 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials,
718 lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn,
719 dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message,
720 hostname=hostname, rootdn=rootdn, erase=erase, domainsid=domainsid, aci=aci,
721 rdn_dc=rdn_dc, domainguid=domainguid, policyguid=policyguid,
722 domainname=domain, blank=blank, adminpass=adminpass, krbtgtpass=krbtgtpass,
723 hostguid=hostguid, invocationid=invocationid, machinepass=machinepass,
726 if lp.get("server role") == "domain controller":
727 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755)
728 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755)
729 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755)
730 if not os.path.isdir(paths.netlogon):
731 os.makedirs(paths.netlogon, 0755)
732 secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials, lp=lp)
733 setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), {
734 "MACHINEPASS_B64": b64encode(machinepass),
737 "LDAPTIME": timestring(int(time.time())),
738 "DNSDOMAIN": dnsdomain,
739 "DOMAINSID": str(domainsid),
740 "SECRETS_KEYTAB": paths.keytab,
741 "NETBIOSNAME": netbiosname,
742 "SAM_LDB": paths.samdb,
743 "DNS_KEYTAB": paths.dns_keytab,
744 "DNSPASS_B64": b64encode(dnspass),
748 setup_name_mappings(samdb, str(domainsid),
749 domaindn, root=root, nobody=nobody,
750 nogroup=nogroup, wheel=wheel, users=users,
753 message("Setting up phpLDAPadmin configuration")
754 create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path)
756 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
758 if lp.get("server role") == "domain controller":
759 samdb = SamDB(paths.samdb, session_info=session_info,
760 credentials=credentials, lp=lp)
762 domainguid = samdb.searchone(domaindn, "objectGUID")
763 assert isinstance(domainguid, str)
764 hostguid = samdb.searchone(domaindn, "objectGUID",
765 expression="(&(objectClass=computer)(cn=%s))" % hostname,
767 assert isinstance(hostguid, str)
769 message("Setting up DNS zone: %s" % dnsdomain)
770 create_zone_file(paths.dns, setup_path, samdb,
771 hostname=hostname, hostip=hostip, dnsdomain=dnsdomain,
772 domaindn=domaindn, dnspass=dnspass, realm=realm,
773 domainguid=domainguid, hostguid=hostguid)
774 message("Please install the zone located in %s into your DNS server" % paths.dns)
778 def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path):
779 """Create a PHP LDAP admin configuration file.
781 :param path: Path to write the configuration to.
782 :param setup_path: Function to generate setup paths.
783 :param s4_ldapi_path: Path to Samba 4 LDAPI socket.
785 setup_file(setup_path("phpldapadmin-config.php"),
786 path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")})
789 def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn,
790 hostip, hostname, dnspass, realm, domainguid, hostguid):
791 """Write out a DNS zone file, from the info in the current database.
793 :param path: Path of the new file.
794 :param setup_path": Setup path function.
795 :param samdb: SamDB object
796 :param dnsdomain: DNS Domain name
797 :param domaindn: DN of the Domain
798 :param hostip: Local IP
799 :param hostname: Local hostname
800 :param dnspass: Password for DNS
801 :param realm: Realm name
802 :param domainguid: GUID of the domain.
803 :param hostguid: GUID of the host.
806 setup_file(setup_path("provision.zone"), path, {
807 "DNSPASS_B64": b64encode(dnspass),
808 "HOSTNAME": hostname,
809 "DNSDOMAIN": dnsdomain,
812 "DOMAINGUID": domainguid,
813 "DATESTRING": time.strftime("%Y%m%d%H"),
814 "DEFAULTSITE": DEFAULTSITE,
815 "HOSTGUID": hostguid,
819 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
822 :param samdb: Load a schema into a SamDB.
823 :param setup_path: Setup path function.
824 :param schemadn: DN of the schema
825 :param netbiosname: NetBIOS name of the host.
826 :param configdn: DN of the configuration
828 schema_data = open(setup_path("schema.ldif"), 'r').read()
829 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
830 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
831 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
832 head_data = substitute_var(head_data, {
833 "SCHEMADN": schemadn,
834 "NETBIOSNAME": netbiosname,
835 "CONFIGDN": configdn,
836 "DEFAULTSITE": DEFAULTSITE})
837 samdb.attach_schema_from_ldif(head_data, schema_data)