2
# Unix SMB/CIFS implementation.
3
# backend code for provisioning a Samba4 server
5
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
6
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
7
# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
9
# Based on the original in EJS:
10
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
12
# This program is free software; you can redistribute it and/or modify
13
# it under the terms of the GNU General Public License as published by
14
# the Free Software Foundation; either version 3 of the License, or
15
# (at your option) any later version.
17
# This program is distributed in the hope that it will be useful,
18
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
# GNU General Public License for more details.
22
# You should have received a copy of the GNU General Public License
23
# along with this program. If not, see <http://www.gnu.org/licenses/>.
26
"""Functions for setting up a Samba configuration (LDB and LDAP backends)."""
28
from base64 import b64encode
39
from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring
41
from samba import Ldb, read_and_sub_file, setup_file
42
from samba.credentials import Credentials, DONT_USE_KERBEROS
43
from samba.schema import Schema
45
class SlapdAlreadyRunning(Exception):
47
def __init__(self, uri):
49
super(SlapdAlreadyRunning, self).__init__("Another slapd Instance "
50
"seems already running on this host, listening to %s." %
54
class ProvisionBackend(object):
55
def __init__(self, backend_type, paths=None, lp=None,
56
credentials=None, names=None, logger=None):
57
"""Provision a backend for samba4"""
60
self.credentials = credentials
64
self.type = backend_type
66
# Set a default - the code for "existing" below replaces this
67
self.ldap_backend_type = backend_type
70
"""Initialize the backend."""
71
raise NotImplementedError(self.init)
74
"""Start the backend."""
75
raise NotImplementedError(self.start)
78
"""Shutdown the backend."""
79
raise NotImplementedError(self.shutdown)
83
raise NotImplementedError(self.post_setup)
86
class LDBBackend(ProvisionBackend):
89
self.credentials = None
90
self.secrets_credentials = None
92
# Wipe the old sam.ldb databases away
93
shutil.rmtree(self.paths.samdb + ".d", True)
101
def post_setup(self):
105
class ExistingBackend(ProvisionBackend):
107
def __init__(self, backend_type, paths=None, lp=None,
108
credentials=None, names=None, logger=None, ldapi_uri=None):
110
super(ExistingBackend, self).__init__(backend_type=backend_type,
112
credentials=credentials, names=names, logger=logger,
113
ldap_backend_forced_uri=ldapi_uri)
116
# Check to see that this 'existing' LDAP backend in fact exists
117
ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
118
ldapi_db.search(base="", scope=SCOPE_BASE,
119
expression="(objectClass=OpenLDAProotDSE)")
121
# If we have got here, then we must have a valid connection to the LDAP
122
# server, with valid credentials supplied This caused them to be set
123
# into the long-term database later in the script.
124
self.secrets_credentials = self.credentials
126
# For now, assume existing backends at least emulate OpenLDAP
127
self.ldap_backend_type = "openldap"
130
class LDAPBackend(ProvisionBackend):
132
def __init__(self, backend_type, paths=None, lp=None,
133
credentials=None, names=None, logger=None, domainsid=None,
134
schema=None, hostname=None, ldapadminpass=None,
135
slapd_path=None, ldap_backend_extra_port=None,
136
ldap_backend_forced_uri=None, ldap_dryrun_mode=False):
138
super(LDAPBackend, self).__init__(backend_type=backend_type,
140
credentials=credentials, names=names, logger=logger)
142
self.domainsid = domainsid
144
self.hostname = hostname
146
self.ldapdir = os.path.join(paths.private_dir, "ldap")
147
self.ldapadminpass = ldapadminpass
149
self.slapd_path = slapd_path
150
self.slapd_command = None
151
self.slapd_command_escaped = None
152
self.slapd_pid = os.path.join(self.ldapdir, "slapd.pid")
154
self.ldap_backend_extra_port = ldap_backend_extra_port
155
self.ldap_dryrun_mode = ldap_dryrun_mode
157
if ldap_backend_forced_uri is not None:
158
self.ldap_uri = ldap_backend_forced_uri
160
self.ldap_uri = "ldapi://%s" % urllib.quote(
161
os.path.join(self.ldapdir, "ldapi"), safe="")
163
if not os.path.exists(self.ldapdir):
164
os.mkdir(self.ldapdir)
167
from samba.provision import ProvisioningError
168
# we will shortly start slapd with ldapi for final provisioning. first
169
# check with ldapsearch -> rootDSE via self.ldap_uri if another
170
# instance of slapd is already running
172
ldapi_db = Ldb(self.ldap_uri)
173
ldapi_db.search(base="", scope=SCOPE_BASE,
174
expression="(objectClass=OpenLDAProotDSE)")
176
f = open(self.slapd_pid, "r")
178
if err != errno.ENOENT:
183
self.logger.info("Check for slapd Process with PID: %s and terminate it manually." % p)
184
raise SlapdAlreadyRunning(self.ldap_uri)
186
# XXX: We should never be catching all Ldb errors
189
# Try to print helpful messages when the user has not specified the
191
if self.slapd_path is None:
192
raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
193
if not os.path.exists(self.slapd_path):
194
self.logger.warning("Path (%s) to slapd does not exist!",
197
if not os.path.isdir(self.ldapdir):
198
os.makedirs(self.ldapdir, 0700)
200
# Put the LDIF of the schema into a database so we can search on
201
# it to generate schema-dependent configurations in Fedora DS and
203
schemadb_path = os.path.join(self.ldapdir, "schema-tmp.ldb")
205
os.unlink(schemadb_path)
209
self.schema.write_to_tmp_ldb(schemadb_path)
211
self.credentials = Credentials()
212
self.credentials.guess(self.lp)
213
# Kerberos to an ldapi:// backend makes no sense
214
self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
215
self.credentials.set_password(self.ldapadminpass)
217
self.secrets_credentials = Credentials()
218
self.secrets_credentials.guess(self.lp)
219
# Kerberos to an ldapi:// backend makes no sense
220
self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
221
self.secrets_credentials.set_username("samba-admin")
222
self.secrets_credentials.set_password(self.ldapadminpass)
230
from samba.provision import ProvisioningError
231
self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
232
f = open(os.path.join(self.ldapdir, "ldap_backend_startup.sh"), 'w')
234
f.write("#!/bin/sh\n" + self.slapd_command_escaped + "\n")
238
# Now start the slapd, so we can provision onto it. We keep the
239
# subprocess context around, to kill this off at the successful
241
self.slapd = subprocess.Popen(self.slapd_provision_command,
242
close_fds=True, shell=False)
245
while self.slapd.poll() is None:
246
# Wait until the socket appears
248
ldapi_db = Ldb(self.ldap_uri, lp=self.lp, credentials=self.credentials)
249
ldapi_db.search(base="", scope=SCOPE_BASE,
250
expression="(objectClass=OpenLDAProotDSE)")
251
# If we have got here, then we must have a valid connection to
259
self.logger.error("Could not connect to slapd started with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
260
raise ProvisioningError("slapd never accepted a connection within 15 seconds of starting")
262
self.logger.error("Could not start slapd with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
263
raise ProvisioningError("slapd died before we could make a connection to it")
266
# if an LDAP backend is in use, terminate slapd after final provision
267
# and check its proper termination
268
if self.slapd.poll() is None:
270
if getattr(self.slapd, "terminate", None) is not None:
271
self.slapd.terminate()
273
# Older python versions don't have .terminate()
275
os.kill(self.slapd.pid, signal.SIGTERM)
277
# and now wait for it to die
278
self.slapd.communicate()
280
def post_setup(self):
284
class OpenLDAPBackend(LDAPBackend):
286
def __init__(self, backend_type, paths=None, lp=None,
287
credentials=None, names=None, logger=None, domainsid=None,
288
schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
289
ldap_backend_extra_port=None, ldap_dryrun_mode=False,
290
ol_mmr_urls=None, nosync=False, ldap_backend_forced_uri=None):
291
from samba.provision import setup_path
292
super(OpenLDAPBackend, self).__init__( backend_type=backend_type,
294
credentials=credentials, names=names, logger=logger,
295
domainsid=domainsid, schema=schema, hostname=hostname,
296
ldapadminpass=ldapadminpass, slapd_path=slapd_path,
297
ldap_backend_extra_port=ldap_backend_extra_port,
298
ldap_backend_forced_uri=ldap_backend_forced_uri,
299
ldap_dryrun_mode=ldap_dryrun_mode)
301
self.ol_mmr_urls = ol_mmr_urls
304
self.slapdconf = os.path.join(self.ldapdir, "slapd.conf")
305
self.modulesconf = os.path.join(self.ldapdir, "modules.conf")
306
self.memberofconf = os.path.join(self.ldapdir, "memberof.conf")
307
self.olmmrserveridsconf = os.path.join(self.ldapdir, "mmr_serverids.conf")
308
self.olmmrsyncreplconf = os.path.join(self.ldapdir, "mmr_syncrepl.conf")
309
self.olcdir = os.path.join(self.ldapdir, "slapd.d")
310
self.olcseedldif = os.path.join(self.ldapdir, "olc_seed.ldif")
312
self.schema = Schema(self.domainsid,
313
schemadn=self.names.schemadn, files=[
314
setup_path("schema_samba4.ldif")])
316
def setup_db_config(self, dbdir):
317
"""Setup a Berkeley database.
319
:param dbdir: Database directory.
321
from samba.provision import setup_path
322
if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
323
os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
324
if not os.path.isdir(os.path.join(dbdir, "tmp")):
325
os.makedirs(os.path.join(dbdir, "tmp"), 0700)
327
setup_file(setup_path("DB_CONFIG"),
328
os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir})
331
from samba.provision import ProvisioningError, setup_path
332
# Wipe the directories so we can start
333
shutil.rmtree(os.path.join(self.ldapdir, "db"), True)
335
# Allow the test scripts to turn off fsync() for OpenLDAP as for TDB
339
nosync_config = "dbnosync"
341
lnkattr = self.schema.linked_attributes()
342
refint_attributes = ""
343
memberof_config = "# Generated from Samba4 schema\n"
344
for att in lnkattr.keys():
345
if lnkattr[att] is not None:
346
refint_attributes = refint_attributes + " " + att
348
memberof_config += read_and_sub_file(
349
setup_path("memberof.conf"), {
351
"MEMBEROF_ATTR" : lnkattr[att] })
353
refint_config = read_and_sub_file(setup_path("refint.conf"),
354
{ "LINK_ATTRS" : refint_attributes})
356
attrs = ["linkID", "lDAPDisplayName"]
357
res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
359
for i in range (0, len(res)):
360
index_attr = res[i]["lDAPDisplayName"][0]
361
if index_attr == "objectGUID":
362
index_attr = "entryUUID"
364
index_config += "index " + index_attr + " eq\n"
366
# generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
368
mmr_replicator_acl = ""
369
mmr_serverids_config = ""
370
mmr_syncrepl_schema_config = ""
371
mmr_syncrepl_config_config = ""
372
mmr_syncrepl_user_config = ""
374
if self.ol_mmr_urls is not None:
375
# For now, make these equal
376
mmr_pass = self.ldapadminpass
378
url_list = filter(None,self.ol_mmr_urls.split(','))
380
self.logger.info("Using LDAP-URL: "+url)
381
if len(url_list) == 1:
382
raise ProvisioningError("At least 2 LDAP-URLs needed for MMR!")
384
mmr_on_config = "MirrorMode On"
385
mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
388
serverid = serverid + 1
389
mmr_serverids_config += read_and_sub_file(
390
setup_path("mmr_serverids.conf"), {
391
"SERVERID": str(serverid),
395
mmr_syncrepl_schema_config += read_and_sub_file(
396
setup_path("mmr_syncrepl.conf"), {
398
"MMRDN": self.names.schemadn,
400
"MMR_PASSWORD": mmr_pass})
403
mmr_syncrepl_config_config += read_and_sub_file(
404
setup_path("mmr_syncrepl.conf"), {
406
"MMRDN": self.names.configdn,
408
"MMR_PASSWORD": mmr_pass})
411
mmr_syncrepl_user_config += read_and_sub_file(
412
setup_path("mmr_syncrepl.conf"), {
414
"MMRDN": self.names.domaindn,
416
"MMR_PASSWORD": mmr_pass })
417
# OpenLDAP cn=config initialisation
418
olc_syncrepl_config = ""
420
# if mmr = yes, generate cn=config-replication directives
421
# and olc_seed.lif for the other mmr-servers
422
if self.ol_mmr_urls is not None:
424
olc_serverids_config = ""
425
olc_syncrepl_seed_config = ""
426
olc_mmr_config += read_and_sub_file(
427
setup_path("olc_mmr.conf"), {})
430
serverid = serverid + 1
431
olc_serverids_config += read_and_sub_file(
432
setup_path("olc_serverid.conf"), {
433
"SERVERID" : str(serverid), "LDAPSERVER" : url })
436
olc_syncrepl_config += read_and_sub_file(
437
setup_path("olc_syncrepl.conf"), {
438
"RID" : str(rid), "LDAPSERVER" : url,
439
"MMR_PASSWORD": mmr_pass})
441
olc_syncrepl_seed_config += read_and_sub_file(
442
setup_path("olc_syncrepl_seed.conf"), {
443
"RID" : str(rid), "LDAPSERVER" : url})
445
setup_file(setup_path("olc_seed.ldif"), self.olcseedldif,
446
{"OLC_SERVER_ID_CONF": olc_serverids_config,
447
"OLC_PW": self.ldapadminpass,
448
"OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
451
setup_file(setup_path("slapd.conf"), self.slapdconf,
452
{"DNSDOMAIN": self.names.dnsdomain,
453
"LDAPDIR": self.ldapdir,
454
"DOMAINDN": self.names.domaindn,
455
"CONFIGDN": self.names.configdn,
456
"SCHEMADN": self.names.schemadn,
457
"MEMBEROF_CONFIG": memberof_config,
458
"MIRRORMODE": mmr_on_config,
459
"REPLICATOR_ACL": mmr_replicator_acl,
460
"MMR_SERVERIDS_CONFIG": mmr_serverids_config,
461
"MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
462
"MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
463
"MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
464
"OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
465
"OLC_MMR_CONFIG": olc_mmr_config,
466
"REFINT_CONFIG": refint_config,
467
"INDEX_CONFIG": index_config,
468
"NOSYNC": nosync_config})
470
self.setup_db_config(os.path.join(self.ldapdir, "db", "user"))
471
self.setup_db_config(os.path.join(self.ldapdir, "db", "config"))
472
self.setup_db_config(os.path.join(self.ldapdir, "db", "schema"))
474
if not os.path.exists(os.path.join(self.ldapdir, "db", "samba", "cn=samba")):
475
os.makedirs(os.path.join(self.ldapdir, "db", "samba", "cn=samba"), 0700)
477
setup_file(setup_path("cn=samba.ldif"),
478
os.path.join(self.ldapdir, "db", "samba", "cn=samba.ldif"),
479
{ "UUID": str(uuid.uuid4()),
480
"LDAPTIME": timestring(int(time.time()))} )
481
setup_file(setup_path("cn=samba-admin.ldif"),
482
os.path.join(self.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
483
{"LDAPADMINPASS_B64": b64encode(self.ldapadminpass),
484
"UUID": str(uuid.uuid4()),
485
"LDAPTIME": timestring(int(time.time()))} )
487
if self.ol_mmr_urls is not None:
488
setup_file(setup_path("cn=replicator.ldif"),
489
os.path.join(self.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
490
{"MMR_PASSWORD_B64": b64encode(mmr_pass),
491
"UUID": str(uuid.uuid4()),
492
"LDAPTIME": timestring(int(time.time()))} )
494
mapping = "schema-map-openldap-2.3"
495
backend_schema = "backend-schema.schema"
497
f = open(setup_path(mapping), 'r')
498
backend_schema_data = self.schema.convert_to_openldap(
499
"openldap", f.read())
500
assert backend_schema_data is not None
501
f = open(os.path.join(self.ldapdir, backend_schema), 'w')
503
f.write(backend_schema_data)
507
# now we generate the needed strings to start slapd automatically,
508
if self.ldap_backend_extra_port is not None:
509
# When we use MMR, we can't use 0.0.0.0 as it uses the name
510
# specified there as part of it's clue as to it's own name,
511
# and not to replicate to itself
512
if self.ol_mmr_urls is None:
513
server_port_string = "ldap://0.0.0.0:%d" % self.ldap_backend_extra_port
515
server_port_string = "ldap://%s.%s:%d" (self.names.hostname,
516
self.names.dnsdomain, self.ldap_backend_extra_port)
518
server_port_string = ""
520
# Prepare the 'result' information - the commands to return in
522
self.slapd_provision_command = [self.slapd_path, "-F" + self.olcdir,
525
# copy this command so we have two version, one with -d0 and only
526
# ldapi (or the forced ldap_uri), and one with all the listen commands
527
self.slapd_command = list(self.slapd_provision_command)
529
self.slapd_provision_command.extend([self.ldap_uri, "-d0"])
532
if server_port_string is not "":
533
uris = uris + " " + server_port_string
535
self.slapd_command.append(uris)
537
# Set the username - done here because Fedora DS still uses the admin
539
self.credentials.set_username("samba-admin")
541
# Wipe the old sam.ldb databases away
542
shutil.rmtree(self.olcdir, True)
543
os.makedirs(self.olcdir, 0770)
545
# If we were just looking for crashes up to this point, it's a
546
# good time to exit before we realise we don't have OpenLDAP on
548
if self.ldap_dryrun_mode:
551
slapd_cmd = [self.slapd_path, "-Ttest", "-n", "0", "-f",
552
self.slapdconf, "-F", self.olcdir]
553
retcode = subprocess.call(slapd_cmd, close_fds=True, shell=False)
556
self.logger.error("conversion from slapd.conf to cn=config failed slapd started with: %s" % "\'" + "\' \'".join(slapd_cmd) + "\'")
557
raise ProvisioningError("conversion from slapd.conf to cn=config failed")
559
if not os.path.exists(os.path.join(self.olcdir, "cn=config.ldif")):
560
raise ProvisioningError("conversion from slapd.conf to cn=config failed")
562
# Don't confuse the admin by leaving the slapd.conf around
563
os.remove(self.slapdconf)
566
class FDSBackend(LDAPBackend):
568
def __init__(self, backend_type, paths=None, lp=None,
569
credentials=None, names=None, logger=None, domainsid=None,
570
schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
571
ldap_backend_extra_port=None, ldap_dryrun_mode=False, root=None,
574
from samba.provision import setup_path
576
super(FDSBackend, self).__init__(backend_type=backend_type,
578
credentials=credentials, names=names, logger=logger,
579
domainsid=domainsid, schema=schema, hostname=hostname,
580
ldapadminpass=ldapadminpass, slapd_path=slapd_path,
581
ldap_backend_extra_port=ldap_backend_extra_port,
582
ldap_backend_forced_uri=ldap_backend_forced_uri,
583
ldap_dryrun_mode=ldap_dryrun_mode)
586
self.setup_ds_path = setup_ds_path
587
self.ldap_instance = self.names.netbiosname.lower()
589
self.sambadn = "CN=Samba"
591
self.fedoradsinf = os.path.join(self.ldapdir, "fedorads.inf")
592
self.partitions_ldif = os.path.join(self.ldapdir,
593
"fedorads-partitions.ldif")
594
self.sasl_ldif = os.path.join(self.ldapdir, "fedorads-sasl.ldif")
595
self.dna_ldif = os.path.join(self.ldapdir, "fedorads-dna.ldif")
596
self.pam_ldif = os.path.join(self.ldapdir, "fedorads-pam.ldif")
597
self.refint_ldif = os.path.join(self.ldapdir, "fedorads-refint.ldif")
598
self.linked_attrs_ldif = os.path.join(self.ldapdir,
599
"fedorads-linked-attributes.ldif")
600
self.index_ldif = os.path.join(self.ldapdir, "fedorads-index.ldif")
601
self.samba_ldif = os.path.join(self.ldapdir, "fedorads-samba.ldif")
603
self.samba3_schema = setup_path(
604
"../../examples/LDAP/samba.schema")
605
self.samba3_ldif = os.path.join(self.ldapdir, "samba3.ldif")
607
self.retcode = subprocess.call(["bin/oLschema2ldif",
608
"-I", self.samba3_schema,
609
"-O", self.samba3_ldif,
610
"-b", self.names.domaindn],
611
close_fds=True, shell=False)
613
if self.retcode != 0:
614
raise Exception("Unable to convert Samba 3 schema.")
616
self.schema = Schema(
618
schemadn=self.names.schemadn,
619
files=[setup_path("schema_samba4.ldif"), self.samba3_ldif],
620
additional_prefixmap=["1000:1.3.6.1.4.1.7165.2.1",
621
"1001:1.3.6.1.4.1.7165.2.2"])
624
from samba.provision import ProvisioningError, setup_path
625
if self.ldap_backend_extra_port is not None:
626
serverport = "ServerPort=%d" % self.ldap_backend_extra_port
630
setup_file(setup_path("fedorads.inf"), self.fedoradsinf,
632
"HOSTNAME": self.hostname,
633
"DNSDOMAIN": self.names.dnsdomain,
634
"LDAPDIR": self.ldapdir,
635
"DOMAINDN": self.names.domaindn,
636
"LDAP_INSTANCE": self.ldap_instance,
637
"LDAPMANAGERDN": self.names.ldapmanagerdn,
638
"LDAPMANAGERPASS": self.ldapadminpass,
639
"SERVERPORT": serverport})
641
setup_file(setup_path("fedorads-partitions.ldif"),
642
self.partitions_ldif,
643
{"CONFIGDN": self.names.configdn,
644
"SCHEMADN": self.names.schemadn,
645
"SAMBADN": self.sambadn,
648
setup_file(setup_path("fedorads-sasl.ldif"), self.sasl_ldif,
649
{"SAMBADN": self.sambadn,
652
setup_file(setup_path("fedorads-dna.ldif"), self.dna_ldif,
653
{"DOMAINDN": self.names.domaindn,
654
"SAMBADN": self.sambadn,
655
"DOMAINSID": str(self.domainsid),
658
setup_file(setup_path("fedorads-pam.ldif"), self.pam_ldif)
660
lnkattr = self.schema.linked_attributes()
662
refint_config = open(setup_path("fedorads-refint-delete.ldif"), 'r').read()
667
for attr in lnkattr.keys():
668
if lnkattr[attr] is not None:
669
refint_config += read_and_sub_file(
670
setup_path("fedorads-refint-add.ldif"),
671
{ "ARG_NUMBER" : str(argnum),
672
"LINK_ATTR" : attr })
673
memberof_config += read_and_sub_file(
674
setup_path("fedorads-linked-attributes.ldif"),
675
{ "MEMBER_ATTR" : attr,
676
"MEMBEROF_ATTR" : lnkattr[attr] })
677
index_config += read_and_sub_file(
678
setup_path("fedorads-index.ldif"), { "ATTR" : attr })
681
open(self.refint_ldif, 'w').write(refint_config)
682
open(self.linked_attrs_ldif, 'w').write(memberof_config)
684
attrs = ["lDAPDisplayName"]
685
res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
687
for i in range (0, len(res)):
688
attr = res[i]["lDAPDisplayName"][0]
690
if attr == "objectGUID":
693
index_config += read_and_sub_file(
694
setup_path("fedorads-index.ldif"), { "ATTR" : attr })
696
open(self.index_ldif, 'w').write(index_config)
698
setup_file(setup_path("fedorads-samba.ldif"), self.samba_ldif, {
699
"SAMBADN": self.sambadn,
700
"LDAPADMINPASS": self.ldapadminpass
703
mapping = "schema-map-fedora-ds-1.0"
704
backend_schema = "99_ad.ldif"
706
# Build a schema file in Fedora DS format
707
backend_schema_data = self.schema.convert_to_openldap("fedora-ds",
708
open(setup_path(mapping), 'r').read())
709
assert backend_schema_data is not None
710
f = open(os.path.join(self.ldapdir, backend_schema), 'w')
712
f.write(backend_schema_data)
716
self.credentials.set_bind_dn(self.names.ldapmanagerdn)
718
# Destory the target directory, or else setup-ds.pl will complain
719
fedora_ds_dir = os.path.join(self.ldapdir,
720
"slapd-" + self.ldap_instance)
721
shutil.rmtree(fedora_ds_dir, True)
723
self.slapd_provision_command = [self.slapd_path, "-D", fedora_ds_dir,
724
"-i", self.slapd_pid]
725
# In the 'provision' command line, stay in the foreground so we can
727
self.slapd_provision_command.append("-d0")
729
#the command for the final run is the normal script
730
self.slapd_command = [os.path.join(self.ldapdir,
731
"slapd-" + self.ldap_instance, "start-slapd")]
733
# If we were just looking for crashes up to this point, it's a
734
# good time to exit before we realise we don't have Fedora DS on
735
if self.ldap_dryrun_mode:
738
# Try to print helpful messages when the user has not specified the
739
# path to the setup-ds tool
740
if self.setup_ds_path is None:
741
raise ProvisioningError("Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
742
if not os.path.exists(self.setup_ds_path):
743
self.logger.warning("Path (%s) to slapd does not exist!",
746
# Run the Fedora DS setup utility
747
retcode = subprocess.call([self.setup_ds_path, "--silent", "--file",
748
self.fedoradsinf], close_fds=True, shell=False)
750
raise ProvisioningError("setup-ds failed")
753
retcode = subprocess.call([
754
os.path.join(self.ldapdir, "slapd-" + self.ldap_instance, "ldif2db"), "-s", self.sambadn, "-i", self.samba_ldif],
755
close_fds=True, shell=False)
757
raise ProvisioningError("ldif2db failed")
759
def post_setup(self):
760
ldapi_db = Ldb(self.ldap_uri, credentials=self.credentials)
762
# configure in-directory access control on Fedora DS via the aci
763
# attribute (over a direct ldapi:// socket)
764
aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % self.sambadn
767
m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
769
for dnstring in (self.names.domaindn, self.names.configdn,
770
self.names.schemadn):
771
m.dn = ldb.Dn(ldapi_db, dnstring)