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
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from base64 import b64encode
31 from socket import gethostname, gethostbyname
35 from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
36 from samba.samdb import SamDB
39 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \
40 LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE
42 """Functions for setting up a Samba configuration."""
44 DEFAULTSITE = "Default-First-Site-Name"
46 class InvalidNetbiosName(Exception):
47 def __init__(self, name):
48 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
64 self.dns_keytab = None
67 self.ldap_basedn_ldif = None
68 self.ldap_config_basedn_ldif = None
69 self.ldap_schema_basedn_ldif = None
72 def check_install(lp, session_info, credentials):
73 """Check whether the current install seems ok.
75 :param lp: Loadparm context
76 :param session_info: Session information
77 :param credentials: Credentials
79 if lp.get("realm") == "":
80 raise Error("Realm empty")
81 ldb = Ldb(lp.get("sam database"), session_info=session_info,
82 credentials=credentials, lp=lp)
83 if len(ldb.search("(cn=Administrator)")) != 1:
84 raise "No administrator account found"
87 def findnss(nssfn, *names):
88 """Find a user or group from a list of possibilities."""
94 raise Exception("Unable to find user/group for %s" % arguments[1])
97 def open_ldb(session_info, credentials, lp, dbname):
98 """Open a LDB, thrashing it if it is corrupt.
100 :param session_info: auth session information
101 :param credentials: credentials
102 :param lp: Loadparm context
103 :param dbname: Path of the database to open.
104 :return: a Ldb object
106 assert session_info is not None
108 return Ldb(dbname, session_info=session_info, credentials=credentials,
113 return Ldb(dbname, session_info=session_info, credentials=credentials,
117 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
118 """Setup a ldb in the private dir.
120 :param ldb: LDB file to import data into
121 :param ldif_path: Path of the LDIF file to load
122 :param subst_vars: Optional variables to subsitute in LDIF.
124 assert isinstance(ldif_path, str)
126 data = open(ldif_path, 'r').read()
127 if subst_vars is not None:
128 data = substitute_var(data, subst_vars)
130 check_all_substituted(data)
135 def setup_modify_ldif(ldb, ldif_path, substvars=None):
136 """Modify a ldb in the private dir.
138 :param ldb: LDB object.
139 :param ldif_path: LDIF file path.
140 :param substvars: Optional dictionary with substitution variables.
142 data = open(ldif_path, 'r').read()
143 if substvars is not None:
144 data = substitute_var(data, substvars)
146 check_all_substituted(data)
148 ldb.modify_ldif(data)
151 def setup_ldb(ldb, ldif_path, subst_vars):
152 assert ldb is not None
153 ldb.transaction_start()
155 setup_add_ldif(ldb, ldif_path, subst_vars)
157 ldb.transaction_cancel()
159 ldb.transaction_commit()
162 def setup_file(template, fname, substvars):
163 """Setup a file in the private dir.
165 :param template: Path of the template file.
166 :param fname: Path of the file to create.
167 :param substvars: Substitution variables.
171 if os.path.exists(f):
174 data = open(template, 'r').read()
176 data = substitute_var(data, substvars)
177 check_all_substituted(data)
179 open(f, 'w').write(data)
182 def provision_paths_from_lp(lp, dnsdomain, private_dir=None):
183 """Set the default paths for provisioning.
185 :param lp: Loadparm context.
186 :param dnsdomain: DNS Domain name
188 paths = ProvisionPaths()
189 if private_dir is None:
190 private_dir = lp.get("private dir")
191 paths.keytab = "secrets.keytab"
192 paths.dns_keytab = "dns.keytab"
194 paths.keytab = os.path.join(private_dir, "secrets.keytab")
195 paths.dns_keytab = os.path.join(private_dir, "dns.keytab")
197 paths.shareconf = os.path.join(private_dir, "share.ldb")
198 paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb")
199 paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb")
200 paths.templates = os.path.join(private_dir, "templates.ldb")
201 paths.dns = os.path.join(private_dir, dnsdomain + ".zone")
202 paths.winsdb = os.path.join(private_dir, "wins.ldb")
203 paths.s4_ldapi_path = os.path.join(private_dir, "ldapi")
204 paths.phpldapadminconfig = os.path.join(private_dir,
205 "phpldapadmin-config.php")
206 paths.hklm = "hklm.ldb"
207 paths.hkcr = "hkcr.ldb"
208 paths.hkcu = "hkcu.ldb"
209 paths.hku = "hku.ldb"
210 paths.hkpd = "hkpd.ldb"
211 paths.hkpt = "hkpt.ldb"
213 paths.sysvol = lp.get("sysvol", "path")
214 if paths.sysvol is None:
215 paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol")
217 paths.netlogon = lp.get("netlogon", "path")
218 if paths.netlogon is None:
219 paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts"))
224 def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users,
226 """setup reasonable name mappings for sam names to unix names.
228 :param ldb: SamDB object.
229 :param sid: The domain sid.
230 :param domaindn: The domain DN.
231 :param root: Name of the UNIX root user.
232 :param nobody: Name of the UNIX nobody user.
233 :param nogroup: Name of the unix nobody group.
234 :param users: Name of the unix users group.
235 :param wheel: Name of the wheel group (users that can become root).
236 :param backup: Name of the backup group."""
237 # add some foreign sids if they are not present already
238 ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
239 ldb.add_foreign(domaindn, "S-1-1-0", "World")
240 ldb.add_foreign(domaindn, "S-1-5-2", "Network")
241 ldb.add_foreign(domaindn, "S-1-5-18", "System")
242 ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users")
244 # some well known sids
245 ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody)
246 ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup)
247 ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup)
248 ldb.setup_name_mapping(domaindn, "S-1-5-18", root)
249 ldb.setup_name_mapping(domaindn, "S-1-5-11", users)
250 ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel)
251 ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users)
252 ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup)
253 ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup)
255 # and some well known domain rids
256 ldb.setup_name_mapping(domaindn, sid + "-500", root)
257 ldb.setup_name_mapping(domaindn, sid + "-518", wheel)
258 ldb.setup_name_mapping(domaindn, sid + "-519", wheel)
259 ldb.setup_name_mapping(domaindn, sid + "-512", wheel)
260 ldb.setup_name_mapping(domaindn, sid + "-513", users)
261 ldb.setup_name_mapping(domaindn, sid + "-520", wheel)
264 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
265 credentials, configdn, schemadn, domaindn,
266 hostname, netbiosname, dnsdomain, realm,
267 rootdn, serverrole, ldap_backend=None,
268 ldap_backend_type=None, erase=False):
269 """Setup the partitions for the SAM database.
271 Alternatively, provision() may call this, and then populate the database.
273 :param erase: Remove the existing data present in the database.
276 :note: This will wipe the Sam Database!
278 :note: This function always removes the local SAM LDB file. The erase
279 parameter controls whether to erase the existing data, which
280 may not be stored locally but in LDAP.
282 assert session_info is not None
284 if os.path.exists(samdb_path):
285 os.unlink(samdb_path)
287 # Also wipes the database
288 samdb = SamDB(samdb_path, session_info=session_info,
289 credentials=credentials, lp=lp)
291 #Add modules to the list to activate them by default
292 #beware often order is important
294 # Some Known ordering constraints:
295 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
296 # - objectclass must be before password_hash, because password_hash checks
297 # that the objectclass is of type person (filled in by objectclass
298 # module when expanding the objectclass list)
299 # - partition must be last
300 # - each partition has its own module list then
301 modules_list = ["rootdse",
317 modules_list2 = ["show_deleted",
320 domaindn_ldb = "users.ldb"
321 if ldap_backend is not None:
322 domaindn_ldb = ldap_backend
323 configdn_ldb = "configuration.ldb"
324 if ldap_backend is not None:
325 configdn_ldb = ldap_backend
326 schema_ldb = "schema.ldb"
327 if ldap_backend is not None:
328 schema_ldb = ldap_backend
330 if ldap_backend_type == "fedora-ds":
331 backend_modules = ["nsuniqueid","paged_searches"]
332 elif ldap_backend_type == "openldap":
333 backend_modules = ["normalise","entryuuid","paged_searches"]
334 elif serverrole == "domain controller":
335 backend_modules = ["repl_meta_data"]
337 backend_modules = ["objectguid"]
339 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
340 "SCHEMADN": schemadn,
341 "SCHEMADN_LDB": "schema.ldb",
342 "SCHEMADN_MOD2": ",objectguid",
343 "CONFIGDN": configdn,
344 "CONFIGDN_LDB": "configuration.ldb",
345 "DOMAINDN": domaindn,
346 "DOMAINDN_LDB": "users.ldb",
347 "SCHEMADN_MOD": "schema_fsmo,instancetype",
348 "CONFIGDN_MOD": "naming_fsmo,instancetype",
349 "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype",
350 "MODULES_LIST": ",".join(modules_list),
351 "TDB_MODULES_LIST": ","+",".join(tdb_modules_list),
352 "MODULES_LIST2": ",".join(modules_list2),
353 "BACKEND_MOD": ",".join(backend_modules),
356 samdb = SamDB(samdb_path, session_info=session_info,
357 credentials=credentials, lp=lp)
359 samdb.transaction_start()
361 message("Setting up sam.ldb attributes")
362 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
364 message("Setting up sam.ldb rootDSE")
365 setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname,
366 dnsdomain, realm, rootdn, configdn, netbiosname)
369 message("Erasing data from partitions")
370 samdb.erase_partitions()
373 samdb.transaction_cancel()
376 samdb.transaction_commit()
381 def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
382 netbiosname, domainsid, keytab_path, samdb_url,
383 dns_keytab_path, dnspass, machinepass):
384 """Add DC-specific bits to a secrets database.
386 :param secretsdb: Ldb Handle to the secrets database
387 :param setup_path: Setup path function
388 :param machinepass: Machine password
390 setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), {
391 "MACHINEPASS_B64": b64encode(machinepass),
394 "DNSDOMAIN": dnsdomain,
395 "DOMAINSID": str(domainsid),
396 "SECRETS_KEYTAB": keytab_path,
397 "NETBIOSNAME": netbiosname,
398 "SAM_LDB": samdb_url,
399 "DNS_KEYTAB": dns_keytab_path,
400 "DNSPASS_B64": b64encode(dnspass),
404 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
405 """Setup the secrets database.
407 :param path: Path to the secrets database.
408 :param setup_path: Get the path to a setup file.
409 :param session_info: Session info.
410 :param credentials: Credentials
411 :param lp: Loadparm context
412 :return: LDB handle for the created secrets database
414 if os.path.exists(path):
416 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
419 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
420 secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
422 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
426 def setup_templatesdb(path, setup_path, session_info, credentials, lp):
427 """Setup the templates database.
429 :param path: Path to the database.
430 :param setup_path: Function for obtaining the path to setup files.
431 :param session_info: Session info
432 :param credentials: Credentials
433 :param lp: Loadparm context
435 templates_ldb = SamDB(path, session_info=session_info,
436 credentials=credentials, lp=lp)
437 templates_ldb.erase()
438 templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
441 def setup_registry(path, setup_path, session_info, credentials, lp):
442 """Setup the registry.
444 :param path: Path to the registry database
445 :param setup_path: Function that returns the path to a setup.
446 :param session_info: Session information
447 :param credentials: Credentials
448 :param lp: Loadparm context
450 reg = registry.Registry()
452 hive = registry.open_ldb(path, session_info=session_info,
453 credentials=credentials, lp_ctx=lp)
454 reg.mount_hive(hive, "HKEY_LOCAL_MACHINE")
455 provision_reg = setup_path("provision.reg")
456 assert os.path.exists(provision_reg)
457 reg.diff_apply(provision_reg)
460 def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname,
461 dnsdomain, realm, rootdn, configdn, netbiosname):
462 """Setup the SamDB rootdse.
464 :param samdb: Sam Database handle
465 :param setup_path: Obtain setup path
468 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
469 "SCHEMADN": schemadn,
470 "NETBIOSNAME": netbiosname,
471 "DNSDOMAIN": dnsdomain,
472 "DEFAULTSITE": DEFAULTSITE,
474 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
475 "DOMAINDN": domaindn,
477 "CONFIGDN": configdn,
478 "VERSION": samba.version(),
482 def setup_self_join(samdb, configdn, schemadn, domaindn,
483 netbiosname, hostname, dnsdomain, machinepass, dnspass,
484 realm, domainname, domainsid, invocationid, setup_path,
485 policyguid, hostguid=None):
486 """Join a host to its own domain."""
487 if hostguid is not None:
488 hostguid_add = "objectGUID: %s" % hostguid
492 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
493 "CONFIGDN": configdn,
494 "SCHEMADN": schemadn,
495 "DOMAINDN": domaindn,
496 "INVOCATIONID": invocationid,
497 "NETBIOSNAME": netbiosname,
498 "DEFAULTSITE": DEFAULTSITE,
499 "DNSNAME": "%s.%s" % (hostname, dnsdomain),
500 "MACHINEPASS_B64": b64encode(machinepass),
501 "DNSPASS_B64": b64encode(dnspass),
503 "DOMAIN": domainname,
504 "HOSTGUID_ADD": hostguid_add,
505 "DNSDOMAIN": dnsdomain})
506 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
507 "POLICYGUID": policyguid,
508 "DNSDOMAIN": dnsdomain,
509 "DOMAINSID": str(domainsid),
510 "DOMAINDN": domaindn})
513 def setup_samdb(path, setup_path, session_info, credentials, lp,
514 schemadn, configdn, domaindn, dnsdomain, realm,
515 netbiosname, message, hostname, rootdn, erase,
516 domainsid, aci, domainguid, policyguid,
517 domainname, fill, adminpass, krbtgtpass,
518 machinepass, hostguid, invocationid, dnspass,
519 serverrole, ldap_backend=None, ldap_backend_type=None):
520 """Setup a complete SAM Database.
524 # Also wipes the database
525 setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn,
526 domaindn=domaindn, message=message, lp=lp,
527 credentials=credentials, session_info=session_info,
528 hostname=hostname, netbiosname=netbiosname,
529 dnsdomain=dnsdomain, realm=realm, rootdn=rootdn,
530 ldap_backend=ldap_backend, serverrole=serverrole,
531 ldap_backend_type=ldap_backend_type, erase=erase)
533 samdb = SamDB(path, session_info=session_info,
534 credentials=credentials, lp=lp)
537 # We want to finish here, but setup the index before we do so
538 message("Setting up sam.ldb index")
539 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
542 message("Pre-loading the Samba 4 and AD schema")
543 samdb = SamDB(path, session_info=session_info,
544 credentials=credentials, lp=lp)
545 samdb.set_domain_sid(domainsid)
546 if lp.get("server role") == "domain controller":
547 samdb.set_invocation_id(invocationid)
549 load_schema(setup_path, samdb, schemadn, netbiosname, configdn)
551 samdb.transaction_start()
554 message("Adding DomainDN: %s (permitted to fail)" % domaindn)
555 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
556 "DOMAINDN": domaindn,
560 message("Modifying DomainDN: " + domaindn + "")
561 if domainguid is not None:
562 domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
566 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
567 "LDAPTIME": timestring(int(time.time())),
568 "DOMAINSID": str(domainsid),
569 "SCHEMADN": schemadn,
570 "NETBIOSNAME": netbiosname,
571 "DEFAULTSITE": DEFAULTSITE,
572 "CONFIGDN": configdn,
573 "POLICYGUID": policyguid,
574 "DOMAINDN": domaindn,
575 "DOMAINGUID_MOD": domainguid_mod,
578 message("Adding configuration container (permitted to fail)")
579 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
580 "CONFIGDN": configdn,
582 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
584 message("Modifying configuration container")
585 setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
586 "CONFIGDN": configdn,
587 "SCHEMADN": schemadn,
590 message("Adding schema container (permitted to fail)")
591 setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
592 "SCHEMADN": schemadn,
594 "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
596 message("Modifying schema container")
597 setup_modify_ldif(samdb,
598 setup_path("provision_schema_basedn_modify.ldif"), {
599 "SCHEMADN": schemadn,
600 "NETBIOSNAME": netbiosname,
601 "DEFAULTSITE": DEFAULTSITE,
602 "CONFIGDN": configdn,
605 message("Setting up sam.ldb Samba4 schema")
606 setup_add_ldif(samdb, setup_path("schema_samba4.ldif"),
607 {"SCHEMADN": schemadn })
608 message("Setting up sam.ldb AD schema")
609 setup_add_ldif(samdb, setup_path("schema.ldif"),
610 {"SCHEMADN": schemadn})
612 message("Setting up sam.ldb configuration data")
613 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
614 "CONFIGDN": configdn,
615 "NETBIOSNAME": netbiosname,
616 "DEFAULTSITE": DEFAULTSITE,
617 "DNSDOMAIN": dnsdomain,
618 "DOMAIN": domainname,
619 "SCHEMADN": schemadn,
620 "DOMAINDN": domaindn,
623 message("Setting up display specifiers")
624 setup_add_ldif(samdb, setup_path("display_specifiers.ldif"),
625 {"CONFIGDN": configdn})
627 message("Adding users container (permitted to fail)")
628 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
629 "DOMAINDN": domaindn})
630 message("Modifying users container")
631 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
632 "DOMAINDN": domaindn})
633 message("Adding computers container (permitted to fail)")
634 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
635 "DOMAINDN": domaindn})
636 message("Modifying computers container")
637 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
638 "DOMAINDN": domaindn})
639 message("Setting up sam.ldb data")
640 setup_add_ldif(samdb, setup_path("provision.ldif"), {
641 "DOMAINDN": domaindn,
642 "NETBIOSNAME": netbiosname,
643 "DEFAULTSITE": DEFAULTSITE,
644 "CONFIGDN": configdn,
647 if fill == FILL_FULL:
648 message("Setting up sam.ldb users and groups")
649 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
650 "DOMAINDN": domaindn,
651 "DOMAINSID": str(domainsid),
652 "CONFIGDN": configdn,
653 "ADMINPASS_B64": b64encode(adminpass),
654 "KRBTGTPASS_B64": b64encode(krbtgtpass),
657 if lp.get("server role") == "domain controller":
658 message("Setting up self join")
659 setup_self_join(samdb, configdn=configdn, schemadn=schemadn,
660 domaindn=domaindn, invocationid=invocationid,
661 dnspass=dnspass, netbiosname=netbiosname,
662 dnsdomain=dnsdomain, realm=realm,
663 machinepass=machinepass, domainname=domainname,
664 domainsid=domainsid, policyguid=policyguid,
665 hostname=hostname, hostguid=hostguid,
666 setup_path=setup_path)
668 #We want to setup the index last, as adds are faster unindexed
669 message("Setting up sam.ldb index")
670 samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
672 samdb.transaction_cancel()
675 samdb.transaction_commit()
679 FILL_NT4SYNC = "NT4SYNC"
682 def provision(lp, setup_dir, message, paths, session_info,
683 credentials, ldapbackend, samdb_fill=FILL_FULL, realm=None, rootdn=None,
684 domain=None, hostname=None, hostip=None, domainsid=None,
685 hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None,
686 policyguid=None, invocationid=None, machinepass=None,
687 dnspass=None, root=None, nobody=None, nogroup=None, users=None,
688 wheel=None, backup=None, aci=None, serverrole=None, erase=False,
689 ldap_backend=None, ldap_backend_type=None):
692 :note: caution, this wipes all existing data!
695 def setup_path(file):
696 return os.path.join(setup_dir, file)
698 if domainsid is None:
699 domainsid = security.random_sid()
700 if policyguid is None:
701 policyguid = uuid.random()
702 if adminpass is None:
703 adminpass = misc.random_password(12)
704 if krbtgtpass is None:
705 krbtgtpass = misc.random_password(12)
706 if machinepass is None:
707 machinepass = misc.random_password(12)
709 dnspass = misc.random_password(12)
711 root = findnss(pwd.getpwnam, "root")[0]
713 nobody = findnss(pwd.getpwnam, "nobody")[0]
715 nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[0]
717 users = findnss(grp.getgrnam, "users", "guest", "other", "unknown",
720 wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[0]
722 backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[0]
724 aci = "# no aci for local ldb"
725 if serverrole is None:
726 serverrole = lp.get("server role")
727 if invocationid is None and serverrole == "domain controller":
728 invocationid = uuid.random()
731 realm = lp.get("realm")
733 if lp.get("realm").upper() != realm.upper():
734 raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" %
735 (lp.get("realm"), realm))
737 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
739 if ldap_backend == "ldapi":
740 # provision-backend will set this path suggested slapd command line / fedorads.inf
741 ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="")
743 assert realm is not None
744 realm = realm.upper()
747 hostname = gethostname().split(".")[0].lower()
750 hostip = gethostbyname(hostname)
752 netbiosname = hostname.upper()
753 if not valid_netbios_name(netbiosname):
754 raise InvalidNetbiosName(netbiosname)
756 dnsdomain = realm.lower()
757 if serverrole == "domain controller":
758 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
760 domain = lp.get("workgroup")
762 if lp.get("workgroup").upper() != domain.upper():
763 raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'",
764 lp.get("workgroup"), domain)
766 assert domain is not None
767 domain = domain.upper()
768 if not valid_netbios_name(domain):
769 raise InvalidNetbiosName(domain)
772 domaindn = "CN=" + netbiosname
778 configdn = "CN=Configuration," + rootdn
779 schemadn = "CN=Schema," + configdn
781 message("set DOMAIN SID: %s" % str(domainsid))
782 message("Provisioning for %s in realm %s" % (domain, realm))
783 message("Using administrator password: %s" % adminpass)
785 assert paths.smbconf is not None
787 # only install a new smb.conf if there isn't one there already
788 if not os.path.exists(paths.smbconf):
789 message("Setting up smb.conf")
790 if serverrole == "domain controller":
792 elif serverrole == "member":
793 smbconfsuffix = "member"
795 assert "Invalid server role setting: %s" % serverrole
796 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
798 "HOSTNAME": hostname,
799 "DOMAIN_CONF": domain,
801 "SERVERROLE": serverrole,
802 "NETLOGONPATH": paths.netlogon,
803 "SYSVOLPATH": paths.sysvol,
807 # only install a new shares config db if there is none
808 if not os.path.exists(paths.shareconf):
809 message("Setting up share.ldb")
810 share_ldb = Ldb(paths.shareconf, session_info=session_info,
811 credentials=credentials, lp=lp)
812 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
815 message("Setting up secrets.ldb")
816 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
817 session_info=session_info,
818 credentials=credentials, lp=lp)
820 message("Setting up the registry")
821 setup_registry(paths.hklm, setup_path, session_info,
822 credentials=credentials, lp=lp)
824 message("Setting up templates db")
825 setup_templatesdb(paths.templates, setup_path, session_info=session_info,
826 credentials=credentials, lp=lp)
828 samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
829 credentials=credentials, lp=lp, schemadn=schemadn,
830 configdn=configdn, domaindn=domaindn,
831 dnsdomain=dnsdomain, netbiosname=netbiosname,
832 realm=realm, message=message, hostname=hostname,
833 rootdn=rootdn, erase=erase, domainsid=domainsid,
834 aci=aci, domainguid=domainguid, policyguid=policyguid,
835 domainname=domain, fill=samdb_fill,
836 adminpass=adminpass, krbtgtpass=krbtgtpass,
837 hostguid=hostguid, invocationid=invocationid,
838 machinepass=machinepass, dnspass=dnspass,
839 serverrole=serverrole, ldap_backend=ldap_backend,
840 ldap_backend_type=ldap_backend_type)
842 if lp.get("server role") == "domain controller":
843 policy_path = os.path.join(paths.sysvol, dnsdomain, "Policies",
844 "{" + policyguid + "}")
845 os.makedirs(policy_path, 0755)
846 os.makedirs(os.path.join(policy_path, "Machine"), 0755)
847 os.makedirs(os.path.join(policy_path, "User"), 0755)
848 if not os.path.isdir(paths.netlogon):
849 os.makedirs(paths.netlogon, 0755)
850 secrets_ldb = Ldb(paths.secrets, session_info=session_info,
851 credentials=credentials, lp=lp)
852 secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=realm,
853 netbiosname=netbiosname, domainsid=domainsid,
854 keytab_path=paths.keytab, samdb_url=paths.samdb,
855 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
856 machinepass=machinepass, dnsdomain=dnsdomain)
858 if samdb_fill == FILL_FULL:
859 setup_name_mappings(samdb, str(domainsid), domaindn, root=root,
860 nobody=nobody, nogroup=nogroup, wheel=wheel,
861 users=users, backup=backup)
863 message("Setting up sam.ldb rootDSE marking as synchronized")
864 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
866 message("Setting up phpLDAPadmin configuration")
867 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
870 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
872 if lp.get("server role") == "domain controller":
873 samdb = SamDB(paths.samdb, session_info=session_info,
874 credentials=credentials, lp=lp)
876 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
877 assert isinstance(domainguid, str)
878 hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID",
879 expression="(&(objectClass=computer)(cn=%s))" % hostname,
881 assert isinstance(hostguid, str)
883 message("Setting up DNS zone: %s" % dnsdomain)
884 create_zone_file(paths.dns, setup_path, samdb,
885 hostname=hostname, hostip=hostip, dnsdomain=dnsdomain,
886 domaindn=domaindn, dnspass=dnspass, realm=realm,
887 domainguid=domainguid, hostguid=hostguid)
888 message("Please install the zone located in %s into your DNS server" % paths.dns)
893 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
894 """Create a PHP LDAP admin configuration file.
896 :param path: Path to write the configuration to.
897 :param setup_path: Function to generate setup paths.
899 setup_file(setup_path("phpldapadmin-config.php"), path,
900 {"S4_LDAPI_URI": ldapi_uri})
903 def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn,
904 hostip, hostname, dnspass, realm, domainguid, hostguid):
905 """Write out a DNS zone file, from the info in the current database.
907 :param path: Path of the new file.
908 :param setup_path": Setup path function.
909 :param samdb: SamDB object
910 :param dnsdomain: DNS Domain name
911 :param domaindn: DN of the Domain
912 :param hostip: Local IP
913 :param hostname: Local hostname
914 :param dnspass: Password for DNS
915 :param realm: Realm name
916 :param domainguid: GUID of the domain.
917 :param hostguid: GUID of the host.
919 assert isinstance(domainguid, str)
921 setup_file(setup_path("provision.zone"), path, {
922 "DNSPASS_B64": b64encode(dnspass),
923 "HOSTNAME": hostname,
924 "DNSDOMAIN": dnsdomain,
927 "DOMAINGUID": domainguid,
928 "DATESTRING": time.strftime("%Y%m%d%H"),
929 "DEFAULTSITE": DEFAULTSITE,
930 "HOSTGUID": hostguid,
934 def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
937 :param samdb: Load a schema into a SamDB.
938 :param setup_path: Setup path function.
939 :param schemadn: DN of the schema
940 :param netbiosname: NetBIOS name of the host.
941 :param configdn: DN of the configuration
943 schema_data = open(setup_path("schema.ldif"), 'r').read()
944 schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
945 schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
946 head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
947 head_data = substitute_var(head_data, {
948 "SCHEMADN": schemadn,
949 "NETBIOSNAME": netbiosname,
950 "CONFIGDN": configdn,
951 "DEFAULTSITE": DEFAULTSITE
953 samdb.attach_schema_from_ldif(head_data, schema_data)