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 auth import system_session, admin_session
44 from samba import version, Ldb, substitute_var, valid_netbios_name, setup_file
45 from samba import check_all_substituted, read_and_sub_file
46 from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008
47 from samba.samdb import SamDB
48 from samba.idmap import IDmapDB
49 from samba.dcerpc import security
50 from samba.ndr import ndr_pack
52 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
53 from ms_display_specifiers import read_ms_ldif
54 from schema import Schema
55 from provisionbackend import LDBBackend, ExistingBackend, FDSBackend, OpenLDAPBackend
56 from signal import SIGTERM
57 from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
59 __docformat__ = "restructuredText"
62 """Find the setup directory used by provision."""
63 dirname = os.path.dirname(__file__)
64 if "/site-packages/" in dirname:
65 prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
66 for suffix in ["share/setup", "share/samba/setup", "setup"]:
67 ret = os.path.join(prefix, suffix)
68 if os.path.isdir(ret):
71 ret = os.path.join(dirname, "../../../setup")
72 if os.path.isdir(ret):
74 raise Exception("Unable to find setup directory.")
76 # descriptors of the naming contexts
77 # hard coded at this point, but will probably be changed when
78 # we enable different fsmo roles
80 def get_config_descriptor(domain_sid):
81 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
82 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
83 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
84 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
85 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
86 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
87 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
88 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
89 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
90 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
91 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
92 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
93 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
94 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
95 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
96 sec = security.descriptor.from_sddl(sddl, domain_sid)
97 return b64encode(ndr_pack(sec))
99 def get_domain_descriptor(domain_sid):
100 sddl= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
101 "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
102 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
103 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
104 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
105 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
106 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
107 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
108 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
109 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
110 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-832762594-175224951-1765713900-498)" \
111 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
112 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
113 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
114 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
115 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
116 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
117 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
118 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
119 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
120 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
121 "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;S-1-5-32-557)" \
122 "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
123 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
124 "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
125 "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
126 "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
127 "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
128 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
129 "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
130 "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
131 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
132 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
133 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
134 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
135 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
136 "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
137 "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
138 "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
141 "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
143 "(A;;RPLCLORC;;;ED)" \
144 "(A;;RPLCLORC;;;AU)" \
145 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
146 "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
147 "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
148 "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
149 sec = security.descriptor.from_sddl(sddl, domain_sid)
150 return b64encode(ndr_pack(sec))
152 DEFAULTSITE = "Default-First-Site-Name"
156 class ProvisioningError(Exception):
157 """A generic provision error."""
159 class InvalidNetbiosName(Exception):
160 """A specified name was not a valid NetBIOS name."""
161 def __init__(self, name):
162 super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
165 class ProvisionPaths(object):
167 self.shareconf = None
178 self.dns_keytab = None
181 self.private_dir = None
183 self.slapdconf = None
184 self.modulesconf = None
185 self.memberofconf = None
187 self.olmmrserveridsconf = None
188 self.olmmrsyncreplconf = None
191 self.olcseedldif = None
194 class ProvisionNames(object):
200 self.ldapmanagerdn = None
201 self.dnsdomain = None
203 self.netbiosname = None
210 class ProvisionResult(object):
217 def check_install(lp, session_info, credentials):
218 """Check whether the current install seems ok.
220 :param lp: Loadparm context
221 :param session_info: Session information
222 :param credentials: Credentials
224 if lp.get("realm") == "":
225 raise Exception("Realm empty")
226 ldb = Ldb(lp.get("sam database"), session_info=session_info,
227 credentials=credentials, lp=lp)
228 if len(ldb.search("(cn=Administrator)")) != 1:
229 raise ProvisioningError("No administrator account found")
232 def findnss(nssfn, names):
233 """Find a user or group from a list of possibilities.
235 :param nssfn: NSS Function to try (should raise KeyError if not found)
236 :param names: Names to check.
237 :return: Value return by first names list.
244 raise KeyError("Unable to find user/group %r" % names)
247 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
248 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
251 def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
252 """Setup a ldb in the private dir.
254 :param ldb: LDB file to import data into
255 :param ldif_path: Path of the LDIF file to load
256 :param subst_vars: Optional variables to subsitute in LDIF.
257 :param nocontrols: Optional list of controls, can be None for no controls
259 assert isinstance(ldif_path, str)
260 data = read_and_sub_file(ldif_path, subst_vars)
261 ldb.add_ldif(data,controls)
264 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
265 """Modify a ldb in the private dir.
267 :param ldb: LDB object.
268 :param ldif_path: LDIF file path.
269 :param subst_vars: Optional dictionary with substitution variables.
271 data = read_and_sub_file(ldif_path, subst_vars)
273 ldb.modify_ldif(data)
276 def setup_ldb(ldb, ldif_path, subst_vars):
277 """Import a LDIF a file into a LDB handle, optionally substituting variables.
279 :note: Either all LDIF data will be added or none (using transactions).
281 :param ldb: LDB file to import into.
282 :param ldif_path: Path to the LDIF file.
283 :param subst_vars: Dictionary with substitution variables.
285 assert ldb is not None
286 ldb.transaction_start()
288 setup_add_ldif(ldb, ldif_path, subst_vars)
290 ldb.transaction_cancel()
292 ldb.transaction_commit()
295 def provision_paths_from_lp(lp, dnsdomain):
296 """Set the default paths for provisioning.
298 :param lp: Loadparm context.
299 :param dnsdomain: DNS Domain name
301 paths = ProvisionPaths()
302 paths.private_dir = lp.get("private dir")
303 paths.dns_keytab = "dns.keytab"
305 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
306 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
307 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
308 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
309 paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
310 paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
311 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
312 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
313 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
314 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
315 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
316 paths.phpldapadminconfig = os.path.join(paths.private_dir,
317 "phpldapadmin-config.php")
318 paths.ldapdir = os.path.join(paths.private_dir,
320 paths.slapdconf = os.path.join(paths.ldapdir,
322 paths.slapdpid = os.path.join(paths.ldapdir,
324 paths.modulesconf = os.path.join(paths.ldapdir,
326 paths.memberofconf = os.path.join(paths.ldapdir,
328 paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
329 "mmr_serverids.conf")
330 paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
332 paths.olcdir = os.path.join(paths.ldapdir,
334 paths.olcseedldif = os.path.join(paths.ldapdir,
336 paths.hklm = "hklm.ldb"
337 paths.hkcr = "hkcr.ldb"
338 paths.hkcu = "hkcu.ldb"
339 paths.hku = "hku.ldb"
340 paths.hkpd = "hkpd.ldb"
341 paths.hkpt = "hkpt.ldb"
343 paths.sysvol = lp.get("path", "sysvol")
345 paths.netlogon = lp.get("path", "netlogon")
347 paths.smbconf = lp.configfile
352 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
353 serverrole=None, rootdn=None, domaindn=None, configdn=None,
354 schemadn=None, serverdn=None, sitename=None):
355 """Guess configuration settings to use."""
358 hostname = socket.gethostname().split(".")[0]
360 netbiosname = lp.get("netbios name")
361 if netbiosname is None:
362 netbiosname = hostname
363 assert netbiosname is not None
364 netbiosname = netbiosname.upper()
365 if not valid_netbios_name(netbiosname):
366 raise InvalidNetbiosName(netbiosname)
368 if dnsdomain is None:
369 dnsdomain = lp.get("realm")
370 assert dnsdomain is not None
371 dnsdomain = dnsdomain.lower()
373 if serverrole is None:
374 serverrole = lp.get("server role")
375 assert serverrole is not None
376 serverrole = serverrole.lower()
378 realm = dnsdomain.upper()
380 if lp.get("realm").upper() != realm:
381 raise ProvisioningError("guess_names: Realm '%s' in smb.conf must match chosen realm '%s'!", lp.get("realm").upper(), realm)
383 if serverrole == "domain controller":
385 domain = lp.get("workgroup")
386 assert domain is not None
387 domain = domain.upper()
389 if lp.get("workgroup").upper() != domain:
390 raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!", lp.get("workgroup").upper(), domain)
393 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
397 domaindn = "DC=" + netbiosname
399 if not valid_netbios_name(domain):
400 raise InvalidNetbiosName(domain)
402 if hostname.upper() == realm:
403 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!", realm, hostname)
404 if netbiosname == realm:
405 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!", realm, netbiosname)
407 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!", realm, domain)
413 configdn = "CN=Configuration," + rootdn
415 schemadn = "CN=Schema," + configdn
420 names = ProvisionNames()
421 names.rootdn = rootdn
422 names.domaindn = domaindn
423 names.configdn = configdn
424 names.schemadn = schemadn
425 names.ldapmanagerdn = "CN=Manager," + rootdn
426 names.dnsdomain = dnsdomain
427 names.domain = domain
429 names.netbiosname = netbiosname
430 names.hostname = hostname
431 names.sitename = sitename
432 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
437 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
438 targetdir, sid_generator):
439 """Create a new smb.conf file based on a couple of basic settings.
441 assert smbconf is not None
443 hostname = socket.gethostname().split(".")[0]
444 netbiosname = hostname.upper()
446 if serverrole is None:
447 serverrole = "standalone"
449 assert serverrole in ("domain controller", "member server", "standalone")
450 if serverrole == "domain controller":
452 elif serverrole == "member server":
453 smbconfsuffix = "member"
454 elif serverrole == "standalone":
455 smbconfsuffix = "standalone"
457 if sid_generator is None:
458 sid_generator = "internal"
460 assert domain is not None
461 domain = domain.upper()
463 assert realm is not None
464 realm = realm.upper()
466 default_lp = param.LoadParm()
467 #Load non-existant file
468 if os.path.exists(smbconf):
469 default_lp.load(smbconf)
471 if targetdir is not None:
472 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
473 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
475 default_lp.set("lock dir", os.path.abspath(targetdir))
480 if sid_generator == "internal":
481 sid_generator_line = ""
483 sid_generator_line = "sid generator = " + sid_generator
485 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
486 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
488 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
490 "NETBIOS_NAME": netbiosname,
493 "SERVERROLE": serverrole,
494 "NETLOGONPATH": netlogon,
495 "SYSVOLPATH": sysvol,
496 "SIDGENERATOR_LINE": sid_generator_line,
497 "PRIVATEDIR_LINE": privatedir_line,
498 "LOCKDIR_LINE": lockdir_line
502 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
503 users_gid, wheel_gid):
504 """setup reasonable name mappings for sam names to unix names.
506 :param samdb: SamDB object.
507 :param idmap: IDmap db object.
508 :param sid: The domain sid.
509 :param domaindn: The domain DN.
510 :param root_uid: uid of the UNIX root user.
511 :param nobody_uid: uid of the UNIX nobody user.
512 :param users_gid: gid of the UNIX users group.
513 :param wheel_gid: gid of the UNIX wheel group."""
515 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
516 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
518 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
519 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
521 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
522 provision_backend, names, schema,
525 """Setup the partitions for the SAM database.
527 Alternatively, provision() may call this, and then populate the database.
529 :note: This will wipe the Sam Database!
531 :note: This function always removes the local SAM LDB file. The erase
532 parameter controls whether to erase the existing data, which
533 may not be stored locally but in LDAP.
536 assert session_info is not None
538 old_partitions = None
539 new_partitions = None
541 # We use options=["modules:"] to stop the modules loading - we
542 # just want to wipe and re-initialise the database, not start it up
545 os.unlink(samdb_path)
549 samdb = Ldb(url=samdb_path, session_info=session_info,
550 lp=lp, options=["modules:"])
552 #Add modules to the list to activate them by default
553 #beware often order is important
555 # Some Known ordering constraints:
556 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
557 # - extended_dn_in must be before objectclass.c, as it resolves the DN
558 # - objectclass must be before password_hash, because password_hash checks
559 # that the objectclass is of type person (filled in by objectclass
560 # module when expanding the objectclass list)
561 # - partition must be last
562 # - each partition has its own module list then
563 modules_list = ["resolve_oids",
583 if serverrole == "domain controller":
584 objectguid_module = "repl_meta_data"
586 objectguid_module = "objectguid"
591 extended_dn_module = "extended_dn_out_ldb"
592 modules_list2 = ["show_deleted",
598 ldap_backend_line = "# No LDAP backend"
599 if provision_backend.type is not "ldb":
600 ldap_backend_line = "ldapBackend: %s" % provision_backend.ldapi_uri
602 # The LDAP backends assign the objectGUID on thier own
603 objectguid_module = None
604 # OpenLDAP and FDS handles subtree renames, so we don't want to do any of these things
605 tdb_modules_list = []
607 if provision_backend.ldap_backend_type == "fedora-ds":
608 backend_modules = ["nsuniqueid", "paged_searches"]
609 extended_dn_module_list = ["extended_dn_out_fds"];
610 elif provision_backend.ldap_backend_type == "openldap":
611 backend_modules = ["entryuuid", "paged_searches"]
612 extended_dn_module_list = ["extended_dn_out_openldap"]
614 if objectguid_module is not None:
615 modules_list.append(objectguid_module)
617 for m in tdb_modules_list:
618 modules_list.append(m)
620 modules_list.append(extended_dn_module)
622 for m in modules_list2:
623 modules_list.append(m)
625 samdb.transaction_start()
627 message("Setting up sam.ldb partitions and settings")
628 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
629 "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
630 "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
631 "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
632 "SCHEMADN_MOD": "schema_data",
633 "CONFIGDN_MOD": "naming_fsmo",
634 "DOMAINDN_MOD": "pdc_fsmo",
635 "MODULES_LIST": ",".join(modules_list),
636 "BACKEND_MOD": ",".join(backend_modules),
637 "LDAP_BACKEND_LINE": ldap_backend_line,
641 samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
643 message("Setting up sam.ldb rootDSE")
644 setup_samdb_rootdse(samdb, setup_path, names)
647 samdb.transaction_cancel()
650 samdb.transaction_commit()
653 def secretsdb_self_join(secretsdb, domain,
654 netbiosname, domainsid, machinepass,
655 realm=None, dnsdomain=None,
657 key_version_number=1,
658 secure_channel_type=SEC_CHAN_WKSTA):
659 """Add domain join-specific bits to a secrets database.
661 :param secretsdb: Ldb Handle to the secrets database
662 :param machinepass: Machine password
664 attrs=["whenChanged",
672 msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
673 msg["secureChannelType"] = str(secure_channel_type)
674 msg["flatname"] = [domain]
675 msg["objectClass"] = ["top", "primaryDomain"]
676 if realm is not None:
677 if dnsdomain is None:
678 dnsdomain = realm.lower()
679 msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
681 msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
682 msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
683 msg["privateKeytab"] = ["secrets.keytab"];
686 msg["secret"] = [machinepass]
687 msg["samAccountName"] = ["%s$" % netbiosname]
688 msg["secureChannelType"] = [str(secure_channel_type)]
689 msg["objectSid"] = [ndr_pack(domainsid)]
691 res = secretsdb.search(base="cn=Primary Domains",
693 expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
694 scope=SCOPE_ONELEVEL)
697 if del_msg.dn is not msg.dn:
698 secretsdb.delete(del_msg.dn)
700 res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
703 msg["priorSecret"] = res[0]["secret"]
704 msg["priorWhenChanged"] = res[0]["whenChanged"]
706 if res["privateKeytab"] is not None:
707 msg["privateKeytab"] = res[0]["privateKeytab"]
709 if res["krb5Keytab"] is not None:
710 msg["krb5Keytab"] = res[0]["krb5Keytab"]
713 el.set_flags(ldb.FLAG_MOD_REPLACE)
714 secretsdb.modify(msg)
719 def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
720 dns_keytab_path, dnspass):
721 """Add DNS specific bits to a secrets database.
723 :param secretsdb: Ldb Handle to the secrets database
724 :param setup_path: Setup path function
725 :param machinepass: Machine password
727 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
729 "DNSDOMAIN": dnsdomain,
730 "DNS_KEYTAB": dns_keytab_path,
731 "DNSPASS_B64": b64encode(dnspass),
735 def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
736 """Setup the secrets database.
738 :param path: Path to the secrets database.
739 :param setup_path: Get the path to a setup file.
740 :param session_info: Session info.
741 :param credentials: Credentials
742 :param lp: Loadparm context
743 :return: LDB handle for the created secrets database
745 if os.path.exists(path):
747 secrets_ldb = Ldb(path, session_info=session_info,
750 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
751 secrets_ldb = Ldb(path, session_info=session_info,
753 secrets_ldb.transaction_start()
754 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
756 if backend_credentials is not None and backend_credentials.authentication_requested():
757 if backend_credentials.get_bind_dn() is not None:
758 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
759 "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
760 "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
763 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
764 "LDAPADMINUSER": backend_credentials.get_username(),
765 "LDAPADMINREALM": backend_credentials.get_realm(),
766 "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
771 def setup_privileges(path, setup_path, session_info, lp):
772 """Setup the privileges database.
774 :param path: Path to the privileges database.
775 :param setup_path: Get the path to a setup file.
776 :param session_info: Session info.
777 :param credentials: Credentials
778 :param lp: Loadparm context
779 :return: LDB handle for the created secrets database
781 if os.path.exists(path):
783 privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
784 privilege_ldb.erase()
785 privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
788 def setup_registry(path, setup_path, session_info, lp):
789 """Setup the registry.
791 :param path: Path to the registry database
792 :param setup_path: Function that returns the path to a setup.
793 :param session_info: Session information
794 :param credentials: Credentials
795 :param lp: Loadparm context
797 reg = registry.Registry()
798 hive = registry.open_ldb(path, session_info=session_info,
800 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
801 provision_reg = setup_path("provision.reg")
802 assert os.path.exists(provision_reg)
803 reg.diff_apply(provision_reg)
806 def setup_idmapdb(path, setup_path, session_info, lp):
807 """Setup the idmap database.
809 :param path: path to the idmap database
810 :param setup_path: Function that returns a path to a setup file
811 :param session_info: Session information
812 :param credentials: Credentials
813 :param lp: Loadparm context
815 if os.path.exists(path):
818 idmap_ldb = IDmapDB(path, session_info=session_info,
822 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
826 def setup_samdb_rootdse(samdb, setup_path, names):
827 """Setup the SamDB rootdse.
829 :param samdb: Sam Database handle
830 :param setup_path: Obtain setup path
832 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
833 "SCHEMADN": names.schemadn,
834 "NETBIOSNAME": names.netbiosname,
835 "DNSDOMAIN": names.dnsdomain,
836 "REALM": names.realm,
837 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
838 "DOMAINDN": names.domaindn,
839 "ROOTDN": names.rootdn,
840 "CONFIGDN": names.configdn,
841 "SERVERDN": names.serverdn,
845 def setup_self_join(samdb, names,
846 machinepass, dnspass,
847 domainsid, invocationid, setup_path,
848 policyguid, policyguid_dc, domainControllerFunctionality,
850 """Join a host to its own domain."""
851 assert isinstance(invocationid, str)
852 if ntdsguid is not None:
853 ntdsguid_line = "objectGUID: %s\n"%ntdsguid
856 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
857 "CONFIGDN": names.configdn,
858 "SCHEMADN": names.schemadn,
859 "DOMAINDN": names.domaindn,
860 "SERVERDN": names.serverdn,
861 "INVOCATIONID": invocationid,
862 "NETBIOSNAME": names.netbiosname,
863 "DEFAULTSITE": names.sitename,
864 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
865 "MACHINEPASS_B64": b64encode(machinepass),
866 "DNSPASS_B64": b64encode(dnspass),
867 "REALM": names.realm,
868 "DOMAIN": names.domain,
869 "DNSDOMAIN": names.dnsdomain,
870 "SAMBA_VERSION_STRING": version,
871 "NTDSGUID": ntdsguid_line,
872 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
874 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
875 "POLICYGUID": policyguid,
876 "POLICYGUID_DC": policyguid_dc,
877 "DNSDOMAIN": names.dnsdomain,
878 "DOMAINSID": str(domainsid),
879 "DOMAINDN": names.domaindn})
881 # add the NTDSGUID based SPNs
882 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
883 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
884 expression="", scope=SCOPE_BASE)
885 assert isinstance(names.ntdsguid, str)
887 # Setup fSMORoleOwner entries to point at the newly created DC entry
888 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
889 "DOMAIN": names.domain,
890 "DNSDOMAIN": names.dnsdomain,
891 "DOMAINDN": names.domaindn,
892 "CONFIGDN": names.configdn,
893 "SCHEMADN": names.schemadn,
894 "DEFAULTSITE": names.sitename,
895 "SERVERDN": names.serverdn,
896 "NETBIOSNAME": names.netbiosname,
897 "NTDSGUID": names.ntdsguid
901 def setup_samdb(path, setup_path, session_info, provision_backend, lp,
903 domainsid, domainguid, policyguid, policyguid_dc,
904 fill, adminpass, krbtgtpass,
905 machinepass, invocationid, dnspass, ntdsguid,
906 serverrole, dom_for_fun_level=None,
908 """Setup a complete SAM Database.
910 :note: This will wipe the main SAM database file!
913 # ATTENTION: Do NOT change these default values without discussion with the
914 # team and/or release manager. They have a big impact on the whole program!
915 domainControllerFunctionality = DS_DC_FUNCTION_2008
917 if dom_for_fun_level is None:
918 dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
919 if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003:
920 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!")
922 if dom_for_fun_level > domainControllerFunctionality:
923 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008). This won't work!")
925 domainFunctionality = dom_for_fun_level
926 forestFunctionality = dom_for_fun_level
928 # Also wipes the database
929 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
930 provision_backend=provision_backend, session_info=session_info,
932 serverrole=serverrole, schema=schema)
935 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn)
937 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
938 samdb = Ldb(session_info=session_info,
939 credentials=provision_backend.credentials, lp=lp)
941 message("Pre-loading the Samba 4 and AD schema")
943 # Load the schema from the one we computed earlier
944 samdb.set_schema_from_ldb(schema.ldb)
946 # And now we can connect to the DB - the schema won't be loaded from the DB
952 samdb.transaction_start()
954 # Set the domain functionality levels onto the database.
955 # Various module (the password_hash module in particular) need
956 # to know what level of AD we are emulating.
958 # These will be fixed into the database via the database
959 # modifictions below, but we need them set from the start.
960 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
961 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
962 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
964 samdb.set_domain_sid(str(domainsid))
965 if serverrole == "domain controller":
966 samdb.set_invocation_id(invocationid)
968 message("Adding DomainDN: %s" % names.domaindn)
970 #impersonate domain admin
971 admin_session_info = admin_session(lp, str(domainsid))
972 samdb.set_session_info(admin_session_info)
973 if domainguid is not None:
974 domainguid_line = "objectGUID: %s\n-" % domainguid
978 descr = get_domain_descriptor(domainsid)
979 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
980 "DOMAINDN": names.domaindn,
981 "DOMAINGUID": domainguid_line,
986 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
987 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
988 "DOMAINSID": str(domainsid),
989 "SCHEMADN": names.schemadn,
990 "NETBIOSNAME": names.netbiosname,
991 "DEFAULTSITE": names.sitename,
992 "CONFIGDN": names.configdn,
993 "SERVERDN": names.serverdn,
994 "POLICYGUID": policyguid,
995 "DOMAINDN": names.domaindn,
996 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
997 "SAMBA_VERSION_STRING": version
1000 message("Adding configuration container")
1001 descr = get_config_descriptor(domainsid);
1002 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
1003 "CONFIGDN": names.configdn,
1004 "DESCRIPTOR": descr,
1007 # The LDIF here was created when the Schema object was constructed
1008 message("Setting up sam.ldb schema")
1009 samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
1010 samdb.modify_ldif(schema.schema_dn_modify)
1011 samdb.write_prefixes_from_schema()
1012 samdb.add_ldif(schema.schema_data, controls=["relax:0"])
1013 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
1014 {"SCHEMADN": names.schemadn})
1016 message("Setting up sam.ldb configuration data")
1017 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
1018 "CONFIGDN": names.configdn,
1019 "NETBIOSNAME": names.netbiosname,
1020 "DEFAULTSITE": names.sitename,
1021 "DNSDOMAIN": names.dnsdomain,
1022 "DOMAIN": names.domain,
1023 "SCHEMADN": names.schemadn,
1024 "DOMAINDN": names.domaindn,
1025 "SERVERDN": names.serverdn,
1026 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
1029 message("Setting up display specifiers")
1030 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1031 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
1032 check_all_substituted(display_specifiers_ldif)
1033 samdb.add_ldif(display_specifiers_ldif)
1035 message("Adding users container")
1036 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1037 "DOMAINDN": names.domaindn})
1038 message("Modifying users container")
1039 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1040 "DOMAINDN": names.domaindn})
1041 message("Adding computers container")
1042 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1043 "DOMAINDN": names.domaindn})
1044 message("Modifying computers container")
1045 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
1046 "DOMAINDN": names.domaindn})
1047 message("Setting up sam.ldb data")
1048 setup_add_ldif(samdb, setup_path("provision.ldif"), {
1049 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
1050 "DOMAINDN": names.domaindn,
1051 "NETBIOSNAME": names.netbiosname,
1052 "DEFAULTSITE": names.sitename,
1053 "CONFIGDN": names.configdn,
1054 "SERVERDN": names.serverdn,
1055 "POLICYGUID_DC": policyguid_dc
1058 setup_modify_ldif(samdb, setup_path("provision_basedn_references.ldif"), {
1059 "DOMAINDN": names.domaindn})
1061 setup_modify_ldif(samdb, setup_path("provision_configuration_references.ldif"), {
1062 "CONFIGDN": names.configdn,
1063 "SCHEMADN": names.schemadn})
1064 if fill == FILL_FULL:
1065 message("Setting up sam.ldb users and groups")
1066 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1067 "DOMAINDN": names.domaindn,
1068 "DOMAINSID": str(domainsid),
1069 "CONFIGDN": names.configdn,
1070 "ADMINPASS_B64": b64encode(adminpass),
1071 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1074 if serverrole == "domain controller":
1075 message("Setting up self join")
1076 setup_self_join(samdb, names=names, invocationid=invocationid,
1078 machinepass=machinepass,
1079 domainsid=domainsid, policyguid=policyguid,
1080 policyguid_dc=policyguid_dc,
1081 setup_path=setup_path,
1082 domainControllerFunctionality=domainControllerFunctionality,
1085 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
1086 names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1087 attribute="objectGUID", expression="", scope=SCOPE_BASE)
1088 assert isinstance(names.ntdsguid, str)
1091 samdb.transaction_cancel()
1094 samdb.transaction_commit()
1099 FILL_NT4SYNC = "NT4SYNC"
1103 def provision(setup_dir, message, session_info,
1104 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
1106 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1108 domain=None, hostname=None, hostip=None, hostip6=None,
1109 domainsid=None, adminpass=None, ldapadminpass=None,
1110 krbtgtpass=None, domainguid=None,
1111 policyguid=None, policyguid_dc=None, invocationid=None,
1112 machinepass=None, ntdsguid=None,
1113 dnspass=None, root=None, nobody=None, users=None,
1114 wheel=None, backup=None, aci=None, serverrole=None,
1115 dom_for_fun_level=None,
1116 ldap_backend_extra_port=None, backend_type=None,
1118 ol_mmr_urls=None, ol_olc=None,
1119 setup_ds_path=None, slapd_path=None, nosync=False,
1120 ldap_dryrun_mode=False):
1123 :note: caution, this wipes all existing data!
1126 def setup_path(file):
1127 return os.path.join(setup_dir, file)
1129 if domainsid is None:
1130 domainsid = security.random_sid()
1132 domainsid = security.dom_sid(domainsid)
1134 # create/adapt the group policy GUIDs
1135 if policyguid is None:
1136 policyguid = str(uuid.uuid4())
1137 policyguid = policyguid.upper()
1138 if policyguid_dc is None:
1139 policyguid_dc = str(uuid.uuid4())
1140 policyguid_dc = policyguid_dc.upper()
1142 if adminpass is None:
1143 adminpass = glue.generate_random_str(12)
1144 if krbtgtpass is None:
1145 krbtgtpass = glue.generate_random_str(12)
1146 if machinepass is None:
1147 machinepass = glue.generate_random_str(12)
1149 dnspass = glue.generate_random_str(12)
1150 if ldapadminpass is None:
1151 #Make a new, random password between Samba and it's LDAP server
1152 ldapadminpass=glue.generate_random_str(12)
1154 if backend_type is None:
1155 backend_type = "ldb"
1157 sid_generator = "internal"
1158 if backend_type == "fedora-ds":
1159 sid_generator = "backend"
1161 root_uid = findnss_uid([root or "root"])
1162 nobody_uid = findnss_uid([nobody or "nobody"])
1163 users_gid = findnss_gid([users or "users"])
1165 wheel_gid = findnss_gid(["wheel", "adm"])
1167 wheel_gid = findnss_gid([wheel])
1169 if targetdir is not None:
1170 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1171 os.makedirs(os.path.join(targetdir, "etc"))
1172 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1173 elif smbconf is None:
1174 smbconf = param.default_path()
1176 # only install a new smb.conf if there isn't one there already
1177 if not os.path.exists(smbconf):
1178 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1179 targetdir, sid_generator)
1181 lp = param.LoadParm()
1184 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1185 dnsdomain=realm, serverrole=serverrole,
1186 domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1187 serverdn=serverdn, sitename=sitename)
1189 paths = provision_paths_from_lp(lp, names.dnsdomain)
1193 hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1194 except socket.gaierror, (socket.EAI_NODATA, msg):
1199 hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
1200 except socket.gaierror, (socket.EAI_NODATA, msg):
1203 if serverrole is None:
1204 serverrole = lp.get("server role")
1206 assert serverrole in ("domain controller", "member server", "standalone")
1207 if invocationid is None and serverrole == "domain controller":
1208 invocationid = str(uuid.uuid4())
1210 if not os.path.exists(paths.private_dir):
1211 os.mkdir(paths.private_dir)
1213 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1215 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn)
1217 if backend_type == "ldb":
1218 provision_backend = LDBBackend(backend_type,
1219 paths=paths, setup_path=setup_path,
1220 lp=lp, credentials=credentials,
1223 elif backend_type == "existing":
1224 provision_backend = ExistingBackend(backend_type,
1225 paths=paths, setup_path=setup_path,
1226 lp=lp, credentials=credentials,
1229 elif backend_type == "fedora-ds":
1230 provision_backend = FDSBackend(backend_type,
1231 paths=paths, setup_path=setup_path,
1232 lp=lp, credentials=credentials,
1235 domainsid=domainsid,
1238 ldapadminpass=ldapadminpass,
1239 slapd_path=slapd_path,
1240 ldap_backend_extra_port=ldap_backend_extra_port,
1241 ldap_dryrun_mode=ldap_dryrun_mode,
1243 setup_ds_path=setup_ds_path)
1244 elif backend_type == "openldap":
1245 provision_backend = OpenLDAPBackend(backend_type,
1246 paths=paths, setup_path=setup_path,
1247 lp=lp, credentials=credentials,
1250 domainsid=domainsid,
1253 ldapadminpass=ldapadminpass,
1254 slapd_path=slapd_path,
1255 ldap_backend_extra_port=ldap_backend_extra_port,
1256 ldap_dryrun_mode=ldap_dryrun_mode,
1257 ol_mmr_urls=ol_mmr_urls,
1260 raise ProvisioningError("Unknown LDAP backend type selected")
1262 provision_backend.init()
1263 provision_backend.start()
1265 # only install a new shares config db if there is none
1266 if not os.path.exists(paths.shareconf):
1267 message("Setting up share.ldb")
1268 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1270 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1273 message("Setting up secrets.ldb")
1274 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1275 session_info=session_info,
1276 backend_credentials=provision_backend.secrets_credentials, lp=lp)
1278 message("Setting up the registry")
1279 setup_registry(paths.hklm, setup_path, session_info,
1282 message("Setting up the privileges database")
1283 setup_privileges(paths.privilege, setup_path, session_info, lp=lp)
1285 message("Setting up idmap db")
1286 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1289 message("Setting up SAM db")
1290 samdb = setup_samdb(paths.samdb, setup_path, session_info,
1291 provision_backend, lp, names,
1293 domainsid=domainsid,
1294 schema=schema, domainguid=domainguid,
1295 policyguid=policyguid, policyguid_dc=policyguid_dc,
1297 adminpass=adminpass, krbtgtpass=krbtgtpass,
1298 invocationid=invocationid,
1299 machinepass=machinepass, dnspass=dnspass,
1300 ntdsguid=ntdsguid, serverrole=serverrole,
1301 dom_for_fun_level=dom_for_fun_level)
1303 if serverrole == "domain controller":
1304 if paths.netlogon is None:
1305 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1306 message("Please either remove %s or see the template at %s" %
1307 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1308 assert(paths.netlogon is not None)
1310 if paths.sysvol is None:
1311 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1312 message("Please either remove %s or see the template at %s" %
1313 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1314 assert(paths.sysvol is not None)
1316 # Set up group policies (domain policy and domain controller policy)
1318 policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1319 "{" + policyguid + "}")
1320 os.makedirs(policy_path, 0755)
1321 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1322 "[General]\r\nVersion=65543")
1323 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
1324 os.makedirs(os.path.join(policy_path, "USER"), 0755)
1326 policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
1327 "{" + policyguid_dc + "}")
1328 os.makedirs(policy_path_dc, 0755)
1329 open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
1330 "[General]\r\nVersion=2")
1331 os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
1332 os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
1334 if not os.path.isdir(paths.netlogon):
1335 os.makedirs(paths.netlogon, 0755)
1337 if samdb_fill == FILL_FULL:
1338 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1339 root_uid=root_uid, nobody_uid=nobody_uid,
1340 users_gid=users_gid, wheel_gid=wheel_gid)
1342 message("Setting up sam.ldb rootDSE marking as synchronized")
1343 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1345 # Only make a zone file on the first DC, it should be replicated with DNS replication
1346 if serverrole == "domain controller":
1347 secretsdb_self_join(secrets_ldb, domain=domain,
1349 dnsdomain=names.dnsdomain,
1350 netbiosname=names.netbiosname,
1351 domainsid=domainsid,
1352 machinepass=machinepass,
1353 secure_channel_type=SEC_CHAN_BDC)
1355 secretsdb_setup_dns(secrets_ldb, setup_path,
1356 realm=names.realm, dnsdomain=names.dnsdomain,
1357 dns_keytab_path=paths.dns_keytab,
1360 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1361 assert isinstance(domainguid, str)
1363 create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
1365 hostip6=hostip6, hostname=names.hostname,
1367 domainguid=domainguid, ntdsguid=names.ntdsguid)
1369 create_named_conf(paths.namedconf, setup_path, realm=names.realm,
1370 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1372 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1373 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1374 keytab_name=paths.dns_keytab)
1375 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1376 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1378 create_krb5_conf(paths.krb5conf, setup_path,
1379 dnsdomain=names.dnsdomain, hostname=names.hostname,
1381 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1383 provision_backend.post_setup()
1384 provision_backend.shutdown()
1386 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1389 #Now commit the secrets.ldb to disk
1390 secrets_ldb.transaction_commit()
1392 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1394 message("Once the above files are installed, your Samba4 server will be ready to use")
1395 message("Server Role: %s" % serverrole)
1396 message("Hostname: %s" % names.hostname)
1397 message("NetBIOS Domain: %s" % names.domain)
1398 message("DNS Domain: %s" % names.dnsdomain)
1399 message("DOMAIN SID: %s" % str(domainsid))
1400 if samdb_fill == FILL_FULL:
1401 message("Admin password: %s" % adminpass)
1402 if provision_backend.type is not "ldb":
1403 if provision_backend.credentials.get_bind_dn() is not None:
1404 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1406 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1408 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1410 if provision_backend.slapd_command_escaped is not None:
1411 # now display slapd_command_file.txt to show how slapd must be started next time
1412 message("Use later the following commandline to start slapd, then Samba:")
1413 message(provision_backend.slapd_command_escaped)
1414 message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
1417 result = ProvisionResult()
1418 result.domaindn = domaindn
1419 result.paths = paths
1421 result.samdb = samdb
1426 def provision_become_dc(setup_dir=None,
1427 smbconf=None, targetdir=None, realm=None,
1428 rootdn=None, domaindn=None, schemadn=None,
1429 configdn=None, serverdn=None,
1430 domain=None, hostname=None, domainsid=None,
1431 adminpass=None, krbtgtpass=None, domainguid=None,
1432 policyguid=None, policyguid_dc=None, invocationid=None,
1434 dnspass=None, root=None, nobody=None, users=None,
1435 wheel=None, backup=None, serverrole=None,
1436 ldap_backend=None, ldap_backend_type=None,
1437 sitename=None, debuglevel=1):
1440 """print a message if quiet is not set."""
1443 glue.set_debug_level(debuglevel)
1445 return provision(setup_dir, message, system_session(), None,
1446 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1447 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1448 configdn=configdn, serverdn=serverdn, domain=domain,
1449 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1450 machinepass=machinepass, serverrole="domain controller",
1454 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1455 """Create a PHP LDAP admin configuration file.
1457 :param path: Path to write the configuration to.
1458 :param setup_path: Function to generate setup paths.
1460 setup_file(setup_path("phpldapadmin-config.php"), path,
1461 {"S4_LDAPI_URI": ldapi_uri})
1464 def create_zone_file(path, setup_path, dnsdomain,
1465 hostip, hostip6, hostname, realm, domainguid,
1467 """Write out a DNS zone file, from the info in the current database.
1469 :param path: Path of the new zone file.
1470 :param setup_path: Setup path function.
1471 :param dnsdomain: DNS Domain name
1472 :param domaindn: DN of the Domain
1473 :param hostip: Local IPv4 IP
1474 :param hostip6: Local IPv6 IP
1475 :param hostname: Local hostname
1476 :param realm: Realm name
1477 :param domainguid: GUID of the domain.
1478 :param ntdsguid: GUID of the hosts nTDSDSA record.
1480 assert isinstance(domainguid, str)
1482 if hostip6 is not None:
1483 hostip6_base_line = " IN AAAA " + hostip6
1484 hostip6_host_line = hostname + " IN AAAA " + hostip6
1486 hostip6_base_line = ""
1487 hostip6_host_line = ""
1489 if hostip is not None:
1490 hostip_base_line = " IN A " + hostip
1491 hostip_host_line = hostname + " IN A " + hostip
1493 hostip_base_line = ""
1494 hostip_host_line = ""
1496 setup_file(setup_path("provision.zone"), path, {
1497 "HOSTNAME": hostname,
1498 "DNSDOMAIN": dnsdomain,
1500 "HOSTIP_BASE_LINE": hostip_base_line,
1501 "HOSTIP_HOST_LINE": hostip_host_line,
1502 "DOMAINGUID": domainguid,
1503 "DATESTRING": time.strftime("%Y%m%d%H"),
1504 "DEFAULTSITE": DEFAULTSITE,
1505 "NTDSGUID": ntdsguid,
1506 "HOSTIP6_BASE_LINE": hostip6_base_line,
1507 "HOSTIP6_HOST_LINE": hostip6_host_line,
1511 def create_named_conf(path, setup_path, realm, dnsdomain,
1513 """Write out a file containing zone statements suitable for inclusion in a
1514 named.conf file (including GSS-TSIG configuration).
1516 :param path: Path of the new named.conf file.
1517 :param setup_path: Setup path function.
1518 :param realm: Realm name
1519 :param dnsdomain: DNS Domain name
1520 :param private_dir: Path to private directory
1521 :param keytab_name: File name of DNS keytab file
1524 setup_file(setup_path("named.conf"), path, {
1525 "DNSDOMAIN": dnsdomain,
1527 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1528 "PRIVATE_DIR": private_dir
1531 def create_named_txt(path, setup_path, realm, dnsdomain,
1532 private_dir, keytab_name):
1533 """Write out a file containing zone statements suitable for inclusion in a
1534 named.conf file (including GSS-TSIG configuration).
1536 :param path: Path of the new named.conf file.
1537 :param setup_path: Setup path function.
1538 :param realm: Realm name
1539 :param dnsdomain: DNS Domain name
1540 :param private_dir: Path to private directory
1541 :param keytab_name: File name of DNS keytab file
1544 setup_file(setup_path("named.txt"), path, {
1545 "DNSDOMAIN": dnsdomain,
1547 "DNS_KEYTAB": keytab_name,
1548 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1549 "PRIVATE_DIR": private_dir
1552 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1553 """Write out a file containing zone statements suitable for inclusion in a
1554 named.conf file (including GSS-TSIG configuration).
1556 :param path: Path of the new named.conf file.
1557 :param setup_path: Setup path function.
1558 :param dnsdomain: DNS Domain name
1559 :param hostname: Local hostname
1560 :param realm: Realm name
1563 setup_file(setup_path("krb5.conf"), path, {
1564 "DNSDOMAIN": dnsdomain,
1565 "HOSTNAME": hostname,