2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 """Functions for setting up a Samba configuration."""
27 from base64
import b64encode
37 from auth
import system_session
38 from samba
import Ldb
, substitute_var
, valid_netbios_name
, check_all_substituted
39 from samba
.samdb
import SamDB
40 from samba
.idmap
import IDmapDB
43 from ldb
import SCOPE_SUBTREE
, SCOPE_ONELEVEL
, SCOPE_BASE
, LdbError
, \
44 LDB_ERR_NO_SUCH_OBJECT
, timestring
, CHANGETYPE_MODIFY
, CHANGETYPE_NONE
46 __docformat__
= "restructuredText"
48 DEFAULTSITE
= "Default-First-Site-Name"
50 class InvalidNetbiosName(Exception):
51 """A specified name was not a valid NetBIOS name."""
52 def __init__(self
, name
):
53 super(InvalidNetbiosName
, self
).__init
__("The name '%r' is not a valid NetBIOS name" % name
)
56 class ProvisionPaths(object):
69 self
.dns_keytab
= None
72 self
.private_dir
= None
75 self
.modulesconf
= None
76 self
.memberofconf
= None
77 self
.fedoradsinf
= None
78 self
.fedoradspartitions
= None
80 self
.olmmrserveridsconf
= None
81 self
.olmmrsyncreplconf
= None
83 class ProvisionNames(object):
89 self
.ldapmanagerdn
= None
92 self
.netbiosname
= None
99 class ProvisionResult(object):
106 def check_install(lp
, session_info
, credentials
):
107 """Check whether the current install seems ok.
109 :param lp: Loadparm context
110 :param session_info: Session information
111 :param credentials: Credentials
113 if lp
.get("realm") == "":
114 raise Exception("Realm empty")
115 ldb
= Ldb(lp
.get("sam database"), session_info
=session_info
,
116 credentials
=credentials
, lp
=lp
)
117 if len(ldb
.search("(cn=Administrator)")) != 1:
118 raise "No administrator account found"
121 def findnss(nssfn
, names
):
122 """Find a user or group from a list of possibilities.
124 :param nssfn: NSS Function to try (should raise KeyError if not found)
125 :param names: Names to check.
126 :return: Value return by first names list.
133 raise KeyError("Unable to find user/group %r" % names
)
136 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
137 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
140 def read_and_sub_file(file, subst_vars
):
141 """Read a file and sub in variables found in it
143 :param file: File to be read (typically from setup directory)
144 param subst_vars: Optional variables to subsitute in the file.
146 data
= open(file, 'r').read()
147 if subst_vars
is not None:
148 data
= substitute_var(data
, subst_vars
)
149 check_all_substituted(data
)
153 def setup_add_ldif(ldb
, ldif_path
, subst_vars
=None):
154 """Setup a ldb in the private dir.
156 :param ldb: LDB file to import data into
157 :param ldif_path: Path of the LDIF file to load
158 :param subst_vars: Optional variables to subsitute in LDIF.
160 assert isinstance(ldif_path
, str)
162 data
= read_and_sub_file(ldif_path
, subst_vars
)
166 def setup_modify_ldif(ldb
, ldif_path
, subst_vars
=None):
167 """Modify a ldb in the private dir.
169 :param ldb: LDB object.
170 :param ldif_path: LDIF file path.
171 :param subst_vars: Optional dictionary with substitution variables.
173 data
= read_and_sub_file(ldif_path
, subst_vars
)
175 ldb
.modify_ldif(data
)
178 def setup_ldb(ldb
, ldif_path
, subst_vars
):
179 """Import a LDIF a file into a LDB handle, optionally substituting variables.
181 :note: Either all LDIF data will be added or none (using transactions).
183 :param ldb: LDB file to import into.
184 :param ldif_path: Path to the LDIF file.
185 :param subst_vars: Dictionary with substitution variables.
187 assert ldb
is not None
188 ldb
.transaction_start()
190 setup_add_ldif(ldb
, ldif_path
, subst_vars
)
192 ldb
.transaction_cancel()
194 ldb
.transaction_commit()
197 def setup_file(template
, fname
, subst_vars
):
198 """Setup a file in the private dir.
200 :param template: Path of the template file.
201 :param fname: Path of the file to create.
202 :param subst_vars: Substitution variables.
206 if os
.path
.exists(f
):
209 data
= read_and_sub_file(template
, subst_vars
)
210 open(f
, 'w').write(data
)
213 def provision_paths_from_lp(lp
, dnsdomain
):
214 """Set the default paths for provisioning.
216 :param lp: Loadparm context.
217 :param dnsdomain: DNS Domain name
219 paths
= ProvisionPaths()
220 paths
.private_dir
= lp
.get("private dir")
221 paths
.keytab
= "secrets.keytab"
222 paths
.dns_keytab
= "dns.keytab"
224 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
225 paths
.samdb
= os
.path
.join(paths
.private_dir
, lp
.get("sam database") or "samdb.ldb")
226 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, lp
.get("idmap database") or "idmap.ldb")
227 paths
.secrets
= os
.path
.join(paths
.private_dir
, lp
.get("secrets database") or "secrets.ldb")
228 paths
.templates
= os
.path
.join(paths
.private_dir
, "templates.ldb")
229 paths
.dns
= os
.path
.join(paths
.private_dir
, dnsdomain
+ ".zone")
230 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
231 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
232 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
233 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
234 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
235 paths
.phpldapadminconfig
= os
.path
.join(paths
.private_dir
,
236 "phpldapadmin-config.php")
237 paths
.ldapdir
= os
.path
.join(paths
.private_dir
,
239 paths
.slapdconf
= os
.path
.join(paths
.ldapdir
,
241 paths
.modulesconf
= os
.path
.join(paths
.ldapdir
,
243 paths
.memberofconf
= os
.path
.join(paths
.ldapdir
,
245 paths
.fedoradsinf
= os
.path
.join(paths
.ldapdir
,
247 paths
.fedoradspartitions
= os
.path
.join(paths
.ldapdir
,
248 "fedorads-partitions.ldif")
249 paths
.olmmrserveridsconf
= os
.path
.join(paths
.ldapdir
,
250 "mmr_serverids.conf")
251 paths
.olmmrsyncreplconf
= os
.path
.join(paths
.ldapdir
,
253 paths
.hklm
= "hklm.ldb"
254 paths
.hkcr
= "hkcr.ldb"
255 paths
.hkcu
= "hkcu.ldb"
256 paths
.hku
= "hku.ldb"
257 paths
.hkpd
= "hkpd.ldb"
258 paths
.hkpt
= "hkpt.ldb"
260 paths
.sysvol
= lp
.get("path", "sysvol")
262 paths
.netlogon
= lp
.get("path", "netlogon")
264 paths
.smbconf
= lp
.configfile()
269 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None, serverrole
=None,
270 rootdn
=None, domaindn
=None, configdn
=None, schemadn
=None, serverdn
=None,
272 """Guess configuration settings to use."""
275 hostname
= socket
.gethostname().split(".")[0].lower()
277 netbiosname
= hostname
.upper()
278 if not valid_netbios_name(netbiosname
):
279 raise InvalidNetbiosName(netbiosname
)
281 hostname
= hostname
.lower()
283 if dnsdomain
is None:
284 dnsdomain
= lp
.get("realm")
286 if serverrole
is None:
287 serverrole
= lp
.get("server role")
289 assert dnsdomain
is not None
290 realm
= dnsdomain
.upper()
292 if lp
.get("realm").upper() != realm
:
293 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
294 (lp
.get("realm"), lp
.configfile(), realm
))
296 dnsdomain
= dnsdomain
.lower()
298 if serverrole
== "domain controller":
300 domain
= lp
.get("workgroup")
302 domaindn
= "DC=" + dnsdomain
.replace(".", ",DC=")
303 if lp
.get("workgroup").upper() != domain
.upper():
304 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
305 lp
.get("workgroup"), domain
)
309 domaindn
= "CN=" + netbiosname
311 assert domain
is not None
312 domain
= domain
.upper()
313 if not valid_netbios_name(domain
):
314 raise InvalidNetbiosName(domain
)
320 configdn
= "CN=Configuration," + rootdn
322 schemadn
= "CN=Schema," + configdn
327 names
= ProvisionNames()
328 names
.rootdn
= rootdn
329 names
.domaindn
= domaindn
330 names
.configdn
= configdn
331 names
.schemadn
= schemadn
332 names
.ldapmanagerdn
= "CN=Manager," + rootdn
333 names
.dnsdomain
= dnsdomain
334 names
.domain
= domain
336 names
.netbiosname
= netbiosname
337 names
.hostname
= hostname
338 names
.sitename
= sitename
339 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname
, sitename
, configdn
)
344 def make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
347 hostname
= socket
.gethostname().split(".")[0].lower()
349 if serverrole
is None:
350 serverrole
= "standalone"
352 assert serverrole
in ("domain controller", "member server", "standalone")
353 if serverrole
== "domain controller":
355 elif serverrole
== "member server":
356 smbconfsuffix
= "member"
357 elif serverrole
== "standalone":
358 smbconfsuffix
= "standalone"
360 assert domain
is not None
361 assert realm
is not None
363 default_lp
= param
.LoadParm()
364 #Load non-existant file
365 default_lp
.load(smbconf
)
367 if targetdir
is not None:
368 privatedir_line
= "private dir = " + os
.path
.abspath(os
.path
.join(targetdir
, "private"))
369 lockdir_line
= "lock dir = " + os
.path
.abspath(targetdir
)
371 default_lp
.set("lock dir", os
.path
.abspath(targetdir
))
376 sysvol
= os
.path
.join(default_lp
.get("lock dir"), "sysvol")
377 netlogon
= os
.path
.join(sysvol
, realm
.lower(), "scripts")
379 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix
),
381 "HOSTNAME": hostname
,
384 "SERVERROLE": serverrole
,
385 "NETLOGONPATH": netlogon
,
386 "SYSVOLPATH": sysvol
,
387 "PRIVATEDIR_LINE": privatedir_line
,
388 "LOCKDIR_LINE": lockdir_line
393 def setup_name_mappings(samdb
, idmap
, sid
, domaindn
, root_uid
, nobody_uid
,
394 users_gid
, wheel_gid
):
395 """setup reasonable name mappings for sam names to unix names.
397 :param samdb: SamDB object.
398 :param idmap: IDmap db object.
399 :param sid: The domain sid.
400 :param domaindn: The domain DN.
401 :param root_uid: uid of the UNIX root user.
402 :param nobody_uid: uid of the UNIX nobody user.
403 :param users_gid: gid of the UNIX users group.
404 :param wheel_gid: gid of the UNIX wheel group."""
405 # add some foreign sids if they are not present already
406 samdb
.add_foreign(domaindn
, "S-1-5-7", "Anonymous")
407 samdb
.add_foreign(domaindn
, "S-1-1-0", "World")
408 samdb
.add_foreign(domaindn
, "S-1-5-2", "Network")
409 samdb
.add_foreign(domaindn
, "S-1-5-18", "System")
410 samdb
.add_foreign(domaindn
, "S-1-5-11", "Authenticated Users")
412 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
413 idmap
.setup_name_mapping("S-1-5-32-544", idmap
.TYPE_GID
, wheel_gid
)
415 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
416 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
419 def setup_samdb_partitions(samdb_path
, setup_path
, message
, lp
, session_info
,
421 serverrole
, ldap_backend
=None,
422 ldap_backend_type
=None, erase
=False):
423 """Setup the partitions for the SAM database.
425 Alternatively, provision() may call this, and then populate the database.
427 :note: This will wipe the Sam Database!
429 :note: This function always removes the local SAM LDB file. The erase
430 parameter controls whether to erase the existing data, which
431 may not be stored locally but in LDAP.
433 assert session_info
is not None
435 samdb
= SamDB(samdb_path
, session_info
=session_info
,
436 credentials
=credentials
, lp
=lp
)
442 os
.unlink(samdb_path
)
444 samdb
= SamDB(samdb_path
, session_info
=session_info
,
445 credentials
=credentials
, lp
=lp
)
447 #Add modules to the list to activate them by default
448 #beware often order is important
450 # Some Known ordering constraints:
451 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
452 # - objectclass must be before password_hash, because password_hash checks
453 # that the objectclass is of type person (filled in by objectclass
454 # module when expanding the objectclass list)
455 # - partition must be last
456 # - each partition has its own module list then
457 modules_list
= ["rootdse",
475 modules_list2
= ["show_deleted",
478 domaindn_ldb
= "users.ldb"
479 if ldap_backend
is not None:
480 domaindn_ldb
= ldap_backend
481 configdn_ldb
= "configuration.ldb"
482 if ldap_backend
is not None:
483 configdn_ldb
= ldap_backend
484 schemadn_ldb
= "schema.ldb"
485 if ldap_backend
is not None:
486 schema_ldb
= ldap_backend
487 schemadn_ldb
= ldap_backend
489 if ldap_backend_type
== "fedora-ds":
490 backend_modules
= ["nsuniqueid", "paged_searches"]
491 # We can handle linked attributes here, as we don't have directory-side subtree operations
492 tdb_modules_list
= ["linked_attributes"]
493 elif ldap_backend_type
== "openldap":
494 backend_modules
= ["normalise", "entryuuid", "paged_searches"]
495 # OpenLDAP handles subtree renames, so we don't want to do any of these things
496 tdb_modules_list
= None
497 elif ldap_backend
is not None:
498 raise "LDAP Backend specified, but LDAP Backend Type not specified"
499 elif serverrole
== "domain controller":
500 backend_modules
= ["repl_meta_data"]
502 backend_modules
= ["objectguid"]
504 if tdb_modules_list
is None:
505 tdb_modules_list_as_string
= ""
507 tdb_modules_list_as_string
= ","+",".join(tdb_modules_list
)
509 samdb
.transaction_start()
511 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
512 "SCHEMADN": names
.schemadn
,
513 "SCHEMADN_LDB": schemadn_ldb
,
514 "SCHEMADN_MOD2": ",objectguid",
515 "CONFIGDN": names
.configdn
,
516 "CONFIGDN_LDB": configdn_ldb
,
517 "DOMAINDN": names
.domaindn
,
518 "DOMAINDN_LDB": domaindn_ldb
,
519 "SCHEMADN_MOD": "schema_fsmo,instancetype",
520 "CONFIGDN_MOD": "naming_fsmo,instancetype",
521 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
522 "MODULES_LIST": ",".join(modules_list
),
523 "TDB_MODULES_LIST": tdb_modules_list_as_string
,
524 "MODULES_LIST2": ",".join(modules_list2
),
525 "BACKEND_MOD": ",".join(backend_modules
),
529 samdb
.transaction_cancel()
532 samdb
.transaction_commit()
534 samdb
= SamDB(samdb_path
, session_info
=session_info
,
535 credentials
=credentials
, lp
=lp
)
537 samdb
.transaction_start()
539 message("Setting up sam.ldb attributes")
540 samdb
.load_ldif_file_add(setup_path("provision_init.ldif"))
542 message("Setting up sam.ldb rootDSE")
543 setup_samdb_rootdse(samdb
, setup_path
, names
)
546 message("Erasing data from partitions")
547 samdb
.erase_partitions()
550 samdb
.transaction_cancel()
553 samdb
.transaction_commit()
558 def secretsdb_become_dc(secretsdb
, setup_path
, domain
, realm
, dnsdomain
,
559 netbiosname
, domainsid
, keytab_path
, samdb_url
,
560 dns_keytab_path
, dnspass
, machinepass
):
561 """Add DC-specific bits to a secrets database.
563 :param secretsdb: Ldb Handle to the secrets database
564 :param setup_path: Setup path function
565 :param machinepass: Machine password
567 setup_ldb(secretsdb
, setup_path("secrets_dc.ldif"), {
568 "MACHINEPASS_B64": b64encode(machinepass
),
571 "DNSDOMAIN": dnsdomain
,
572 "DOMAINSID": str(domainsid
),
573 "SECRETS_KEYTAB": keytab_path
,
574 "NETBIOSNAME": netbiosname
,
575 "SAM_LDB": samdb_url
,
576 "DNS_KEYTAB": dns_keytab_path
,
577 "DNSPASS_B64": b64encode(dnspass
),
581 def setup_secretsdb(path
, setup_path
, session_info
, credentials
, lp
):
582 """Setup the secrets database.
584 :param path: Path to the secrets database.
585 :param setup_path: Get the path to a setup file.
586 :param session_info: Session info.
587 :param credentials: Credentials
588 :param lp: Loadparm context
589 :return: LDB handle for the created secrets database
591 if os
.path
.exists(path
):
593 secrets_ldb
= Ldb(path
, session_info
=session_info
, credentials
=credentials
,
596 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
597 secrets_ldb
= Ldb(path
, session_info
=session_info
, credentials
=credentials
,
599 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
601 if credentials
is not None and credentials
.authentication_requested():
602 if credentials
.get_bind_dn() is not None:
603 setup_add_ldif(secrets_ldb
, setup_path("secrets_simple_ldap.ldif"), {
604 "LDAPMANAGERDN": credentials
.get_bind_dn(),
605 "LDAPMANAGERPASS_B64": b64encode(credentials
.get_password())
608 setup_add_ldif(secrets_ldb
, setup_path("secrets_sasl_ldap.ldif"), {
609 "LDAPADMINUSER": credentials
.get_username(),
610 "LDAPADMINREALM": credentials
.get_realm(),
611 "LDAPADMINPASS_B64": b64encode(credentials
.get_password())
617 def setup_templatesdb(path
, setup_path
, session_info
, credentials
, lp
):
618 """Setup the templates database.
620 :param path: Path to the database.
621 :param setup_path: Function for obtaining the path to setup files.
622 :param session_info: Session info
623 :param credentials: Credentials
624 :param lp: Loadparm context
626 templates_ldb
= SamDB(path
, session_info
=session_info
,
627 credentials
=credentials
, lp
=lp
)
630 templates_ldb
.erase()
634 templates_ldb
.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
636 templates_ldb
= SamDB(path
, session_info
=session_info
,
637 credentials
=credentials
, lp
=lp
)
639 templates_ldb
.load_ldif_file_add(setup_path("provision_templates.ldif"))
642 def setup_registry(path
, setup_path
, session_info
, credentials
, lp
):
643 """Setup the registry.
645 :param path: Path to the registry database
646 :param setup_path: Function that returns the path to a setup.
647 :param session_info: Session information
648 :param credentials: Credentials
649 :param lp: Loadparm context
651 reg
= registry
.Registry()
652 hive
= registry
.open_ldb(path
, session_info
=session_info
,
653 credentials
=credentials
, lp_ctx
=lp
)
654 reg
.mount_hive(hive
, "HKEY_LOCAL_MACHINE")
655 provision_reg
= setup_path("provision.reg")
656 assert os
.path
.exists(provision_reg
)
657 reg
.diff_apply(provision_reg
)
660 def setup_idmapdb(path
, setup_path
, session_info
, credentials
, lp
):
661 """Setup the idmap database.
663 :param path: path to the idmap database
664 :param setup_path: Function that returns a path to a setup file
665 :param session_info: Session information
666 :param credentials: Credentials
667 :param lp: Loadparm context
669 if os
.path
.exists(path
):
672 idmap_ldb
= IDmapDB(path
, session_info
=session_info
,
673 credentials
=credentials
, lp
=lp
)
676 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
680 def setup_samdb_rootdse(samdb
, setup_path
, names
):
681 """Setup the SamDB rootdse.
683 :param samdb: Sam Database handle
684 :param setup_path: Obtain setup path
686 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
687 "SCHEMADN": names
.schemadn
,
688 "NETBIOSNAME": names
.netbiosname
,
689 "DNSDOMAIN": names
.dnsdomain
,
690 "REALM": names
.realm
,
691 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
692 "DOMAINDN": names
.domaindn
,
693 "ROOTDN": names
.rootdn
,
694 "CONFIGDN": names
.configdn
,
695 "SERVERDN": names
.serverdn
,
699 def setup_self_join(samdb
, names
,
700 machinepass
, dnspass
,
701 domainsid
, invocationid
, setup_path
,
703 """Join a host to its own domain."""
704 assert isinstance(invocationid
, str)
705 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
706 "CONFIGDN": names
.configdn
,
707 "SCHEMADN": names
.schemadn
,
708 "DOMAINDN": names
.domaindn
,
709 "SERVERDN": names
.serverdn
,
710 "INVOCATIONID": invocationid
,
711 "NETBIOSNAME": names
.netbiosname
,
712 "DEFAULTSITE": names
.sitename
,
713 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
714 "MACHINEPASS_B64": b64encode(machinepass
),
715 "DNSPASS_B64": b64encode(dnspass
),
716 "REALM": names
.realm
,
717 "DOMAIN": names
.domain
,
718 "DNSDOMAIN": names
.dnsdomain
})
719 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
720 "POLICYGUID": policyguid
,
721 "DNSDOMAIN": names
.dnsdomain
,
722 "DOMAINSID": str(domainsid
),
723 "DOMAINDN": names
.domaindn
})
726 def setup_samdb(path
, setup_path
, session_info
, credentials
, lp
,
728 domainsid
, aci
, domainguid
, policyguid
,
729 fill
, adminpass
, krbtgtpass
,
730 machinepass
, invocationid
, dnspass
,
731 serverrole
, ldap_backend
=None,
732 ldap_backend_type
=None):
733 """Setup a complete SAM Database.
735 :note: This will wipe the main SAM database file!
738 erase
= (fill
!= FILL_DRS
)
740 # Also wipes the database
741 setup_samdb_partitions(path
, setup_path
, message
=message
, lp
=lp
,
742 credentials
=credentials
, session_info
=session_info
,
744 ldap_backend
=ldap_backend
, serverrole
=serverrole
,
745 ldap_backend_type
=ldap_backend_type
, erase
=erase
)
747 samdb
= SamDB(path
, session_info
=session_info
,
748 credentials
=credentials
, lp
=lp
)
752 message("Pre-loading the Samba 4 and AD schema")
753 samdb
.set_domain_sid(domainsid
)
754 if serverrole
== "domain controller":
755 samdb
.set_invocation_id(invocationid
)
757 load_schema(setup_path
, samdb
, names
.schemadn
, names
.netbiosname
,
758 names
.configdn
, names
.sitename
, names
.serverdn
,
761 samdb
.transaction_start()
764 message("Adding DomainDN: %s (permitted to fail)" % names
.domaindn
)
765 if serverrole
== "domain controller":
766 domain_oc
= "domainDNS"
768 domain_oc
= "samba4LocalDomain"
770 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
771 "DOMAINDN": names
.domaindn
,
773 "DOMAIN_OC": domain_oc
776 message("Modifying DomainDN: " + names
.domaindn
+ "")
777 if domainguid
is not None:
778 domainguid_mod
= "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
782 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
783 "LDAPTIME": timestring(int(time
.time())),
784 "DOMAINSID": str(domainsid
),
785 "SCHEMADN": names
.schemadn
,
786 "NETBIOSNAME": names
.netbiosname
,
787 "DEFAULTSITE": names
.sitename
,
788 "CONFIGDN": names
.configdn
,
789 "SERVERDN": names
.serverdn
,
790 "POLICYGUID": policyguid
,
791 "DOMAINDN": names
.domaindn
,
792 "DOMAINGUID_MOD": domainguid_mod
,
795 message("Adding configuration container (permitted to fail)")
796 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
797 "CONFIGDN": names
.configdn
,
800 message("Modifying configuration container")
801 setup_modify_ldif(samdb
, setup_path("provision_configuration_basedn_modify.ldif"), {
802 "CONFIGDN": names
.configdn
,
803 "SCHEMADN": names
.schemadn
,
806 message("Adding schema container (permitted to fail)")
807 setup_add_ldif(samdb
, setup_path("provision_schema_basedn.ldif"), {
808 "SCHEMADN": names
.schemadn
,
811 message("Modifying schema container")
813 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
815 setup_modify_ldif(samdb
,
816 setup_path("provision_schema_basedn_modify.ldif"), {
817 "SCHEMADN": names
.schemadn
,
818 "NETBIOSNAME": names
.netbiosname
,
819 "DEFAULTSITE": names
.sitename
,
820 "CONFIGDN": names
.configdn
,
821 "SERVERDN": names
.serverdn
,
822 "PREFIXMAP_B64": b64encode(prefixmap
)
825 message("Setting up sam.ldb Samba4 schema")
826 setup_add_ldif(samdb
, setup_path("schema_samba4.ldif"),
827 {"SCHEMADN": names
.schemadn
})
828 message("Setting up sam.ldb AD schema")
829 setup_add_ldif(samdb
, setup_path("schema.ldif"),
830 {"SCHEMADN": names
.schemadn
})
832 message("Setting up sam.ldb configuration data")
833 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
834 "CONFIGDN": names
.configdn
,
835 "NETBIOSNAME": names
.netbiosname
,
836 "DEFAULTSITE": names
.sitename
,
837 "DNSDOMAIN": names
.dnsdomain
,
838 "DOMAIN": names
.domain
,
839 "SCHEMADN": names
.schemadn
,
840 "DOMAINDN": names
.domaindn
,
841 "SERVERDN": names
.serverdn
844 message("Setting up display specifiers")
845 setup_add_ldif(samdb
, setup_path("display_specifiers.ldif"),
846 {"CONFIGDN": names
.configdn
})
848 message("Adding users container (permitted to fail)")
849 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
850 "DOMAINDN": names
.domaindn
})
851 message("Modifying users container")
852 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
853 "DOMAINDN": names
.domaindn
})
854 message("Adding computers container (permitted to fail)")
855 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
856 "DOMAINDN": names
.domaindn
})
857 message("Modifying computers container")
858 setup_modify_ldif(samdb
, setup_path("provision_computers_modify.ldif"), {
859 "DOMAINDN": names
.domaindn
})
860 message("Setting up sam.ldb data")
861 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
862 "DOMAINDN": names
.domaindn
,
863 "NETBIOSNAME": names
.netbiosname
,
864 "DEFAULTSITE": names
.sitename
,
865 "CONFIGDN": names
.configdn
,
866 "SERVERDN": names
.serverdn
869 if fill
== FILL_FULL
:
870 message("Setting up sam.ldb users and groups")
871 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
872 "DOMAINDN": names
.domaindn
,
873 "DOMAINSID": str(domainsid
),
874 "CONFIGDN": names
.configdn
,
875 "ADMINPASS_B64": b64encode(adminpass
),
876 "KRBTGTPASS_B64": b64encode(krbtgtpass
),
879 if serverrole
== "domain controller":
880 message("Setting up self join")
881 setup_self_join(samdb
, names
=names
, invocationid
=invocationid
,
883 machinepass
=machinepass
,
884 domainsid
=domainsid
, policyguid
=policyguid
,
885 setup_path
=setup_path
)
888 samdb
.transaction_cancel()
891 samdb
.transaction_commit()
896 FILL_NT4SYNC
= "NT4SYNC"
899 def provision(setup_dir
, message
, session_info
,
900 credentials
, smbconf
=None, targetdir
=None, samdb_fill
=FILL_FULL
, realm
=None,
901 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
903 domain
=None, hostname
=None, hostip
=None, hostip6
=None,
904 domainsid
=None, adminpass
=None, krbtgtpass
=None, domainguid
=None,
905 policyguid
=None, invocationid
=None, machinepass
=None,
906 dnspass
=None, root
=None, nobody
=None, nogroup
=None, users
=None,
907 wheel
=None, backup
=None, aci
=None, serverrole
=None,
908 ldap_backend
=None, ldap_backend_type
=None, sitename
=None):
911 :note: caution, this wipes all existing data!
914 def setup_path(file):
915 return os
.path
.join(setup_dir
, file)
917 if domainsid
is None:
918 domainsid
= security
.random_sid()
920 domainsid
= security
.Sid(domainsid
)
922 if policyguid
is None:
923 policyguid
= str(uuid
.uuid4())
924 if adminpass
is None:
925 adminpass
= misc
.random_password(12)
926 if krbtgtpass
is None:
927 krbtgtpass
= misc
.random_password(12)
928 if machinepass
is None:
929 machinepass
= misc
.random_password(12)
931 dnspass
= misc
.random_password(12)
932 root_uid
= findnss_uid([root
or "root"])
933 nobody_uid
= findnss_uid([nobody
or "nobody"])
934 users_gid
= findnss_gid([users
or "users"])
936 wheel_gid
= findnss_gid(["wheel", "adm"])
938 wheel_gid
= findnss_gid([wheel
])
940 aci
= "# no aci for local ldb"
942 if targetdir
is not None:
943 if (not os
.path
.exists(os
.path
.join(targetdir
, "etc"))):
944 os
.makedirs(os
.path
.join(targetdir
, "etc"))
945 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
947 # only install a new smb.conf if there isn't one there already
948 if not os
.path
.exists(smbconf
):
949 make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
952 lp
= param
.LoadParm()
955 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
956 dnsdomain
=realm
, serverrole
=serverrole
, sitename
=sitename
,
957 rootdn
=rootdn
, domaindn
=domaindn
, configdn
=configdn
, schemadn
=schemadn
,
960 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
964 hostip
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
965 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
970 hostip6
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET6
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
971 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
974 if serverrole
is None:
975 serverrole
= lp
.get("server role")
977 assert serverrole
in ("domain controller", "member server", "standalone")
978 if invocationid
is None and serverrole
== "domain controller":
979 invocationid
= str(uuid
.uuid4())
981 if not os
.path
.exists(paths
.private_dir
):
982 os
.mkdir(paths
.private_dir
)
984 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
986 if ldap_backend
is not None:
987 if ldap_backend
== "ldapi":
988 # provision-backend will set this path suggested slapd command line / fedorads.inf
989 ldap_backend
= "ldapi://%s" % urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
991 # only install a new shares config db if there is none
992 if not os
.path
.exists(paths
.shareconf
):
993 message("Setting up share.ldb")
994 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
,
995 credentials
=credentials
, lp
=lp
)
996 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
999 message("Setting up secrets.ldb")
1000 secrets_ldb
= setup_secretsdb(paths
.secrets
, setup_path
,
1001 session_info
=session_info
,
1002 credentials
=credentials
, lp
=lp
)
1004 message("Setting up the registry")
1005 setup_registry(paths
.hklm
, setup_path
, session_info
,
1006 credentials
=credentials
, lp
=lp
)
1008 message("Setting up templates db")
1009 setup_templatesdb(paths
.templates
, setup_path
, session_info
=session_info
,
1010 credentials
=credentials
, lp
=lp
)
1012 message("Setting up idmap db")
1013 idmap
= setup_idmapdb(paths
.idmapdb
, setup_path
, session_info
=session_info
,
1014 credentials
=credentials
, lp
=lp
)
1016 samdb
= setup_samdb(paths
.samdb
, setup_path
, session_info
=session_info
,
1017 credentials
=credentials
, lp
=lp
, names
=names
,
1019 domainsid
=domainsid
,
1020 aci
=aci
, domainguid
=domainguid
, policyguid
=policyguid
,
1022 adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1023 invocationid
=invocationid
,
1024 machinepass
=machinepass
, dnspass
=dnspass
,
1025 serverrole
=serverrole
, ldap_backend
=ldap_backend
,
1026 ldap_backend_type
=ldap_backend_type
)
1028 if lp
.get("server role") == "domain controller":
1029 if paths
.netlogon
is None:
1030 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1031 message("Please either remove %s or see the template at %s" %
1032 ( paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1033 assert(paths
.netlogon
is not None)
1035 if paths
.sysvol
is None:
1036 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1037 message("Please either remove %s or see the template at %s" %
1038 (paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1039 assert(paths
.sysvol
is not None)
1041 policy_path
= os
.path
.join(paths
.sysvol
, names
.dnsdomain
, "Policies",
1042 "{" + policyguid
+ "}")
1043 os
.makedirs(policy_path
, 0755)
1044 open(os
.path
.join(policy_path
, "GPT.INI"), 'w').write("")
1045 os
.makedirs(os
.path
.join(policy_path
, "Machine"), 0755)
1046 os
.makedirs(os
.path
.join(policy_path
, "User"), 0755)
1047 if not os
.path
.isdir(paths
.netlogon
):
1048 os
.makedirs(paths
.netlogon
, 0755)
1050 if samdb_fill
== FILL_FULL
:
1051 setup_name_mappings(samdb
, idmap
, str(domainsid
), names
.domaindn
,
1052 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
1053 users_gid
=users_gid
, wheel_gid
=wheel_gid
)
1055 message("Setting up sam.ldb rootDSE marking as synchronized")
1056 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"))
1058 # Only make a zone file on the first DC, it should be replicated with DNS replication
1059 if serverrole
== "domain controller":
1060 secrets_ldb
= Ldb(paths
.secrets
, session_info
=session_info
,
1061 credentials
=credentials
, lp
=lp
)
1062 secretsdb_become_dc(secrets_ldb
, setup_path
, domain
=domain
, realm
=names
.realm
,
1063 netbiosname
=names
.netbiosname
, domainsid
=domainsid
,
1064 keytab_path
=paths
.keytab
, samdb_url
=paths
.samdb
,
1065 dns_keytab_path
=paths
.dns_keytab
, dnspass
=dnspass
,
1066 machinepass
=machinepass
, dnsdomain
=names
.dnsdomain
)
1068 samdb
= SamDB(paths
.samdb
, session_info
=session_info
,
1069 credentials
=credentials
, lp
=lp
)
1071 domainguid
= samdb
.searchone(basedn
=domaindn
, attribute
="objectGUID")
1072 assert isinstance(domainguid
, str)
1073 hostguid
= samdb
.searchone(basedn
=domaindn
, attribute
="objectGUID",
1074 expression
="(&(objectClass=computer)(cn=%s))" % names
.hostname
,
1075 scope
=SCOPE_SUBTREE
)
1076 assert isinstance(hostguid
, str)
1078 create_zone_file(paths
.dns
, setup_path
, dnsdomain
=names
.dnsdomain
,
1079 domaindn
=names
.domaindn
, hostip
=hostip
,
1080 hostip6
=hostip6
, hostname
=names
.hostname
,
1081 dnspass
=dnspass
, realm
=names
.realm
,
1082 domainguid
=domainguid
, hostguid
=hostguid
)
1084 create_named_conf(paths
.namedconf
, setup_path
, realm
=names
.realm
,
1085 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
)
1087 create_named_txt(paths
.namedtxt
, setup_path
, realm
=names
.realm
,
1088 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
,
1089 keytab_name
=paths
.dns_keytab
)
1090 message("See %s for an example configuration include file for BIND" % paths
.namedconf
)
1091 message("and %s for further documentation required for secure DNS updates" % paths
.namedtxt
)
1093 create_krb5_conf(paths
.krb5conf
, setup_path
, dnsdomain
=names
.dnsdomain
,
1094 hostname
=names
.hostname
, realm
=names
.realm
)
1095 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths
.krb5conf
)
1097 create_phpldapadmin_config(paths
.phpldapadminconfig
, setup_path
,
1100 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths
.phpldapadminconfig
)
1102 message("Once the above files are installed, your Samba4 server will be ready to use")
1103 message("Server Role: %s" % serverrole
)
1104 message("Hostname: %s" % names
.hostname
)
1105 message("NetBIOS Domain: %s" % names
.domain
)
1106 message("DNS Domain: %s" % names
.dnsdomain
)
1107 message("DOMAIN SID: %s" % str(domainsid
))
1108 message("Admin password: %s" % adminpass
)
1110 result
= ProvisionResult()
1111 result
.domaindn
= domaindn
1112 result
.paths
= paths
1114 result
.samdb
= samdb
1118 def provision_become_dc(setup_dir
=None,
1119 smbconf
=None, targetdir
=None, realm
=None,
1120 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1122 domain
=None, hostname
=None, domainsid
=None,
1123 adminpass
=None, krbtgtpass
=None, domainguid
=None,
1124 policyguid
=None, invocationid
=None, machinepass
=None,
1125 dnspass
=None, root
=None, nobody
=None, nogroup
=None, users
=None,
1126 wheel
=None, backup
=None, aci
=None, serverrole
=None,
1127 ldap_backend
=None, ldap_backend_type
=None, sitename
=None):
1130 """print a message if quiet is not set."""
1133 return provision(setup_dir
, message
, system_session(), None,
1134 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
, realm
=realm
,
1135 rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
, configdn
=configdn
, serverdn
=serverdn
,
1136 domain
=domain
, hostname
=hostname
, hostip
="127.0.0.1", domainsid
=domainsid
, machinepass
=machinepass
, serverrole
="domain controller", sitename
=sitename
)
1139 def setup_db_config(setup_path
, dbdir
):
1140 """Setup a Berkeley database.
1142 :param setup_path: Setup path function.
1143 :param dbdir: Database directory."""
1144 if not os
.path
.isdir(os
.path
.join(dbdir
, "bdb-logs")):
1145 os
.makedirs(os
.path
.join(dbdir
, "bdb-logs"), 0700)
1146 if not os
.path
.isdir(os
.path
.join(dbdir
, "tmp")):
1147 os
.makedirs(os
.path
.join(dbdir
, "tmp"), 0700)
1149 setup_file(setup_path("DB_CONFIG"), os
.path
.join(dbdir
, "DB_CONFIG"),
1150 {"LDAPDBDIR": dbdir
})
1154 def provision_backend(setup_dir
=None, message
=None,
1155 smbconf
=None, targetdir
=None, realm
=None,
1156 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1157 domain
=None, hostname
=None, adminpass
=None, root
=None, serverrole
=None,
1158 ldap_backend_type
=None, ldap_backend_port
=None,
1161 def setup_path(file):
1162 return os
.path
.join(setup_dir
, file)
1164 if hostname
is None:
1165 hostname
= socket
.gethostname().split(".")[0].lower()
1168 root
= findnss(pwd
.getpwnam
, ["root"])[0]
1170 if adminpass
is None:
1171 adminpass
= misc
.random_password(12)
1173 if targetdir
is not None:
1174 if (not os
.path
.exists(os
.path
.join(targetdir
, "etc"))):
1175 os
.makedirs(os
.path
.join(targetdir
, "etc"))
1176 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1178 # only install a new smb.conf if there isn't one there already
1179 if not os
.path
.exists(smbconf
):
1180 make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
1183 lp
= param
.LoadParm()
1186 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1187 dnsdomain
=realm
, serverrole
=serverrole
,
1188 rootdn
=rootdn
, domaindn
=domaindn
, configdn
=configdn
,
1191 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1193 if not os
.path
.isdir(paths
.ldapdir
):
1194 os
.makedirs(paths
.ldapdir
, 0700)
1195 schemadb_path
= os
.path
.join(paths
.ldapdir
, "schema-tmp.ldb")
1197 os
.unlink(schemadb_path
)
1201 schemadb
= Ldb(schemadb_path
, lp
=lp
)
1203 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
1205 setup_add_ldif(schemadb
, setup_path("provision_schema_basedn.ldif"),
1206 {"SCHEMADN": names
.schemadn
,
1209 setup_modify_ldif(schemadb
,
1210 setup_path("provision_schema_basedn_modify.ldif"), \
1211 {"SCHEMADN": names
.schemadn
,
1212 "NETBIOSNAME": names
.netbiosname
,
1213 "DEFAULTSITE": DEFAULTSITE
,
1214 "CONFIGDN": names
.configdn
,
1215 "SERVERDN": names
.serverdn
,
1216 "PREFIXMAP_B64": b64encode(prefixmap
)
1219 setup_add_ldif(schemadb
, setup_path("schema_samba4.ldif"),
1220 {"SCHEMADN": names
.schemadn
})
1221 setup_add_ldif(schemadb
, setup_path("schema.ldif"),
1222 {"SCHEMADN": names
.schemadn
})
1224 if ldap_backend_type
== "fedora-ds":
1225 if ldap_backend_port
is not None:
1226 serverport
= "ServerPort=%d" % ldap_backend_port
1230 setup_file(setup_path("fedorads.inf"), paths
.fedoradsinf
,
1232 "HOSTNAME": hostname
,
1233 "DNSDOMAIN": names
.dnsdomain
,
1234 "LDAPDIR": paths
.ldapdir
,
1235 "DOMAINDN": names
.domaindn
,
1236 "LDAPMANAGERDN": names
.ldapmanagerdn
,
1237 "LDAPMANAGERPASS": adminpass
,
1238 "SERVERPORT": serverport
})
1240 setup_file(setup_path("fedorads-partitions.ldif"), paths
.fedoradspartitions
,
1241 {"CONFIGDN": names
.configdn
,
1242 "SCHEMADN": names
.schemadn
,
1245 mapping
= "schema-map-fedora-ds-1.0"
1246 backend_schema
= "99_ad.ldif"
1248 slapdcommand
="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths
.fedoradsinf
1250 ldapuser
= "--simple-bind-dn=" + names
.ldapmanagerdn
1252 elif ldap_backend_type
== "openldap":
1253 attrs
= ["linkID", "lDAPDisplayName"]
1254 res
= schemadb
.search(expression
="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base
=names
.schemadn
, scope
=SCOPE_SUBTREE
, attrs
=attrs
)
1256 memberof_config
= "# Generated from schema in %s\n" % schemadb_path
1257 refint_attributes
= ""
1258 for i
in range (0, len(res
)):
1259 expression
= "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res
[i
]["linkID"][0])+1)
1260 target
= schemadb
.searchone(basedn
=names
.schemadn
,
1261 expression
=expression
,
1262 attribute
="lDAPDisplayName",
1263 scope
=SCOPE_SUBTREE
)
1264 if target
is not None:
1265 refint_attributes
= refint_attributes
+ " " + target
+ " " + res
[i
]["lDAPDisplayName"][0]
1267 memberof_config
+= read_and_sub_file(setup_path("memberof.conf"),
1268 { "MEMBER_ATTR" : str(res
[i
]["lDAPDisplayName"][0]),
1269 "MEMBEROF_ATTR" : str(target
) })
1271 refint_config
= read_and_sub_file(setup_path("refint.conf"),
1272 { "LINK_ATTRS" : refint_attributes
})
1274 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1276 mmr_replicator_acl
= ""
1277 mmr_serverids_config
= ""
1278 mmr_syncrepl_schema_config
= ""
1279 mmr_syncrepl_config_config
= ""
1280 mmr_syncrepl_user_config
= ""
1282 if ol_mmr_urls
is not None:
1283 # For now, make these equal
1284 mmr_pass
= adminpass
1286 url_list
=filter(None,ol_mmr_urls
.split(' '))
1287 if (len(url_list
) == 1):
1288 url_list
=filter(None,ol_mmr_urls
.split(','))
1291 mmr_on_config
= "MirrorMode On"
1292 mmr_replicator_acl
= " by dn=cn=replicator,cn=samba read"
1294 for url
in url_list
:
1296 mmr_serverids_config
+= read_and_sub_file(setup_path("mmr_serverids.conf"),
1297 { "SERVERID" : str(serverid
),
1298 "LDAPSERVER" : url
})
1301 mmr_syncrepl_schema_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1303 "MMRDN": names
.schemadn
,
1305 "MMR_PASSWORD": mmr_pass
})
1308 mmr_syncrepl_config_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1310 "MMRDN": names
.configdn
,
1312 "MMR_PASSWORD": mmr_pass
})
1315 mmr_syncrepl_user_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1317 "MMRDN": names
.domaindn
,
1319 "MMR_PASSWORD": mmr_pass
})
1322 setup_file(setup_path("slapd.conf"), paths
.slapdconf
,
1323 {"DNSDOMAIN": names
.dnsdomain
,
1324 "LDAPDIR": paths
.ldapdir
,
1325 "DOMAINDN": names
.domaindn
,
1326 "CONFIGDN": names
.configdn
,
1327 "SCHEMADN": names
.schemadn
,
1328 "MEMBEROF_CONFIG": memberof_config
,
1329 "MIRRORMODE": mmr_on_config
,
1330 "REPLICATOR_ACL": mmr_replicator_acl
,
1331 "MMR_SERVERIDS_CONFIG": mmr_serverids_config
,
1332 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config
,
1333 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config
,
1334 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config
,
1335 "REFINT_CONFIG": refint_config
})
1336 setup_file(setup_path("modules.conf"), paths
.modulesconf
,
1337 {"REALM": names
.realm
})
1339 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "user"))
1340 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "config"))
1341 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "schema"))
1343 if not os
.path
.exists(os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba")):
1344 os
.makedirs(os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba"), 0700)
1346 setup_file(setup_path("cn=samba.ldif"),
1347 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba.ldif"),
1348 { "UUID": str(uuid
.uuid4()),
1349 "LDAPTIME": timestring(int(time
.time()))} )
1350 setup_file(setup_path("cn=samba-admin.ldif"),
1351 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1352 {"LDAPADMINPASS_B64": b64encode(adminpass
),
1353 "UUID": str(uuid
.uuid4()),
1354 "LDAPTIME": timestring(int(time
.time()))} )
1356 if ol_mmr_urls
is not None:
1357 setup_file(setup_path("cn=replicator.ldif"),
1358 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1359 {"MMR_PASSWORD_B64": b64encode(mmr_pass
),
1360 "UUID": str(uuid
.uuid4()),
1361 "LDAPTIME": timestring(int(time
.time()))} )
1365 mapping
= "schema-map-openldap-2.3"
1366 backend_schema
= "backend-schema.schema"
1368 ldapi_uri
= "ldapi://" + urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1369 if ldap_backend_port
is not None:
1370 server_port_string
= " -h ldap://0.0.0.0:%d" % ldap_backend_port
1372 server_port_string
= ""
1374 slapdcommand
="Start slapd with: slapd -f " + paths
.ldapdir
+ "/slapd.conf -h " + ldapi_uri
+ server_port_string
1376 ldapuser
= "--username=samba-admin"
1379 schema_command
= "bin/ad2oLschema --option=convert:target=" + ldap_backend_type
+ " -I " + setup_path(mapping
) + " -H tdb://" + schemadb_path
+ " -O " + os
.path
.join(paths
.ldapdir
, backend_schema
)
1381 os
.system(schema_command
)
1383 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type
)
1384 message("Server Role: %s" % serverrole
)
1385 message("Hostname: %s" % names
.hostname
)
1386 message("DNS Domain: %s" % names
.dnsdomain
)
1387 message("Base DN: %s" % names
.domaindn
)
1389 if ldap_backend_type
== "openldap":
1390 message("LDAP admin user: samba-admin")
1392 message("LDAP admin DN: %s" % names
.ldapmanagerdn
)
1394 message("LDAP admin password: %s" % adminpass
)
1395 message(slapdcommand
)
1396 message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type
+ " --password=" + adminpass
+ " " + ldapuser
)
1398 def create_phpldapadmin_config(path
, setup_path
, ldapi_uri
):
1399 """Create a PHP LDAP admin configuration file.
1401 :param path: Path to write the configuration to.
1402 :param setup_path: Function to generate setup paths.
1404 setup_file(setup_path("phpldapadmin-config.php"), path
,
1405 {"S4_LDAPI_URI": ldapi_uri
})
1408 def create_zone_file(path
, setup_path
, dnsdomain
, domaindn
,
1409 hostip
, hostip6
, hostname
, dnspass
, realm
, domainguid
, hostguid
):
1410 """Write out a DNS zone file, from the info in the current database.
1412 :param path: Path of the new zone file.
1413 :param setup_path: Setup path function.
1414 :param dnsdomain: DNS Domain name
1415 :param domaindn: DN of the Domain
1416 :param hostip: Local IPv4 IP
1417 :param hostip6: Local IPv6 IP
1418 :param hostname: Local hostname
1419 :param dnspass: Password for DNS
1420 :param realm: Realm name
1421 :param domainguid: GUID of the domain.
1422 :param hostguid: GUID of the host.
1424 assert isinstance(domainguid
, str)
1426 if hostip6
is not None:
1427 hostip6_base_line
= " IN AAAA " + hostip6
1428 hostip6_host_line
= hostname
+ " IN AAAA " + hostip6
1430 hostip6_base_line
= ""
1431 hostip6_host_line
= ""
1433 if hostip
is not None:
1434 hostip_base_line
= " IN A " + hostip
1435 hostip_host_line
= hostname
+ " IN A " + hostip
1437 hostip_base_line
= ""
1438 hostip_host_line
= ""
1440 setup_file(setup_path("provision.zone"), path
, {
1441 "DNSPASS_B64": b64encode(dnspass
),
1442 "HOSTNAME": hostname
,
1443 "DNSDOMAIN": dnsdomain
,
1445 "HOSTIP_BASE_LINE": hostip_base_line
,
1446 "HOSTIP_HOST_LINE": hostip_host_line
,
1447 "DOMAINGUID": domainguid
,
1448 "DATESTRING": time
.strftime("%Y%m%d%H"),
1449 "DEFAULTSITE": DEFAULTSITE
,
1450 "HOSTGUID": hostguid
,
1451 "HOSTIP6_BASE_LINE": hostip6_base_line
,
1452 "HOSTIP6_HOST_LINE": hostip6_host_line
,
1456 def create_named_conf(path
, setup_path
, realm
, dnsdomain
,
1458 """Write out a file containing zone statements suitable for inclusion in a
1459 named.conf file (including GSS-TSIG configuration).
1461 :param path: Path of the new named.conf file.
1462 :param setup_path: Setup path function.
1463 :param realm: Realm name
1464 :param dnsdomain: DNS Domain name
1465 :param private_dir: Path to private directory
1466 :param keytab_name: File name of DNS keytab file
1469 setup_file(setup_path("named.conf"), path
, {
1470 "DNSDOMAIN": dnsdomain
,
1472 "REALM_WC": "*." + ".".join(realm
.split(".")[1:]),
1473 "PRIVATE_DIR": private_dir
1476 def create_named_txt(path
, setup_path
, realm
, dnsdomain
,
1477 private_dir
, keytab_name
):
1478 """Write out a file containing zone statements suitable for inclusion in a
1479 named.conf file (including GSS-TSIG configuration).
1481 :param path: Path of the new named.conf file.
1482 :param setup_path: Setup path function.
1483 :param realm: Realm name
1484 :param dnsdomain: DNS Domain name
1485 :param private_dir: Path to private directory
1486 :param keytab_name: File name of DNS keytab file
1489 setup_file(setup_path("named.txt"), path
, {
1490 "DNSDOMAIN": dnsdomain
,
1492 "DNS_KEYTAB": keytab_name
,
1493 "DNS_KEYTAB_ABS": os
.path
.join(private_dir
, keytab_name
),
1494 "PRIVATE_DIR": private_dir
1497 def create_krb5_conf(path
, setup_path
, dnsdomain
, hostname
, realm
):
1498 """Write out a file containing zone statements suitable for inclusion in a
1499 named.conf file (including GSS-TSIG configuration).
1501 :param path: Path of the new named.conf file.
1502 :param setup_path: Setup path function.
1503 :param dnsdomain: DNS Domain name
1504 :param hostname: Local hostname
1505 :param realm: Realm name
1508 setup_file(setup_path("krb5.conf"), path
, {
1509 "DNSDOMAIN": dnsdomain
,
1510 "HOSTNAME": hostname
,
1515 def load_schema(setup_path
, samdb
, schemadn
, netbiosname
, configdn
, sitename
,
1516 serverdn
, servername
):
1517 """Load schema for the SamDB.
1519 :param samdb: Load a schema into a SamDB.
1520 :param setup_path: Setup path function.
1521 :param schemadn: DN of the schema
1522 :param netbiosname: NetBIOS name of the host.
1523 :param configdn: DN of the configuration
1524 :param serverdn: DN of the server
1525 :param servername: Host name of the server
1527 schema_data
= open(setup_path("schema.ldif"), 'r').read()
1528 schema_data
+= open(setup_path("schema_samba4.ldif"), 'r').read()
1529 schema_data
= substitute_var(schema_data
, {"SCHEMADN": schemadn
})
1530 check_all_substituted(schema_data
)
1531 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
1532 prefixmap
= b64encode(prefixmap
)
1534 head_data
= open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1535 head_data
= substitute_var(head_data
, {
1536 "SCHEMADN": schemadn
,
1537 "NETBIOSNAME": netbiosname
,
1538 "CONFIGDN": configdn
,
1539 "DEFAULTSITE": sitename
,
1540 "PREFIXMAP_B64": prefixmap
,
1541 "SERVERDN": serverdn
,
1542 "SERVERNAME": servername
,
1544 check_all_substituted(head_data
)
1545 samdb
.attach_schema_from_ldif(head_data
, schema_data
)