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 provisionexceptions
import ProvisioningError
, InvalidNetbiosName
57 from signal
import SIGTERM
58 from dcerpc
.misc
import SEC_CHAN_BDC
, SEC_CHAN_WKSTA
60 __docformat__
= "restructuredText"
63 """Find the setup directory used by provision."""
64 dirname
= os
.path
.dirname(__file__
)
65 if "/site-packages/" in dirname
:
66 prefix
= "/".join(dirname
[:dirname
.index("/site-packages/")].split("/")[:-2])
67 for suffix
in ["share/setup", "share/samba/setup", "setup"]:
68 ret
= os
.path
.join(prefix
, suffix
)
69 if os
.path
.isdir(ret
):
72 ret
= os
.path
.join(dirname
, "../../../setup")
73 if os
.path
.isdir(ret
):
75 raise Exception("Unable to find setup directory.")
77 # descriptors of the naming contexts
78 # hard coded at this point, but will probably be changed when
79 # we enable different fsmo roles
81 def get_config_descriptor(domain_sid
):
82 sddl
= "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
83 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
84 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
85 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
86 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
87 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
88 "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
89 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
90 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
91 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
92 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
93 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
94 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
95 "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
96 "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
97 sec
= security
.descriptor
.from_sddl(sddl
, domain_sid
)
98 return b64encode(ndr_pack(sec
))
100 def get_domain_descriptor(domain_sid
):
101 sddl
= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
102 "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
103 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
104 "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
105 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
106 "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
107 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
108 "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
109 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
110 "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
111 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-832762594-175224951-1765713900-498)" \
112 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
113 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
114 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
115 "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
116 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
117 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
118 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
119 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
120 "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
121 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
122 "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;S-1-5-32-557)" \
123 "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
124 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
125 "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
126 "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
127 "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
128 "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
129 "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
130 "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
131 "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
132 "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
133 "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
134 "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
135 "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
136 "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
137 "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
138 "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
139 "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
142 "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
144 "(A;;RPLCLORC;;;ED)" \
145 "(A;;RPLCLORC;;;AU)" \
146 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
147 "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
148 "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
149 "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
150 sec
= security
.descriptor
.from_sddl(sddl
, domain_sid
)
151 return b64encode(ndr_pack(sec
))
153 DEFAULTSITE
= "Default-First-Site-Name"
157 class ProvisionPaths(object):
159 self
.shareconf
= None
170 self
.dns_keytab
= None
173 self
.private_dir
= None
175 self
.slapdconf
= None
176 self
.modulesconf
= None
177 self
.memberofconf
= None
179 self
.olmmrserveridsconf
= None
180 self
.olmmrsyncreplconf
= None
183 self
.olcseedldif
= None
186 class ProvisionNames(object):
192 self
.ldapmanagerdn
= None
193 self
.dnsdomain
= None
195 self
.netbiosname
= None
202 class ProvisionResult(object):
209 def check_install(lp
, session_info
, credentials
):
210 """Check whether the current install seems ok.
212 :param lp: Loadparm context
213 :param session_info: Session information
214 :param credentials: Credentials
216 if lp
.get("realm") == "":
217 raise Exception("Realm empty")
218 ldb
= Ldb(lp
.get("sam database"), session_info
=session_info
,
219 credentials
=credentials
, lp
=lp
)
220 if len(ldb
.search("(cn=Administrator)")) != 1:
221 raise ProvisioningError("No administrator account found")
224 def findnss(nssfn
, names
):
225 """Find a user or group from a list of possibilities.
227 :param nssfn: NSS Function to try (should raise KeyError if not found)
228 :param names: Names to check.
229 :return: Value return by first names list.
236 raise KeyError("Unable to find user/group %r" % names
)
239 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
240 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
243 def setup_add_ldif(ldb
, ldif_path
, subst_vars
=None,controls
=["relax:0"]):
244 """Setup a ldb in the private dir.
246 :param ldb: LDB file to import data into
247 :param ldif_path: Path of the LDIF file to load
248 :param subst_vars: Optional variables to subsitute in LDIF.
249 :param nocontrols: Optional list of controls, can be None for no controls
251 assert isinstance(ldif_path
, str)
252 data
= read_and_sub_file(ldif_path
, subst_vars
)
253 ldb
.add_ldif(data
,controls
)
256 def setup_modify_ldif(ldb
, ldif_path
, subst_vars
=None):
257 """Modify a ldb in the private dir.
259 :param ldb: LDB object.
260 :param ldif_path: LDIF file path.
261 :param subst_vars: Optional dictionary with substitution variables.
263 data
= read_and_sub_file(ldif_path
, subst_vars
)
265 ldb
.modify_ldif(data
)
268 def setup_ldb(ldb
, ldif_path
, subst_vars
):
269 """Import a LDIF a file into a LDB handle, optionally substituting variables.
271 :note: Either all LDIF data will be added or none (using transactions).
273 :param ldb: LDB file to import into.
274 :param ldif_path: Path to the LDIF file.
275 :param subst_vars: Dictionary with substitution variables.
277 assert ldb
is not None
278 ldb
.transaction_start()
280 setup_add_ldif(ldb
, ldif_path
, subst_vars
)
282 ldb
.transaction_cancel()
284 ldb
.transaction_commit()
287 def provision_paths_from_lp(lp
, dnsdomain
):
288 """Set the default paths for provisioning.
290 :param lp: Loadparm context.
291 :param dnsdomain: DNS Domain name
293 paths
= ProvisionPaths()
294 paths
.private_dir
= lp
.get("private dir")
295 paths
.dns_keytab
= "dns.keytab"
297 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
298 paths
.samdb
= os
.path
.join(paths
.private_dir
, lp
.get("sam database") or "samdb.ldb")
299 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, lp
.get("idmap database") or "idmap.ldb")
300 paths
.secrets
= os
.path
.join(paths
.private_dir
, lp
.get("secrets database") or "secrets.ldb")
301 paths
.privilege
= os
.path
.join(paths
.private_dir
, "privilege.ldb")
302 paths
.dns
= os
.path
.join(paths
.private_dir
, dnsdomain
+ ".zone")
303 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
304 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
305 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
306 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
307 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
308 paths
.phpldapadminconfig
= os
.path
.join(paths
.private_dir
,
309 "phpldapadmin-config.php")
310 paths
.ldapdir
= os
.path
.join(paths
.private_dir
,
312 paths
.slapdconf
= os
.path
.join(paths
.ldapdir
,
314 paths
.slapdpid
= os
.path
.join(paths
.ldapdir
,
316 paths
.modulesconf
= os
.path
.join(paths
.ldapdir
,
318 paths
.memberofconf
= os
.path
.join(paths
.ldapdir
,
320 paths
.olmmrserveridsconf
= os
.path
.join(paths
.ldapdir
,
321 "mmr_serverids.conf")
322 paths
.olmmrsyncreplconf
= os
.path
.join(paths
.ldapdir
,
324 paths
.olcdir
= os
.path
.join(paths
.ldapdir
,
326 paths
.olcseedldif
= os
.path
.join(paths
.ldapdir
,
328 paths
.hklm
= "hklm.ldb"
329 paths
.hkcr
= "hkcr.ldb"
330 paths
.hkcu
= "hkcu.ldb"
331 paths
.hku
= "hku.ldb"
332 paths
.hkpd
= "hkpd.ldb"
333 paths
.hkpt
= "hkpt.ldb"
335 paths
.sysvol
= lp
.get("path", "sysvol")
337 paths
.netlogon
= lp
.get("path", "netlogon")
339 paths
.smbconf
= lp
.configfile
344 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None,
345 serverrole
=None, rootdn
=None, domaindn
=None, configdn
=None,
346 schemadn
=None, serverdn
=None, sitename
=None):
347 """Guess configuration settings to use."""
350 hostname
= socket
.gethostname().split(".")[0]
352 netbiosname
= lp
.get("netbios name")
353 if netbiosname
is None:
354 netbiosname
= hostname
355 assert netbiosname
is not None
356 netbiosname
= netbiosname
.upper()
357 if not valid_netbios_name(netbiosname
):
358 raise InvalidNetbiosName(netbiosname
)
360 if dnsdomain
is None:
361 dnsdomain
= lp
.get("realm")
362 assert dnsdomain
is not None
363 dnsdomain
= dnsdomain
.lower()
365 if serverrole
is None:
366 serverrole
= lp
.get("server role")
367 assert serverrole
is not None
368 serverrole
= serverrole
.lower()
370 realm
= dnsdomain
.upper()
372 if lp
.get("realm").upper() != realm
:
373 raise ProvisioningError("guess_names: Realm '%s' in smb.conf must match chosen realm '%s'!", lp
.get("realm").upper(), realm
)
375 if serverrole
== "domain controller":
377 domain
= lp
.get("workgroup")
378 assert domain
is not None
379 domain
= domain
.upper()
381 if lp
.get("workgroup").upper() != domain
:
382 raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!", lp
.get("workgroup").upper(), domain
)
385 domaindn
= "DC=" + dnsdomain
.replace(".", ",DC=")
389 domaindn
= "DC=" + netbiosname
391 if not valid_netbios_name(domain
):
392 raise InvalidNetbiosName(domain
)
394 if hostname
.upper() == realm
:
395 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!", realm
, hostname
)
396 if netbiosname
== realm
:
397 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!", realm
, netbiosname
)
399 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!", realm
, domain
)
405 configdn
= "CN=Configuration," + rootdn
407 schemadn
= "CN=Schema," + configdn
412 names
= ProvisionNames()
413 names
.rootdn
= rootdn
414 names
.domaindn
= domaindn
415 names
.configdn
= configdn
416 names
.schemadn
= schemadn
417 names
.ldapmanagerdn
= "CN=Manager," + rootdn
418 names
.dnsdomain
= dnsdomain
419 names
.domain
= domain
421 names
.netbiosname
= netbiosname
422 names
.hostname
= hostname
423 names
.sitename
= sitename
424 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname
, sitename
, configdn
)
429 def make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
430 targetdir
, sid_generator
):
431 """Create a new smb.conf file based on a couple of basic settings.
433 assert smbconf
is not None
435 hostname
= socket
.gethostname().split(".")[0]
436 netbiosname
= hostname
.upper()
438 if serverrole
is None:
439 serverrole
= "standalone"
441 assert serverrole
in ("domain controller", "member server", "standalone")
442 if serverrole
== "domain controller":
444 elif serverrole
== "member server":
445 smbconfsuffix
= "member"
446 elif serverrole
== "standalone":
447 smbconfsuffix
= "standalone"
449 if sid_generator
is None:
450 sid_generator
= "internal"
452 assert domain
is not None
453 domain
= domain
.upper()
455 assert realm
is not None
456 realm
= realm
.upper()
458 default_lp
= param
.LoadParm()
459 #Load non-existant file
460 if os
.path
.exists(smbconf
):
461 default_lp
.load(smbconf
)
463 if targetdir
is not None:
464 privatedir_line
= "private dir = " + os
.path
.abspath(os
.path
.join(targetdir
, "private"))
465 lockdir_line
= "lock dir = " + os
.path
.abspath(targetdir
)
467 default_lp
.set("lock dir", os
.path
.abspath(targetdir
))
472 if sid_generator
== "internal":
473 sid_generator_line
= ""
475 sid_generator_line
= "sid generator = " + sid_generator
477 sysvol
= os
.path
.join(default_lp
.get("lock dir"), "sysvol")
478 netlogon
= os
.path
.join(sysvol
, realm
.lower(), "scripts")
480 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix
),
482 "NETBIOS_NAME": netbiosname
,
485 "SERVERROLE": serverrole
,
486 "NETLOGONPATH": netlogon
,
487 "SYSVOLPATH": sysvol
,
488 "SIDGENERATOR_LINE": sid_generator_line
,
489 "PRIVATEDIR_LINE": privatedir_line
,
490 "LOCKDIR_LINE": lockdir_line
494 def setup_name_mappings(samdb
, idmap
, sid
, domaindn
, root_uid
, nobody_uid
,
495 users_gid
, wheel_gid
):
496 """setup reasonable name mappings for sam names to unix names.
498 :param samdb: SamDB object.
499 :param idmap: IDmap db object.
500 :param sid: The domain sid.
501 :param domaindn: The domain DN.
502 :param root_uid: uid of the UNIX root user.
503 :param nobody_uid: uid of the UNIX nobody user.
504 :param users_gid: gid of the UNIX users group.
505 :param wheel_gid: gid of the UNIX wheel group."""
507 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
508 idmap
.setup_name_mapping("S-1-5-32-544", idmap
.TYPE_GID
, wheel_gid
)
510 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
511 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
513 def setup_samdb_partitions(samdb_path
, setup_path
, message
, lp
, session_info
,
514 provision_backend
, names
, schema
,
517 """Setup the partitions for the SAM database.
519 Alternatively, provision() may call this, and then populate the database.
521 :note: This will wipe the Sam Database!
523 :note: This function always removes the local SAM LDB file. The erase
524 parameter controls whether to erase the existing data, which
525 may not be stored locally but in LDAP.
528 assert session_info
is not None
530 old_partitions
= None
531 new_partitions
= None
533 # We use options=["modules:"] to stop the modules loading - we
534 # just want to wipe and re-initialise the database, not start it up
537 os
.unlink(samdb_path
)
541 samdb
= Ldb(url
=samdb_path
, session_info
=session_info
,
542 lp
=lp
, options
=["modules:"])
544 ldap_backend_line
= "# No LDAP backend"
545 if provision_backend
.type is not "ldb":
546 ldap_backend_line
= "ldapBackend: %s" % provision_backend
.ldapi_uri
548 samdb
.transaction_start()
550 message("Setting up sam.ldb partitions and settings")
551 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
552 "SCHEMADN": ldb
.Dn(schema
.ldb
, names
.schemadn
).get_casefold(),
553 "CONFIGDN": ldb
.Dn(schema
.ldb
, names
.configdn
).get_casefold(),
554 "DOMAINDN": ldb
.Dn(schema
.ldb
, names
.domaindn
).get_casefold(),
555 "LDAP_BACKEND_LINE": ldap_backend_line
,
559 setup_add_ldif(samdb
, setup_path("provision_init.ldif"), {
560 "BACKEND_TYPE": provision_backend
.type,
561 "SERVER_ROLE": serverrole
564 message("Setting up sam.ldb rootDSE")
565 setup_samdb_rootdse(samdb
, setup_path
, names
)
568 samdb
.transaction_cancel()
571 samdb
.transaction_commit()
574 def secretsdb_self_join(secretsdb
, domain
,
575 netbiosname
, machinepass
, domainsid
=None,
576 realm
=None, dnsdomain
=None,
578 key_version_number
=1,
579 secure_channel_type
=SEC_CHAN_WKSTA
):
580 """Add domain join-specific bits to a secrets database.
582 :param secretsdb: Ldb Handle to the secrets database
583 :param machinepass: Machine password
585 attrs
=["whenChanged",
593 msg
= ldb
.Message(ldb
.Dn(secretsdb
, "flatname=%s,cn=Primary Domains" % domain
));
594 msg
["secureChannelType"] = str(secure_channel_type
)
595 msg
["flatname"] = [domain
]
596 msg
["objectClass"] = ["top", "primaryDomain"]
597 if realm
is not None:
598 if dnsdomain
is None:
599 dnsdomain
= realm
.lower()
600 msg
["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
602 msg
["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname
.lower(), dnsdomain
.lower(), realm
.upper())
603 msg
["msDS-KeyVersionNumber"] = [str(key_version_number
)]
604 msg
["privateKeytab"] = ["secrets.keytab"];
607 msg
["secret"] = [machinepass
]
608 msg
["samAccountName"] = ["%s$" % netbiosname
]
609 msg
["secureChannelType"] = [str(secure_channel_type
)]
610 if domainsid
is not None:
611 msg
["objectSid"] = [ndr_pack(domainsid
)]
613 res
= secretsdb
.search(base
="cn=Primary Domains",
615 expression
=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain
, realm
, str(domainsid
))),
616 scope
=SCOPE_ONELEVEL
)
619 if del_msg
.dn
is not msg
.dn
:
620 secretsdb
.delete(del_msg
.dn
)
622 res
= secretsdb
.search(base
=msg
.dn
, attrs
=attrs
, scope
=SCOPE_BASE
)
625 msg
["priorSecret"] = res
[0]["secret"]
626 msg
["priorWhenChanged"] = res
[0]["whenChanged"]
628 if res
["privateKeytab"] is not None:
629 msg
["privateKeytab"] = res
[0]["privateKeytab"]
631 if res
["krb5Keytab"] is not None:
632 msg
["krb5Keytab"] = res
[0]["krb5Keytab"]
635 el
.set_flags(ldb
.FLAG_MOD_REPLACE
)
636 secretsdb
.modify(msg
)
641 def secretsdb_setup_dns(secretsdb
, setup_path
, realm
, dnsdomain
,
642 dns_keytab_path
, dnspass
):
643 """Add DNS specific bits to a secrets database.
645 :param secretsdb: Ldb Handle to the secrets database
646 :param setup_path: Setup path function
647 :param machinepass: Machine password
649 setup_ldb(secretsdb
, setup_path("secrets_dns.ldif"), {
651 "DNSDOMAIN": dnsdomain
,
652 "DNS_KEYTAB": dns_keytab_path
,
653 "DNSPASS_B64": b64encode(dnspass
),
657 def setup_secretsdb(path
, setup_path
, session_info
, backend_credentials
, lp
):
658 """Setup the secrets database.
660 :param path: Path to the secrets database.
661 :param setup_path: Get the path to a setup file.
662 :param session_info: Session info.
663 :param credentials: Credentials
664 :param lp: Loadparm context
665 :return: LDB handle for the created secrets database
667 if os
.path
.exists(path
):
669 secrets_ldb
= Ldb(path
, session_info
=session_info
,
672 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
673 secrets_ldb
= Ldb(path
, session_info
=session_info
,
675 secrets_ldb
.transaction_start()
676 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
678 if backend_credentials
is not None and backend_credentials
.authentication_requested():
679 if backend_credentials
.get_bind_dn() is not None:
680 setup_add_ldif(secrets_ldb
, setup_path("secrets_simple_ldap.ldif"), {
681 "LDAPMANAGERDN": backend_credentials
.get_bind_dn(),
682 "LDAPMANAGERPASS_B64": b64encode(backend_credentials
.get_password())
685 setup_add_ldif(secrets_ldb
, setup_path("secrets_sasl_ldap.ldif"), {
686 "LDAPADMINUSER": backend_credentials
.get_username(),
687 "LDAPADMINREALM": backend_credentials
.get_realm(),
688 "LDAPADMINPASS_B64": b64encode(backend_credentials
.get_password())
693 def setup_privileges(path
, setup_path
, session_info
, lp
):
694 """Setup the privileges database.
696 :param path: Path to the privileges database.
697 :param setup_path: Get the path to a setup file.
698 :param session_info: Session info.
699 :param credentials: Credentials
700 :param lp: Loadparm context
701 :return: LDB handle for the created secrets database
703 if os
.path
.exists(path
):
705 privilege_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
706 privilege_ldb
.erase()
707 privilege_ldb
.load_ldif_file_add(setup_path("provision_privilege.ldif"))
710 def setup_registry(path
, setup_path
, session_info
, lp
):
711 """Setup the registry.
713 :param path: Path to the registry database
714 :param setup_path: Function that returns the path to a setup.
715 :param session_info: Session information
716 :param credentials: Credentials
717 :param lp: Loadparm context
719 reg
= registry
.Registry()
720 hive
= registry
.open_ldb(path
, session_info
=session_info
,
722 reg
.mount_hive(hive
, registry
.HKEY_LOCAL_MACHINE
)
723 provision_reg
= setup_path("provision.reg")
724 assert os
.path
.exists(provision_reg
)
725 reg
.diff_apply(provision_reg
)
728 def setup_idmapdb(path
, setup_path
, session_info
, lp
):
729 """Setup the idmap database.
731 :param path: path to the idmap database
732 :param setup_path: Function that returns a path to a setup file
733 :param session_info: Session information
734 :param credentials: Credentials
735 :param lp: Loadparm context
737 if os
.path
.exists(path
):
740 idmap_ldb
= IDmapDB(path
, session_info
=session_info
,
744 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
748 def setup_samdb_rootdse(samdb
, setup_path
, names
):
749 """Setup the SamDB rootdse.
751 :param samdb: Sam Database handle
752 :param setup_path: Obtain setup path
754 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
755 "SCHEMADN": names
.schemadn
,
756 "NETBIOSNAME": names
.netbiosname
,
757 "DNSDOMAIN": names
.dnsdomain
,
758 "REALM": names
.realm
,
759 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
760 "DOMAINDN": names
.domaindn
,
761 "ROOTDN": names
.rootdn
,
762 "CONFIGDN": names
.configdn
,
763 "SERVERDN": names
.serverdn
,
767 def setup_self_join(samdb
, names
,
768 machinepass
, dnspass
,
769 domainsid
, invocationid
, setup_path
,
770 policyguid
, policyguid_dc
, domainControllerFunctionality
,
772 """Join a host to its own domain."""
773 assert isinstance(invocationid
, str)
774 if ntdsguid
is not None:
775 ntdsguid_line
= "objectGUID: %s\n"%ntdsguid
778 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
779 "CONFIGDN": names
.configdn
,
780 "SCHEMADN": names
.schemadn
,
781 "DOMAINDN": names
.domaindn
,
782 "SERVERDN": names
.serverdn
,
783 "INVOCATIONID": invocationid
,
784 "NETBIOSNAME": names
.netbiosname
,
785 "DEFAULTSITE": names
.sitename
,
786 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
787 "MACHINEPASS_B64": b64encode(machinepass
),
788 "DNSPASS_B64": b64encode(dnspass
),
789 "REALM": names
.realm
,
790 "DOMAIN": names
.domain
,
791 "DNSDOMAIN": names
.dnsdomain
,
792 "SAMBA_VERSION_STRING": version
,
793 "NTDSGUID": ntdsguid_line
,
794 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality
)})
796 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
797 "POLICYGUID": policyguid
,
798 "POLICYGUID_DC": policyguid_dc
,
799 "DNSDOMAIN": names
.dnsdomain
,
800 "DOMAINSID": str(domainsid
),
801 "DOMAINDN": names
.domaindn
})
803 # add the NTDSGUID based SPNs
804 ntds_dn
= "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names
.hostname
, names
.domaindn
)
805 names
.ntdsguid
= samdb
.searchone(basedn
=ntds_dn
, attribute
="objectGUID",
806 expression
="", scope
=SCOPE_BASE
)
807 assert isinstance(names
.ntdsguid
, str)
809 # Setup fSMORoleOwner entries to point at the newly created DC entry
810 setup_modify_ldif(samdb
, setup_path("provision_self_join_modify.ldif"), {
811 "DOMAIN": names
.domain
,
812 "DNSDOMAIN": names
.dnsdomain
,
813 "DOMAINDN": names
.domaindn
,
814 "CONFIGDN": names
.configdn
,
815 "SCHEMADN": names
.schemadn
,
816 "DEFAULTSITE": names
.sitename
,
817 "SERVERDN": names
.serverdn
,
818 "NETBIOSNAME": names
.netbiosname
,
819 "NTDSGUID": names
.ntdsguid
823 def setup_samdb(path
, setup_path
, session_info
, provision_backend
, lp
,
825 domainsid
, domainguid
, policyguid
, policyguid_dc
,
826 fill
, adminpass
, krbtgtpass
,
827 machinepass
, invocationid
, dnspass
, ntdsguid
,
828 serverrole
, dom_for_fun_level
=None,
830 """Setup a complete SAM Database.
832 :note: This will wipe the main SAM database file!
835 # ATTENTION: Do NOT change these default values without discussion with the
836 # team and/or release manager. They have a big impact on the whole program!
837 domainControllerFunctionality
= DS_DC_FUNCTION_2008
839 if dom_for_fun_level
is None:
840 dom_for_fun_level
= DS_DOMAIN_FUNCTION_2003
841 if dom_for_fun_level
< DS_DOMAIN_FUNCTION_2003
:
842 raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!")
844 if dom_for_fun_level
> domainControllerFunctionality
:
845 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!")
847 domainFunctionality
= dom_for_fun_level
848 forestFunctionality
= dom_for_fun_level
850 # Also wipes the database
851 setup_samdb_partitions(path
, setup_path
, message
=message
, lp
=lp
,
852 provision_backend
=provision_backend
, session_info
=session_info
,
854 serverrole
=serverrole
, schema
=schema
)
857 schema
= Schema(setup_path
, domainsid
, schemadn
=names
.schemadn
, serverdn
=names
.serverdn
)
859 # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
860 samdb
= Ldb(session_info
=session_info
,
861 credentials
=provision_backend
.credentials
, lp
=lp
)
863 message("Pre-loading the Samba 4 and AD schema")
865 # Load the schema from the one we computed earlier
866 samdb
.set_schema_from_ldb(schema
.ldb
)
868 # And now we can connect to the DB - the schema won't be loaded from the DB
874 samdb
.transaction_start()
876 # Set the domain functionality levels onto the database.
877 # Various module (the password_hash module in particular) need
878 # to know what level of AD we are emulating.
880 # These will be fixed into the database via the database
881 # modifictions below, but we need them set from the start.
882 samdb
.set_opaque_integer("domainFunctionality", domainFunctionality
)
883 samdb
.set_opaque_integer("forestFunctionality", forestFunctionality
)
884 samdb
.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality
)
886 samdb
.set_domain_sid(str(domainsid
))
887 if serverrole
== "domain controller":
888 samdb
.set_invocation_id(invocationid
)
890 message("Adding DomainDN: %s" % names
.domaindn
)
892 #impersonate domain admin
893 admin_session_info
= admin_session(lp
, str(domainsid
))
894 samdb
.set_session_info(admin_session_info
)
895 if domainguid
is not None:
896 domainguid_line
= "objectGUID: %s\n-" % domainguid
900 descr
= get_domain_descriptor(domainsid
)
901 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
902 "DOMAINDN": names
.domaindn
,
903 "DOMAINGUID": domainguid_line
,
908 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
909 "CREATTIME": str(int(time
.time() * 1e7
)), # seconds -> ticks
910 "DOMAINSID": str(domainsid
),
911 "SCHEMADN": names
.schemadn
,
912 "NETBIOSNAME": names
.netbiosname
,
913 "DEFAULTSITE": names
.sitename
,
914 "CONFIGDN": names
.configdn
,
915 "SERVERDN": names
.serverdn
,
916 "POLICYGUID": policyguid
,
917 "DOMAINDN": names
.domaindn
,
918 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
919 "SAMBA_VERSION_STRING": version
922 message("Adding configuration container")
923 descr
= get_config_descriptor(domainsid
);
924 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
925 "CONFIGDN": names
.configdn
,
929 # The LDIF here was created when the Schema object was constructed
930 message("Setting up sam.ldb schema")
931 samdb
.add_ldif(schema
.schema_dn_add
, controls
=["relax:0"])
932 samdb
.modify_ldif(schema
.schema_dn_modify
)
933 samdb
.write_prefixes_from_schema()
934 samdb
.add_ldif(schema
.schema_data
, controls
=["relax:0"])
935 setup_add_ldif(samdb
, setup_path("aggregate_schema.ldif"),
936 {"SCHEMADN": names
.schemadn
})
938 message("Setting up sam.ldb configuration data")
939 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
940 "CONFIGDN": names
.configdn
,
941 "NETBIOSNAME": names
.netbiosname
,
942 "DEFAULTSITE": names
.sitename
,
943 "DNSDOMAIN": names
.dnsdomain
,
944 "DOMAIN": names
.domain
,
945 "SCHEMADN": names
.schemadn
,
946 "DOMAINDN": names
.domaindn
,
947 "SERVERDN": names
.serverdn
,
948 "FOREST_FUNCTIONALALITY": str(forestFunctionality
)
951 message("Setting up display specifiers")
952 display_specifiers_ldif
= read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
953 display_specifiers_ldif
= substitute_var(display_specifiers_ldif
, {"CONFIGDN": names
.configdn
})
954 check_all_substituted(display_specifiers_ldif
)
955 samdb
.add_ldif(display_specifiers_ldif
)
957 message("Adding users container")
958 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
959 "DOMAINDN": names
.domaindn
})
960 message("Modifying users container")
961 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
962 "DOMAINDN": names
.domaindn
})
963 message("Adding computers container")
964 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
965 "DOMAINDN": names
.domaindn
})
966 message("Modifying computers container")
967 setup_modify_ldif(samdb
, setup_path("provision_computers_modify.ldif"), {
968 "DOMAINDN": names
.domaindn
})
969 message("Setting up sam.ldb data")
970 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
971 "CREATTIME": str(int(time
.time() * 1e7
)), # seconds -> ticks
972 "DOMAINDN": names
.domaindn
,
973 "NETBIOSNAME": names
.netbiosname
,
974 "DEFAULTSITE": names
.sitename
,
975 "CONFIGDN": names
.configdn
,
976 "SERVERDN": names
.serverdn
,
977 "POLICYGUID_DC": policyguid_dc
980 setup_modify_ldif(samdb
, setup_path("provision_basedn_references.ldif"), {
981 "DOMAINDN": names
.domaindn
})
983 setup_modify_ldif(samdb
, setup_path("provision_configuration_references.ldif"), {
984 "CONFIGDN": names
.configdn
,
985 "SCHEMADN": names
.schemadn
})
986 if fill
== FILL_FULL
:
987 message("Setting up sam.ldb users and groups")
988 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
989 "DOMAINDN": names
.domaindn
,
990 "DOMAINSID": str(domainsid
),
991 "CONFIGDN": names
.configdn
,
992 "ADMINPASS_B64": b64encode(adminpass
),
993 "KRBTGTPASS_B64": b64encode(krbtgtpass
),
996 if serverrole
== "domain controller":
997 message("Setting up self join")
998 setup_self_join(samdb
, names
=names
, invocationid
=invocationid
,
1000 machinepass
=machinepass
,
1001 domainsid
=domainsid
, policyguid
=policyguid
,
1002 policyguid_dc
=policyguid_dc
,
1003 setup_path
=setup_path
,
1004 domainControllerFunctionality
=domainControllerFunctionality
,
1007 ntds_dn
= "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names
.hostname
, names
.domaindn
)
1008 names
.ntdsguid
= samdb
.searchone(basedn
=ntds_dn
,
1009 attribute
="objectGUID", expression
="", scope
=SCOPE_BASE
)
1010 assert isinstance(names
.ntdsguid
, str)
1013 samdb
.transaction_cancel()
1016 samdb
.transaction_commit()
1021 FILL_NT4SYNC
= "NT4SYNC"
1025 def provision(setup_dir
, message
, session_info
,
1026 credentials
, smbconf
=None, targetdir
=None, samdb_fill
=FILL_FULL
,
1028 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1030 domain
=None, hostname
=None, hostip
=None, hostip6
=None,
1031 domainsid
=None, adminpass
=None, ldapadminpass
=None,
1032 krbtgtpass
=None, domainguid
=None,
1033 policyguid
=None, policyguid_dc
=None, invocationid
=None,
1034 machinepass
=None, ntdsguid
=None,
1035 dnspass
=None, root
=None, nobody
=None, users
=None,
1036 wheel
=None, backup
=None, aci
=None, serverrole
=None,
1037 dom_for_fun_level
=None,
1038 ldap_backend_extra_port
=None, backend_type
=None,
1040 ol_mmr_urls
=None, ol_olc
=None,
1041 setup_ds_path
=None, slapd_path
=None, nosync
=False,
1042 ldap_dryrun_mode
=False):
1045 :note: caution, this wipes all existing data!
1048 def setup_path(file):
1049 return os
.path
.join(setup_dir
, file)
1051 if domainsid
is None:
1052 domainsid
= security
.random_sid()
1054 domainsid
= security
.dom_sid(domainsid
)
1056 # create/adapt the group policy GUIDs
1057 if policyguid
is None:
1058 policyguid
= str(uuid
.uuid4())
1059 policyguid
= policyguid
.upper()
1060 if policyguid_dc
is None:
1061 policyguid_dc
= str(uuid
.uuid4())
1062 policyguid_dc
= policyguid_dc
.upper()
1064 if adminpass
is None:
1065 adminpass
= glue
.generate_random_str(12)
1066 if krbtgtpass
is None:
1067 krbtgtpass
= glue
.generate_random_str(12)
1068 if machinepass
is None:
1069 machinepass
= glue
.generate_random_str(12)
1071 dnspass
= glue
.generate_random_str(12)
1072 if ldapadminpass
is None:
1073 #Make a new, random password between Samba and it's LDAP server
1074 ldapadminpass
=glue
.generate_random_str(12)
1076 if backend_type
is None:
1077 backend_type
= "ldb"
1079 sid_generator
= "internal"
1080 if backend_type
== "fedora-ds":
1081 sid_generator
= "backend"
1083 root_uid
= findnss_uid([root
or "root"])
1084 nobody_uid
= findnss_uid([nobody
or "nobody"])
1085 users_gid
= findnss_gid([users
or "users"])
1087 wheel_gid
= findnss_gid(["wheel", "adm"])
1089 wheel_gid
= findnss_gid([wheel
])
1091 if targetdir
is not None:
1092 if (not os
.path
.exists(os
.path
.join(targetdir
, "etc"))):
1093 os
.makedirs(os
.path
.join(targetdir
, "etc"))
1094 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1095 elif smbconf
is None:
1096 smbconf
= param
.default_path()
1098 # only install a new smb.conf if there isn't one there already
1099 if not os
.path
.exists(smbconf
):
1100 make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
1101 targetdir
, sid_generator
)
1103 lp
= param
.LoadParm()
1106 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1107 dnsdomain
=realm
, serverrole
=serverrole
,
1108 domaindn
=domaindn
, configdn
=configdn
, schemadn
=schemadn
,
1109 serverdn
=serverdn
, sitename
=sitename
)
1111 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1115 hostip
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
1116 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
1121 hostip6
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET6
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
1122 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
1125 if serverrole
is None:
1126 serverrole
= lp
.get("server role")
1128 assert serverrole
in ("domain controller", "member server", "standalone")
1129 if invocationid
is None and serverrole
== "domain controller":
1130 invocationid
= str(uuid
.uuid4())
1132 if not os
.path
.exists(paths
.private_dir
):
1133 os
.mkdir(paths
.private_dir
)
1134 if not os
.path
.exists(os
.path
.join(paths
.private_dir
,"tls")):
1135 os
.mkdir(os
.path
.join(paths
.private_dir
,"tls"))
1137 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
1139 schema
= Schema(setup_path
, domainsid
, schemadn
=names
.schemadn
, serverdn
=names
.serverdn
)
1141 if backend_type
== "ldb":
1142 provision_backend
= LDBBackend(backend_type
,
1143 paths
=paths
, setup_path
=setup_path
,
1144 lp
=lp
, credentials
=credentials
,
1147 elif backend_type
== "existing":
1148 provision_backend
= ExistingBackend(backend_type
,
1149 paths
=paths
, setup_path
=setup_path
,
1150 lp
=lp
, credentials
=credentials
,
1153 elif backend_type
== "fedora-ds":
1154 provision_backend
= FDSBackend(backend_type
,
1155 paths
=paths
, setup_path
=setup_path
,
1156 lp
=lp
, credentials
=credentials
,
1159 domainsid
=domainsid
,
1162 ldapadminpass
=ldapadminpass
,
1163 slapd_path
=slapd_path
,
1164 ldap_backend_extra_port
=ldap_backend_extra_port
,
1165 ldap_dryrun_mode
=ldap_dryrun_mode
,
1167 setup_ds_path
=setup_ds_path
)
1168 elif backend_type
== "openldap":
1169 provision_backend
= OpenLDAPBackend(backend_type
,
1170 paths
=paths
, setup_path
=setup_path
,
1171 lp
=lp
, credentials
=credentials
,
1174 domainsid
=domainsid
,
1177 ldapadminpass
=ldapadminpass
,
1178 slapd_path
=slapd_path
,
1179 ldap_backend_extra_port
=ldap_backend_extra_port
,
1180 ldap_dryrun_mode
=ldap_dryrun_mode
,
1181 ol_mmr_urls
=ol_mmr_urls
,
1184 raise ProvisioningError("Unknown LDAP backend type selected")
1186 provision_backend
.init()
1187 provision_backend
.start()
1189 # only install a new shares config db if there is none
1190 if not os
.path
.exists(paths
.shareconf
):
1191 message("Setting up share.ldb")
1192 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
,
1194 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
1197 message("Setting up secrets.ldb")
1198 secrets_ldb
= setup_secretsdb(paths
.secrets
, setup_path
,
1199 session_info
=session_info
,
1200 backend_credentials
=provision_backend
.secrets_credentials
, lp
=lp
)
1202 message("Setting up the registry")
1203 setup_registry(paths
.hklm
, setup_path
, session_info
,
1206 message("Setting up the privileges database")
1207 setup_privileges(paths
.privilege
, setup_path
, session_info
, lp
=lp
)
1209 message("Setting up idmap db")
1210 idmap
= setup_idmapdb(paths
.idmapdb
, setup_path
, session_info
=session_info
,
1213 message("Setting up SAM db")
1214 samdb
= setup_samdb(paths
.samdb
, setup_path
, session_info
,
1215 provision_backend
, lp
, names
,
1217 domainsid
=domainsid
,
1218 schema
=schema
, domainguid
=domainguid
,
1219 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1221 adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1222 invocationid
=invocationid
,
1223 machinepass
=machinepass
, dnspass
=dnspass
,
1224 ntdsguid
=ntdsguid
, serverrole
=serverrole
,
1225 dom_for_fun_level
=dom_for_fun_level
)
1227 if serverrole
== "domain controller":
1228 if paths
.netlogon
is None:
1229 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1230 message("Please either remove %s or see the template at %s" %
1231 ( paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1232 assert(paths
.netlogon
is not None)
1234 if paths
.sysvol
is None:
1235 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1236 message("Please either remove %s or see the template at %s" %
1237 (paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1238 assert(paths
.sysvol
is not None)
1240 # Set up group policies (domain policy and domain controller policy)
1242 policy_path
= os
.path
.join(paths
.sysvol
, names
.dnsdomain
, "Policies",
1243 "{" + policyguid
+ "}")
1244 os
.makedirs(policy_path
, 0755)
1245 open(os
.path
.join(policy_path
, "GPT.INI"), 'w').write(
1246 "[General]\r\nVersion=65543")
1247 os
.makedirs(os
.path
.join(policy_path
, "MACHINE"), 0755)
1248 os
.makedirs(os
.path
.join(policy_path
, "USER"), 0755)
1250 policy_path_dc
= os
.path
.join(paths
.sysvol
, names
.dnsdomain
, "Policies",
1251 "{" + policyguid_dc
+ "}")
1252 os
.makedirs(policy_path_dc
, 0755)
1253 open(os
.path
.join(policy_path_dc
, "GPT.INI"), 'w').write(
1254 "[General]\r\nVersion=2")
1255 os
.makedirs(os
.path
.join(policy_path_dc
, "MACHINE"), 0755)
1256 os
.makedirs(os
.path
.join(policy_path_dc
, "USER"), 0755)
1258 if not os
.path
.isdir(paths
.netlogon
):
1259 os
.makedirs(paths
.netlogon
, 0755)
1261 if samdb_fill
== FILL_FULL
:
1262 setup_name_mappings(samdb
, idmap
, str(domainsid
), names
.domaindn
,
1263 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
1264 users_gid
=users_gid
, wheel_gid
=wheel_gid
)
1266 message("Setting up sam.ldb rootDSE marking as synchronized")
1267 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"))
1269 # Only make a zone file on the first DC, it should be replicated with DNS replication
1270 if serverrole
== "domain controller":
1271 secretsdb_self_join(secrets_ldb
, domain
=names
.domain
,
1273 dnsdomain
=names
.dnsdomain
,
1274 netbiosname
=names
.netbiosname
,
1275 domainsid
=domainsid
,
1276 machinepass
=machinepass
,
1277 secure_channel_type
=SEC_CHAN_BDC
)
1279 secretsdb_setup_dns(secrets_ldb
, setup_path
,
1280 realm
=names
.realm
, dnsdomain
=names
.dnsdomain
,
1281 dns_keytab_path
=paths
.dns_keytab
,
1284 domainguid
= samdb
.searchone(basedn
=domaindn
, attribute
="objectGUID")
1285 assert isinstance(domainguid
, str)
1287 create_zone_file(paths
.dns
, setup_path
, dnsdomain
=names
.dnsdomain
,
1289 hostip6
=hostip6
, hostname
=names
.hostname
,
1291 domainguid
=domainguid
, ntdsguid
=names
.ntdsguid
)
1293 create_named_conf(paths
.namedconf
, setup_path
, realm
=names
.realm
,
1294 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
)
1296 create_named_txt(paths
.namedtxt
, setup_path
, realm
=names
.realm
,
1297 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
,
1298 keytab_name
=paths
.dns_keytab
)
1299 message("See %s for an example configuration include file for BIND" % paths
.namedconf
)
1300 message("and %s for further documentation required for secure DNS updates" % paths
.namedtxt
)
1302 create_krb5_conf(paths
.krb5conf
, setup_path
,
1303 dnsdomain
=names
.dnsdomain
, hostname
=names
.hostname
,
1305 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths
.krb5conf
)
1307 provision_backend
.post_setup()
1308 provision_backend
.shutdown()
1310 create_phpldapadmin_config(paths
.phpldapadminconfig
, setup_path
,
1313 #Now commit the secrets.ldb to disk
1314 secrets_ldb
.transaction_commit()
1316 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths
.phpldapadminconfig
)
1318 message("Once the above files are installed, your Samba4 server will be ready to use")
1319 message("Server Role: %s" % serverrole
)
1320 message("Hostname: %s" % names
.hostname
)
1321 message("NetBIOS Domain: %s" % names
.domain
)
1322 message("DNS Domain: %s" % names
.dnsdomain
)
1323 message("DOMAIN SID: %s" % str(domainsid
))
1324 if samdb_fill
== FILL_FULL
:
1325 message("Admin password: %s" % adminpass
)
1326 if provision_backend
.type is not "ldb":
1327 if provision_backend
.credentials
.get_bind_dn() is not None:
1328 message("LDAP Backend Admin DN: %s" % provision_backend
.credentials
.get_bind_dn())
1330 message("LDAP Admin User: %s" % provision_backend
.credentials
.get_username())
1332 message("LDAP Admin Password: %s" % provision_backend
.credentials
.get_password())
1334 if provision_backend
.slapd_command_escaped
is not None:
1335 # now display slapd_command_file.txt to show how slapd must be started next time
1336 message("Use later the following commandline to start slapd, then Samba:")
1337 message(provision_backend
.slapd_command_escaped
)
1338 message("This slapd-Commandline is also stored under: " + paths
.ldapdir
+ "/ldap_backend_startup.sh")
1341 result
= ProvisionResult()
1342 result
.domaindn
= domaindn
1343 result
.paths
= paths
1345 result
.samdb
= samdb
1350 def provision_become_dc(setup_dir
=None,
1351 smbconf
=None, targetdir
=None, realm
=None,
1352 rootdn
=None, domaindn
=None, schemadn
=None,
1353 configdn
=None, serverdn
=None,
1354 domain
=None, hostname
=None, domainsid
=None,
1355 adminpass
=None, krbtgtpass
=None, domainguid
=None,
1356 policyguid
=None, policyguid_dc
=None, invocationid
=None,
1358 dnspass
=None, root
=None, nobody
=None, users
=None,
1359 wheel
=None, backup
=None, serverrole
=None,
1360 ldap_backend
=None, ldap_backend_type
=None,
1361 sitename
=None, debuglevel
=1):
1364 """print a message if quiet is not set."""
1367 glue
.set_debug_level(debuglevel
)
1369 return provision(setup_dir
, message
, system_session(), None,
1370 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
,
1371 realm
=realm
, rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
,
1372 configdn
=configdn
, serverdn
=serverdn
, domain
=domain
,
1373 hostname
=hostname
, hostip
="127.0.0.1", domainsid
=domainsid
,
1374 machinepass
=machinepass
, serverrole
="domain controller",
1378 def create_phpldapadmin_config(path
, setup_path
, ldapi_uri
):
1379 """Create a PHP LDAP admin configuration file.
1381 :param path: Path to write the configuration to.
1382 :param setup_path: Function to generate setup paths.
1384 setup_file(setup_path("phpldapadmin-config.php"), path
,
1385 {"S4_LDAPI_URI": ldapi_uri
})
1388 def create_zone_file(path
, setup_path
, dnsdomain
,
1389 hostip
, hostip6
, hostname
, realm
, domainguid
,
1391 """Write out a DNS zone file, from the info in the current database.
1393 :param path: Path of the new zone file.
1394 :param setup_path: Setup path function.
1395 :param dnsdomain: DNS Domain name
1396 :param domaindn: DN of the Domain
1397 :param hostip: Local IPv4 IP
1398 :param hostip6: Local IPv6 IP
1399 :param hostname: Local hostname
1400 :param realm: Realm name
1401 :param domainguid: GUID of the domain.
1402 :param ntdsguid: GUID of the hosts nTDSDSA record.
1404 assert isinstance(domainguid
, str)
1406 if hostip6
is not None:
1407 hostip6_base_line
= " IN AAAA " + hostip6
1408 hostip6_host_line
= hostname
+ " IN AAAA " + hostip6
1410 hostip6_base_line
= ""
1411 hostip6_host_line
= ""
1413 if hostip
is not None:
1414 hostip_base_line
= " IN A " + hostip
1415 hostip_host_line
= hostname
+ " IN A " + hostip
1417 hostip_base_line
= ""
1418 hostip_host_line
= ""
1420 setup_file(setup_path("provision.zone"), path
, {
1421 "HOSTNAME": hostname
,
1422 "DNSDOMAIN": dnsdomain
,
1424 "HOSTIP_BASE_LINE": hostip_base_line
,
1425 "HOSTIP_HOST_LINE": hostip_host_line
,
1426 "DOMAINGUID": domainguid
,
1427 "DATESTRING": time
.strftime("%Y%m%d%H"),
1428 "DEFAULTSITE": DEFAULTSITE
,
1429 "NTDSGUID": ntdsguid
,
1430 "HOSTIP6_BASE_LINE": hostip6_base_line
,
1431 "HOSTIP6_HOST_LINE": hostip6_host_line
,
1435 def create_named_conf(path
, setup_path
, realm
, dnsdomain
,
1437 """Write out a file containing zone statements suitable for inclusion in a
1438 named.conf file (including GSS-TSIG configuration).
1440 :param path: Path of the new named.conf file.
1441 :param setup_path: Setup path function.
1442 :param realm: Realm name
1443 :param dnsdomain: DNS Domain name
1444 :param private_dir: Path to private directory
1445 :param keytab_name: File name of DNS keytab file
1448 setup_file(setup_path("named.conf"), path
, {
1449 "DNSDOMAIN": dnsdomain
,
1451 "REALM_WC": "*." + ".".join(realm
.split(".")[1:]),
1452 "PRIVATE_DIR": private_dir
1455 def create_named_txt(path
, setup_path
, realm
, dnsdomain
,
1456 private_dir
, keytab_name
):
1457 """Write out a file containing zone statements suitable for inclusion in a
1458 named.conf file (including GSS-TSIG configuration).
1460 :param path: Path of the new named.conf file.
1461 :param setup_path: Setup path function.
1462 :param realm: Realm name
1463 :param dnsdomain: DNS Domain name
1464 :param private_dir: Path to private directory
1465 :param keytab_name: File name of DNS keytab file
1468 setup_file(setup_path("named.txt"), path
, {
1469 "DNSDOMAIN": dnsdomain
,
1471 "DNS_KEYTAB": keytab_name
,
1472 "DNS_KEYTAB_ABS": os
.path
.join(private_dir
, keytab_name
),
1473 "PRIVATE_DIR": private_dir
1476 def create_krb5_conf(path
, setup_path
, dnsdomain
, hostname
, realm
):
1477 """Write out a file containing zone statements suitable for inclusion in a
1478 named.conf file (including GSS-TSIG configuration).
1480 :param path: Path of the new named.conf file.
1481 :param setup_path: Setup path function.
1482 :param dnsdomain: DNS Domain name
1483 :param hostname: Local hostname
1484 :param realm: Realm name
1487 setup_file(setup_path("krb5.conf"), path
, {
1488 "DNSDOMAIN": dnsdomain
,
1489 "HOSTNAME": hostname
,