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 samba.auth import system_session, admin_session
44 from samba import glue, version, Ldb, substitute_var, valid_netbios_name
45 from samba import check_all_substituted, read_and_sub_file, setup_file
46 from samba import DS_DOMAIN_FUNCTION_2003, DS_DC_FUNCTION_2008
47 from samba.dcerpc import security
48 from samba.dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
49 from samba.idmap import IDmapDB
50 from samba.ntacls import setntacl, dsacl2fsacl
51 from samba.ndr import ndr_pack,ndr_unpack
52 from samba.schema import Schema
53 from ms_display_specifiers import read_ms_ldif
54 from samba.provisionbackend import LDBBackend, ExistingBackend, FDSBackend, OpenLDAPBackend
55 from provisionexceptions import ProvisioningError, InvalidNetbiosName
57 __docformat__ = "restructuredText"
60 """Find the setup directory used by provision."""
61 dirname = os.path.dirname(__file__)
62 if "/site-packages/" in dirname:
63 prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
64 for suffix in ["share/setup", "share/samba/setup", "setup"]:
65 ret = os.path.join(prefix, suffix)
66 if os.path.isdir(ret):
69 ret = os.path.join(dirname, "../../../setup")
70 if os.path.isdir(ret):
72 raise Exception("Unable to find setup directory.")
74 # descriptors of the naming contexts
75 # hard coded at this point, but will probably be changed when
76 # we enable different fsmo roles
78 def get_config_descriptor(domain_sid):
79 sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
80 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
81 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
82 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
83 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
84 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
85 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
86 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
87 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
88 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
89 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
90 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
91 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
92 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
93 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
94 sec = security.descriptor.from_sddl(sddl, domain_sid)
97 def get_domain_descriptor(domain_sid):
98 sddl= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
99 "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
100 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
101 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
102 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
103 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
104 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
105 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
106 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
107 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
108 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
109 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
110 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
111 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
112 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
113 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
114 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
115 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
116 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
117 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
118 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
119 "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
120 "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
121 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
122 "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
123 "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
124 "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
125 "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
126 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
127 "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
128 "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
129 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
130 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
131 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
132 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
133 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
134 "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
135 "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
136 "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
139 "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
141 "(A;;RPLCLORC;;;ED)" \
142 "(A;;RPLCLORC;;;AU)" \
143 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
144 "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
145 "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
146 "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
147 sec = security.descriptor.from_sddl(sddl, domain_sid)
150 DEFAULTSITE = "Default-First-Site-Name"
154 class ProvisionPaths(object):
156 self.shareconf = None
167 self.dns_keytab = None
170 self.private_dir = None
173 class ProvisionNames(object):
179 self.ldapmanagerdn = None
180 self.dnsdomain = None
182 self.netbiosname = None
189 class ProvisionResult(object):
196 def check_install(lp, session_info, credentials):
197 """Check whether the current install seems ok.
199 :param lp: Loadparm context
200 :param session_info: Session information
201 :param credentials: Credentials
203 if lp.get("realm") == "":
204 raise Exception("Realm empty")
205 ldb = Ldb(lp.get("sam database"), session_info=session_info,
206 credentials=credentials, lp=lp)
207 if len(ldb.search("(cn=Administrator)")) != 1:
208 raise ProvisioningError("No administrator account found")
211 def findnss(nssfn, names):
212 """Find a user or group from a list of possibilities.
214 :param nssfn: NSS Function to try (should raise KeyError if not found)
215 :param names: Names to check.
216 :return: Value return by first names list.
223 raise KeyError("Unable to find user/group in %r" % names)
226 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
227 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
230 def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
231 """Setup a ldb in the private dir.
233 :param ldb: LDB file to import data into
234 :param ldif_path: Path of the LDIF file to load
235 :param subst_vars: Optional variables to subsitute in LDIF.
236 :param nocontrols: Optional list of controls, can be None for no controls
238 assert isinstance(ldif_path, str)
239 data = read_and_sub_file(ldif_path, subst_vars)
240 ldb.add_ldif(data, controls)
243 def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
244 """Modify a ldb in the private dir.
246 :param ldb: LDB object.
247 :param ldif_path: LDIF file path.
248 :param subst_vars: Optional dictionary with substitution variables.
250 data = read_and_sub_file(ldif_path, subst_vars)
251 ldb.modify_ldif(data)
254 def setup_ldb(ldb, ldif_path, subst_vars):
255 """Import a LDIF a file into a LDB handle, optionally substituting variables.
257 :note: Either all LDIF data will be added or none (using transactions).
259 :param ldb: LDB file to import into.
260 :param ldif_path: Path to the LDIF file.
261 :param subst_vars: Dictionary with substitution variables.
263 assert ldb is not None
264 ldb.transaction_start()
266 setup_add_ldif(ldb, ldif_path, subst_vars)
268 ldb.transaction_cancel()
270 ldb.transaction_commit()
273 def provision_paths_from_lp(lp, dnsdomain):
274 """Set the default paths for provisioning.
276 :param lp: Loadparm context.
277 :param dnsdomain: DNS Domain name
279 paths = ProvisionPaths()
280 paths.private_dir = lp.get("private dir")
281 paths.dns_keytab = "dns.keytab"
283 paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
284 paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
285 paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
286 paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
287 paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
288 paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone")
289 paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list")
290 paths.namedconf = os.path.join(paths.private_dir, "named.conf")
291 paths.namedconf_update = os.path.join(paths.private_dir, "named.conf.update")
292 paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
293 paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
294 paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
295 paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
296 paths.phpldapadminconfig = os.path.join(paths.private_dir,
297 "phpldapadmin-config.php")
298 paths.hklm = "hklm.ldb"
299 paths.hkcr = "hkcr.ldb"
300 paths.hkcu = "hkcu.ldb"
301 paths.hku = "hku.ldb"
302 paths.hkpd = "hkpd.ldb"
303 paths.hkpt = "hkpt.ldb"
304 paths.sysvol = lp.get("path", "sysvol")
305 paths.netlogon = lp.get("path", "netlogon")
306 paths.smbconf = lp.configfile
310 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
311 serverrole=None, rootdn=None, domaindn=None, configdn=None,
312 schemadn=None, serverdn=None, sitename=None):
313 """Guess configuration settings to use."""
316 hostname = socket.gethostname().split(".")[0]
318 netbiosname = lp.get("netbios name")
319 if netbiosname is None:
320 netbiosname = hostname
321 assert netbiosname is not None
322 netbiosname = netbiosname.upper()
323 if not valid_netbios_name(netbiosname):
324 raise InvalidNetbiosName(netbiosname)
326 if dnsdomain is None:
327 dnsdomain = lp.get("realm")
328 if dnsdomain is None or dnsdomain == "":
329 raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp.configfile)
331 dnsdomain = dnsdomain.lower()
333 if serverrole is None:
334 serverrole = lp.get("server role")
335 if serverrole is None:
336 raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp.configfile)
338 serverrole = serverrole.lower()
340 realm = dnsdomain.upper()
342 if lp.get("realm") == "":
343 raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp.configfile)
345 if lp.get("realm").upper() != realm:
346 raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile))
348 if lp.get("server role").lower() != serverrole:
349 raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("server role").upper(), serverrole, lp.configfile))
351 if serverrole == "domain controller":
353 # This will, for better or worse, default to 'WORKGROUP'
354 domain = lp.get("workgroup")
355 domain = domain.upper()
357 if lp.get("workgroup").upper() != domain:
358 raise ProvisioningError("guess_names: Workgroup '%s' in %s must match chosen domain '%s'! Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile))
361 domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
365 domaindn = "DC=" + netbiosname
367 if not valid_netbios_name(domain):
368 raise InvalidNetbiosName(domain)
370 if hostname.upper() == realm:
371 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm, hostname))
372 if netbiosname == realm:
373 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm, netbiosname))
375 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm, domain))
381 configdn = "CN=Configuration," + rootdn
383 schemadn = "CN=Schema," + configdn
388 names = ProvisionNames()
389 names.rootdn = rootdn
390 names.domaindn = domaindn
391 names.configdn = configdn
392 names.schemadn = schemadn
393 names.ldapmanagerdn = "CN=Manager," + rootdn
394 names.dnsdomain = dnsdomain
395 names.domain = domain
397 names.netbiosname = netbiosname
398 names.hostname = hostname
399 names.sitename = sitename
400 names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
405 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
406 targetdir, sid_generator,eadb):
407 """Create a new smb.conf file based on a couple of basic settings.
409 assert smbconf is not None
411 hostname = socket.gethostname().split(".")[0]
412 netbiosname = hostname.upper()
414 if serverrole is None:
415 serverrole = "standalone"
417 assert serverrole in ("domain controller", "member server", "standalone")
418 if serverrole == "domain controller":
420 elif serverrole == "member server":
421 smbconfsuffix = "member"
422 elif serverrole == "standalone":
423 smbconfsuffix = "standalone"
425 if sid_generator is None:
426 sid_generator = "internal"
428 assert domain is not None
429 domain = domain.upper()
431 assert realm is not None
432 realm = realm.upper()
434 default_lp = param.LoadParm()
435 #Load non-existant file
436 if os.path.exists(smbconf):
437 default_lp.load(smbconf)
439 if targetdir is not None:
440 privdir = os.path.join(targetdir, "private")
442 privdir = default_lp.get("private dir")
443 posixeadb_line = "posix:eadb = " + os.path.abspath(os.path.join(privdir,"eadb.tdb"))
447 if targetdir is not None:
448 privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
449 lockdir_line = "lock dir = " + os.path.abspath(targetdir)
451 default_lp.set("lock dir", os.path.abspath(targetdir))
456 if sid_generator == "internal":
457 sid_generator_line = ""
459 sid_generator_line = "sid generator = " + sid_generator
461 sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
462 netlogon = os.path.join(sysvol, realm.lower(), "scripts")
464 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
466 "NETBIOS_NAME": netbiosname,
469 "SERVERROLE": serverrole,
470 "NETLOGONPATH": netlogon,
471 "SYSVOLPATH": sysvol,
472 "SIDGENERATOR_LINE": sid_generator_line,
473 "PRIVATEDIR_LINE": privatedir_line,
474 "LOCKDIR_LINE": lockdir_line,
475 "POSIXEADB_LINE": posixeadb_line
479 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
480 users_gid, wheel_gid):
481 """setup reasonable name mappings for sam names to unix names.
483 :param samdb: SamDB object.
484 :param idmap: IDmap db object.
485 :param sid: The domain sid.
486 :param domaindn: The domain DN.
487 :param root_uid: uid of the UNIX root user.
488 :param nobody_uid: uid of the UNIX nobody user.
489 :param users_gid: gid of the UNIX users group.
490 :param wheel_gid: gid of the UNIX wheel group."""
492 idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
493 idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
495 idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
496 idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
498 def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
499 provision_backend, names, schema,
502 """Setup the partitions for the SAM database.
504 Alternatively, provision() may call this, and then populate the database.
506 :note: This will wipe the Sam Database!
508 :note: This function always removes the local SAM LDB file. The erase
509 parameter controls whether to erase the existing data, which
510 may not be stored locally but in LDAP.
513 assert session_info is not None
515 # We use options=["modules:"] to stop the modules loading - we
516 # just want to wipe and re-initialise the database, not start it up
519 os.unlink(samdb_path)
523 samdb = Ldb(url=samdb_path, session_info=session_info,
524 lp=lp, options=["modules:"])
526 ldap_backend_line = "# No LDAP backend"
527 if provision_backend.type is not "ldb":
528 ldap_backend_line = "ldapBackend: %s" % provision_backend.ldapi_uri
530 samdb.transaction_start()
532 message("Setting up sam.ldb partitions and settings")
533 setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
534 "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
535 "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
536 "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
537 "LDAP_BACKEND_LINE": ldap_backend_line,
541 setup_add_ldif(samdb, setup_path("provision_init.ldif"), {
542 "BACKEND_TYPE": provision_backend.type,
543 "SERVER_ROLE": serverrole
546 message("Setting up sam.ldb rootDSE")
547 setup_samdb_rootdse(samdb, setup_path, names)
550 samdb.transaction_cancel()
553 samdb.transaction_commit()
556 def secretsdb_self_join(secretsdb, domain,
557 netbiosname, machinepass, domainsid=None,
558 realm=None, dnsdomain=None,
560 key_version_number=1,
561 secure_channel_type=SEC_CHAN_WKSTA):
562 """Add domain join-specific bits to a secrets database.
564 :param secretsdb: Ldb Handle to the secrets database
565 :param machinepass: Machine password
567 attrs=["whenChanged",
575 msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain))
576 msg["secureChannelType"] = str(secure_channel_type)
577 msg["flatname"] = [domain]
578 msg["objectClass"] = ["top", "primaryDomain"]
579 if realm is not None:
580 if dnsdomain is None:
581 dnsdomain = realm.lower()
582 msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
584 msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
585 msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
586 msg["privateKeytab"] = ["secrets.keytab"]
589 msg["secret"] = [machinepass]
590 msg["samAccountName"] = ["%s$" % netbiosname]
591 msg["secureChannelType"] = [str(secure_channel_type)]
592 if domainsid is not None:
593 msg["objectSid"] = [ndr_pack(domainsid)]
595 res = secretsdb.search(base="cn=Primary Domains",
597 expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
598 scope=ldb.SCOPE_ONELEVEL)
601 if del_msg.dn is not msg.dn:
602 secretsdb.delete(del_msg.dn)
604 res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE)
607 msg["priorSecret"] = res[0]["secret"]
608 msg["priorWhenChanged"] = res[0]["whenChanged"]
610 if res["privateKeytab"] is not None:
611 msg["privateKeytab"] = res[0]["privateKeytab"]
613 if res["krb5Keytab"] is not None:
614 msg["krb5Keytab"] = res[0]["krb5Keytab"]
617 el.set_flags(ldb.FLAG_MOD_REPLACE)
618 secretsdb.modify(msg)
623 def secretsdb_setup_dns(secretsdb, setup_path, private_dir,
625 dns_keytab_path, dnspass):
626 """Add DNS specific bits to a secrets database.
628 :param secretsdb: Ldb Handle to the secrets database
629 :param setup_path: Setup path function
630 :param machinepass: Machine password
633 os.unlink(os.path.join(private_dir, dns_keytab_path))
637 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
639 "DNSDOMAIN": dnsdomain,
640 "DNS_KEYTAB": dns_keytab_path,
641 "DNSPASS_B64": b64encode(dnspass),
645 def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
646 """Setup the secrets database.
648 :param path: Path to the secrets database.
649 :param setup_path: Get the path to a setup file.
650 :param session_info: Session info.
651 :param credentials: Credentials
652 :param lp: Loadparm context
653 :return: LDB handle for the created secrets database
655 if os.path.exists(path):
657 secrets_ldb = Ldb(path, session_info=session_info,
660 secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
661 secrets_ldb = Ldb(path, session_info=session_info,
663 secrets_ldb.transaction_start()
664 secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
666 if backend_credentials is not None and backend_credentials.authentication_requested():
667 if backend_credentials.get_bind_dn() is not None:
668 setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
669 "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
670 "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
673 setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
674 "LDAPADMINUSER": backend_credentials.get_username(),
675 "LDAPADMINREALM": backend_credentials.get_realm(),
676 "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
681 def setup_privileges(path, setup_path, session_info, lp):
682 """Setup the privileges database.
684 :param path: Path to the privileges database.
685 :param setup_path: Get the path to a setup file.
686 :param session_info: Session info.
687 :param credentials: Credentials
688 :param lp: Loadparm context
689 :return: LDB handle for the created secrets database
691 if os.path.exists(path):
693 privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
694 privilege_ldb.erase()
695 privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
698 def setup_registry(path, setup_path, session_info, lp):
699 """Setup the registry.
701 :param path: Path to the registry database
702 :param setup_path: Function that returns the path to a setup.
703 :param session_info: Session information
704 :param credentials: Credentials
705 :param lp: Loadparm context
707 reg = registry.Registry()
708 hive = registry.open_ldb(path, session_info=session_info,
710 reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
711 provision_reg = setup_path("provision.reg")
712 assert os.path.exists(provision_reg)
713 reg.diff_apply(provision_reg)
716 def setup_idmapdb(path, setup_path, session_info, lp):
717 """Setup the idmap database.
719 :param path: path to the idmap database
720 :param setup_path: Function that returns a path to a setup file
721 :param session_info: Session information
722 :param credentials: Credentials
723 :param lp: Loadparm context
725 if os.path.exists(path):
728 idmap_ldb = IDmapDB(path, session_info=session_info,
732 idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
736 def setup_samdb_rootdse(samdb, setup_path, names):
737 """Setup the SamDB rootdse.
739 :param samdb: Sam Database handle
740 :param setup_path: Obtain setup path
742 setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
743 "SCHEMADN": names.schemadn,
744 "NETBIOSNAME": names.netbiosname,
745 "DNSDOMAIN": names.dnsdomain,
746 "REALM": names.realm,
747 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
748 "DOMAINDN": names.domaindn,
749 "ROOTDN": names.rootdn,
750 "CONFIGDN": names.configdn,
751 "SERVERDN": names.serverdn,
755 def setup_self_join(samdb, names,
756 machinepass, dnspass,
757 domainsid, invocationid, setup_path,
758 policyguid, policyguid_dc, domainControllerFunctionality,
760 """Join a host to its own domain."""
761 assert isinstance(invocationid, str)
762 if ntdsguid is not None:
763 ntdsguid_line = "objectGUID: %s\n"%ntdsguid
766 setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
767 "CONFIGDN": names.configdn,
768 "SCHEMADN": names.schemadn,
769 "DOMAINDN": names.domaindn,
770 "SERVERDN": names.serverdn,
771 "INVOCATIONID": invocationid,
772 "NETBIOSNAME": names.netbiosname,
773 "DEFAULTSITE": names.sitename,
774 "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
775 "MACHINEPASS_B64": b64encode(machinepass),
776 "REALM": names.realm,
777 "DOMAIN": names.domain,
778 "DOMAINSID": str(domainsid),
779 "DNSDOMAIN": names.dnsdomain,
780 "SAMBA_VERSION_STRING": version,
781 "NTDSGUID": ntdsguid_line,
782 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
784 setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
785 "POLICYGUID": policyguid,
786 "POLICYGUID_DC": policyguid_dc,
787 "DNSDOMAIN": names.dnsdomain,
788 "DOMAINSID": str(domainsid),
789 "DOMAINDN": names.domaindn})
791 # add the NTDSGUID based SPNs
792 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
793 names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
794 expression="", scope=ldb.SCOPE_BASE)
795 assert isinstance(names.ntdsguid, str)
797 # Setup fSMORoleOwner entries to point at the newly created DC entry
798 setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
799 "DOMAIN": names.domain,
800 "DNSDOMAIN": names.dnsdomain,
801 "DOMAINDN": names.domaindn,
802 "CONFIGDN": names.configdn,
803 "SCHEMADN": names.schemadn,
804 "DEFAULTSITE": names.sitename,
805 "SERVERDN": names.serverdn,
806 "NETBIOSNAME": names.netbiosname,
807 "NTDSGUID": names.ntdsguid,
808 "DNSPASS_B64": b64encode(dnspass),
810 def getpolicypath(sysvolpath,dnsdomain,guid):
811 if string.find(guid,"{",0,1) == -1:
813 policy_path = os.path.join(sysvolpath, dnsdomain, "Policies", guid )
816 def create_gpo_struct(policy_path):
817 os.makedirs(policy_path, 0755)
818 open(os.path.join(policy_path, "GPT.INI"), 'w').write(
819 "[General]\r\nVersion=65543")
820 os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
821 os.makedirs(os.path.join(policy_path, "USER"), 0755)
823 def setup_gpo(sysvolpath,dnsdomain,policyguid,policyguid_dc):
825 policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid)
826 create_gpo_struct(policy_path)
828 policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid_dc)
829 create_gpo_struct(policy_path)
831 def setup_samdb(path, setup_path, session_info, provision_backend, lp,
833 domainsid, domainguid, policyguid, policyguid_dc,
834 fill, adminpass, krbtgtpass,
835 machinepass, invocationid, dnspass, ntdsguid,
836 serverrole, dom_for_fun_level=None,
838 """Setup a complete SAM Database.
840 :note: This will wipe the main SAM database file!
843 # ATTENTION: Do NOT change these default values without discussion with the
844 # team and/or release manager. They have a big impact on the whole program!
845 domainControllerFunctionality = DS_DC_FUNCTION_2008
847 if dom_for_fun_level is None:
848 dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
849 if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003:
850 message("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This is not recommended")
852 if dom_for_fun_level > domainControllerFunctionality:
853 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!")
855 domainFunctionality = dom_for_fun_level
856 forestFunctionality = dom_for_fun_level
858 # Also wipes the database
859 setup_samdb_partitions(path, setup_path, message=message, lp=lp,
860 provision_backend=provision_backend, session_info=session_info,
862 serverrole=serverrole, schema=schema)
865 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn)
867 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
868 samdb = Ldb(session_info=session_info,
869 credentials=provision_backend.credentials, lp=lp)
871 message("Pre-loading the Samba 4 and AD schema")
873 # Load the schema from the one we computed earlier
874 samdb.set_schema_from_ldb(schema.ldb)
876 # And now we can connect to the DB - the schema won't be loaded from the DB
882 samdb.transaction_start()
884 # Set the domain functionality levels onto the database.
885 # Various module (the password_hash module in particular) need
886 # to know what level of AD we are emulating.
888 # These will be fixed into the database via the database
889 # modifictions below, but we need them set from the start.
890 samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
891 samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
892 samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
894 samdb.set_domain_sid(str(domainsid))
895 samdb.set_invocation_id(invocationid)
897 message("Adding DomainDN: %s" % names.domaindn)
899 #impersonate domain admin
900 admin_session_info = admin_session(lp, str(domainsid))
901 samdb.set_session_info(admin_session_info)
902 if domainguid is not None:
903 domainguid_line = "objectGUID: %s\n-" % domainguid
907 descr = b64encode(get_domain_descriptor(domainsid))
908 setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
909 "DOMAINDN": names.domaindn,
910 "DOMAINGUID": domainguid_line,
915 setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
916 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
917 "DOMAINSID": str(domainsid),
918 "SCHEMADN": names.schemadn,
919 "NETBIOSNAME": names.netbiosname,
920 "DEFAULTSITE": names.sitename,
921 "CONFIGDN": names.configdn,
922 "SERVERDN": names.serverdn,
923 "POLICYGUID": policyguid,
924 "DOMAINDN": names.domaindn,
925 "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
926 "SAMBA_VERSION_STRING": version
929 message("Adding configuration container")
930 descr = b64encode(get_config_descriptor(domainsid))
931 setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
932 "CONFIGDN": names.configdn,
936 # The LDIF here was created when the Schema object was constructed
937 message("Setting up sam.ldb schema")
938 samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
939 samdb.modify_ldif(schema.schema_dn_modify)
940 samdb.write_prefixes_from_schema()
941 samdb.add_ldif(schema.schema_data, controls=["relax:0"])
942 setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
943 {"SCHEMADN": names.schemadn})
945 message("Reopening sam.ldb with new schema")
946 samdb.transaction_commit()
947 samdb = Ldb(session_info=admin_session_info,
948 credentials=provision_backend.credentials, lp=lp)
950 samdb.transaction_start()
951 samdb.set_invocation_id(invocationid)
953 message("Setting up sam.ldb configuration data")
954 setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
955 "CONFIGDN": names.configdn,
956 "NETBIOSNAME": names.netbiosname,
957 "DEFAULTSITE": names.sitename,
958 "DNSDOMAIN": names.dnsdomain,
959 "DOMAIN": names.domain,
960 "SCHEMADN": names.schemadn,
961 "DOMAINDN": names.domaindn,
962 "SERVERDN": names.serverdn,
963 "FOREST_FUNCTIONALALITY": str(forestFunctionality)
966 message("Setting up display specifiers")
967 display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
968 display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
969 check_all_substituted(display_specifiers_ldif)
970 samdb.add_ldif(display_specifiers_ldif)
972 message("Adding users container")
973 setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
974 "DOMAINDN": names.domaindn})
975 message("Modifying users container")
976 setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
977 "DOMAINDN": names.domaindn})
978 message("Adding computers container")
979 setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
980 "DOMAINDN": names.domaindn})
981 message("Modifying computers container")
982 setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
983 "DOMAINDN": names.domaindn})
984 message("Setting up sam.ldb data")
985 setup_add_ldif(samdb, setup_path("provision.ldif"), {
986 "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
987 "DOMAINDN": names.domaindn,
988 "NETBIOSNAME": names.netbiosname,
989 "DEFAULTSITE": names.sitename,
990 "CONFIGDN": names.configdn,
991 "SERVERDN": names.serverdn,
992 "POLICYGUID_DC": policyguid_dc
995 setup_modify_ldif(samdb, setup_path("provision_basedn_references.ldif"), {
996 "DOMAINDN": names.domaindn})
998 setup_modify_ldif(samdb, setup_path("provision_configuration_references.ldif"), {
999 "CONFIGDN": names.configdn,
1000 "SCHEMADN": names.schemadn})
1001 if fill == FILL_FULL:
1002 message("Setting up sam.ldb users and groups")
1003 setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1004 "DOMAINDN": names.domaindn,
1005 "DOMAINSID": str(domainsid),
1006 "CONFIGDN": names.configdn,
1007 "ADMINPASS_B64": b64encode(adminpass),
1008 "KRBTGTPASS_B64": b64encode(krbtgtpass),
1011 message("Setting up self join")
1012 setup_self_join(samdb, names=names, invocationid=invocationid,
1014 machinepass=machinepass,
1015 domainsid=domainsid, policyguid=policyguid,
1016 policyguid_dc=policyguid_dc,
1017 setup_path=setup_path,
1018 domainControllerFunctionality=domainControllerFunctionality,
1021 ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
1022 names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1023 attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE)
1024 assert isinstance(names.ntdsguid, str)
1027 samdb.transaction_cancel()
1030 samdb.transaction_commit()
1035 FILL_NT4SYNC = "NT4SYNC"
1037 SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
1038 POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
1040 def set_dir_acl(path,acl,lp,domsid):
1041 setntacl(lp,path,acl,domsid)
1042 for root, dirs, files in os.walk(path, topdown=False):
1044 setntacl(lp,os.path.join(root, name),acl,domsid)
1046 setntacl(lp,os.path.join(root, name),acl,domsid)
1048 def set_gpo_acl(sysvol,dnsdomain,domainsid,domaindn,samdb,lp):
1050 policy_path = os.path.join(sysvol, dnsdomain, "Policies")
1051 set_dir_acl(policy_path,dsacl2fsacl(POLICIES_ACL,str(domainsid)),lp,str(domainsid))
1052 res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn),
1053 attrs=["cn","nTSecurityDescriptor"],
1054 expression="", scope=ldb.SCOPE_ONELEVEL)
1056 acl = ndr_unpack(security.descriptor,str(policy["nTSecurityDescriptor"])).as_sddl()
1057 policy_path = getpolicypath(sysvol,dnsdomain,str(policy["cn"]))
1058 set_dir_acl(policy_path,dsacl2fsacl(acl,str(domainsid)),lp,str(domainsid))
1060 def setsysvolacl(samdb,netlogon,sysvol,gid,domainsid,dnsdomain,domaindn,lp):
1063 os.chown(sysvol,-1,gid)
1067 setntacl(lp,sysvol,SYSVOL_ACL,str(domainsid))
1068 for root, dirs, files in os.walk(sysvol, topdown=False):
1071 os.chown(os.path.join(root, name),-1,gid)
1072 setntacl(lp,os.path.join(root, name),SYSVOL_ACL,str(domainsid))
1075 os.chown(os.path.join(root, name),-1,gid)
1076 setntacl(lp,os.path.join(root, name),SYSVOL_ACL,str(domainsid))
1077 set_gpo_acl(sysvol,dnsdomain,domainsid,domaindn,samdb,lp)
1082 def provision(setup_dir, message, session_info,
1083 credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
1085 rootdn=None, domaindn=None, schemadn=None, configdn=None,
1087 domain=None, hostname=None, hostip=None, hostip6=None,
1088 domainsid=None, adminpass=None, ldapadminpass=None,
1089 krbtgtpass=None, domainguid=None,
1090 policyguid=None, policyguid_dc=None, invocationid=None,
1091 machinepass=None, ntdsguid=None,
1092 dnspass=None, root=None, nobody=None, users=None,
1093 wheel=None, backup=None, aci=None, serverrole=None,
1094 dom_for_fun_level=None,
1095 ldap_backend_extra_port=None, backend_type=None,
1097 ol_mmr_urls=None, ol_olc=None,
1098 setup_ds_path=None, slapd_path=None, nosync=False,
1099 ldap_dryrun_mode=False,useeadb=False):
1102 :note: caution, this wipes all existing data!
1105 def setup_path(file):
1106 return os.path.join(setup_dir, file)
1108 if domainsid is None:
1109 domainsid = security.random_sid()
1111 domainsid = security.dom_sid(domainsid)
1113 # create/adapt the group policy GUIDs
1114 if policyguid is None:
1115 policyguid = str(uuid.uuid4())
1116 policyguid = policyguid.upper()
1117 if policyguid_dc is None:
1118 policyguid_dc = str(uuid.uuid4())
1119 policyguid_dc = policyguid_dc.upper()
1121 if adminpass is None:
1122 adminpass = glue.generate_random_password(12, 32)
1123 if krbtgtpass is None:
1124 krbtgtpass = glue.generate_random_password(128, 255)
1125 if machinepass is None:
1126 machinepass = glue.generate_random_password(128, 255)
1128 dnspass = glue.generate_random_password(128, 255)
1129 if ldapadminpass is None:
1130 #Make a new, random password between Samba and it's LDAP server
1131 ldapadminpass=glue.generate_random_password(128, 255)
1133 if backend_type is None:
1134 backend_type = "ldb"
1136 sid_generator = "internal"
1137 if backend_type == "fedora-ds":
1138 sid_generator = "backend"
1140 root_uid = findnss_uid([root or "root"])
1141 nobody_uid = findnss_uid([nobody or "nobody"])
1142 users_gid = findnss_gid([users or "users", 'users', 'other', 'staff'])
1144 wheel_gid = findnss_gid(["wheel", "adm"])
1146 wheel_gid = findnss_gid([wheel])
1148 bind_gid = findnss_gid(["bind", "named"])
1152 if targetdir is not None:
1153 if (not os.path.exists(os.path.join(targetdir, "etc"))):
1154 os.makedirs(os.path.join(targetdir, "etc"))
1155 smbconf = os.path.join(targetdir, "etc", "smb.conf")
1156 elif smbconf is None:
1157 smbconf = param.default_path()
1159 # only install a new smb.conf if there isn't one there already
1160 if os.path.exists(smbconf):
1161 # if Samba Team members can't figure out the weird errors
1162 # loading an empty smb.conf gives, then we need to be smarter.
1163 # Pretend it just didn't exist --abartlet
1164 data = open(smbconf, 'r').read()
1165 data = data.lstrip()
1166 if data is None or data == "":
1167 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1168 targetdir, sid_generator, useeadb)
1170 make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1171 targetdir, sid_generator, useeadb)
1173 lp = param.LoadParm()
1176 names = guess_names(lp=lp, hostname=hostname, domain=domain,
1177 dnsdomain=realm, serverrole=serverrole,
1178 domaindn=domaindn, configdn=configdn, schemadn=schemadn,
1179 serverdn=serverdn, sitename=sitename)
1181 paths = provision_paths_from_lp(lp, names.dnsdomain)
1183 paths.bind_gid = bind_gid
1186 hostips = glue.interface_ips(lp, False)
1187 if len(hostips) == 0:
1188 message("No external IPv4 address has been found: I use the loopback.")
1189 hostip = '127.0.0.1'
1192 if len(hostips) > 1:
1193 message("More than one IPv4 address found: I use " + hostip + ".")
1197 for ip in socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP):
1200 if hostip6 == '::1' and ip[-1][0] != '::1':
1202 except socket.gaierror, (socket.EAI_NODATA, msg):
1205 if serverrole is None:
1206 serverrole = lp.get("server role")
1208 assert serverrole in ("domain controller", "member server", "standalone")
1209 if invocationid is None:
1210 invocationid = str(uuid.uuid4())
1212 if not os.path.exists(paths.private_dir):
1213 os.mkdir(paths.private_dir)
1214 if not os.path.exists(os.path.join(paths.private_dir,"tls")):
1215 os.mkdir(os.path.join(paths.private_dir,"tls"))
1217 ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1219 schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn)
1221 if backend_type == "ldb":
1222 provision_backend = LDBBackend(backend_type,
1223 paths=paths, setup_path=setup_path,
1224 lp=lp, credentials=credentials,
1227 elif backend_type == "existing":
1228 provision_backend = ExistingBackend(backend_type,
1229 paths=paths, setup_path=setup_path,
1230 lp=lp, credentials=credentials,
1233 ldapi_url=ldapi_url)
1234 elif backend_type == "fedora-ds":
1235 provision_backend = FDSBackend(backend_type,
1236 paths=paths, setup_path=setup_path,
1237 lp=lp, credentials=credentials,
1240 domainsid=domainsid,
1243 ldapadminpass=ldapadminpass,
1244 slapd_path=slapd_path,
1245 ldap_backend_extra_port=ldap_backend_extra_port,
1246 ldap_dryrun_mode=ldap_dryrun_mode,
1248 setup_ds_path=setup_ds_path)
1249 elif backend_type == "openldap":
1250 provision_backend = OpenLDAPBackend(backend_type,
1251 paths=paths, setup_path=setup_path,
1252 lp=lp, credentials=credentials,
1255 domainsid=domainsid,
1258 ldapadminpass=ldapadminpass,
1259 slapd_path=slapd_path,
1260 ldap_backend_extra_port=ldap_backend_extra_port,
1261 ldap_dryrun_mode=ldap_dryrun_mode,
1262 ol_mmr_urls=ol_mmr_urls,
1265 raise ProvisioningError("Unknown LDAP backend type selected")
1267 provision_backend.init()
1268 provision_backend.start()
1270 # only install a new shares config db if there is none
1271 if not os.path.exists(paths.shareconf):
1272 message("Setting up share.ldb")
1273 share_ldb = Ldb(paths.shareconf, session_info=session_info,
1275 share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1278 message("Setting up secrets.ldb")
1279 secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
1280 session_info=session_info,
1281 backend_credentials=provision_backend.secrets_credentials, lp=lp)
1283 message("Setting up the registry")
1284 setup_registry(paths.hklm, setup_path, session_info,
1287 message("Setting up the privileges database")
1288 setup_privileges(paths.privilege, setup_path, session_info, lp=lp)
1290 message("Setting up idmap db")
1291 idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
1294 message("Setting up SAM db")
1295 samdb = setup_samdb(paths.samdb, setup_path, session_info,
1296 provision_backend, lp, names,
1298 domainsid=domainsid,
1299 schema=schema, domainguid=domainguid,
1300 policyguid=policyguid, policyguid_dc=policyguid_dc,
1302 adminpass=adminpass, krbtgtpass=krbtgtpass,
1303 invocationid=invocationid,
1304 machinepass=machinepass, dnspass=dnspass,
1305 ntdsguid=ntdsguid, serverrole=serverrole,
1306 dom_for_fun_level=dom_for_fun_level)
1308 if serverrole == "domain controller":
1309 if paths.netlogon is None:
1310 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1311 message("Please either remove %s or see the template at %s" %
1312 ( paths.smbconf, setup_path("provision.smb.conf.dc")))
1313 assert(paths.netlogon is not None)
1315 if paths.sysvol is None:
1316 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1317 message("Please either remove %s or see the template at %s" %
1318 (paths.smbconf, setup_path("provision.smb.conf.dc")))
1319 assert(paths.sysvol is not None)
1322 if not os.path.isdir(paths.netlogon):
1323 os.makedirs(paths.netlogon, 0755)
1325 if samdb_fill == FILL_FULL:
1326 setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1327 root_uid=root_uid, nobody_uid=nobody_uid,
1328 users_gid=users_gid, wheel_gid=wheel_gid)
1330 if serverrole == "domain controller":
1331 # Set up group policies (domain policy and domain controller policy)
1332 setup_gpo(paths.sysvol,names.dnsdomain,policyguid,policyguid_dc)
1333 setsysvolacl(samdb,paths.netlogon,paths.sysvol,wheel_gid,domainsid,names.dnsdomain,names.domaindn,lp)
1335 message("Setting up sam.ldb rootDSE marking as synchronized")
1336 setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1338 secretsdb_self_join(secrets_ldb, domain=names.domain,
1340 dnsdomain=names.dnsdomain,
1341 netbiosname=names.netbiosname,
1342 domainsid=domainsid,
1343 machinepass=machinepass,
1344 secure_channel_type=SEC_CHAN_BDC)
1346 if serverrole == "domain controller":
1347 secretsdb_setup_dns(secrets_ldb, setup_path,
1349 realm=names.realm, dnsdomain=names.dnsdomain,
1350 dns_keytab_path=paths.dns_keytab,
1353 domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
1354 assert isinstance(domainguid, str)
1356 # Only make a zone file on the first DC, it should be replicated
1357 # with DNS replication
1358 create_zone_file(lp, message, paths, targetdir, setup_path, dnsdomain=names.dnsdomain,
1360 hostip6=hostip6, hostname=names.hostname,
1362 domainguid=domainguid, ntdsguid=names.ntdsguid)
1364 create_named_conf(paths, setup_path, realm=names.realm,
1365 dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1367 create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
1368 dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
1369 keytab_name=paths.dns_keytab)
1370 message("See %s for an example configuration include file for BIND" % paths.namedconf)
1371 message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
1373 create_krb5_conf(paths.krb5conf, setup_path,
1374 dnsdomain=names.dnsdomain, hostname=names.hostname,
1376 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
1378 if serverrole == "domain controller":
1379 create_dns_update_list(lp, message, paths, setup_path)
1381 provision_backend.post_setup()
1382 provision_backend.shutdown()
1384 create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1387 #Now commit the secrets.ldb to disk
1388 secrets_ldb.transaction_commit()
1390 # the commit creates the dns.keytab, now chown it
1391 dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
1392 if (os.path.isfile(dns_keytab_path) and paths.bind_gid is not None):
1394 os.chmod(dns_keytab_path, 0640)
1395 os.chown(dns_keytab_path, -1, paths.bind_gid)
1397 message("Failed to chown %s to bind gid %u" % (dns_keytab_path, paths.bind_gid))
1400 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
1402 message("Once the above files are installed, your Samba4 server will be ready to use")
1403 message("Server Role: %s" % serverrole)
1404 message("Hostname: %s" % names.hostname)
1405 message("NetBIOS Domain: %s" % names.domain)
1406 message("DNS Domain: %s" % names.dnsdomain)
1407 message("DOMAIN SID: %s" % str(domainsid))
1408 if samdb_fill == FILL_FULL:
1409 message("Admin password: %s" % adminpass)
1410 if provision_backend.type is not "ldb":
1411 if provision_backend.credentials.get_bind_dn() is not None:
1412 message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
1414 message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
1416 message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
1418 if provision_backend.slapd_command_escaped is not None:
1419 # now display slapd_command_file.txt to show how slapd must be started next time
1420 message("Use later the following commandline to start slapd, then Samba:")
1421 message(provision_backend.slapd_command_escaped)
1422 message("This slapd-Commandline is also stored under: " + provision_backend.ldapdir + "/ldap_backend_startup.sh")
1425 result = ProvisionResult()
1426 result.domaindn = domaindn
1427 result.paths = paths
1429 result.samdb = samdb
1434 def provision_become_dc(setup_dir=None,
1435 smbconf=None, targetdir=None, realm=None,
1436 rootdn=None, domaindn=None, schemadn=None,
1437 configdn=None, serverdn=None,
1438 domain=None, hostname=None, domainsid=None,
1439 adminpass=None, krbtgtpass=None, domainguid=None,
1440 policyguid=None, policyguid_dc=None, invocationid=None,
1442 dnspass=None, root=None, nobody=None, users=None,
1443 wheel=None, backup=None, serverrole=None,
1444 ldap_backend=None, ldap_backend_type=None,
1445 sitename=None, debuglevel=1):
1448 """print a message if quiet is not set."""
1451 glue.set_debug_level(debuglevel)
1453 return provision(setup_dir, message, system_session(), None,
1454 smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1455 realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1456 configdn=configdn, serverdn=serverdn, domain=domain,
1457 hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1458 machinepass=machinepass, serverrole="domain controller",
1462 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1463 """Create a PHP LDAP admin configuration file.
1465 :param path: Path to write the configuration to.
1466 :param setup_path: Function to generate setup paths.
1468 setup_file(setup_path("phpldapadmin-config.php"), path,
1469 {"S4_LDAPI_URI": ldapi_uri})
1472 def create_zone_file(lp, message, paths, targetdir, setup_path, dnsdomain,
1473 hostip, hostip6, hostname, realm, domainguid,
1475 """Write out a DNS zone file, from the info in the current database.
1477 :param paths: paths object
1478 :param setup_path: Setup path function.
1479 :param dnsdomain: DNS Domain name
1480 :param domaindn: DN of the Domain
1481 :param hostip: Local IPv4 IP
1482 :param hostip6: Local IPv6 IP
1483 :param hostname: Local hostname
1484 :param realm: Realm name
1485 :param domainguid: GUID of the domain.
1486 :param ntdsguid: GUID of the hosts nTDSDSA record.
1488 assert isinstance(domainguid, str)
1490 if hostip6 is not None:
1491 hostip6_base_line = " IN AAAA " + hostip6
1492 hostip6_host_line = hostname + " IN AAAA " + hostip6
1494 hostip6_base_line = ""
1495 hostip6_host_line = ""
1497 if hostip is not None:
1498 hostip_base_line = " IN A " + hostip
1499 hostip_host_line = hostname + " IN A " + hostip
1501 hostip_base_line = ""
1502 hostip_host_line = ""
1504 dns_dir = os.path.dirname(paths.dns)
1507 shutil.rmtree(dns_dir, True)
1511 os.mkdir(dns_dir, 0775)
1513 # we need to freeze the zone while we update the contents
1514 if targetdir is None:
1515 rndc = ' '.join(lp.get("rndc command"))
1516 os.system(rndc + " freeze " + lp.get("realm"))
1518 setup_file(setup_path("provision.zone"), paths.dns, {
1519 "HOSTNAME": hostname,
1520 "DNSDOMAIN": dnsdomain,
1522 "HOSTIP_BASE_LINE": hostip_base_line,
1523 "HOSTIP_HOST_LINE": hostip_host_line,
1524 "DOMAINGUID": domainguid,
1525 "DATESTRING": time.strftime("%Y%m%d%H"),
1526 "DEFAULTSITE": DEFAULTSITE,
1527 "NTDSGUID": ntdsguid,
1528 "HOSTIP6_BASE_LINE": hostip6_base_line,
1529 "HOSTIP6_HOST_LINE": hostip6_host_line,
1532 # note that we use no variable substitution on this file
1533 # the substitution is done at runtime by samba_dnsupdate
1534 setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
1536 if paths.bind_gid is not None:
1538 os.chown(dns_dir, -1, paths.bind_gid)
1539 os.chown(paths.dns, -1, paths.bind_gid)
1540 # chmod needed to cope with umask
1541 os.chmod(dns_dir, 0775)
1542 os.chmod(paths.dns, 0664)
1544 message("Failed to chown %s to bind gid %u" % (dns_dir, paths.bind_gid))
1546 if targetdir is None:
1547 os.system(rndc + " unfreeze " + lp.get("realm"))
1550 def create_dns_update_list(lp, message, paths, setup_path):
1551 """Write out a dns_update_list file"""
1552 # note that we use no variable substitution on this file
1553 # the substitution is done at runtime by samba_dnsupdate
1554 setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
1557 def create_named_conf(paths, setup_path, realm, dnsdomain,
1559 """Write out a file containing zone statements suitable for inclusion in a
1560 named.conf file (including GSS-TSIG configuration).
1562 :param paths: all paths
1563 :param setup_path: Setup path function.
1564 :param realm: Realm name
1565 :param dnsdomain: DNS Domain name
1566 :param private_dir: Path to private directory
1567 :param keytab_name: File name of DNS keytab file
1570 setup_file(setup_path("named.conf"), paths.namedconf, {
1571 "DNSDOMAIN": dnsdomain,
1573 "ZONE_FILE": paths.dns,
1574 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1575 "NAMED_CONF": paths.namedconf,
1576 "NAMED_CONF_UPDATE": paths.namedconf_update
1579 setup_file(setup_path("named.conf.update"), paths.namedconf_update)
1581 def create_named_txt(path, setup_path, realm, dnsdomain,
1582 private_dir, keytab_name):
1583 """Write out a file containing zone statements suitable for inclusion in a
1584 named.conf file (including GSS-TSIG configuration).
1586 :param path: Path of the new named.conf file.
1587 :param setup_path: Setup path function.
1588 :param realm: Realm name
1589 :param dnsdomain: DNS Domain name
1590 :param private_dir: Path to private directory
1591 :param keytab_name: File name of DNS keytab file
1594 setup_file(setup_path("named.txt"), path, {
1595 "DNSDOMAIN": dnsdomain,
1597 "DNS_KEYTAB": keytab_name,
1598 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1599 "PRIVATE_DIR": private_dir
1602 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1603 """Write out a file containing zone statements suitable for inclusion in a
1604 named.conf file (including GSS-TSIG configuration).
1606 :param path: Path of the new named.conf file.
1607 :param setup_path: Setup path function.
1608 :param dnsdomain: DNS Domain name
1609 :param hostname: Local hostname
1610 :param realm: Realm name
1613 setup_file(setup_path("krb5.conf"), path, {
1614 "DNSDOMAIN": dnsdomain,
1615 "HOSTNAME": hostname,