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
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
40 from auth
import system_session
41 from samba
import version
, Ldb
, substitute_var
, valid_netbios_name
, check_all_substituted
, \
43 from samba
.samdb
import SamDB
44 from samba
.idmap
import IDmapDB
45 from samba
.dcerpc
import security
47 from ldb
import SCOPE_SUBTREE
, SCOPE_ONELEVEL
, SCOPE_BASE
, LdbError
, timestring
48 from ms_schema
import read_ms_schema
49 from signal
import SIGTERM
51 __docformat__
= "restructuredText"
55 """Find the setup directory used by provision."""
56 dirname
= os
.path
.dirname(__file__
)
57 if "/site-packages/" in dirname
:
58 prefix
= "/".join(dirname
[:dirname
.index("/site-packages/")].split("/")[:-2])
59 for suffix
in ["share/setup", "share/samba/setup", "setup"]:
60 ret
= os
.path
.join(prefix
, suffix
)
61 if os
.path
.isdir(ret
):
64 ret
= os
.path
.join(dirname
, "../../../setup")
65 if os
.path
.isdir(ret
):
67 raise Exception("Unable to find setup directory.")
70 DEFAULTSITE
= "Default-First-Site-Name"
72 class InvalidNetbiosName(Exception):
73 """A specified name was not a valid NetBIOS name."""
74 def __init__(self
, name
):
75 super(InvalidNetbiosName
, self
).__init
__("The name '%r' is not a valid NetBIOS name" % name
)
78 class ProvisionPaths(object):
91 self
.dns_keytab
= None
94 self
.private_dir
= None
97 self
.modulesconf
= None
98 self
.memberofconf
= None
99 self
.fedoradsinf
= None
100 self
.fedoradspartitions
= None
102 self
.olmmrserveridsconf
= None
103 self
.olmmrsyncreplconf
= None
106 self
.olcseedldif
= None
109 class ProvisionNames(object):
115 self
.ldapmanagerdn
= None
116 self
.dnsdomain
= None
118 self
.netbiosname
= None
125 class ProvisionResult(object):
132 def check_install(lp
, session_info
, credentials
):
133 """Check whether the current install seems ok.
135 :param lp: Loadparm context
136 :param session_info: Session information
137 :param credentials: Credentials
139 if lp
.get("realm") == "":
140 raise Exception("Realm empty")
141 ldb
= Ldb(lp
.get("sam database"), session_info
=session_info
,
142 credentials
=credentials
, lp
=lp
)
143 if len(ldb
.search("(cn=Administrator)")) != 1:
144 raise "No administrator account found"
147 def findnss(nssfn
, names
):
148 """Find a user or group from a list of possibilities.
150 :param nssfn: NSS Function to try (should raise KeyError if not found)
151 :param names: Names to check.
152 :return: Value return by first names list.
159 raise KeyError("Unable to find user/group %r" % names
)
162 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
163 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
166 def read_and_sub_file(file, subst_vars
):
167 """Read a file and sub in variables found in it
169 :param file: File to be read (typically from setup directory)
170 param subst_vars: Optional variables to subsitute in the file.
172 data
= open(file, 'r').read()
173 if subst_vars
is not None:
174 data
= substitute_var(data
, subst_vars
)
175 check_all_substituted(data
)
179 def setup_add_ldif(ldb
, ldif_path
, subst_vars
=None):
180 """Setup a ldb in the private dir.
182 :param ldb: LDB file to import data into
183 :param ldif_path: Path of the LDIF file to load
184 :param subst_vars: Optional variables to subsitute in LDIF.
186 assert isinstance(ldif_path
, str)
188 data
= read_and_sub_file(ldif_path
, subst_vars
)
192 def setup_modify_ldif(ldb
, ldif_path
, subst_vars
=None):
193 """Modify a ldb in the private dir.
195 :param ldb: LDB object.
196 :param ldif_path: LDIF file path.
197 :param subst_vars: Optional dictionary with substitution variables.
199 data
= read_and_sub_file(ldif_path
, subst_vars
)
201 ldb
.modify_ldif(data
)
204 def setup_ldb(ldb
, ldif_path
, subst_vars
):
205 """Import a LDIF a file into a LDB handle, optionally substituting variables.
207 :note: Either all LDIF data will be added or none (using transactions).
209 :param ldb: LDB file to import into.
210 :param ldif_path: Path to the LDIF file.
211 :param subst_vars: Dictionary with substitution variables.
213 assert ldb
is not None
214 ldb
.transaction_start()
216 setup_add_ldif(ldb
, ldif_path
, subst_vars
)
218 ldb
.transaction_cancel()
220 ldb
.transaction_commit()
223 def setup_file(template
, fname
, subst_vars
):
224 """Setup a file in the private dir.
226 :param template: Path of the template file.
227 :param fname: Path of the file to create.
228 :param subst_vars: Substitution variables.
232 if os
.path
.exists(f
):
235 data
= read_and_sub_file(template
, subst_vars
)
236 open(f
, 'w').write(data
)
239 def provision_paths_from_lp(lp
, dnsdomain
):
240 """Set the default paths for provisioning.
242 :param lp: Loadparm context.
243 :param dnsdomain: DNS Domain name
245 paths
= ProvisionPaths()
246 paths
.private_dir
= lp
.get("private dir")
247 paths
.keytab
= "secrets.keytab"
248 paths
.dns_keytab
= "dns.keytab"
250 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
251 paths
.samdb
= os
.path
.join(paths
.private_dir
, lp
.get("sam database") or "samdb.ldb")
252 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, lp
.get("idmap database") or "idmap.ldb")
253 paths
.secrets
= os
.path
.join(paths
.private_dir
, lp
.get("secrets database") or "secrets.ldb")
254 paths
.templates
= os
.path
.join(paths
.private_dir
, "templates.ldb")
255 paths
.dns
= os
.path
.join(paths
.private_dir
, dnsdomain
+ ".zone")
256 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
257 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
258 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
259 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
260 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
261 paths
.phpldapadminconfig
= os
.path
.join(paths
.private_dir
,
262 "phpldapadmin-config.php")
263 paths
.ldapdir
= os
.path
.join(paths
.private_dir
,
265 paths
.slapdconf
= os
.path
.join(paths
.ldapdir
,
267 paths
.slapdpid
= os
.path
.join(paths
.ldapdir
,
269 paths
.modulesconf
= os
.path
.join(paths
.ldapdir
,
271 paths
.memberofconf
= os
.path
.join(paths
.ldapdir
,
273 paths
.fedoradsinf
= os
.path
.join(paths
.ldapdir
,
275 paths
.fedoradspartitions
= os
.path
.join(paths
.ldapdir
,
276 "fedorads-partitions.ldif")
277 paths
.olmmrserveridsconf
= os
.path
.join(paths
.ldapdir
,
278 "mmr_serverids.conf")
279 paths
.olmmrsyncreplconf
= os
.path
.join(paths
.ldapdir
,
281 paths
.olcdir
= os
.path
.join(paths
.ldapdir
,
283 paths
.olcseedldif
= os
.path
.join(paths
.ldapdir
,
285 paths
.hklm
= "hklm.ldb"
286 paths
.hkcr
= "hkcr.ldb"
287 paths
.hkcu
= "hkcu.ldb"
288 paths
.hku
= "hku.ldb"
289 paths
.hkpd
= "hkpd.ldb"
290 paths
.hkpt
= "hkpt.ldb"
292 paths
.sysvol
= lp
.get("path", "sysvol")
294 paths
.netlogon
= lp
.get("path", "netlogon")
296 paths
.smbconf
= lp
.configfile
301 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None, serverrole
=None,
302 rootdn
=None, domaindn
=None, configdn
=None, schemadn
=None, serverdn
=None,
304 """Guess configuration settings to use."""
307 hostname
= socket
.gethostname().split(".")[0].lower()
309 netbiosname
= hostname
.upper()
310 if not valid_netbios_name(netbiosname
):
311 raise InvalidNetbiosName(netbiosname
)
313 hostname
= hostname
.lower()
315 if dnsdomain
is None:
316 dnsdomain
= lp
.get("realm")
318 if serverrole
is None:
319 serverrole
= lp
.get("server role")
321 assert dnsdomain
is not None
322 realm
= dnsdomain
.upper()
324 if lp
.get("realm").upper() != realm
:
325 raise Exception("realm '%s' in %s must match chosen realm '%s'" %
326 (lp
.get("realm"), lp
.configfile
, realm
))
328 dnsdomain
= dnsdomain
.lower()
330 if serverrole
== "domain controller":
332 domain
= lp
.get("workgroup")
334 domaindn
= "DC=" + dnsdomain
.replace(".", ",DC=")
335 if lp
.get("workgroup").upper() != domain
.upper():
336 raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
337 lp
.get("workgroup"), domain
)
341 domaindn
= "CN=" + netbiosname
343 assert domain
is not None
344 domain
= domain
.upper()
345 if not valid_netbios_name(domain
):
346 raise InvalidNetbiosName(domain
)
352 configdn
= "CN=Configuration," + rootdn
354 schemadn
= "CN=Schema," + configdn
359 names
= ProvisionNames()
360 names
.rootdn
= rootdn
361 names
.domaindn
= domaindn
362 names
.configdn
= configdn
363 names
.schemadn
= schemadn
364 names
.ldapmanagerdn
= "CN=Manager," + rootdn
365 names
.dnsdomain
= dnsdomain
366 names
.domain
= domain
368 names
.netbiosname
= netbiosname
369 names
.hostname
= hostname
370 names
.sitename
= sitename
371 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname
, sitename
, configdn
)
376 def make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
378 """Create a new smb.conf file based on a couple of basic settings.
380 assert smbconf
is not None
382 hostname
= socket
.gethostname().split(".")[0].lower()
384 if serverrole
is None:
385 serverrole
= "standalone"
387 assert serverrole
in ("domain controller", "member server", "standalone")
388 if serverrole
== "domain controller":
390 elif serverrole
== "member server":
391 smbconfsuffix
= "member"
392 elif serverrole
== "standalone":
393 smbconfsuffix
= "standalone"
395 assert domain
is not None
396 assert realm
is not None
398 default_lp
= param
.LoadParm()
399 #Load non-existant file
400 if os
.path
.exists(smbconf
):
401 default_lp
.load(smbconf
)
403 if targetdir
is not None:
404 privatedir_line
= "private dir = " + os
.path
.abspath(os
.path
.join(targetdir
, "private"))
405 lockdir_line
= "lock dir = " + os
.path
.abspath(targetdir
)
407 default_lp
.set("lock dir", os
.path
.abspath(targetdir
))
412 sysvol
= os
.path
.join(default_lp
.get("lock dir"), "sysvol")
413 netlogon
= os
.path
.join(sysvol
, realm
.lower(), "scripts")
415 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix
),
417 "HOSTNAME": hostname
,
420 "SERVERROLE": serverrole
,
421 "NETLOGONPATH": netlogon
,
422 "SYSVOLPATH": sysvol
,
423 "PRIVATEDIR_LINE": privatedir_line
,
424 "LOCKDIR_LINE": lockdir_line
428 def setup_name_mappings(samdb
, idmap
, sid
, domaindn
, root_uid
, nobody_uid
,
429 users_gid
, wheel_gid
):
430 """setup reasonable name mappings for sam names to unix names.
432 :param samdb: SamDB object.
433 :param idmap: IDmap db object.
434 :param sid: The domain sid.
435 :param domaindn: The domain DN.
436 :param root_uid: uid of the UNIX root user.
437 :param nobody_uid: uid of the UNIX nobody user.
438 :param users_gid: gid of the UNIX users group.
439 :param wheel_gid: gid of the UNIX wheel group."""
440 # add some foreign sids if they are not present already
441 samdb
.add_stock_foreign_sids()
443 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
444 idmap
.setup_name_mapping("S-1-5-32-544", idmap
.TYPE_GID
, wheel_gid
)
446 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
447 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
450 def setup_samdb_partitions(samdb_path
, setup_path
, message
, lp
, session_info
,
452 serverrole
, ldap_backend
=None,
453 ldap_backend_type
=None, erase
=False):
454 """Setup the partitions for the SAM database.
456 Alternatively, provision() may call this, and then populate the database.
458 :note: This will wipe the Sam Database!
460 :note: This function always removes the local SAM LDB file. The erase
461 parameter controls whether to erase the existing data, which
462 may not be stored locally but in LDAP.
464 assert session_info
is not None
467 samdb
= SamDB(samdb_path
, session_info
=session_info
,
468 credentials
=credentials
, lp
=lp
)
472 os
.unlink(samdb_path
)
473 samdb
= SamDB(samdb_path
, session_info
=session_info
,
474 credentials
=credentials
, lp
=lp
)
479 #Add modules to the list to activate them by default
480 #beware often order is important
482 # Some Known ordering constraints:
483 # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
484 # - objectclass must be before password_hash, because password_hash checks
485 # that the objectclass is of type person (filled in by objectclass
486 # module when expanding the objectclass list)
487 # - partition must be last
488 # - each partition has its own module list then
489 modules_list
= ["rootdse",
507 "extended_dn_out_ldb"]
508 modules_list2
= ["show_deleted",
511 domaindn_ldb
= "users.ldb"
512 if ldap_backend
is not None:
513 domaindn_ldb
= ldap_backend
514 configdn_ldb
= "configuration.ldb"
515 if ldap_backend
is not None:
516 configdn_ldb
= ldap_backend
517 schemadn_ldb
= "schema.ldb"
518 if ldap_backend
is not None:
519 schema_ldb
= ldap_backend
520 schemadn_ldb
= ldap_backend
522 if ldap_backend_type
== "fedora-ds":
523 backend_modules
= ["nsuniqueid", "paged_searches"]
524 # We can handle linked attributes here, as we don't have directory-side subtree operations
525 tdb_modules_list
= ["linked_attributes", "extended_dn_out_dereference"]
526 elif ldap_backend_type
== "openldap":
527 backend_modules
= ["entryuuid", "paged_searches"]
528 # OpenLDAP handles subtree renames, so we don't want to do any of these things
529 tdb_modules_list
= ["extended_dn_out_dereference"]
530 elif ldap_backend
is not None:
531 raise "LDAP Backend specified, but LDAP Backend Type not specified"
532 elif serverrole
== "domain controller":
533 backend_modules
= ["repl_meta_data"]
535 backend_modules
= ["objectguid"]
537 if tdb_modules_list
is None:
538 tdb_modules_list_as_string
= ""
540 tdb_modules_list_as_string
= ","+",".join(tdb_modules_list
)
542 samdb
.transaction_start()
544 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
545 "SCHEMADN": names
.schemadn
,
546 "SCHEMADN_LDB": schemadn_ldb
,
547 "SCHEMADN_MOD2": ",objectguid",
548 "CONFIGDN": names
.configdn
,
549 "CONFIGDN_LDB": configdn_ldb
,
550 "DOMAINDN": names
.domaindn
,
551 "DOMAINDN_LDB": domaindn_ldb
,
552 "SCHEMADN_MOD": "schema_fsmo,instancetype",
553 "CONFIGDN_MOD": "naming_fsmo,instancetype",
554 "DOMAINDN_MOD": "pdc_fsmo,instancetype",
555 "MODULES_LIST": ",".join(modules_list
),
556 "TDB_MODULES_LIST": tdb_modules_list_as_string
,
557 "MODULES_LIST2": ",".join(modules_list2
),
558 "BACKEND_MOD": ",".join(backend_modules
),
562 samdb
.transaction_cancel()
565 samdb
.transaction_commit()
567 samdb
= SamDB(samdb_path
, session_info
=session_info
,
568 credentials
=credentials
, lp
=lp
)
570 samdb
.transaction_start()
572 message("Setting up sam.ldb attributes")
573 samdb
.load_ldif_file_add(setup_path("provision_init.ldif"))
575 message("Setting up sam.ldb rootDSE")
576 setup_samdb_rootdse(samdb
, setup_path
, names
)
579 message("Erasing data from partitions")
580 samdb
.erase_partitions()
583 samdb
.transaction_cancel()
586 samdb
.transaction_commit()
591 def secretsdb_become_dc(secretsdb
, setup_path
, domain
, realm
, dnsdomain
,
592 netbiosname
, domainsid
, keytab_path
, samdb_url
,
593 dns_keytab_path
, dnspass
, machinepass
):
594 """Add DC-specific bits to a secrets database.
596 :param secretsdb: Ldb Handle to the secrets database
597 :param setup_path: Setup path function
598 :param machinepass: Machine password
600 setup_ldb(secretsdb
, setup_path("secrets_dc.ldif"), {
601 "MACHINEPASS_B64": b64encode(machinepass
),
604 "DNSDOMAIN": dnsdomain
,
605 "DOMAINSID": str(domainsid
),
606 "SECRETS_KEYTAB": keytab_path
,
607 "NETBIOSNAME": netbiosname
,
608 "SAM_LDB": samdb_url
,
609 "DNS_KEYTAB": dns_keytab_path
,
610 "DNSPASS_B64": b64encode(dnspass
),
614 def setup_secretsdb(path
, setup_path
, session_info
, credentials
, lp
):
615 """Setup the secrets database.
617 :param path: Path to the secrets database.
618 :param setup_path: Get the path to a setup file.
619 :param session_info: Session info.
620 :param credentials: Credentials
621 :param lp: Loadparm context
622 :return: LDB handle for the created secrets database
624 if os
.path
.exists(path
):
626 secrets_ldb
= Ldb(path
, session_info
=session_info
, credentials
=credentials
,
629 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
630 secrets_ldb
= Ldb(path
, session_info
=session_info
, credentials
=credentials
,
632 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
634 if credentials
is not None and credentials
.authentication_requested():
635 if credentials
.get_bind_dn() is not None:
636 setup_add_ldif(secrets_ldb
, setup_path("secrets_simple_ldap.ldif"), {
637 "LDAPMANAGERDN": credentials
.get_bind_dn(),
638 "LDAPMANAGERPASS_B64": b64encode(credentials
.get_password())
641 setup_add_ldif(secrets_ldb
, setup_path("secrets_sasl_ldap.ldif"), {
642 "LDAPADMINUSER": credentials
.get_username(),
643 "LDAPADMINREALM": credentials
.get_realm(),
644 "LDAPADMINPASS_B64": b64encode(credentials
.get_password())
650 def setup_templatesdb(path
, setup_path
, session_info
, credentials
, lp
):
651 """Setup the templates database.
653 :param path: Path to the database.
654 :param setup_path: Function for obtaining the path to setup files.
655 :param session_info: Session info
656 :param credentials: Credentials
657 :param lp: Loadparm context
659 templates_ldb
= SamDB(path
, session_info
=session_info
,
660 credentials
=credentials
, lp
=lp
)
663 templates_ldb
.erase()
664 # This should be 'except LdbError', but on a re-provision the assert in ldb.erase fires, and we need to catch that too
668 templates_ldb
.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
670 templates_ldb
= SamDB(path
, session_info
=session_info
,
671 credentials
=credentials
, lp
=lp
)
673 templates_ldb
.load_ldif_file_add(setup_path("provision_templates.ldif"))
676 def setup_registry(path
, setup_path
, session_info
, credentials
, lp
):
677 """Setup the registry.
679 :param path: Path to the registry database
680 :param setup_path: Function that returns the path to a setup.
681 :param session_info: Session information
682 :param credentials: Credentials
683 :param lp: Loadparm context
685 reg
= registry
.Registry()
686 hive
= registry
.open_ldb(path
, session_info
=session_info
,
687 credentials
=credentials
, lp_ctx
=lp
)
688 reg
.mount_hive(hive
, registry
.HKEY_LOCAL_MACHINE
)
689 provision_reg
= setup_path("provision.reg")
690 assert os
.path
.exists(provision_reg
)
691 reg
.diff_apply(provision_reg
)
694 def setup_idmapdb(path
, setup_path
, session_info
, credentials
, lp
):
695 """Setup the idmap database.
697 :param path: path to the idmap database
698 :param setup_path: Function that returns a path to a setup file
699 :param session_info: Session information
700 :param credentials: Credentials
701 :param lp: Loadparm context
703 if os
.path
.exists(path
):
706 idmap_ldb
= IDmapDB(path
, session_info
=session_info
,
707 credentials
=credentials
, lp
=lp
)
710 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
714 def setup_samdb_rootdse(samdb
, setup_path
, names
):
715 """Setup the SamDB rootdse.
717 :param samdb: Sam Database handle
718 :param setup_path: Obtain setup path
720 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
721 "SCHEMADN": names
.schemadn
,
722 "NETBIOSNAME": names
.netbiosname
,
723 "DNSDOMAIN": names
.dnsdomain
,
724 "REALM": names
.realm
,
725 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
726 "DOMAINDN": names
.domaindn
,
727 "ROOTDN": names
.rootdn
,
728 "CONFIGDN": names
.configdn
,
729 "SERVERDN": names
.serverdn
,
733 def setup_self_join(samdb
, names
,
734 machinepass
, dnspass
,
735 domainsid
, invocationid
, setup_path
,
736 policyguid
, domainControllerFunctionality
):
737 """Join a host to its own domain."""
738 assert isinstance(invocationid
, str)
739 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
740 "CONFIGDN": names
.configdn
,
741 "SCHEMADN": names
.schemadn
,
742 "DOMAINDN": names
.domaindn
,
743 "SERVERDN": names
.serverdn
,
744 "INVOCATIONID": invocationid
,
745 "NETBIOSNAME": names
.netbiosname
,
746 "DEFAULTSITE": names
.sitename
,
747 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
748 "MACHINEPASS_B64": b64encode(machinepass
),
749 "DNSPASS_B64": b64encode(dnspass
),
750 "REALM": names
.realm
,
751 "DOMAIN": names
.domain
,
752 "DNSDOMAIN": names
.dnsdomain
,
753 "SAMBA_VERSION_STRING": version
,
754 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality
)})
755 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
756 "POLICYGUID": policyguid
,
757 "DNSDOMAIN": names
.dnsdomain
,
758 "DOMAINSID": str(domainsid
),
759 "DOMAINDN": names
.domaindn
})
762 def setup_samdb(path
, setup_path
, session_info
, credentials
, lp
,
764 domainsid
, aci
, domainguid
, policyguid
,
765 fill
, adminpass
, krbtgtpass
,
766 machinepass
, invocationid
, dnspass
,
767 serverrole
, ldap_backend
=None,
768 ldap_backend_type
=None):
769 """Setup a complete SAM Database.
771 :note: This will wipe the main SAM database file!
774 domainFunctionality
= DS_BEHAVIOR_WIN2008
775 forestFunctionality
= DS_BEHAVIOR_WIN2008
776 domainControllerFunctionality
= DS_BEHAVIOR_WIN2008
778 erase
= (fill
!= FILL_DRS
)
780 # Also wipes the database
781 setup_samdb_partitions(path
, setup_path
, message
=message
, lp
=lp
,
782 credentials
=credentials
, session_info
=session_info
,
784 ldap_backend
=ldap_backend
, serverrole
=serverrole
,
785 ldap_backend_type
=ldap_backend_type
, erase
=erase
)
787 samdb
= SamDB(path
, session_info
=session_info
,
788 credentials
=credentials
, lp
=lp
)
792 message("Pre-loading the Samba 4 and AD schema")
794 samdb
.set_opaque_integer("domainFunctionality", domainFunctionality
)
795 samdb
.set_opaque_integer("forestFunctionality", forestFunctionality
)
796 samdb
.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality
)
798 samdb
.set_domain_sid(str(domainsid
))
799 if serverrole
== "domain controller":
800 samdb
.set_invocation_id(invocationid
)
802 schema_data
= load_schema(setup_path
, samdb
, names
.schemadn
, names
.netbiosname
,
803 names
.configdn
, names
.sitename
, names
.serverdn
)
804 samdb
.transaction_start()
807 message("Adding DomainDN: %s (permitted to fail)" % names
.domaindn
)
808 if serverrole
== "domain controller":
809 domain_oc
= "domainDNS"
811 domain_oc
= "samba4LocalDomain"
813 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
814 "DOMAINDN": names
.domaindn
,
816 "DOMAIN_OC": domain_oc
819 message("Modifying DomainDN: " + names
.domaindn
+ "")
820 if domainguid
is not None:
821 domainguid_mod
= "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
825 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
826 "LDAPTIME": timestring(int(time
.time())),
827 "DOMAINSID": str(domainsid
),
828 "SCHEMADN": names
.schemadn
,
829 "NETBIOSNAME": names
.netbiosname
,
830 "DEFAULTSITE": names
.sitename
,
831 "CONFIGDN": names
.configdn
,
832 "SERVERDN": names
.serverdn
,
833 "POLICYGUID": policyguid
,
834 "DOMAINDN": names
.domaindn
,
835 "DOMAINGUID_MOD": domainguid_mod
,
836 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
)
839 message("Adding configuration container (permitted to fail)")
840 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
841 "CONFIGDN": names
.configdn
,
844 message("Modifying configuration container")
845 setup_modify_ldif(samdb
, setup_path("provision_configuration_basedn_modify.ldif"), {
846 "CONFIGDN": names
.configdn
,
847 "SCHEMADN": names
.schemadn
,
850 message("Adding schema container (permitted to fail)")
851 setup_add_ldif(samdb
, setup_path("provision_schema_basedn.ldif"), {
852 "SCHEMADN": names
.schemadn
,
855 message("Modifying schema container")
857 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
859 setup_modify_ldif(samdb
,
860 setup_path("provision_schema_basedn_modify.ldif"), {
861 "SCHEMADN": names
.schemadn
,
862 "NETBIOSNAME": names
.netbiosname
,
863 "DEFAULTSITE": names
.sitename
,
864 "CONFIGDN": names
.configdn
,
865 "SERVERDN": names
.serverdn
,
866 "PREFIXMAP_B64": b64encode(prefixmap
)
869 message("Setting up sam.ldb schema")
870 samdb
.add_ldif(schema_data
)
871 setup_add_ldif(samdb
, setup_path("aggregate_schema.ldif"),
872 {"SCHEMADN": names
.schemadn
})
874 message("Setting up sam.ldb configuration data")
875 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
876 "CONFIGDN": names
.configdn
,
877 "NETBIOSNAME": names
.netbiosname
,
878 "DEFAULTSITE": names
.sitename
,
879 "DNSDOMAIN": names
.dnsdomain
,
880 "DOMAIN": names
.domain
,
881 "SCHEMADN": names
.schemadn
,
882 "DOMAINDN": names
.domaindn
,
883 "SERVERDN": names
.serverdn
,
884 "FOREST_FUNCTIONALALITY": str(forestFunctionality
)
887 message("Setting up display specifiers")
888 setup_add_ldif(samdb
, setup_path("display_specifiers.ldif"),
889 {"CONFIGDN": names
.configdn
})
891 message("Adding users container (permitted to fail)")
892 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
893 "DOMAINDN": names
.domaindn
})
894 message("Modifying users container")
895 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
896 "DOMAINDN": names
.domaindn
})
897 message("Adding computers container (permitted to fail)")
898 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
899 "DOMAINDN": names
.domaindn
})
900 message("Modifying computers container")
901 setup_modify_ldif(samdb
, setup_path("provision_computers_modify.ldif"), {
902 "DOMAINDN": names
.domaindn
})
903 message("Setting up sam.ldb data")
904 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
905 "DOMAINDN": names
.domaindn
,
906 "NETBIOSNAME": names
.netbiosname
,
907 "DEFAULTSITE": names
.sitename
,
908 "CONFIGDN": names
.configdn
,
909 "SERVERDN": names
.serverdn
912 if fill
== FILL_FULL
:
913 message("Setting up sam.ldb users and groups")
914 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
915 "DOMAINDN": names
.domaindn
,
916 "DOMAINSID": str(domainsid
),
917 "CONFIGDN": names
.configdn
,
918 "ADMINPASS_B64": b64encode(adminpass
),
919 "KRBTGTPASS_B64": b64encode(krbtgtpass
),
922 if serverrole
== "domain controller":
923 message("Setting up self join")
924 setup_self_join(samdb
, names
=names
, invocationid
=invocationid
,
926 machinepass
=machinepass
,
927 domainsid
=domainsid
, policyguid
=policyguid
,
928 setup_path
=setup_path
, domainControllerFunctionality
=domainControllerFunctionality
)
931 samdb
.transaction_cancel()
934 samdb
.transaction_commit()
939 FILL_NT4SYNC
= "NT4SYNC"
943 def provision(setup_dir
, message
, session_info
,
944 credentials
, smbconf
=None, targetdir
=None, samdb_fill
=FILL_FULL
, realm
=None,
945 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
947 domain
=None, hostname
=None, hostip
=None, hostip6
=None,
948 domainsid
=None, adminpass
=None, krbtgtpass
=None, domainguid
=None,
949 policyguid
=None, invocationid
=None, machinepass
=None,
950 dnspass
=None, root
=None, nobody
=None, nogroup
=None, users
=None,
951 wheel
=None, backup
=None, aci
=None, serverrole
=None,
952 ldap_backend
=None, ldap_backend_type
=None, sitename
=None):
955 :note: caution, this wipes all existing data!
958 def setup_path(file):
959 return os
.path
.join(setup_dir
, file)
961 if domainsid
is None:
962 domainsid
= security
.random_sid()
964 if policyguid
is None:
965 policyguid
= str(uuid
.uuid4())
966 if adminpass
is None:
967 adminpass
= glue
.generate_random_str(12)
968 if krbtgtpass
is None:
969 krbtgtpass
= glue
.generate_random_str(12)
970 if machinepass
is None:
971 machinepass
= glue
.generate_random_str(12)
973 dnspass
= glue
.generate_random_str(12)
974 root_uid
= findnss_uid([root
or "root"])
975 nobody_uid
= findnss_uid([nobody
or "nobody"])
976 users_gid
= findnss_gid([users
or "users"])
978 wheel_gid
= findnss_gid(["wheel", "adm"])
980 wheel_gid
= findnss_gid([wheel
])
982 aci
= "# no aci for local ldb"
984 if targetdir
is not None:
985 if (not os
.path
.exists(os
.path
.join(targetdir
, "etc"))):
986 os
.makedirs(os
.path
.join(targetdir
, "etc"))
987 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
988 elif smbconf
is None:
989 smbconf
= param
.default_path()
991 # only install a new smb.conf if there isn't one there already
992 if not os
.path
.exists(smbconf
):
993 make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
996 lp
= param
.LoadParm()
999 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1000 dnsdomain
=realm
, serverrole
=serverrole
, sitename
=sitename
,
1001 rootdn
=rootdn
, domaindn
=domaindn
, configdn
=configdn
, schemadn
=schemadn
,
1004 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1008 hostip
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
1009 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
1014 hostip6
= socket
.getaddrinfo(names
.hostname
, None, socket
.AF_INET6
, socket
.AI_CANONNAME
, socket
.IPPROTO_IP
)[0][-1][0]
1015 except socket
.gaierror
, (socket
.EAI_NODATA
, msg
):
1018 if serverrole
is None:
1019 serverrole
= lp
.get("server role")
1021 assert serverrole
in ("domain controller", "member server", "standalone")
1022 if invocationid
is None and serverrole
== "domain controller":
1023 invocationid
= str(uuid
.uuid4())
1025 if not os
.path
.exists(paths
.private_dir
):
1026 os
.mkdir(paths
.private_dir
)
1028 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
1030 if ldap_backend
is not None:
1031 if ldap_backend
== "ldapi":
1032 # provision-backend will set this path suggested slapd command line / fedorads.inf
1033 ldap_backend
= "ldapi://%s" % urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1035 # only install a new shares config db if there is none
1036 if not os
.path
.exists(paths
.shareconf
):
1037 message("Setting up share.ldb")
1038 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
,
1039 credentials
=credentials
, lp
=lp
)
1040 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
1043 message("Setting up secrets.ldb")
1044 secrets_ldb
= setup_secretsdb(paths
.secrets
, setup_path
,
1045 session_info
=session_info
,
1046 credentials
=credentials
, lp
=lp
)
1048 message("Setting up the registry")
1049 setup_registry(paths
.hklm
, setup_path
, session_info
,
1050 credentials
=credentials
, lp
=lp
)
1052 message("Setting up templates db")
1053 setup_templatesdb(paths
.templates
, setup_path
, session_info
=session_info
,
1054 credentials
=credentials
, lp
=lp
)
1056 message("Setting up idmap db")
1057 idmap
= setup_idmapdb(paths
.idmapdb
, setup_path
, session_info
=session_info
,
1058 credentials
=credentials
, lp
=lp
)
1060 samdb
= setup_samdb(paths
.samdb
, setup_path
, session_info
=session_info
,
1061 credentials
=credentials
, lp
=lp
, names
=names
,
1063 domainsid
=domainsid
,
1064 aci
=aci
, domainguid
=domainguid
, policyguid
=policyguid
,
1066 adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1067 invocationid
=invocationid
,
1068 machinepass
=machinepass
, dnspass
=dnspass
,
1069 serverrole
=serverrole
, ldap_backend
=ldap_backend
,
1070 ldap_backend_type
=ldap_backend_type
)
1072 if serverrole
== "domain controller":
1073 if paths
.netlogon
is None:
1074 message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1075 message("Please either remove %s or see the template at %s" %
1076 ( paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1077 assert(paths
.netlogon
is not None)
1079 if paths
.sysvol
is None:
1080 message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
1081 message("Please either remove %s or see the template at %s" %
1082 (paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1083 assert(paths
.sysvol
is not None)
1085 policy_path
= os
.path
.join(paths
.sysvol
, names
.dnsdomain
, "Policies",
1086 "{" + policyguid
+ "}")
1087 os
.makedirs(policy_path
, 0755)
1088 open(os
.path
.join(policy_path
, "GPT.INI"), 'w').write("")
1089 os
.makedirs(os
.path
.join(policy_path
, "Machine"), 0755)
1090 os
.makedirs(os
.path
.join(policy_path
, "User"), 0755)
1091 if not os
.path
.isdir(paths
.netlogon
):
1092 os
.makedirs(paths
.netlogon
, 0755)
1094 if samdb_fill
== FILL_FULL
:
1095 setup_name_mappings(samdb
, idmap
, str(domainsid
), names
.domaindn
,
1096 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
1097 users_gid
=users_gid
, wheel_gid
=wheel_gid
)
1099 message("Setting up sam.ldb rootDSE marking as synchronized")
1100 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"))
1102 # Only make a zone file on the first DC, it should be replicated with DNS replication
1103 if serverrole
== "domain controller":
1104 secrets_ldb
= Ldb(paths
.secrets
, session_info
=session_info
,
1105 credentials
=credentials
, lp
=lp
)
1106 secretsdb_become_dc(secrets_ldb
, setup_path
, domain
=domain
, realm
=names
.realm
,
1107 netbiosname
=names
.netbiosname
, domainsid
=domainsid
,
1108 keytab_path
=paths
.keytab
, samdb_url
=paths
.samdb
,
1109 dns_keytab_path
=paths
.dns_keytab
, dnspass
=dnspass
,
1110 machinepass
=machinepass
, dnsdomain
=names
.dnsdomain
)
1112 samdb
= SamDB(paths
.samdb
, session_info
=session_info
,
1113 credentials
=credentials
, lp
=lp
)
1115 domainguid
= samdb
.searchone(basedn
=domaindn
, attribute
="objectGUID")
1116 assert isinstance(domainguid
, str)
1117 hostguid
= samdb
.searchone(basedn
=domaindn
, attribute
="objectGUID",
1118 expression
="(&(objectClass=computer)(cn=%s))" % names
.hostname
,
1119 scope
=SCOPE_SUBTREE
)
1120 assert isinstance(hostguid
, str)
1122 create_zone_file(paths
.dns
, setup_path
, dnsdomain
=names
.dnsdomain
,
1123 domaindn
=names
.domaindn
, hostip
=hostip
,
1124 hostip6
=hostip6
, hostname
=names
.hostname
,
1125 dnspass
=dnspass
, realm
=names
.realm
,
1126 domainguid
=domainguid
, hostguid
=hostguid
)
1128 create_named_conf(paths
.namedconf
, setup_path
, realm
=names
.realm
,
1129 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
)
1131 create_named_txt(paths
.namedtxt
, setup_path
, realm
=names
.realm
,
1132 dnsdomain
=names
.dnsdomain
, private_dir
=paths
.private_dir
,
1133 keytab_name
=paths
.dns_keytab
)
1134 message("See %s for an example configuration include file for BIND" % paths
.namedconf
)
1135 message("and %s for further documentation required for secure DNS updates" % paths
.namedtxt
)
1137 create_krb5_conf(paths
.krb5conf
, setup_path
, dnsdomain
=names
.dnsdomain
,
1138 hostname
=names
.hostname
, realm
=names
.realm
)
1139 message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths
.krb5conf
)
1143 # if backend is openldap, terminate slapd after final provision and check its proper termination
1144 if ldap_backend_type
== "openldap":
1146 # We look if our "provision-slapd" is still up and running,
1147 # listening with the stored PID on our ldapi_uri.
1148 # first we check with ldapsearch -> rootDSE via ldapi_uri
1149 # if slapd is running
1151 # in this case we got a running slapd listening on our ldapi_uri
1152 ldapi_uri
= "ldapi://" + urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1153 ldapi_db
= Ldb(ldapi_uri
)
1154 search_ol_rootdse
= ldapi_db
.search(base
="", scope
=SCOPE_BASE
,
1155 expression
="(objectClass=OpenLDAProotDSE)");
1156 message("LDAP Debug-Output:" + str(search_ol_rootdse
))
1158 # now we check if slapds PID file exists AND is identical to our stored
1159 if os
.path
.exists(paths
.slapdpid
):
1160 f
= open(paths
.slapdpid
, "r")
1163 message("slapd-PID-File found. PID is :" + str(p1
))
1164 # validation against stored PID of "provision-slapd".
1165 # is this the slapd we started from provision-backend?
1166 if os
.path
.exists(paths
.ldapdir
+ "/slapd_provision_pid"):
1167 f
= open(paths
.ldapdir
+ "/slapd_provision_pid", "r")
1170 message("File from provision-backend with stored PID found. PID is :" + str(p2
))
1171 if int(p1
) == int(p2
):
1172 message("slapd-Process used for provisioning with PID: " + str(p1
) + " will now be shut down.")
1173 os
.kill(int(p1
),SIGTERM
)
1175 message("Warning: PIDs are not identical! Locate the active slapd and shut it down before you continue!")
1177 message("Stored PID File could not be found. Sorry. You have to locate the PID and terminate slapd manually.")
1179 message("slapd-PID File could not be found. Sorry. You have to locate the PID and terminate slapd manually.")
1181 # Now verify proper slapd-termination...
1183 # in this case we got still a running slapd listening on our ldapi_uri: bad
1184 ldapi_uri
= "ldapi://" + urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1185 ldapi_db
= Ldb(ldapi_uri
)
1186 search_ol_rootdse
= ldapi_db
.search(base
="", scope
=SCOPE_BASE
,
1187 expression
="(objectClass=OpenLDAProotDSE)");
1188 message("slapd seems still to be running and listening to our "+ ldapi_uri
+ " -socket. Locate an terminate it manually.")
1190 message("slapd-Process used for final provision was properly shut down.")
1191 # in this case we got no running slapd listening on our ldapi_uri: everythings good - do nothing.
1194 # in this case we got no running slapd
1195 message("LDAP Debug-Output:")
1197 message("No running slapd on: " + ldapi_uri
+ " detected. Maybe final provision is incomplete.")
1199 # end slapd-termination check
1201 # now display slapd_command_file.txt to show how slapd must be started next time
1202 if os
.path
.exists(paths
.ldapdir
+"/slapd_command_file.txt"):
1203 message("Use later the following commandline to start slapd, then Samba:")
1204 f
= open(paths
.ldapdir
+"/slapd_command_file.txt", "r")
1208 message("This slapd-Commandline is also stored under: " + str(paths
.ldapdir
) + "/slapd_command_file.txt")
1210 message("Error. slapd-commandline-File could not be found.")
1213 create_phpldapadmin_config(paths
.phpldapadminconfig
, setup_path
,
1216 message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths
.phpldapadminconfig
)
1218 message("Once the above files are installed, your Samba4 server will be ready to use")
1219 message("Server Role: %s" % serverrole
)
1220 message("Hostname: %s" % names
.hostname
)
1221 message("NetBIOS Domain: %s" % names
.domain
)
1222 message("DNS Domain: %s" % names
.dnsdomain
)
1223 message("DOMAIN SID: %s" % str(domainsid
))
1224 if samdb_fill
== FILL_FULL
:
1225 message("Admin password: %s" % adminpass
)
1227 result
= ProvisionResult()
1228 result
.domaindn
= domaindn
1229 result
.paths
= paths
1231 result
.samdb
= samdb
1236 def provision_become_dc(setup_dir
=None,
1237 smbconf
=None, targetdir
=None, realm
=None,
1238 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1240 domain
=None, hostname
=None, domainsid
=None,
1241 adminpass
=None, krbtgtpass
=None, domainguid
=None,
1242 policyguid
=None, invocationid
=None, machinepass
=None,
1243 dnspass
=None, root
=None, nobody
=None, nogroup
=None, users
=None,
1244 wheel
=None, backup
=None, aci
=None, serverrole
=None,
1245 ldap_backend
=None, ldap_backend_type
=None, sitename
=None):
1248 """print a message if quiet is not set."""
1251 return provision(setup_dir
, message
, system_session(), None,
1252 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
, realm
=realm
,
1253 rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
, configdn
=configdn
, serverdn
=serverdn
,
1254 domain
=domain
, hostname
=hostname
, hostip
="127.0.0.1", domainsid
=domainsid
, machinepass
=machinepass
, serverrole
="domain controller", sitename
=sitename
)
1257 def setup_db_config(setup_path
, dbdir
):
1258 """Setup a Berkeley database.
1260 :param setup_path: Setup path function.
1261 :param dbdir: Database directory."""
1262 if not os
.path
.isdir(os
.path
.join(dbdir
, "bdb-logs")):
1263 os
.makedirs(os
.path
.join(dbdir
, "bdb-logs"), 0700)
1264 if not os
.path
.isdir(os
.path
.join(dbdir
, "tmp")):
1265 os
.makedirs(os
.path
.join(dbdir
, "tmp"), 0700)
1267 setup_file(setup_path("DB_CONFIG"), os
.path
.join(dbdir
, "DB_CONFIG"),
1268 {"LDAPDBDIR": dbdir
})
1272 def provision_backend(setup_dir
=None, message
=None,
1273 smbconf
=None, targetdir
=None, realm
=None,
1274 rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1275 domain
=None, hostname
=None, adminpass
=None, root
=None, serverrole
=None,
1276 ldap_backend_type
=None, ldap_backend_port
=None,
1277 ol_mmr_urls
=None, ol_olc
=None,
1278 ol_slapd
=None, nosync
=False):
1280 def setup_path(file):
1281 return os
.path
.join(setup_dir
, file)
1283 if hostname
is None:
1284 hostname
= socket
.gethostname().split(".")[0].lower()
1287 root
= findnss(pwd
.getpwnam
, ["root"])[0]
1289 if adminpass
is None:
1290 adminpass
= glue
.generate_random_str(12)
1292 if targetdir
is not None:
1293 if (not os
.path
.exists(os
.path
.join(targetdir
, "etc"))):
1294 os
.makedirs(os
.path
.join(targetdir
, "etc"))
1295 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1296 elif smbconf
is None:
1297 smbconf
= param
.default_path()
1298 assert smbconf
is not None
1300 # only install a new smb.conf if there isn't one there already
1301 if not os
.path
.exists(smbconf
):
1302 make_smbconf(smbconf
, setup_path
, hostname
, domain
, realm
, serverrole
,
1305 # if openldap-backend was chosen, check if path to slapd was given and exists
1306 if ldap_backend_type
== "openldap" and ol_slapd
is None:
1307 sys
.exit("Warning: OpenLDAP-Backend must be setup with path to slapd (OpenLDAP-Daemon), e.g. --ol-slapd=\"/usr/local/libexec/slapd\"!")
1308 if ldap_backend_type
== "openldap" and ol_slapd
is not None:
1309 if not os
.path
.exists(ol_slapd
):
1311 sys
.exit("Warning: Given Path to slapd (OpenLDAP-Daemon) does not exist!")
1313 # openldap-online-configuration: validation of olc and slapd
1314 if ol_olc
== "yes" and ol_slapd
is None:
1315 sys
.exit("Warning: OpenLDAP-Online-Configuration cant be setup without path to slapd!")
1318 lp
= param
.LoadParm()
1321 if serverrole
is None:
1322 serverrole
= lp
.get("server role")
1324 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1325 dnsdomain
=realm
, serverrole
=serverrole
,
1326 rootdn
=rootdn
, domaindn
=domaindn
, configdn
=configdn
,
1329 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1331 if not os
.path
.isdir(paths
.ldapdir
):
1332 os
.makedirs(paths
.ldapdir
, 0700)
1333 schemadb_path
= os
.path
.join(paths
.ldapdir
, "schema-tmp.ldb")
1335 os
.unlink(schemadb_path
)
1339 schemadb
= SamDB(schemadb_path
, lp
=lp
)
1340 schemadb
.transaction_start()
1343 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
1345 setup_add_ldif(schemadb
, setup_path("provision_schema_basedn.ldif"),
1346 {"SCHEMADN": names
.schemadn
,
1349 setup_modify_ldif(schemadb
,
1350 setup_path("provision_schema_basedn_modify.ldif"), \
1351 {"SCHEMADN": names
.schemadn
,
1352 "NETBIOSNAME": names
.netbiosname
,
1353 "DEFAULTSITE": DEFAULTSITE
,
1354 "CONFIGDN": names
.configdn
,
1355 "SERVERDN": names
.serverdn
,
1356 "PREFIXMAP_B64": b64encode(prefixmap
)
1359 data
= load_schema(setup_path
, schemadb
, names
.schemadn
, names
.netbiosname
,
1360 names
.configdn
, DEFAULTSITE
, names
.serverdn
)
1361 schemadb
.add_ldif(data
)
1363 schemadb
.transaction_cancel()
1365 schemadb
.transaction_commit()
1367 if ldap_backend_type
== "fedora-ds":
1368 if ldap_backend_port
is not None:
1369 serverport
= "ServerPort=%d" % ldap_backend_port
1373 setup_file(setup_path("fedorads.inf"), paths
.fedoradsinf
,
1375 "HOSTNAME": hostname
,
1376 "DNSDOMAIN": names
.dnsdomain
,
1377 "LDAPDIR": paths
.ldapdir
,
1378 "DOMAINDN": names
.domaindn
,
1379 "LDAPMANAGERDN": names
.ldapmanagerdn
,
1380 "LDAPMANAGERPASS": adminpass
,
1381 "SERVERPORT": serverport
})
1383 setup_file(setup_path("fedorads-partitions.ldif"), paths
.fedoradspartitions
,
1384 {"CONFIGDN": names
.configdn
,
1385 "SCHEMADN": names
.schemadn
,
1388 mapping
= "schema-map-fedora-ds-1.0"
1389 backend_schema
= "99_ad.ldif"
1391 slapdcommand
="Initialise Fedora DS with: setup-ds.pl --file=%s" % paths
.fedoradsinf
1393 ldapuser
= "--simple-bind-dn=" + names
.ldapmanagerdn
1395 elif ldap_backend_type
== "openldap":
1396 #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
1399 nosync_config
= "dbnosync"
1402 attrs
= ["linkID", "lDAPDisplayName"]
1403 res
= schemadb
.search(expression
="(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base
=names
.schemadn
, scope
=SCOPE_ONELEVEL
, attrs
=attrs
)
1405 memberof_config
= "# Generated from schema in %s\n" % schemadb_path
1406 refint_attributes
= ""
1407 for i
in range (0, len(res
)):
1408 expression
= "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res
[i
]["linkID"][0])+1)
1409 target
= schemadb
.searchone(basedn
=names
.schemadn
,
1410 expression
=expression
,
1411 attribute
="lDAPDisplayName",
1412 scope
=SCOPE_SUBTREE
)
1413 if target
is not None:
1414 refint_attributes
= refint_attributes
+ " " + res
[i
]["lDAPDisplayName"][0]
1416 memberof_config
+= read_and_sub_file(setup_path("memberof.conf"),
1417 { "MEMBER_ATTR" : str(res
[i
]["lDAPDisplayName"][0]),
1418 "MEMBEROF_ATTR" : str(target
) })
1420 refint_config
= read_and_sub_file(setup_path("refint.conf"),
1421 { "LINK_ATTRS" : refint_attributes
})
1423 res
= schemadb
.search(expression
="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base
=names
.schemadn
, scope
=SCOPE_ONELEVEL
, attrs
=attrs
)
1425 for i
in range (0, len(res
)):
1426 index_attr
= res
[i
]["lDAPDisplayName"][0]
1427 if index_attr
== "objectGUID":
1428 index_attr
= "entryUUID"
1430 index_config
+= "index " + index_attr
+ " eq\n"
1432 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
1434 mmr_replicator_acl
= ""
1435 mmr_serverids_config
= ""
1436 mmr_syncrepl_schema_config
= ""
1437 mmr_syncrepl_config_config
= ""
1438 mmr_syncrepl_user_config
= ""
1441 if ol_mmr_urls
is not None:
1442 # For now, make these equal
1443 mmr_pass
= adminpass
1445 url_list
=filter(None,ol_mmr_urls
.split(' '))
1446 if (len(url_list
) == 1):
1447 url_list
=filter(None,ol_mmr_urls
.split(','))
1450 mmr_on_config
= "MirrorMode On"
1451 mmr_replicator_acl
= " by dn=cn=replicator,cn=samba read"
1453 for url
in url_list
:
1455 mmr_serverids_config
+= read_and_sub_file(setup_path("mmr_serverids.conf"),
1456 { "SERVERID" : str(serverid
),
1457 "LDAPSERVER" : url
})
1460 mmr_syncrepl_schema_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1462 "MMRDN": names
.schemadn
,
1464 "MMR_PASSWORD": mmr_pass
})
1467 mmr_syncrepl_config_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1469 "MMRDN": names
.configdn
,
1471 "MMR_PASSWORD": mmr_pass
})
1474 mmr_syncrepl_user_config
+= read_and_sub_file(setup_path("mmr_syncrepl.conf"),
1476 "MMRDN": names
.domaindn
,
1478 "MMR_PASSWORD": mmr_pass
})
1480 olc_config_pass
= ""
1482 olc_syncrepl_config
= ""
1485 olc_config_pass
+= read_and_sub_file(setup_path("olc_pass.conf"),
1486 { "OLC_PW": adminpass
})
1487 olc_config_acl
+= read_and_sub_file(setup_path("olc_acl.conf"),{})
1489 # if olc = yes + mmr = yes, generate cn=config-replication directives
1490 # and olc_seed.lif for the other mmr-servers
1491 if ol_olc
== "yes" and ol_mmr_urls
is not None:
1493 olc_serverids_config
= ""
1494 olc_syncrepl_config
= ""
1495 olc_syncrepl_seed_config
= ""
1497 olc_mmr_config
+= read_and_sub_file(setup_path("olc_mmr.conf"),{})
1499 for url
in url_list
:
1501 olc_serverids_config
+= read_and_sub_file(setup_path("olc_serverid.conf"),
1502 { "SERVERID" : str(serverid
),
1503 "LDAPSERVER" : url
})
1506 olc_syncrepl_config
+= read_and_sub_file(setup_path("olc_syncrepl.conf"),
1509 "MMR_PASSWORD": adminpass
})
1511 olc_syncrepl_seed_config
+= read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
1513 "LDAPSERVER" : url
})
1515 setup_file(setup_path("olc_seed.ldif"), paths
.olcseedldif
,
1516 {"OLC_SERVER_ID_CONF": olc_serverids_config
,
1517 "OLC_PW": adminpass
,
1518 "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config
})
1523 setup_file(setup_path("slapd.conf"), paths
.slapdconf
,
1524 {"DNSDOMAIN": names
.dnsdomain
,
1525 "LDAPDIR": paths
.ldapdir
,
1526 "DOMAINDN": names
.domaindn
,
1527 "CONFIGDN": names
.configdn
,
1528 "SCHEMADN": names
.schemadn
,
1529 "MEMBEROF_CONFIG": memberof_config
,
1530 "MIRRORMODE": mmr_on_config
,
1531 "REPLICATOR_ACL": mmr_replicator_acl
,
1532 "MMR_SERVERIDS_CONFIG": mmr_serverids_config
,
1533 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config
,
1534 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config
,
1535 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config
,
1536 "OLC_CONFIG_PASS": olc_config_pass
,
1537 "OLC_SYNCREPL_CONFIG": olc_syncrepl_config
,
1538 "OLC_CONFIG_ACL": olc_config_acl
,
1539 "OLC_MMR_CONFIG": olc_mmr_config
,
1540 "REFINT_CONFIG": refint_config
,
1541 "INDEX_CONFIG": index_config
,
1542 "NOSYNC": nosync_config
})
1543 setup_file(setup_path("modules.conf"), paths
.modulesconf
,
1544 {"REALM": names
.realm
})
1546 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "user"))
1547 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "config"))
1548 setup_db_config(setup_path
, os
.path
.join(paths
.ldapdir
, "db", "schema"))
1550 if not os
.path
.exists(os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba")):
1551 os
.makedirs(os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba"), 0700)
1553 setup_file(setup_path("cn=samba.ldif"),
1554 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba.ldif"),
1555 { "UUID": str(uuid
.uuid4()),
1556 "LDAPTIME": timestring(int(time
.time()))} )
1557 setup_file(setup_path("cn=samba-admin.ldif"),
1558 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
1559 {"LDAPADMINPASS_B64": b64encode(adminpass
),
1560 "UUID": str(uuid
.uuid4()),
1561 "LDAPTIME": timestring(int(time
.time()))} )
1563 if ol_mmr_urls
is not None:
1564 setup_file(setup_path("cn=replicator.ldif"),
1565 os
.path
.join(paths
.ldapdir
, "db", "samba", "cn=samba", "cn=replicator.ldif"),
1566 {"MMR_PASSWORD_B64": b64encode(mmr_pass
),
1567 "UUID": str(uuid
.uuid4()),
1568 "LDAPTIME": timestring(int(time
.time()))} )
1571 mapping
= "schema-map-openldap-2.3"
1572 backend_schema
= "backend-schema.schema"
1574 # now we generate the needed strings to start slapd automatically,
1575 # first ldapi_uri...
1576 ldapi_uri
= "ldapi://" + urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1577 if ldap_backend_port
is not None:
1578 server_port_string
= " -h ldap://0.0.0.0:%d" % ldap_backend_port
1580 server_port_string
= ""
1582 # ..and now the slapd-commandline with (optional) mmr and/or olc
1583 if ol_olc
!= "yes" and ol_mmr_urls
is None:
1584 slapdcommand_prov
=ol_slapd
+ " -f " + paths
.ldapdir
+ "/slapd.conf -h " + ldapi_uri
1585 slapdcommand
=ol_slapd
+ " -f " + paths
.ldapdir
+ "/slapd.conf -h " + ldapi_uri
+ server_port_string
1587 if ol_olc
== "yes" and ol_mmr_urls
is None:
1588 slapdcommand_prov
=ol_slapd
+ " -F " + paths
.olcdir
+ " -h " + ldapi_uri
1589 slapdcommand
=ol_slapd
+ " -F " + paths
.olcdir
+ " -h \"" + ldapi_uri
+ " ldap://" + names
.hostname
+ "." + names
.dnsdomain
+":<Chosen PORT (<> 389!)>\""
1591 if ol_olc
!= "yes" and ol_mmr_urls
is not None:
1592 slapdcommand_prov
=ol_slapd
+ " -f " + paths
.ldapdir
+ "/slapd.conf -h " + ldapi_uri
1593 slapdcommand
=ol_slapd
+ " -f " + paths
.ldapdir
+ "/slapd.conf -h \"" + ldapi_uri
+ " ldap://" + names
.hostname
+ "." + names
.dnsdomain
+":<Chosen PORT (<> 389!)>\""
1595 if ol_olc
== "yes" and ol_mmr_urls
is not None:
1596 slapdcommand_prov
=ol_slapd
+ " -F " + paths
.olcdir
+ " -h " + ldapi_uri
1597 slapdcommand
=ol_slapd
+ " -F " + paths
.olcdir
+ " -h \"" + ldapi_uri
+ " ldap://" + names
.hostname
+ "." + names
.dnsdomain
+":<Chosen PORT (<> 389!)>\""
1599 # now generate file with complete slapd-commandline.
1600 # it is read out later when final provision's done and ol/s4 are ready to be started manually
1601 f
= open(paths
.ldapdir
+"/slapd_command_file.txt", "w")
1602 f
.write(str(slapdcommand
+ "\n"))
1605 ldapuser
= "--username=samba-admin"
1608 backend_schema_data
= schemadb
.convert_schema_to_openldap(ldap_backend_type
, open(setup_path(mapping
), 'r').read())
1609 assert backend_schema_data
is not None
1610 open(os
.path
.join(paths
.ldapdir
, backend_schema
), 'w').write(backend_schema_data
)
1612 message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type
)
1613 message("Server Role: %s" % serverrole
)
1614 message("Hostname: %s" % names
.hostname
)
1615 message("DNS Domain: %s" % names
.dnsdomain
)
1616 message("Base DN: %s" % names
.domaindn
)
1618 if ldap_backend_type
== "openldap":
1619 message("LDAP admin user: samba-admin")
1621 message("LDAP admin DN: %s" % names
.ldapmanagerdn
)
1623 message("LDAP admin password: %s" % adminpass
)
1624 if ol_olc
== "yes" or ol_mmr_urls
is not None:
1625 message("Attention! You are using olc and/or MMR: The slapd-PORT you choose later must be different than 389!")
1627 # if --ol-olc=yes, generate online-configuration in ../private/ldap/slapd.d
1629 if not os
.path
.isdir(paths
.olcdir
):
1630 os
.makedirs(paths
.olcdir
, 0770)
1631 paths
.olslapd
= str(ol_slapd
)
1632 olc_command
= paths
.olslapd
+ " -Ttest -f " + paths
.slapdconf
+ " -F " + paths
.olcdir
+ " >/dev/null 2>&1"
1633 os
.system(olc_command
)
1634 os
.remove(paths
.slapdconf
)
1635 # for debugging purposes, remove: ' + ">/dev/null 2>&1" ' from the line 'olc_command =' above
1639 # start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via ldapi_uri
1640 # if another instance of slapd is already running
1642 ldapi_uri
= "ldapi://" + urllib
.quote(os
.path
.join(paths
.private_dir
, "ldap", "ldapi"), safe
="")
1643 ldapi_db
= Ldb(ldapi_uri
)
1644 search_ol_rootdse
= ldapi_db
.search(base
="", scope
=SCOPE_BASE
,
1645 expression
="(objectClass=OpenLDAProotDSE)");
1646 message("LDAP Debug-Output:" + str(search_ol_rootdse
))
1647 if os
.path
.exists(paths
.slapdpid
):
1648 f
= open(paths
.slapdpid
, "r")
1651 message("Check for slapd-Process with PID: " + str(p
) + " and terminate it manually.")
1653 message("slapd-PID File could not be found. Sorry. You have to locate the PID manually.")
1655 sys
.exit("Warning: Another slapd Instance seems already running on this host, listening to " + ldapi_uri
+ ". Please shut it down before you continue. Exiting now.")
1658 message("LDAP Debug-Output:")
1660 message("Ok. - No other slapd-Instance listening on: " + ldapi_uri
+ ". Starting slapd now for final provision.")
1662 p
= subprocess
.Popen(slapdcommand_prov
, shell
=True)
1664 # after startup: store slapd-provision-pid also in a separate file.
1665 # this is needed as long as provision/provision-backend are not fully merged,
1666 # to compare pids before shutting down
1668 # wait for pidfile to be created
1670 if os
.path
.exists(paths
.slapdpid
):
1671 f
= open(paths
.slapdpid
, "r")
1674 f
= open(paths
.ldapdir
+"/slapd_provision_pid", "w")
1675 f
.write(str(p
) + "\n")
1677 message("Started slapd for final provisioning with PID: "+ str(p
))
1679 message("slapd-PID File could not be found. Sorry")
1681 # done slapd checking + start
1685 assert isinstance(ldap_backend_type
, str)
1686 assert isinstance(ldapuser
, str)
1687 assert isinstance(adminpass
, str)
1688 assert isinstance(names
.dnsdomain
, str)
1689 assert isinstance(names
.domain
, str)
1690 assert isinstance(serverrole
, str)
1691 args
= ["--ldap-backend=ldapi",
1692 "--ldap-backend-type=" + ldap_backend_type
,
1693 "--password=" + adminpass
,
1695 "--realm=" + names
.dnsdomain
,
1696 "--domain=" + names
.domain
,
1697 "--server-role='" + serverrole
+ "'"]
1698 message("Now run final provision with: " + " ".join(args
))
1702 def create_phpldapadmin_config(path
, setup_path
, ldapi_uri
):
1703 """Create a PHP LDAP admin configuration file.
1705 :param path: Path to write the configuration to.
1706 :param setup_path: Function to generate setup paths.
1708 setup_file(setup_path("phpldapadmin-config.php"), path
,
1709 {"S4_LDAPI_URI": ldapi_uri
})
1712 def create_zone_file(path
, setup_path
, dnsdomain
, domaindn
,
1713 hostip
, hostip6
, hostname
, dnspass
, realm
, domainguid
, hostguid
):
1714 """Write out a DNS zone file, from the info in the current database.
1716 :param path: Path of the new zone file.
1717 :param setup_path: Setup path function.
1718 :param dnsdomain: DNS Domain name
1719 :param domaindn: DN of the Domain
1720 :param hostip: Local IPv4 IP
1721 :param hostip6: Local IPv6 IP
1722 :param hostname: Local hostname
1723 :param dnspass: Password for DNS
1724 :param realm: Realm name
1725 :param domainguid: GUID of the domain.
1726 :param hostguid: GUID of the host.
1728 assert isinstance(domainguid
, str)
1730 if hostip6
is not None:
1731 hostip6_base_line
= " IN AAAA " + hostip6
1732 hostip6_host_line
= hostname
+ " IN AAAA " + hostip6
1734 hostip6_base_line
= ""
1735 hostip6_host_line
= ""
1737 if hostip
is not None:
1738 hostip_base_line
= " IN A " + hostip
1739 hostip_host_line
= hostname
+ " IN A " + hostip
1741 hostip_base_line
= ""
1742 hostip_host_line
= ""
1744 setup_file(setup_path("provision.zone"), path
, {
1745 "DNSPASS_B64": b64encode(dnspass
),
1746 "HOSTNAME": hostname
,
1747 "DNSDOMAIN": dnsdomain
,
1749 "HOSTIP_BASE_LINE": hostip_base_line
,
1750 "HOSTIP_HOST_LINE": hostip_host_line
,
1751 "DOMAINGUID": domainguid
,
1752 "DATESTRING": time
.strftime("%Y%m%d%H"),
1753 "DEFAULTSITE": DEFAULTSITE
,
1754 "HOSTGUID": hostguid
,
1755 "HOSTIP6_BASE_LINE": hostip6_base_line
,
1756 "HOSTIP6_HOST_LINE": hostip6_host_line
,
1760 def create_named_conf(path
, setup_path
, realm
, dnsdomain
,
1762 """Write out a file containing zone statements suitable for inclusion in a
1763 named.conf file (including GSS-TSIG configuration).
1765 :param path: Path of the new named.conf file.
1766 :param setup_path: Setup path function.
1767 :param realm: Realm name
1768 :param dnsdomain: DNS Domain name
1769 :param private_dir: Path to private directory
1770 :param keytab_name: File name of DNS keytab file
1773 setup_file(setup_path("named.conf"), path
, {
1774 "DNSDOMAIN": dnsdomain
,
1776 "REALM_WC": "*." + ".".join(realm
.split(".")[1:]),
1777 "PRIVATE_DIR": private_dir
1780 def create_named_txt(path
, setup_path
, realm
, dnsdomain
,
1781 private_dir
, keytab_name
):
1782 """Write out a file containing zone statements suitable for inclusion in a
1783 named.conf file (including GSS-TSIG configuration).
1785 :param path: Path of the new named.conf file.
1786 :param setup_path: Setup path function.
1787 :param realm: Realm name
1788 :param dnsdomain: DNS Domain name
1789 :param private_dir: Path to private directory
1790 :param keytab_name: File name of DNS keytab file
1793 setup_file(setup_path("named.txt"), path
, {
1794 "DNSDOMAIN": dnsdomain
,
1796 "DNS_KEYTAB": keytab_name
,
1797 "DNS_KEYTAB_ABS": os
.path
.join(private_dir
, keytab_name
),
1798 "PRIVATE_DIR": private_dir
1801 def create_krb5_conf(path
, setup_path
, dnsdomain
, hostname
, realm
):
1802 """Write out a file containing zone statements suitable for inclusion in a
1803 named.conf file (including GSS-TSIG configuration).
1805 :param path: Path of the new named.conf file.
1806 :param setup_path: Setup path function.
1807 :param dnsdomain: DNS Domain name
1808 :param hostname: Local hostname
1809 :param realm: Realm name
1812 setup_file(setup_path("krb5.conf"), path
, {
1813 "DNSDOMAIN": dnsdomain
,
1814 "HOSTNAME": hostname
,
1819 def load_schema(setup_path
, samdb
, schemadn
, netbiosname
, configdn
, sitename
,
1821 """Load schema for the SamDB.
1823 :param samdb: Load a schema into a SamDB.
1824 :param setup_path: Setup path function.
1825 :param schemadn: DN of the schema
1826 :param netbiosname: NetBIOS name of the host.
1827 :param configdn: DN of the configuration
1828 :param serverdn: DN of the server
1830 Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db
1832 schema_data
= get_schema_data(setup_path
, {"SCHEMADN": schemadn
})
1833 schema_data
+= open(setup_path("schema_samba4.ldif"), 'r').read()
1834 schema_data
= substitute_var(schema_data
, {"SCHEMADN": schemadn
})
1835 check_all_substituted(schema_data
)
1836 prefixmap
= open(setup_path("prefixMap.txt"), 'r').read()
1837 prefixmap
= b64encode(prefixmap
)
1839 head_data
= open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read()
1840 head_data
= substitute_var(head_data
, {
1841 "SCHEMADN": schemadn
,
1842 "NETBIOSNAME": netbiosname
,
1843 "CONFIGDN": configdn
,
1844 "DEFAULTSITE": sitename
,
1845 "PREFIXMAP_B64": prefixmap
,
1846 "SERVERDN": serverdn
,
1848 check_all_substituted(head_data
)
1849 samdb
.attach_schema_from_ldif(head_data
, schema_data
)
1852 def get_schema_data(setup_path
, subst_vars
= None):
1853 """Get schema data from the AD schema files instead of schema.ldif.
1855 :param setup_path: Setup path function.
1856 :param subst_vars: Optional variables to substitute in the file.
1858 Returns the schema data after substitution
1861 # this data used to be read from schema.ldif
1863 data
= read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'),
1864 setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt'))
1866 if subst_vars
is not None:
1867 data
= substitute_var(data
, subst_vars
)
1868 check_all_substituted(data
)