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 Dn, 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(ldb.Dn("(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.ldap_basedn_ldif = os.path.join(private_dir,
185 paths.ldap_config_basedn_ldif = os.path.join(private_dir,
186 dnsdomain + "-config.ldif")
187 paths.ldap_schema_basedn_ldif = os.path.join(private_dir,
188 dnsdomain + "-schema.ldif")
189 paths.s4_ldapi_path = os.path.join(private_dir, "ldapi")
190 paths.phpldapadminconfig = os.path.join(private_dir,
191 "phpldapadmin-config.php")
192 paths.hklm = os.path.join(private_dir, "hklm.ldb")
193 paths.sysvol = lp.get("sysvol", "path")
194 if paths.sysvol is None:
195 paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol")
197 paths.netlogon = lp.get("netlogon", "path")
198 if paths.netlogon is None:
199 paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts"))
204 def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users,
206 """setup reasonable name mappings for sam names to unix names.
208 :param ldb: SamDB object.
209 :param sid: The domain sid.
210 :param domaindn: The domain DN.
211 :param root: Name of the UNIX root user.
212 :param nobody: Name of the UNIX nobody user.
213 :param nogroup: Name of the unix nobody group.
214 :param users: Name of the unix users group.
215 :param wheel: Name of the wheel group (users that can become root).
216 :param backup: Name of the backup group."""
217 # add some foreign sids if they are not present already
218 ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
219 ldb.add_foreign(domaindn, "S-1-1-0", "World")
220 ldb.add_foreign(domaindn, "S-1-5-2", "Network")
221 ldb.add_foreign(domaindn, "S-1-5-18", "System")
222 ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
224 # some well known sids
225 ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody)
226 ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup)
227 ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup)
228 ldb.setup_name_mapping(domaindn, "S-1-5-18", root)
229 ldb.setup_name_mapping(domaindn, "S-1-5-11", users)
230 ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel)
231 ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users)
232 ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup)
233 ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup)
235 # and some well known domain rids
236 ldb.setup_name_mapping(domaindn, sid + "-500", root)
237 ldb.setup_name_mapping(domaindn, sid + "-518", wheel)
238 ldb.setup_name_mapping(domaindn, sid + "-519", wheel)
239 ldb.setup_name_mapping(domaindn, sid + "-512", wheel)
240 ldb.setup_name_mapping(domaindn, sid + "-513", users)
241 ldb.setup_name_mapping(domaindn, sid + "-520", wheel)
244 def provision_become_dc(setup_dir, message, paths, lp, session_info,
246 assert session_info is not None
249 def setup_path(file):
250 return os.path.join(setup_dir, file)
251 os.path.unlink(paths.samdb)
253 message("Setting up templates db")
254 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
255 credentials=credentials, lp=lp)
257 # Also wipes the database
258 message("Setting up sam.ldb")
259 samdb = SamDB(paths.samdb, session_info=session_info,
260 credentials=credentials, lp=lp)
262 message("Setting up sam.ldb partitions")
263 setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn)
265 samdb = SamDB(paths.samdb, session_info=session_info,
266 credentials=credentials, lp=lp)
268 ldb.transaction_start()
270 message("Setting up sam.ldb attributes")
271 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
273 message("Setting up sam.ldb rootDSE")
274 setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn,
275 hostname, dnsdomain, realm, rootdn, configdn,
279 message("Erasing data from partitions")
280 samdb.erase_partitions()
282 message("Setting up sam.ldb indexes")
283 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
285 samdb.transaction_cancel()
288 samdb.transaction_commit()
290 message("Setting up %s" % paths.secrets)
291 secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info,
293 setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"),
294 { "MACHINEPASS_B64": b64encode(machinepass) })
297 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
298 if os.path.exists(path):
300 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp)
302 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
303 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
307 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
308 templates_ldb = SamDB(path, session_info=session_info,
309 credentials=credentials, lp=lp)
310 templates_ldb.erase()
311 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
314 def setup_registry(path, setup_path, session_info, credentials, lp):
315 reg = registry.Registry()
316 hive = registry.open_ldb(path, session_info=session_info,
317 credentials=credentials, lp_ctx=lp)
318 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
319 provision_reg = setup_path("provision.reg")
320 assert os.path.exists(provision_reg)
321 reg.diff_apply(provision_reg)
324 def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname,
325 dnsdomain, realm, rootdn, configdn, netbiosname):
326 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
327 "SCHEMADN": schemadn,
328 "NETBIOSNAME": netbiosname,
329 "DNSDOMAIN": dnsdomain,
330 "DEFAULTSITE": DEFAULTSITE,
332 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
333 "DOMAINDN": domaindn,
335 "CONFIGDN": configdn,
336 "VERSION": samba.version(),
340 def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn):
341 #Add modules to the list to activate them by default
342 #beware often order is important
344 # Some Known ordering constraints:
345 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
346 # - objectclass must be before password_hash, because password_hash checks
347 # that the objectclass is of type person (filled in by objectclass
348 # module when expanding the objectclass list)
349 # - partition must be last
350 # - each partition has its own module list then
351 modules_list = ["rootdse",
367 modules_list2 = ["show_deleted",
370 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
371 "SCHEMADN": schemadn,
372 "SCHEMADN_LDB": "schema.ldb",
373 "SCHEMADN_MOD2": ",objectguid",
374 "CONFIGDN": configdn,
375 "CONFIGDN_LDB": "configuration.ldb",
376 "DOMAINDN": domaindn,
377 "DOMAINDN_LDB": "users.ldb",
378 "SCHEMADN_MOD": "schema_fsmo",
379 "CONFIGDN_MOD": "naming_fsmo",
380 "CONFIGDN_MOD2": ",objectguid",
381 "DOMAINDN_MOD": "pdc_fsmo,password_hash",
382 "DOMAINDN_MOD2": ",objectguid",
383 "MODULES_LIST": ",".join(modules_list),
384 "TDB_MODULES_LIST": ","+",".join(tdb_modules_list),
385 "MODULES_LIST2": ",".join(modules_list2),
389 def setup_self_join(samdb, configdn, schemadn, domaindn,
390 netbiosname, hostname, dnsdomain, machinepass, dnspass,
391 realm, domainname, domainsid, invocationid, setup_path,
392 policyguid, hostguid=None):
393 if hostguid is not None:
394 hostguid_add = "objectGUID: %s" % hostguid
398 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
399 "CONFIGDN": configdn,
400 "SCHEMADN": schemadn,
401 "DOMAINDN": domaindn,
402 "INVOCATIONID": invocationid,
403 "NETBIOSNAME": netbiosname,
404 "DEFAULTSITE": DEFAULTSITE,
405 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
406 "MACHINEPASS_B64": b64encode(machinepass),
407 "DNSPASS_B64": b64encode(dnspass),
409 "DOMAIN": domainname,
410 "HOSTGUID_ADD": hostguid_add,
411 "DNSDOMAIN": dnsdomain})
412 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
413 "POLICYGUID": policyguid,
414 "DNSDOMAIN": dnsdomain,
415 "DOMAINSID": str(domainsid),
416 "DOMAINDN": domaindn})
419 def setup_samdb(path, setup_path, session_info, credentials, lp,
420 schemadn, configdn, domaindn, dnsdomain, realm,
421 netbiosname, message, hostname, rootdn, erase,
422 domainsid, aci, rdn_dc, domainguid, policyguid,
423 domainname, blank, adminpass, krbtgtpass,
424 machinepass, hostguid, invocationid, dnspass):
425 # Also wipes the database
426 message("Setting up sam.ldb")
427 samdb = SamDB(path, session_info=session_info,
428 credentials=credentials, lp=lp)
430 message("Setting up sam.ldb partitions")
431 setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn)
433 samdb = SamDB(path, session_info=session_info,
434 credentials=credentials, lp=lp)
436 samdb.transaction_start()
438 message("Setting up sam.ldb attributes")
439 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
441 message("Setting up sam.ldb rootDSE")
442 setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn,
443 hostname, dnsdomain, realm, rootdn, configdn,
447 message("Erasing data from partitions")
448 samdb.erase_partitions()
450 samdb.transaction_cancel()
453 samdb.transaction_commit()
455 message("Pre-loading the Samba 4 and AD schema")
456 samdb = SamDB(path, session_info=session_info,
457 credentials=credentials, lp=lp)
458 samdb.set_domain_sid(domainsid)
459 load_schema(setup_path, samdb, schemadn, netbiosname, configdn)
461 samdb.transaction_start()
464 message("Adding DomainDN: %s (permitted to fail)" % domaindn)
465 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
466 "DOMAINDN": domaindn,
468 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
472 message("Modifying DomainDN: " + domaindn + "")
473 if domainguid is not None:
474 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
478 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
480 "LDAPTIME": timestring(int(time.time())),
481 "DOMAINSID": str(domainsid),
482 "SCHEMADN": schemadn,
483 "NETBIOSNAME": netbiosname,
484 "DEFAULTSITE": DEFAULTSITE,
485 "CONFIGDN": configdn,
486 "POLICYGUID": policyguid,
487 "DOMAINDN": domaindn,
488 "DOMAINGUID_MOD": domainguid_mod,
491 message("Adding configuration container (permitted to fail)")
492 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
493 "CONFIGDN": configdn,
495 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
497 message("Modifying configuration container")
498 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
499 "CONFIGDN": configdn,
500 "SCHEMADN": schemadn,
503 message("Adding schema container (permitted to fail)")
504 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
505 "SCHEMADN": schemadn,
507 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
509 message("Modifying schema container")
510 setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), {
511 "SCHEMADN": schemadn,
512 "NETBIOSNAME": netbiosname,
513 "DEFAULTSITE": DEFAULTSITE,
514 "CONFIGDN": configdn,
517 message("Setting up sam.ldb Samba4 schema")
518 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
519 {"SCHEMADN": schemadn })
520 message("Setting up sam.ldb AD schema")
521 setup_add_ldif(samdb, setup_path("schema.ldif"),
522 {"SCHEMADN": schemadn})
524 message("Setting up sam.ldb configuration data")
525 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
526 "CONFIGDN": configdn,
527 "NETBIOSNAME": netbiosname,
528 "DEFAULTSITE": DEFAULTSITE,
529 "DNSDOMAIN": dnsdomain,
530 "DOMAIN": domainname,
531 "SCHEMADN": schemadn,
532 "DOMAINDN": domaindn,
535 message("Setting up display specifiers")
536 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
537 {"CONFIGDN": configdn})
539 message("Adding users container (permitted to fail)")
540 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
541 "DOMAINDN": domaindn})
542 message("Modifying users container")
543 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
544 "DOMAINDN": domaindn})
545 message("Adding computers container (permitted to fail)")
546 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
547 "DOMAINDN": domaindn})
548 message("Modifying computers container")
549 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
550 "DOMAINDN": domaindn})
551 message("Setting up sam.ldb data")
552 setup_add_ldif(samdb, setup_path("provision.ldif"), {
553 "DOMAINDN": domaindn,
554 "NETBIOSNAME": netbiosname,
555 "DEFAULTSITE": DEFAULTSITE,
556 "CONFIGDN": configdn,
560 message("Setting up sam.ldb users and groups")
561 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
562 "DOMAINDN": domaindn,
563 "DOMAINSID": str(domainsid),
564 "CONFIGDN": configdn,
565 "ADMINPASS_B64": b64encode(adminpass),
566 "KRBTGTPASS_B64": b64encode(krbtgtpass),
569 if lp.get("server role") == "domain controller":
570 message("Setting up self join")
571 setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn,
572 invocationid=invocationid, dnspass=dnspass, netbiosname=netbiosname,
573 dnsdomain=dnsdomain, realm=realm, machinepass=machinepass,
574 domainname=domainname, domainsid=domainsid, policyguid=policyguid,
575 hostname=hostname, hostguid=hostguid, setup_path=setup_path)
577 message("Setting up sam.ldb index")
578 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
580 message("Setting up sam.ldb rootDSE marking as synchronized")
581 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
583 samdb.transaction_cancel()
586 samdb.transaction_commit()
590 def provision(lp, setup_dir, message, blank, paths, session_info,
591 credentials, ldapbackend, realm=None, domain=None, hostname=None,
592 hostip=None, domainsid=None, hostguid=None, adminpass=None,
593 krbtgtpass=None, domainguid=None, policyguid=None,
594 invocationid=None, machinepass=None, dnspass=None, root=None,
595 nobody=None, nogroup=None, users=None, wheel=None, backup=None,
596 aci=None, serverrole=None):
599 :note: caution, this wipes all existing data!
602 def setup_path(file):
603 return os.path.join(setup_dir, file)
607 if domainsid is None:
608 domainsid = security.random_sid()
609 if policyguid is None:
610 policyguid = uuid.random()
611 if invocationid is None:
612 invocationid = uuid.random()
613 if adminpass is None:
614 adminpass = misc.random_password(12)
615 if krbtgtpass is None:
616 krbtgtpass = misc.random_password(12)
617 if machinepass is None:
618 machinepass = misc.random_password(12)
620 dnspass = misc.random_password(12)
622 root = findnss(pwd.getpwnam, "root")[4]
624 nobody = findnss(pwd.getpwnam, "nobody")[4]
626 nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2]
628 users = findnss(grp.getgrnam, "users", "guest", "other", "unknown",
631 wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2]
633 backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2]
635 aci = "# no aci for local ldb"
636 if serverrole is None:
637 serverrole = lp.get("server role")
640 realm = lp.get("realm")
642 if lp.get("realm").upper() != realm.upper():
643 raise Exception("realm '%s' in smb.conf must match chosen realm '%s'\n" %
644 (lp.get("realm"), realm))
646 assert realm is not None
647 realm = realm.upper()
650 domain = lp.get("workgroup")
652 if lp.get("workgroup").upper() != domain.upper():
653 raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n",
654 lp.get("workgroup"), domain)
656 assert domain is not None
657 domain = domain.upper()
658 if not valid_netbios_name(domain):
659 raise InvalidNetbiosName(domain)
662 hostname = gethostname().split(".")[0].lower()
665 hostip = gethostbyname(hostname)
667 netbiosname = hostname.upper()
668 if not valid_netbios_name(netbiosname):
669 raise InvalidNetbiosName(netbiosname)
671 dnsdomain = realm.lower()
672 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
674 configdn = "CN=Configuration," + rootdn
675 schemadn = "CN=Schema," + configdn
677 rdn_dc = domaindn.split(",")[0][len("DC="):]
679 message("set DOMAIN SID: %s" % str(domainsid))
680 message("Provisioning for %s in realm %s" % (domain, realm))
681 message("Using administrator password: %s" % adminpass)
683 assert paths.smbconf is not None
685 # only install a new smb.conf if there isn't one there already
686 if not os.path.exists(paths.smbconf):
687 message("Setting up smb.conf")
688 if serverrole == "domain controller":
690 elif serverrole == "member":
691 smbconfsuffix = "member"
693 assert "Invalid server role setting: %s" % serverrole
694 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, {
695 "HOSTNAME": hostname,
696 "DOMAIN_CONF": domain,
698 "SERVERROLE": serverrole,
699 "NETLOGONPATH": paths.netlogon,
700 "SYSVOLPATH": paths.sysvol,
704 # only install a new shares config db if there is none
705 if not os.path.exists(paths.shareconf):
706 message("Setting up share.ldb")
707 share_ldb = Ldb(paths.shareconf, session_info=session_info,
708 credentials=credentials, lp=lp)
709 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
711 message("Setting up secrets.ldb")
712 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
713 session_info=session_info,
714 credentials=credentials, lp=lp)
716 message("Setting up the registry")
717 setup_registry(paths.hklm, setup_path, session_info,
718 credentials=credentials, lp=lp)
720 message("Setting up templates db")
721 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
722 credentials=credentials, lp=lp)
724 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials,
725 lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn,
726 dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message,
727 hostname=hostname, rootdn=rootdn, erase=erase, domainsid=domainsid, aci=aci,
728 rdn_dc=rdn_dc, domainguid=domainguid, policyguid=policyguid,
729 domainname=domain, blank=blank, adminpass=adminpass, krbtgtpass=krbtgtpass,
730 hostguid=hostguid, invocationid=invocationid, machinepass=machinepass,
733 if lp.get("server role") == "domain controller":
734 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755)
735 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755)
736 os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755)
737 if not os.path.isdir(paths.netlogon):
738 os.makedirs(paths.netlogon, 0755)
739 secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials, lp=lp)
740 setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), {
741 "MACHINEPASS_B64": b64encode(machinepass),
744 "LDAPTIME": timestring(int(time.time())),
745 "DNSDOMAIN": dnsdomain,
746 "DOMAINSID": str(domainsid),
747 "SECRETS_KEYTAB": paths.keytab,
748 "NETBIOSNAME": netbiosname,
749 "SAM_LDB": paths.samdb,
750 "DNS_KEYTAB": paths.dns_keytab,
751 "DNSPASS_B64": b64encode(dnspass),
755 setup_name_mappings(samdb, str(domainsid),
756 domaindn, root=root, nobody=nobody,
757 nogroup=nogroup, wheel=wheel, users=users,
760 message("Setting up phpLDAPadmin configuration")
761 create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path)
763 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
765 if lp.get("server role") == "domain controller":
766 samdb = SamDB(paths.samdb, session_info=session_info,
767 credentials=credentials, lp=lp)
769 domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID")
770 assert isinstance(domainguid, str)
771 hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID",
772 expression="(&(objectClass=computer)(cn=%s))" % hostname,
774 assert isinstance(hostguid, str)
776 message("Setting up DNS zone: %s" % dnsdomain)
777 create_zone_file(paths.dns, setup_path, samdb,
778 hostname=hostname, hostip=hostip, dnsdomain=dnsdomain,
779 domaindn=domaindn, dnspass=dnspass, realm=realm,
780 domainguid=domainguid, hostguid=hostguid)
781 message("Please install the zone located in %s into your DNS server" % paths.dns)
785 def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path):
786 """Create a PHP LDAP admin configuration file.
788 :param path: Path to write the configuration to.
789 :param setup_path: Function to generate setup paths.
790 :param s4_ldapi_path: Path to Samba 4 LDAPI socket.
792 setup_file(setup_path("phpldapadmin-config.php"),
793 path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")})
796 def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn,
797 hostip, hostname, dnspass, realm, domainguid, hostguid):
798 """Write out a DNS zone file, from the info in the current database.
800 :param path: Path of the new file.
801 :param setup_path": Setup path function.
802 :param samdb: SamDB object
803 :param dnsdomain: DNS Domain name
804 :param domaindn: DN of the Domain
805 :param hostip: Local IP
806 :param hostname: Local hostname
807 :param dnspass: Password for DNS
808 :param realm: Realm name
809 :param domainguid: GUID of the domain.
810 :param hostguid: GUID of the host.
813 setup_file(setup_path("provision.zone"), path, {
814 "DNSPASS_B64": b64encode(dnspass),
815 "HOSTNAME": hostname,
816 "DNSDOMAIN": dnsdomain,
819 "DOMAINGUID": domainguid,
820 "DATESTRING": time.strftime("%Y%m%d%H"),
821 "DEFAULTSITE": DEFAULTSITE,
822 "HOSTGUID": hostguid,
826 def provision_ldapbase(setup_dir, message, paths):
827 """Write out a DNS zone file, from the info in the current database."""
828 message("Setting up LDAP base entry: %s" % domaindn)
829 rdns = domaindn.split(",")
831 rdn_dc = rdns[0][len("DC="):]
833 def setup_path(file):
834 return os.path.join(setup_dir, file)
836 setup_file(setup_path("provision_basedn.ldif"),
837 paths.ldap_basedn_ldif)
839 setup_file(setup_path("provision_configuration_basedn.ldif"),
840 paths.ldap_config_basedn_ldif)
842 setup_file(setup_path("provision_schema_basedn.ldif"),
843 paths.ldap_schema_basedn_ldif, {
844 "SCHEMADN": schemadn,
845 "ACI": "# no aci for local ldb",
846 "EXTENSIBLEOBJECT": "objectClass: extensibleObject"})
848 message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server")
851 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
854 :param samdb: Load a schema into a SamDB.
855 :param setup_path: Setup path function.
856 :param schemadn: DN of the schema
857 :param netbiosname: NetBIOS name of the host.
858 :param configdn: DN of the configuration
860 schema_data = open(setup_path("schema.ldif"), 'r').read()
861 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
862 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
863 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
864 head_data = substitute_var(head_data, {
865 "SCHEMADN": schemadn,
866 "NETBIOSNAME": netbiosname,
867 "CONFIGDN": configdn,
868 "DEFAULTSITE": DEFAULTSITE})
869 samdb.attach_schema_from_ldif(head_data, schema_data)